


























@@ -0,0 +1,142 @@
1+import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
2+import { resetLogger, setLoggerOverride } from "../../logging/logger.js";
3+import { loggingState } from "../../logging/state.js";
4+import {
5+createOpenClawTestState,
6+type OpenClawTestState,
7+} from "../../test-utils/openclaw-test-state.js";
8+import {
9+legacyOAuthSidecarInternalTestUtils,
10+legacyOAuthSidecarTestUtils,
11+loadLegacyOAuthSidecarMaterial,
12+} from "./legacy-oauth-sidecar.js";
13+14+const states: OpenClawTestState[] = [];
15+16+function setPlatform(value: NodeJS.Platform): () => void {
17+const descriptor = Object.getOwnPropertyDescriptor(process, "platform");
18+Object.defineProperty(process, "platform", { value, configurable: true });
19+return () => {
20+if (descriptor) {
21+Object.defineProperty(process, "platform", descriptor);
22+}
23+};
24+}
25+26+async function writeLegacySidecarThatNeedsKeychain(): Promise<{
27+state: OpenClawTestState;
28+ref: { source: "openclaw-credentials"; provider: "openai-codex"; id: string };
29+profileId: string;
30+}> {
31+const state = await createOpenClawTestState({
32+layout: "state-only",
33+prefix: "openclaw-legacy-oauth-keychain-warn-",
34+env: {
35+OPENCLAW_AGENT_DIR: undefined,
36+OPENCLAW_AUTH_PROFILE_SECRET_KEY: undefined,
37+},
38+});
39+states.push(state);
40+const profileId = "openai-codex:default";
41+const ref = {
42+source: "openclaw-credentials" as const,
43+provider: "openai-codex" as const,
44+id: "0123456789abcdef0123456789abcdef",
45+};
46+await state.writeJson(`credentials/auth-profiles/${ref.id}.json`, {
47+version: 1,
48+ profileId,
49+provider: "openai-codex",
50+encrypted: legacyOAuthSidecarTestUtils.encryptLegacyOAuthMaterial({
51+ ref,
52+ profileId,
53+provider: "openai-codex",
54+seed: "only-in-keychain",
55+material: { access: "a", refresh: "b", idToken: "c" },
56+}),
57+});
58+return { state, ref, profileId };
59+}
60+61+afterEach(async () => {
62+for (const state of states.splice(0)) {
63+await state.cleanup();
64+}
65+legacyOAuthSidecarInternalTestUtils.resetKeychainOnlyMigrationHint();
66+});
67+68+describe("loadLegacyOAuthSidecarMaterial keychain-only headless warning", () => {
69+let restorePlatform: () => void;
70+let warnSpy: ReturnType<typeof vi.fn>;
71+72+beforeEach(() => {
73+restorePlatform = setPlatform("darwin");
74+setLoggerOverride({ level: "warn", consoleLevel: "warn" });
75+warnSpy = vi.fn();
76+loggingState.rawConsole = {
77+log: vi.fn(),
78+info: vi.fn(),
79+warn: warnSpy as unknown as typeof console.warn,
80+error: vi.fn(),
81+};
82+});
83+84+afterEach(() => {
85+restorePlatform();
86+loggingState.rawConsole = null;
87+setLoggerOverride(null);
88+resetLogger();
89+});
90+91+function envWithoutVitestSignals(state: OpenClawTestState): NodeJS.ProcessEnv {
92+const env: NodeJS.ProcessEnv = { ...state.env };
93+delete env.VITEST;
94+delete env.VITEST_WORKER_ID;
95+return env;
96+}
97+98+it("emits a single doctor-pointer warning when only Keychain can decrypt and prompts are disabled", async () => {
99+const { state, ref, profileId } = await writeLegacySidecarThatNeedsKeychain();
100+const env = envWithoutVitestSignals(state);
101+102+const firstAttempt = loadLegacyOAuthSidecarMaterial({
103+ ref,
104+ profileId,
105+provider: "openai-codex",
106+allowKeychainPrompt: false,
107+ env,
108+});
109+expect(firstAttempt).toBeNull();
110+expect(warnSpy).toHaveBeenCalledTimes(1);
111+const [firstMessage] = warnSpy.mock.calls[0] as [unknown];
112+expect(String(firstMessage)).toContain("openclaw doctor --fix");
113+expect(String(firstMessage)).toContain("macOS Keychain");
114+115+const secondAttempt = loadLegacyOAuthSidecarMaterial({
116+ ref,
117+ profileId,
118+provider: "openai-codex",
119+allowKeychainPrompt: false,
120+ env,
121+});
122+expect(secondAttempt).toBeNull();
123+expect(warnSpy).toHaveBeenCalledTimes(1);
124+});
125+126+it("does not emit the doctor-pointer warning on non-darwin platforms", async () => {
127+restorePlatform();
128+restorePlatform = setPlatform("linux");
129+const { state, ref, profileId } = await writeLegacySidecarThatNeedsKeychain();
130+const env = envWithoutVitestSignals(state);
131+132+const attempt = loadLegacyOAuthSidecarMaterial({
133+ ref,
134+ profileId,
135+provider: "openai-codex",
136+allowKeychainPrompt: false,
137+ env,
138+});
139+expect(attempt).toBeNull();
140+expect(warnSpy).not.toHaveBeenCalled();
141+});
142+});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。