mirror of
https://github.com/openclaw/openclaw.git
synced 2026-03-27 09:21:35 +07:00
Gateway: require caller scope for subagent session deletion (#55281)
This commit is contained in:
@@ -470,16 +470,59 @@ describe("loadGatewayPlugins", () => {
|
||||
expect(getLastDispatchedClientScopes()).not.toContain("operator.admin");
|
||||
});
|
||||
|
||||
test("keeps admin scope for fallback session deletion", async () => {
|
||||
test("rejects fallback session deletion without minting admin scope", async () => {
|
||||
const serverPlugins = serverPluginsModule;
|
||||
const runtime = await createSubagentRuntime(serverPlugins);
|
||||
serverPlugins.setFallbackGatewayContext(createTestContext("synthetic-delete-session"));
|
||||
|
||||
await runtime.deleteSession({
|
||||
sessionKey: "s-delete",
|
||||
deleteTranscript: true,
|
||||
handleGatewayRequest.mockImplementationOnce(async (opts: HandleGatewayRequestOptions) => {
|
||||
// Re-run the gateway scope check here so the test proves fallback dispatch
|
||||
// does not smuggle admin into the request client.
|
||||
const scopes = Array.isArray(opts.client?.connect?.scopes) ? opts.client.connect.scopes : [];
|
||||
const auth = methodScopesModule.authorizeOperatorScopesForMethod("sessions.delete", scopes);
|
||||
if (!auth.allowed) {
|
||||
opts.respond(false, undefined, {
|
||||
code: "INVALID_REQUEST",
|
||||
message: `missing scope: ${auth.missingScope}`,
|
||||
});
|
||||
return;
|
||||
}
|
||||
opts.respond(true, {});
|
||||
});
|
||||
|
||||
await expect(
|
||||
runtime.deleteSession({
|
||||
sessionKey: "s-delete",
|
||||
deleteTranscript: true,
|
||||
}),
|
||||
).rejects.toThrow("missing scope: operator.admin");
|
||||
|
||||
expect(getLastDispatchedClientScopes()).toEqual(["operator.write"]);
|
||||
expect(getLastDispatchedClientScopes()).not.toContain("operator.admin");
|
||||
});
|
||||
|
||||
test("allows session deletion when the request scope already has admin", async () => {
|
||||
const serverPlugins = serverPluginsModule;
|
||||
const runtime = await createSubagentRuntime(serverPlugins);
|
||||
const scope = {
|
||||
context: createTestContext("request-scope-delete-session"),
|
||||
client: {
|
||||
connect: {
|
||||
scopes: ["operator.admin"],
|
||||
},
|
||||
} as GatewayRequestOptions["client"],
|
||||
isWebchatConnect: () => false,
|
||||
} satisfies PluginRuntimeGatewayRequestScope;
|
||||
|
||||
await expect(
|
||||
gatewayRequestScopeModule.withPluginRuntimeGatewayRequestScope(scope, () =>
|
||||
runtime.deleteSession({
|
||||
sessionKey: "s-delete-admin",
|
||||
deleteTranscript: true,
|
||||
}),
|
||||
),
|
||||
).resolves.toBeUndefined();
|
||||
|
||||
expect(getLastDispatchedClientScopes()).toEqual(["operator.admin"]);
|
||||
});
|
||||
|
||||
|
||||
@@ -367,16 +367,10 @@ export function createGatewaySubagentRuntime(): PluginRuntime["subagent"] {
|
||||
return getSessionMessages(params);
|
||||
},
|
||||
async deleteSession(params) {
|
||||
await dispatchGatewayMethod(
|
||||
"sessions.delete",
|
||||
{
|
||||
key: params.sessionKey,
|
||||
deleteTranscript: params.deleteTranscript ?? true,
|
||||
},
|
||||
{
|
||||
syntheticScopes: [ADMIN_SCOPE],
|
||||
},
|
||||
);
|
||||
await dispatchGatewayMethod("sessions.delete", {
|
||||
key: params.sessionKey,
|
||||
deleteTranscript: params.deleteTranscript ?? true,
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user