repositories
loading repo index
repositories
loading repo index
repository
loading code, commits, and activity
public Clawd ADK gateway launch mirror
stars
latest
clone command
git clone gitlawb://did:key:z6Mkq5mY...iFZ5/my-project-publ...git clone gitlawb://did:key:z6Mkq5mY.../my-project-publ...2fa351d6docs: add automaton and perps launch sources16d ago| #1 | /** |
| #2 | * Regression tests for per-agent memory isolation helpers. |
| #3 | * |
| #4 | * Addresses review feedback: targeted coverage for auth/session state, |
| #5 | * malformed input, and the resolveUserId priority chain. |
| #6 | */ |
| #7 | import { describe, it, expect } from "vitest"; |
| #8 | import { |
| #9 | extractAgentId, |
| #10 | effectiveUserId, |
| #11 | agentUserId, |
| #12 | resolveUserId, |
| #13 | } from "./index.ts"; |
| #14 | |
| #15 | // --------------------------------------------------------------------------- |
| #16 | // extractAgentId |
| #17 | // --------------------------------------------------------------------------- |
| #18 | describe("extractAgentId", () => { |
| #19 | it("returns agentId from a well-formed session key", () => { |
| #20 | expect(extractAgentId("agent:researcher:550e8400-e29b")).toBe("researcher"); |
| #21 | }); |
| #22 | |
| #23 | it("returns undefined for the 'main' sentinel", () => { |
| #24 | expect(extractAgentId("agent:main:abc-123")).toBeUndefined(); |
| #25 | }); |
| #26 | |
| #27 | it("returns undefined for undefined/null/empty input", () => { |
| #28 | expect(extractAgentId(undefined)).toBeUndefined(); |
| #29 | expect(extractAgentId("")).toBeUndefined(); |
| #30 | }); |
| #31 | |
| #32 | it("returns undefined for non-agent session keys", () => { |
| #33 | expect(extractAgentId("user:alice:xyz")).toBeUndefined(); |
| #34 | expect(extractAgentId("some-random-uuid")).toBeUndefined(); |
| #35 | }); |
| #36 | |
| #37 | it("handles keys with extra colons after the UUID portion", () => { |
| #38 | expect(extractAgentId("agent:beta:uuid:extra:stuff")).toBe("beta"); |
| #39 | }); |
| #40 | |
| #41 | it("returns undefined when agentId segment is empty", () => { |
| #42 | // pattern: agent::<uuid> — empty agentId |
| #43 | expect(extractAgentId("agent::some-uuid")).toBeUndefined(); |
| #44 | }); |
| #45 | |
| #46 | it("returns undefined when key is only 'agent:' with no trailing colon", () => { |
| #47 | expect(extractAgentId("agent:")).toBeUndefined(); |
| #48 | }); |
| #49 | |
| #50 | it("is case-sensitive (Agent != agent)", () => { |
| #51 | expect(extractAgentId("Agent:researcher:uuid")).toBeUndefined(); |
| #52 | }); |
| #53 | |
| #54 | it("handles whitespace-only agentId as truthy string", () => { |
| #55 | // " " is a non-empty match — returned as-is (validation is caller's job) |
| #56 | expect(extractAgentId("agent: :uuid")).toBe(" "); |
| #57 | }); |
| #58 | }); |
| #59 | |
| #60 | // --------------------------------------------------------------------------- |
| #61 | // effectiveUserId |
| #62 | // --------------------------------------------------------------------------- |
| #63 | describe("effectiveUserId", () => { |
| #64 | const base = "alice"; |
| #65 | |
| #66 | it("returns base userId when sessionKey is undefined", () => { |
| #67 | expect(effectiveUserId(base)).toBe("alice"); |
| #68 | expect(effectiveUserId(base, undefined)).toBe("alice"); |
| #69 | }); |
| #70 | |
| #71 | it("returns namespaced userId for agent session keys", () => { |
| #72 | expect(effectiveUserId(base, "agent:researcher:uuid-1")).toBe( |
| #73 | "alice:agent:researcher", |
| #74 | ); |
| #75 | }); |
| #76 | |
| #77 | it("falls back to base for 'main' agent sessions", () => { |
| #78 | expect(effectiveUserId(base, "agent:main:uuid-2")).toBe("alice"); |
| #79 | }); |
| #80 | |
| #81 | it("falls back to base for non-agent session keys", () => { |
| #82 | expect(effectiveUserId(base, "plain-session-id")).toBe("alice"); |
| #83 | }); |
| #84 | }); |
| #85 | |
| #86 | // --------------------------------------------------------------------------- |
| #87 | // agentUserId |
| #88 | // --------------------------------------------------------------------------- |
| #89 | describe("agentUserId", () => { |
| #90 | it("produces the correct namespaced format", () => { |
| #91 | expect(agentUserId("alice", "researcher")).toBe("alice:agent:researcher"); |
| #92 | }); |
| #93 | |
| #94 | it("handles empty agentId (caller is responsible for validation)", () => { |
| #95 | expect(agentUserId("alice", "")).toBe("alice:agent:"); |
| #96 | }); |
| #97 | }); |
| #98 | |
| #99 | // --------------------------------------------------------------------------- |
| #100 | // resolveUserId — priority chain |
| #101 | // --------------------------------------------------------------------------- |
| #102 | describe("resolveUserId", () => { |
| #103 | const base = "alice"; |
| #104 | |
| #105 | it("prefers explicit agentId over everything else", () => { |
| #106 | expect( |
| #107 | resolveUserId( |
| #108 | base, |
| #109 | { agentId: "researcher", userId: "bob" }, |
| #110 | "agent:beta:uuid", |
| #111 | ), |
| #112 | ).toBe("alice:agent:researcher"); |
| #113 | }); |
| #114 | |
| #115 | it("uses explicit userId when agentId is absent", () => { |
| #116 | expect( |
| #117 | resolveUserId(base, { userId: "bob" }, "agent:beta:uuid"), |
| #118 | ).toBe("bob"); |
| #119 | }); |
| #120 | |
| #121 | it("derives from session key when both agentId and userId are absent", () => { |
| #122 | expect( |
| #123 | resolveUserId(base, {}, "agent:gamma:uuid"), |
| #124 | ).toBe("alice:agent:gamma"); |
| #125 | }); |
| #126 | |
| #127 | it("falls back to base userId when nothing else is provided", () => { |
| #128 | expect(resolveUserId(base, {})).toBe("alice"); |
| #129 | expect(resolveUserId(base, {}, undefined)).toBe("alice"); |
| #130 | }); |
| #131 | |
| #132 | it("ignores empty-string agentId (falsy)", () => { |
| #133 | expect(resolveUserId(base, { agentId: "" })).toBe("alice"); |
| #134 | }); |
| #135 | |
| #136 | it("ignores empty-string userId (falsy)", () => { |
| #137 | expect(resolveUserId(base, { userId: "" })).toBe("alice"); |
| #138 | }); |
| #139 | }); |
| #140 | |
| #141 | // --------------------------------------------------------------------------- |
| #142 | // Cross-agent isolation sanity checks |
| #143 | // --------------------------------------------------------------------------- |
| #144 | describe("multi-agent isolation", () => { |
| #145 | const base = "user-42"; |
| #146 | |
| #147 | it("different agents get different namespaces", () => { |
| #148 | const alphaId = effectiveUserId(base, "agent:alpha:uuid-a"); |
| #149 | const betaId = effectiveUserId(base, "agent:beta:uuid-b"); |
| #150 | expect(alphaId).not.toBe(betaId); |
| #151 | expect(alphaId).toBe("user-42:agent:alpha"); |
| #152 | expect(betaId).toBe("user-42:agent:beta"); |
| #153 | }); |
| #154 | |
| #155 | it("same agent across sessions yields the same namespace", () => { |
| #156 | const s1 = effectiveUserId(base, "agent:alpha:session-1"); |
| #157 | const s2 = effectiveUserId(base, "agent:alpha:session-2"); |
| #158 | expect(s1).toBe(s2); |
| #159 | }); |
| #160 | |
| #161 | it("main session shares the base namespace (no isolation)", () => { |
| #162 | const mainId = effectiveUserId(base, "agent:main:uuid-m"); |
| #163 | expect(mainId).toBe(base); |
| #164 | }); |
| #165 | }); |
| #166 |