refactor(auth): drop persisted external oauth ownership metadata

This commit is contained in:
Vincent Koc
2026-04-17 13:28:29 -07:00
parent 2c7c06c9b3
commit a8a701291b
4 changed files with 85 additions and 2 deletions

View File

@@ -131,6 +131,41 @@ describe("saveAuthProfileStore", () => {
}
});
it("does not persist compatibility-only external oauth ownership metadata", async () => {
const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-save-managedby-"));
try {
const store: AuthProfileStore = {
version: 1,
profiles: {
"openai-codex:default": {
type: "oauth",
provider: "openai-codex",
access: "access-token",
refresh: "refresh-token",
expires: 123,
managedBy: "codex-cli",
},
},
};
saveAuthProfileStore(store, agentDir);
const persisted = JSON.parse(await fs.readFile(resolveAuthStorePath(agentDir), "utf8")) as {
profiles: Record<string, Record<string, unknown>>;
};
expect(persisted.profiles["openai-codex:default"]).toMatchObject({
type: "oauth",
provider: "openai-codex",
access: "access-token",
refresh: "refresh-token",
expires: 123,
});
expect(persisted.profiles["openai-codex:default"]?.managedBy).toBeUndefined();
} finally {
await fs.rm(agentDir, { recursive: true, force: true });
}
});
it("writes runtime scheduling state to auth-state.json only", async () => {
const agentDir = await fs.mkdtemp(path.join(os.tmpdir(), "openclaw-auth-save-state-"));
try {

View File

@@ -192,6 +192,10 @@ export function buildPersistedAuthProfileSecretsStore(
if (shouldPersistProfile && !shouldPersistProfile({ profileId, credential })) {
return [];
}
if (credential.type === "oauth" && credential.managedBy) {
const { managedBy: _managedBy, ...canonicalCredential } = credential;
return [[profileId, canonicalCredential]];
}
if (credential.type === "api_key" && credential.keyRef && credential.key !== undefined) {
const sanitized = { ...credential } as Record<string, unknown>;
delete sanitized.key;
@@ -245,7 +249,6 @@ export function applyLegacyAuthStore(store: AuthProfileStore, legacy: LegacyAuth
...(cred.projectId ? { projectId: cred.projectId } : {}),
...(cred.accountId ? { accountId: cred.accountId } : {}),
...(cred.email ? { email: cred.email } : {}),
...(cred.managedBy ? { managedBy: cred.managedBy } : {}),
};
}
}

View File

@@ -141,4 +141,50 @@ describe("resolveCliAuthEpoch", () => {
expect(second).not.toBe(first);
expect(third).not.toBe(second);
});
it("ignores compatibility-only managedBy metadata on auth profiles", async () => {
let store: AuthProfileStore = {
version: 1,
profiles: {
"openai-codex:default": {
type: "oauth",
provider: "openai-codex",
access: "profile-access",
refresh: "profile-refresh",
expires: 1,
managedBy: "codex-cli",
},
},
};
setCliAuthEpochTestDeps({
loadAuthProfileStoreForRuntime: () => store,
});
const first = await resolveCliAuthEpoch({
provider: "codex-cli",
authProfileId: "openai-codex:default",
});
store = {
version: 1,
profiles: {
"openai-codex:default": {
type: "oauth",
provider: "openai-codex",
access: "profile-access",
refresh: "profile-refresh",
expires: 1,
},
},
};
const second = await resolveCliAuthEpoch({
provider: "codex-cli",
authProfileId: "openai-codex:default",
});
expect(first).toBeDefined();
expect(second).toBeDefined();
expect(second).toBe(first);
});
});

View File

@@ -98,7 +98,6 @@ function encodeAuthProfileCredential(credential: AuthProfileCredential): string
credential.enterpriseUrl ?? null,
credential.projectId ?? null,
credential.accountId ?? null,
credential.managedBy ?? null,
]);
}
throw new Error("Unsupported auth profile credential type");