mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 05:50:43 +00:00
fix: preserve session visibility semantics for runSessionKey (#76708)
- Track isSemanticCurrentRequest before key rewrite - Skip early explicit-agent-key visibility check for current requests - Add isSemanticCurrentRequest to shouldTreatVisibilityTargetAsSelf - Fix test to use default/tree visibility instead of 'all' - Add negative guard test for explicit cross-session key rejection
This commit is contained in:
@@ -492,7 +492,7 @@ describe("session_status tool", () => {
|
||||
expect(details.sessionKey).toBe("main");
|
||||
});
|
||||
|
||||
it("resolves sessionKey=current to runSessionKey when sandbox key differs from live session (#76708)", async () => {
|
||||
it("resolves sessionKey=current to runSessionKey under default tree visibility (#76708)", async () => {
|
||||
resetSessionStore({
|
||||
"agent:main:telegram:default:direct:1234": {
|
||||
sessionId: "s-tg-direct",
|
||||
@@ -506,15 +506,13 @@ describe("session_status tool", () => {
|
||||
},
|
||||
});
|
||||
|
||||
// The tool is constructed with the Telegram sandbox key as agentSessionKey
|
||||
// but the actual live run session key as runSessionKey.
|
||||
// Default visibility is "tree". The tool is constructed with the Telegram
|
||||
// sandbox key as agentSessionKey but the live run session key as runSessionKey.
|
||||
// semantic-current must be treated as self for visibility purposes.
|
||||
const tool = createSessionStatusTool({
|
||||
agentSessionKey: "agent:main:telegram:default:direct:1234",
|
||||
runSessionKey: "agent:main:main",
|
||||
config: {
|
||||
...mockConfig,
|
||||
tools: { ...mockConfig.tools, sessions: { visibility: "all" } },
|
||||
} as never,
|
||||
config: mockConfig as never,
|
||||
});
|
||||
|
||||
const result = await tool.execute("call-current-run-session", { sessionKey: "current" });
|
||||
@@ -523,6 +521,32 @@ describe("session_status tool", () => {
|
||||
expect(details.sessionKey).toBe("agent:main:main");
|
||||
});
|
||||
|
||||
it("rejects explicit cross-session key under tree visibility even when it equals runSessionKey (#76708)", async () => {
|
||||
resetSessionStore({
|
||||
"agent:main:telegram:default:direct:1234": {
|
||||
sessionId: "s-tg-direct",
|
||||
updatedAt: 5,
|
||||
status: "done",
|
||||
},
|
||||
"agent:main:main": {
|
||||
sessionId: "s-main",
|
||||
updatedAt: 10,
|
||||
status: "running",
|
||||
},
|
||||
});
|
||||
|
||||
// Same setup but with an explicit key — should NOT bypass visibility.
|
||||
const tool = createSessionStatusTool({
|
||||
agentSessionKey: "agent:main:telegram:default:direct:1234",
|
||||
runSessionKey: "agent:main:main",
|
||||
config: mockConfig as never,
|
||||
});
|
||||
|
||||
await expect(
|
||||
tool.execute("call-explicit-key", { sessionKey: "agent:main:main" }),
|
||||
).rejects.toThrow(/visibility is restricted/);
|
||||
});
|
||||
|
||||
it("treats the TUI client label as the current requester session", async () => {
|
||||
resetSessionStore({
|
||||
"agent:main:main": {
|
||||
|
||||
@@ -353,9 +353,18 @@ export function createSessionStatusTool(opts?: {
|
||||
const requestedKeyParam = readStringParam(params, "sessionKey");
|
||||
let requestedKeyRaw = requestedKeyParam ?? opts?.agentSessionKey;
|
||||
|
||||
// When sessionKey is literally "current" and a runSessionKey is provided,
|
||||
// resolve directly to the live run session instead of falling through to
|
||||
// stale sandbox/policy key resolution (#76708).
|
||||
// Track whether this is a semantic-current request (literal "current" or a
|
||||
// current-client alias) BEFORE any rewrite, so visibility treats it as self.
|
||||
const isSemanticCurrentRequest =
|
||||
requestedKeyRaw === "current" ||
|
||||
Boolean(
|
||||
resolveCurrentSessionClientAlias({
|
||||
key: requestedKeyRaw ?? "",
|
||||
requesterInternalKey: effectiveRequesterKey,
|
||||
}),
|
||||
);
|
||||
|
||||
// Resolve "current" to the live run session key for lookup purposes (#76708).
|
||||
if (requestedKeyRaw === "current" && opts?.runSessionKey) {
|
||||
requestedKeyRaw = opts.runSessionKey;
|
||||
}
|
||||
@@ -365,9 +374,6 @@ export function createSessionStatusTool(opts?: {
|
||||
requesterInternalKey: effectiveRequesterKey,
|
||||
});
|
||||
if (currentSessionAlias) {
|
||||
// When a runSessionKey is provided (e.g. the live run session key), prefer it
|
||||
// over the sandbox/policy key so "current" resolves to the active run session
|
||||
// instead of a stale sandbox key (e.g. a Telegram direct peer key).
|
||||
requestedKeyRaw = opts?.runSessionKey ?? currentSessionAlias;
|
||||
}
|
||||
const requestedKeyInput = requestedKeyRaw?.trim() ?? "";
|
||||
@@ -391,7 +397,7 @@ export function createSessionStatusTool(opts?: {
|
||||
}
|
||||
};
|
||||
|
||||
if (requestedKeyRaw.startsWith("agent:")) {
|
||||
if (requestedKeyRaw.startsWith("agent:") && !isSemanticCurrentRequest) {
|
||||
const requestedAgentId = resolveAgentIdFromSessionKey(requestedKeyRaw);
|
||||
ensureAgentAccess(requestedAgentId);
|
||||
const access = visibilityGuard.check(
|
||||
@@ -518,6 +524,7 @@ export function createSessionStatusTool(opts?: {
|
||||
|
||||
// Preserve caller-scoped raw-key/current lookups as "self" for visibility checks.
|
||||
const shouldTreatVisibilityTargetAsSelf =
|
||||
isSemanticCurrentRequest ||
|
||||
resolvedViaImplicitCurrentFallback ||
|
||||
(!resolvedViaSessionId &&
|
||||
(requestedKeyInput === "current" || resolved.key === requestedKeyInput));
|
||||
|
||||
Reference in New Issue
Block a user