mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-24 11:25:50 -06:00
fix: preserve configured ACP deleted-agent guard
This commit is contained in:
@@ -846,6 +846,22 @@ describe("gateway session utils", () => {
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
test("resolveDeletedAgentIdFromSessionKey rejects deleted configured ACP binding owners", () => {
|
||||
const cfg = {
|
||||
agents: { list: [{ id: "main", default: true }] },
|
||||
} as OpenClawConfig;
|
||||
|
||||
expect(
|
||||
resolveDeletedAgentIdFromSessionKey(
|
||||
cfg,
|
||||
"agent:deleted-agent:acp:binding:discord:default:feedface",
|
||||
),
|
||||
).toBe("deleted-agent");
|
||||
expect(
|
||||
resolveDeletedAgentIdFromSessionKey(cfg, "agent:main:acp:binding:discord:default:feedface"),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
test("resolveSessionStoreKey canonicalizes bare keys to default agent", () => {
|
||||
const cfg = {
|
||||
session: { mainKey: "main" },
|
||||
|
||||
@@ -922,14 +922,15 @@ export function resolveDeletedAgentIdFromSessionKey(
|
||||
cfg: OpenClawConfig,
|
||||
sessionKey: string,
|
||||
): string | null {
|
||||
// ACP keys use agent:<harnessId>:acp:<uuid>; harness ids are not agents.list entries.
|
||||
if (isAcpSessionKey(sessionKey)) {
|
||||
return null;
|
||||
}
|
||||
const parsed = parseAgentSessionKey(sessionKey);
|
||||
if (!parsed) {
|
||||
return null;
|
||||
}
|
||||
// Free ACP spawn keys use agent:<harnessId>:acp:<uuid>, but configured ACP
|
||||
// bindings use agent:<agentId>:acp:binding:* where agentId remains the owner.
|
||||
if (isAcpSessionKey(sessionKey) && !parsed.rest.startsWith("acp:binding:")) {
|
||||
return null;
|
||||
}
|
||||
const agentId = normalizeAgentId(parsed.agentId);
|
||||
if (listAgentIds(cfg).includes(agentId)) {
|
||||
return null;
|
||||
|
||||
@@ -248,6 +248,51 @@ describe("resolveSessionKeyFromResolveParams store canonicalization", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("rejects configured ACP binding sessions when their owning agent is deleted", async () => {
|
||||
await withStateDirEnv("openclaw-sessions-resolve-acp-binding-deleted-", async () => {
|
||||
const cfg: OpenClawConfig = {
|
||||
agents: { list: [{ id: "main", default: true }] },
|
||||
};
|
||||
const acpBindingKey = "agent:deleted-agent:acp:binding:discord:default:feedface";
|
||||
const deletedStorePath = resolveStorePath(cfg.session?.store, { agentId: "deleted-agent" });
|
||||
await saveSessionStore(deletedStorePath, {
|
||||
[acpBindingKey]: {
|
||||
sessionId: "sess-acp-binding-deleted",
|
||||
label: "deleted-binding",
|
||||
updatedAt: freshUpdatedAt(),
|
||||
},
|
||||
});
|
||||
const expected = {
|
||||
ok: false,
|
||||
error: {
|
||||
code: ErrorCodes.INVALID_REQUEST,
|
||||
message: 'Agent "deleted-agent" no longer exists in configuration',
|
||||
},
|
||||
};
|
||||
|
||||
await expect(
|
||||
resolveSessionKeyFromResolveParams({
|
||||
cfg,
|
||||
p: { key: acpBindingKey },
|
||||
}),
|
||||
).resolves.toEqual(expected);
|
||||
|
||||
await expect(
|
||||
resolveSessionKeyFromResolveParams({
|
||||
cfg,
|
||||
p: { sessionId: "sess-acp-binding-deleted" },
|
||||
}),
|
||||
).resolves.toEqual(expected);
|
||||
|
||||
await expect(
|
||||
resolveSessionKeyFromResolveParams({
|
||||
cfg,
|
||||
p: { label: "deleted-binding" },
|
||||
}),
|
||||
).resolves.toEqual(expected);
|
||||
});
|
||||
});
|
||||
|
||||
it("rejects an explicit listed deleted main key instead of remapping to the live default main", async () => {
|
||||
await withStateDirEnv("openclaw-sessions-resolve-key-deleted-main-", async () => {
|
||||
const cfg: OpenClawConfig = {
|
||||
|
||||
Reference in New Issue
Block a user