test(e2e): seed OAuth authority-chain shared store through its owner

oauth-refresh-authority-chain.e2e failed 2 of 3 cases in the 2026.9.7 repo
E2E Gateway 4/4 lane (readSharedCredential returned undefined). The fixture
wrote the shared auth store straight into the state database without
initializing shared-auth ownership, so the test process resolved and cached
legacy-main ownership while the Gateway later published state-db ownership;
the test then read the empty legacy store. The connect-time ownership reload
no longer covered that gap. Product rotation and mismatch fencing behaved
correctly.

Seed every scenario (including the empty logout store) through
runAuthProfileWriteTransaction so the test and the Gateway select the same
canonical owner before any turn, and drop the obsolete reload. All behavior
assertions are unchanged.

Proof: reproduced 2 failed / 1 passed on origin/main; after the change the
file passes 3/3 (119 s wall, includes Gateway restart and logout), owner
auth-profile tests 7/7.
This commit is contained in:
Peter Steinberger 2026-09-28 18:48:40 -07:00
parent 5b76930a9b
commit 70d7e7abf6

View file

@ -8,19 +8,18 @@ import {
isOAuthRefreshFence,
isPendingOAuthRefreshFence,
} from "../src/agents/auth-profiles/oauth-refresh-marker.js";
import { reloadSharedAuthStoreOwnership } from "../src/agents/auth-profiles/path-resolve.js";
import {
loadPersistedAuthProfileStore,
loadPersistedSharedAuthProfileStore,
} from "../src/agents/auth-profiles/persisted.js";
import { writePersistedAuthProfileStoreRaw } from "../src/agents/auth-profiles/sqlite.js";
import {
runAuthProfileWriteTransaction,
writePersistedAuthProfileStoreRaw,
} from "../src/agents/auth-profiles/sqlite.js";
import type { AuthProfileStore, OAuthCredential } from "../src/agents/auth-profiles/types.js";
import { connectGatewayClient, disconnectGatewayClient } from "../src/gateway/test-helpers.e2e.js";
import { closeOpenClawAgentDatabasesForTest } from "../src/state/openclaw-agent-db.js";
import {
closeOpenClawStateDatabaseForTest,
runOpenClawStateWriteTransaction,
} from "../src/state/openclaw-state-db.js";
import { closeOpenClawStateDatabaseForTest } from "../src/state/openclaw-state-db.js";
import { writeOpenAiResponsesText } from "./helpers/openai-responses-sse.js";
import {
createOpenClawTestInstance,
@ -130,7 +129,7 @@ function authStore(credential?: OAuthCredential): AuthProfileStore {
return {
version: 1,
profiles: credential ? { [PROFILE_ID]: credential } : {},
order: { [PROVIDER_ID]: [PROFILE_ID] },
...(credential ? { order: { [PROVIDER_ID]: [PROFILE_ID] } } : {}),
};
}
@ -410,7 +409,8 @@ async function createScenario(name: string): Promise<Scenario> {
}
function writeSharedStore(instance: OpenClawTestInstance, store: AuthProfileStore): void {
runOpenClawStateWriteTransaction(
runAuthProfileWriteTransaction(
undefined,
(database) => writePersistedAuthProfileStoreRaw(store, undefined, database),
{ env: instance.env },
);
@ -422,9 +422,7 @@ async function seedScenario(params: {
owner: OAuthCredential;
peer: OAuthCredential;
}): Promise<void> {
if (params.shared) {
writeSharedStore(params.instance, authStore(params.shared));
}
writeSharedStore(params.instance, authStore(params.shared));
await params.instance.state.writeAuthProfiles(authStore(params.owner), "owner");
await params.instance.state.writeAuthProfiles(authStore(params.peer), "peer");
closeOpenClawAgentDatabasesForTest(params.instance.stateDir);
@ -468,8 +466,6 @@ function expectAuthError(result: AgentResult, message: string): void {
}
async function connect(instance: OpenClawTestInstance) {
// Gateway startup can publish shared-auth ownership from its separate process.
reloadSharedAuthStoreOwnership(instance.env);
const client = await connectGatewayClient({
url: instance.url,
token: instance.gatewayToken,