惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

雷峰网
雷峰网
WordPress大学
WordPress大学
MyScale Blog
MyScale Blog
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
T
The Blog of Author Tim Ferriss
U
Unit 42
罗磊的独立博客
G
Google Developers Blog
Microsoft Azure Blog
Microsoft Azure Blog
The Cloudflare Blog
aimingoo的专栏
aimingoo的专栏
Vercel News
Vercel News
N
Netflix TechBlog - Medium
H
Hackread – Cybersecurity News, Data Breaches, AI and More
云风的 BLOG
云风的 BLOG
Hugging Face - Blog
Hugging Face - Blog
大猫的无限游戏
大猫的无限游戏
F
Fortinet All Blogs
博客园 - 聂微东
Stack Overflow Blog
Stack Overflow Blog
小众软件
小众软件
博客园 - 【当耐特】
H
Help Net Security
The GitHub Blog
The GitHub Blog

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
fix(auth): emit one-shot doctor-pointer warning for Keych...
RomneyDa · 2026-05-26 · via Recent Commits to openclaw:main

@@ -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+

});