fix: scope CLI auth epochs to agent stores

This commit is contained in:
Shakker
2026-06-15 19:05:28 +01:00
committed by Shakker
parent 8f66a9028c
commit 71c112219f
3 changed files with 68 additions and 1 deletions

View File

@@ -47,6 +47,71 @@ describe("resolveCliAuthEpoch", () => {
).resolves.toBeUndefined();
});
it("loads auth-profile epochs from the selected agent directory", async () => {
const stores: Record<string, AuthProfileStore> = {
"/agents/work/agent": {
version: 1,
profiles: {
"google-gemini-cli:default": {
type: "oauth",
provider: "google-gemini-cli",
access: "work-access",
refresh: "work-refresh",
expires: 1,
email: "work@example.test",
projectId: "work-project",
},
},
},
"/agents/personal/agent": {
version: 1,
profiles: {
"google-gemini-cli:default": {
type: "oauth",
provider: "google-gemini-cli",
access: "personal-access",
refresh: "personal-refresh",
expires: 1,
email: "personal@example.test",
projectId: "personal-project",
},
},
},
};
const loadAuthProfileStoreForRuntime = vi.fn((agentDir?: string) => {
return stores[agentDir ?? ""] ?? { version: 1, profiles: {} };
});
setCliAuthEpochTestDeps({
readGeminiCliCredentialsCached: () => null,
loadAuthProfileStoreForRuntime,
});
const work = await resolveCliAuthEpoch({
provider: "google-gemini-cli",
agentDir: "/agents/work/agent",
authProfileId: "google-gemini-cli:default",
skipLocalCredential: true,
});
const personal = await resolveCliAuthEpoch({
provider: "google-gemini-cli",
agentDir: "/agents/personal/agent",
authProfileId: "google-gemini-cli:default",
skipLocalCredential: true,
});
expectCliAuthEpoch(work);
expectCliAuthEpoch(personal);
expect(work).not.toBe(personal);
expect(loadAuthProfileStoreForRuntime).toHaveBeenCalledWith("/agents/work/agent", {
readOnly: true,
allowKeychainPrompt: false,
});
expect(loadAuthProfileStoreForRuntime).toHaveBeenCalledWith("/agents/personal/agent", {
readOnly: true,
allowKeychainPrompt: false,
});
});
it("keeps identity-less claude cli oauth epochs stable across token changes", async () => {
let access = "access-a";
let refresh = "refresh-a";

View File

@@ -208,6 +208,7 @@ function getAuthProfileCredential(
/** Resolves the stable auth epoch hash for a CLI runtime/provider session. */
export async function resolveCliAuthEpoch(params: {
provider: string;
agentDir?: string;
authProfileId?: string;
skipLocalCredential?: boolean;
}): Promise<string | undefined> {
@@ -223,7 +224,7 @@ export async function resolveCliAuthEpoch(params: {
}
if (authProfileId) {
const store = cliAuthEpochDeps.loadAuthProfileStoreForRuntime(undefined, {
const store = cliAuthEpochDeps.loadAuthProfileStoreForRuntime(params.agentDir, {
readOnly: true,
allowKeychainPrompt: false,
});

View File

@@ -485,6 +485,7 @@ export async function prepareCliRunContext(
});
const authEpoch = await resolveCliAuthEpoch({
provider: params.provider,
agentDir,
authProfileId: effectiveAuthProfileId,
skipLocalCredential: skipLocalCredentialEpoch,
});