Skip to content

Commit 96049e7

Browse files
committed
Prove concurrent sub-agent ALS scopes keep agent labels isolated
Two overlapping runWithSubAgentIdentity scopes must not cross-contaminate agentLabel or cwd on the permission requests they raise.
1 parent 9c5742b commit 96049e7

1 file changed

Lines changed: 31 additions & 0 deletions

File tree

src/permission/permission.test.ts

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2806,4 +2806,35 @@ describe("sub-agent identity on permission requests", () => {
28062806
expect(withA?.agentLabel).toBe("Worker A");
28072807
expect(withoutLabel?.agentLabel).toBeUndefined();
28082808
});
2809+
2810+
test("two concurrent ALS scopes keep their agent labels isolated", async () => {
2811+
const { runWithSubAgentIdentity } = await import("../subagent/identity-context.js");
2812+
const seen: PermissionRequest[] = [];
2813+
const gate = createPermissionGate({
2814+
approvals: [],
2815+
requestApproval: async (request) => {
2816+
seen.push(request);
2817+
// Hold both approvals open so the two scopes truly overlap.
2818+
await new Promise((r) => setTimeout(r, 5));
2819+
return { allow: true };
2820+
},
2821+
interactive: true,
2822+
skipPermissions: false,
2823+
cwd: "/repo",
2824+
});
2825+
await Promise.all([
2826+
runWithSubAgentIdentity({ description: "Worker A", cwd: "/repo-a" }, () =>
2827+
gate.evaluate(shellCall("npm run a")),
2828+
),
2829+
runWithSubAgentIdentity({ description: "Worker B", cwd: "/repo-b" }, () =>
2830+
gate.evaluate(shellCall("npm run b")),
2831+
),
2832+
]);
2833+
const withA = seen.find((r) => r.subject === "npm run a");
2834+
const withB = seen.find((r) => r.subject === "npm run b");
2835+
expect(withA?.agentLabel).toBe("Worker A");
2836+
expect(withA?.cwd).toBe("/repo-a");
2837+
expect(withB?.agentLabel).toBe("Worker B");
2838+
expect(withB?.cwd).toBe("/repo-b");
2839+
});
28092840
});

0 commit comments

Comments
 (0)