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

推荐订阅源

C
Check Point Blog
U
Unit 42
Threat Intelligence Blog | Flashpoint
Threat Intelligence Blog | Flashpoint
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
Martin Fowler
Martin Fowler
L
LangChain Blog
博客园_首页
博客园 - 【当耐特】
Vercel News
Vercel News
I
InfoQ
GbyAI
GbyAI
爱范儿
爱范儿
D
DataBreaches.Net
Blog — PlanetScale
Blog — PlanetScale
B
Blog RSS Feed
A
About on SuperTechFans
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
G
Google Developers Blog
大猫的无限游戏
大猫的无限游戏
Apple Machine Learning Research
Apple Machine Learning Research
F
Fortinet All Blogs
N
Netflix TechBlog - Medium
酷 壳 – CoolShell
酷 壳 – CoolShell
P
Proofpoint News Feed
美团技术团队
V
V2EX
Stack Overflow Blog
Stack Overflow Blog
有赞技术团队
有赞技术团队
Y
Y Combinator Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
H
Help Net Security
Recent Announcements
Recent Announcements
Microsoft Azure Blog
Microsoft Azure Blog
D
Docker
宝玉的分享
宝玉的分享
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
量子位
小众软件
小众软件
J
Java Code Geeks
S
SegmentFault 最新的问题
Engineering at Meta
Engineering at Meta
Google DeepMind News
Google DeepMind News
MongoDB | Blog
MongoDB | Blog
The Cloudflare Blog
Recorded Future
Recorded Future
阮一峰的网络日志
阮一峰的网络日志
T
The Blog of Author Tim Ferriss
MyScale Blog
MyScale Blog
Microsoft Security Blog
Microsoft Security 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 test: trim doctor command hotspots · openclaw/openclaw@c66f16a test: isolate agent auth and spawn hotspots · openclaw/openclaw@9285935 test: stabilize MCP startup disposal race · openclaw/openclaw@dd9d2eb test: merge browser contract server suites · openclaw/openclaw@5817a76 test: narrow ollama provider discovery setup · openclaw/openclaw@a0d9598 build: declare qa-lab aimock runtime dependency · openclaw/openclaw@24431e5 test: speed up safe-bins exec harness · openclaw/openclaw@ee856ab test: preserve tool helpers in embedded runner mocks · openclaw/openclaw@acd86a0 refactor: move memory embeddings into provider plugins · openclaw/openclaw@77e6e4c test: reuse system-run temp fixtures · openclaw/openclaw@7e9ff0f test: trim hotspot wait overhead · openclaw/openclaw@12a59b0 Check: avoid duplicate boundary prep · openclaw/openclaw@baf11b8 test: reduce hotspot fixture overhead · openclaw/openclaw@3a59edd feat(ui): overhaul settings and slash command UX (#67819) thanks @Bun… · openclaw/openclaw@2cfb660 QA Matrix: exit cleanly on failure · openclaw/openclaw@42805d2 QA Matrix: isolate scenario coverage · openclaw/openclaw@7e659e1 Matrix: refresh crypto bootstrap state · openclaw/openclaw@94081d8 QA Lab: add provider registry · openclaw/openclaw@bb7e982 Matrix: add plugin changelog · openclaw/openclaw@4acab55 test: trim more hotspot overhead · openclaw/openclaw@f485311 test: trim remaining hotspot tests · openclaw/openclaw@6ba8626 test: narrow hotspot mocks · openclaw/openclaw@dbc8179 test: isolate gemini embedding request helpers · openclaw/openclaw@cd330f5 test: trim memory and mcp hotspots · openclaw/openclaw@fd48dfa test: slim provider registry mocks · openclaw/openclaw@2e08c77 test: harden Parallels update smoke · openclaw/openclaw@1a98090 feat: default Anthropic to Opus 4.7 · openclaw/openclaw@628b454 fix: harden node-host shell payload mutability checks · openclaw/openclaw@75c551e fix: land node-host approval binding for native binaries (#66731) (th… · openclaw/openclaw@29919bb CI: add daily schedule to CodeQL workflow (#67645) · openclaw/openclaw@69d25f5 fix(gateway): capture config hash after plugin auto-enable to prevent… · openclaw/openclaw@8c11210 fix: repair sanitized replay tool results before send (#67620) (thank… · openclaw/openclaw@c3c7a99 fix: restrict HTML timeout short-circuit to transient statuses · openclaw/openclaw@de129a6 fix: keep TUI watchdog bound to active run (#67401) (thanks @xantorres) · openclaw/openclaw@3525273 Gateway/skills: dedupe skills prefix-match + drop dead fallback on log · openclaw/openclaw@d7f489f Extensions/lmstudio: back off inference preload after consecutive fai… · openclaw/openclaw@b555214 TUI/streaming: add watchdog that resets the activity indicator after … · openclaw/openclaw@f44ab20 Agents/tool-loop: enable unknown-tool stream guard by default · openclaw/openclaw@36ed367 Gateway/skills: invalidate session skills snapshot on config write · openclaw/openclaw@b23d59a fix: classify HTML provider error pages correctly (#67642) (thanks @s… · openclaw/openclaw@e588e90 fix(skills): remove unused model-usage import (#67641) · openclaw/openclaw@55f05df docs(changelog): credit codex fix superseded PRs · openclaw/openclaw@e485f24 fix(openai-codex): normalize stale transport metadata in resolution a… · openclaw/openclaw@90801ba CI: pin Docker-related GitHub Actions (#67632) · openclaw/openclaw@f697b01 Android: modernize WebView and discovery API usage (#67627) · openclaw/openclaw@44a6e50 fix(deps): bump hono to 4.12.14 and @hono/node-server to 1.19.14 (GHS… · openclaw/openclaw@fbccc18 fix(deps): bump dompurify to 3.4.0 (#67614) · openclaw/openclaw@2c2dc00 CI: add explicit permissions to all workflow jobs (fixes code-scannin… · openclaw/openclaw@01b7516 fix: register bundled TTS providers and route overrides correctly (#6… · openclaw/openclaw@6ea3cdd fix: align host tilde paths with OS home (#62804) (thanks @stainlu) · openclaw/openclaw@ecfaf64 fix: flush creds queue before reconnect socket open (#67464) (thanks … · openclaw/openclaw@405c63f fix: strip standalone <function> tool call tags from visible text (#6… · openclaw/openclaw@78df859 fix(agents): preserve cli session metadata before transcript persist … · openclaw/openclaw@898fd04 docs(changelog): move cli transcript entry · openclaw/openclaw@c1817c6 fix(agents): normalize cli transcript api field · openclaw/openclaw@3a3fae0 docs(changelog): note cli transcript persistence · openclaw/openclaw@6c343f1 fix(agents): persist cli transcript turns · openclaw/openclaw@b8ef507 fix(msteams): harden security-sensitive flows (#65841) · openclaw/openclaw@c56b56e [Dashboard] Fix exec approval modal overflow for long command content… · openclaw/openclaw@053c5b0 Docs: remove QA changelog entry · openclaw/openclaw@7fd5771 QA: fix private runtime source loading (#67428) · openclaw/openclaw@d5933af docs(gateway): correct protocol.md schema path, hello-ok example, aut… · openclaw/openclaw@489404d CI: pin Node 22 runners to 22.18.0 · openclaw/openclaw@4ffa621 models.authStatus: normalize provider ids + tighten env-backed escape… · openclaw/openclaw@f2fdb9d Update CHANGELOG.md · openclaw/openclaw@7694a92 test(parallels): clean up npm update guard jobs · openclaw/openclaw@045ea7b Plugins: prefer scanDir override paths · openclaw/openclaw@b2974da fix(dreaming): default storage.mode to "separate" so phase blocks sto… · openclaw/openclaw@8c392f0 fix(memory-core): skip dreaming transcript ingestion via session stor… · openclaw/openclaw@a1b01f0 fix: dedupe replayed exec.finished node events (#67281) · openclaw/openclaw@5dcf526
test: isolate auth profile state dirs · openclaw/openclaw@53978b3
shakkernerd · 2026-06-05 · via Recent Commits to openclaw:main

@@ -10,6 +10,7 @@ import { describe, expect, it } from "vitest";

1010

import { resolveOAuthDir } from "../../config/paths.js";

1111

import { closeOpenClawAgentDatabasesForTest } from "../../state/openclaw-agent-db.js";

1212

import { closeOpenClawStateDatabaseForTest } from "../../state/openclaw-state-db.js";

13+

import { withEnvAsync } from "../../test-utils/env.js";

1314

import { AUTH_STORE_VERSION } from "./constants.js";

1415

import { loadPersistedAuthProfileStore } from "./persisted.js";

1516

import {

@@ -36,6 +37,39 @@ type ExpectedOAuthCredentialFields = {

3637

chatgptPlanType?: string;

3738

};

383940+

type AuthProfileTestState = {

41+

stateDir: string;

42+

agentDir: string;

43+

agentDirFor: (agentId: string) => string;

44+

};

45+46+

async function withAuthProfileTestState<T>(

47+

prefix: string,

48+

run: (state: AuthProfileTestState) => Promise<T> | T,

49+

options: { clearOAuthDir?: boolean } = {},

50+

): Promise<T> {

51+

const stateDir = fs.mkdtempSync(path.join(os.tmpdir(), prefix));

52+

const agentDirFor = (agentId: string) => path.join(stateDir, "agents", agentId, "agent");

53+

try {

54+

return await withEnvAsync(

55+

{

56+

OPENCLAW_STATE_DIR: stateDir,

57+

...(options.clearOAuthDir ? { OPENCLAW_OAUTH_DIR: undefined } : {}),

58+

},

59+

async () =>

60+

await run({

61+

stateDir,

62+

agentDir: agentDirFor("main"),

63+

agentDirFor,

64+

}),

65+

);

66+

} finally {

67+

closeOpenClawAgentDatabasesForTest();

68+

closeOpenClawStateDatabaseForTest();

69+

fs.rmSync(stateDir, { recursive: true, force: true });

70+

}

71+

}

72+3973

function expectOAuthCredentialFields(

4074

value: unknown,

4175

expected: ExpectedOAuthCredentialFields,

@@ -64,66 +98,48 @@ function expectOAuthCredentialFields(

64986599

describe("promoteAuthProfileInOrder", () => {

66100

it("normalizes copied secrets when using the locked upsert path", async () => {

67-

const stateDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-auth-profile-upsert-"));

68-

const agentDir = path.join(stateDir, "agents", "main", "agent");

69-

const previousStateDir = process.env.OPENCLAW_STATE_DIR;

70-

const previousOAuthDir = process.env.OPENCLAW_OAUTH_DIR;

71-

process.env.OPENCLAW_STATE_DIR = stateDir;

72-

delete process.env.OPENCLAW_OAUTH_DIR;

73-

try {

74-

fs.mkdirSync(agentDir, { recursive: true });

101+

await withAuthProfileTestState(

102+

"openclaw-auth-profile-upsert-",

103+

async ({ agentDir }) => {

104+

fs.mkdirSync(agentDir, { recursive: true });

105+106+

await upsertAuthProfileWithLock({

107+

profileId: "openai:manual",

108+

credential: {

109+

type: "token",

110+

provider: "openai",

111+

token: " bearer\r\n-token\u2502 ",

112+

},

113+

agentDir,

114+

});

115+

await upsertAuthProfileWithLock({

116+

profileId: "anthropic:key",

117+

credential: {

118+

type: "api_key",

119+

provider: "anthropic",

120+

key: " sk-\r\nant\u2502 ",

121+

},

122+

agentDir,

123+

});

7512476-

await upsertAuthProfileWithLock({

77-

profileId: "openai:manual",

78-

credential: {

125+

const profiles = loadAuthProfileStoreWithoutExternalProfiles(agentDir).profiles;

126+

expect(profiles["openai:manual"]).toMatchObject({

79127

type: "token",

80128

provider: "openai",

81-

token: " bearer\r\n-token\u2502 ",

82-

},

83-

agentDir,

84-

});

85-

await upsertAuthProfileWithLock({

86-

profileId: "anthropic:key",

87-

credential: {

129+

token: "bearer-token",

130+

});

131+

expect(profiles["anthropic:key"]).toMatchObject({

88132

type: "api_key",

89133

provider: "anthropic",

90-

key: " sk-\r\nant\u2502 ",

91-

},

92-

agentDir,

93-

});

94-95-

const profiles = loadAuthProfileStoreWithoutExternalProfiles(agentDir).profiles;

96-

expect(profiles["openai:manual"]).toMatchObject({

97-

type: "token",

98-

provider: "openai",

99-

token: "bearer-token",

100-

});

101-

expect(profiles["anthropic:key"]).toMatchObject({

102-

type: "api_key",

103-

provider: "anthropic",

104-

key: "sk-ant",

105-

});

106-

} finally {

107-

if (previousStateDir === undefined) {

108-

delete process.env.OPENCLAW_STATE_DIR;

109-

} else {

110-

process.env.OPENCLAW_STATE_DIR = previousStateDir;

111-

}

112-

if (previousOAuthDir === undefined) {

113-

delete process.env.OPENCLAW_OAUTH_DIR;

114-

} else {

115-

process.env.OPENCLAW_OAUTH_DIR = previousOAuthDir;

116-

}

117-

fs.rmSync(stateDir, { recursive: true, force: true });

118-

}

134+

key: "sk-ant",

135+

});

136+

},

137+

{ clearOAuthDir: true },

138+

);

119139

});

120140121-

it("persists openai oauth credentials inline", () => {

122-

const stateDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-auth-profile-metadata-"));

123-

const agentDir = path.join(stateDir, "agents", "main", "agent");

124-

const previousStateDir = process.env.OPENCLAW_STATE_DIR;

125-

process.env.OPENCLAW_STATE_DIR = stateDir;

126-

try {

141+

it("persists openai oauth credentials inline", async () => {

142+

await withAuthProfileTestState("openclaw-auth-profile-metadata-", ({ agentDir }) => {

127143

fs.mkdirSync(agentDir, { recursive: true });

128144

const profileId = "openai:default";

129145

const expires = Date.now() + 60 * 60 * 1000;

@@ -173,24 +189,11 @@ describe("promoteAuthProfileInOrder", () => {

173189

idToken: "local-id-token",

174190

},

175191

);

176-

} finally {

177-

if (previousStateDir === undefined) {

178-

delete process.env.OPENCLAW_STATE_DIR;

179-

} else {

180-

process.env.OPENCLAW_STATE_DIR = previousStateDir;

181-

}

182-

closeOpenClawAgentDatabasesForTest();

183-

closeOpenClawStateDatabaseForTest();

184-

fs.rmSync(stateDir, { recursive: true, force: true });

185-

}

192+

});

186193

});

187194188-

it("preserves access-only openai oauth credentials inline", () => {

189-

const stateDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-auth-profile-access-only-"));

190-

const agentDir = path.join(stateDir, "agents", "main", "agent");

191-

const previousStateDir = process.env.OPENCLAW_STATE_DIR;

192-

process.env.OPENCLAW_STATE_DIR = stateDir;

193-

try {

195+

it("preserves access-only openai oauth credentials inline", async () => {

196+

await withAuthProfileTestState("openclaw-auth-profile-access-only-", ({ agentDir }) => {

194197

fs.mkdirSync(agentDir, { recursive: true });

195198

const profileId = "openai:default";

196199

const expires = Date.now() + 60 * 60 * 1000;

@@ -226,25 +229,13 @@ describe("promoteAuthProfileInOrder", () => {

226229

access: "access-only-token",

227230

},

228231

);

229-

} finally {

230-

if (previousStateDir === undefined) {

231-

delete process.env.OPENCLAW_STATE_DIR;

232-

} else {

233-

process.env.OPENCLAW_STATE_DIR = previousStateDir;

234-

}

235-

closeOpenClawAgentDatabasesForTest();

236-

closeOpenClawStateDatabaseForTest();

237-

fs.rmSync(stateDir, { recursive: true, force: true });

238-

}

232+

});

239233

});

240234241-

it("keeps copied openai oauth profiles inline", () => {

242-

const stateDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-auth-profile-copy-ref-"));

243-

const mainAgentDir = path.join(stateDir, "agents", "main", "agent");

244-

const copiedAgentDir = path.join(stateDir, "agents", "copied", "agent");

245-

const previousStateDir = process.env.OPENCLAW_STATE_DIR;

246-

process.env.OPENCLAW_STATE_DIR = stateDir;

247-

try {

235+

it("keeps copied openai oauth profiles inline", async () => {

236+

await withAuthProfileTestState("openclaw-auth-profile-copy-ref-", ({ agentDirFor }) => {

237+

const mainAgentDir = agentDirFor("main");

238+

const copiedAgentDir = agentDirFor("copied");

248239

fs.mkdirSync(mainAgentDir, { recursive: true });

249240

fs.mkdirSync(copiedAgentDir, { recursive: true });

250241

const originalProfileId = "openai:default";

@@ -308,24 +299,11 @@ describe("promoteAuthProfileInOrder", () => {

308299

access: "copy-access-token",

309300

refresh: "copy-refresh-token",

310301

});

311-

} finally {

312-

if (previousStateDir === undefined) {

313-

delete process.env.OPENCLAW_STATE_DIR;

314-

} else {

315-

process.env.OPENCLAW_STATE_DIR = previousStateDir;

316-

}

317-

closeOpenClawAgentDatabasesForTest();

318-

closeOpenClawStateDatabaseForTest();

319-

fs.rmSync(stateDir, { recursive: true, force: true });

320-

}

302+

});

321303

});

322304323305

it("moves a relogin profile to the front of an existing per-agent provider order", async () => {

324-

const stateDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-auth-order-promote-"));

325-

const agentDir = path.join(stateDir, "agents", "main", "agent");

326-

const previousStateDir = process.env.OPENCLAW_STATE_DIR;

327-

process.env.OPENCLAW_STATE_DIR = stateDir;

328-

try {

306+

await withAuthProfileTestState("openclaw-auth-order-promote-", async ({ agentDir }) => {

329307

fs.mkdirSync(agentDir, { recursive: true });

330308

const newProfileId = "openai:bunsthedev@gmail.com";

331309

const staleProfileId = "openai:val@viewdue.ai";

@@ -367,22 +345,11 @@ describe("promoteAuthProfileInOrder", () => {

367345

newProfileId,

368346

staleProfileId,

369347

]);

370-

} finally {

371-

if (previousStateDir === undefined) {

372-

delete process.env.OPENCLAW_STATE_DIR;

373-

} else {

374-

process.env.OPENCLAW_STATE_DIR = previousStateDir;

375-

}

376-

fs.rmSync(stateDir, { recursive: true, force: true });

377-

}

348+

});

378349

});

379350380351

it("creates a per-agent provider order when relogin has no existing order", async () => {

381-

const stateDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-auth-order-create-"));

382-

const agentDir = path.join(stateDir, "agents", "main", "agent");

383-

const previousStateDir = process.env.OPENCLAW_STATE_DIR;

384-

process.env.OPENCLAW_STATE_DIR = stateDir;

385-

try {

352+

await withAuthProfileTestState("openclaw-auth-order-create-", async ({ agentDir }) => {

386353

fs.mkdirSync(agentDir, { recursive: true });

387354

const newProfileId = "openai:new-login";

388355

const primaryProfileId = "openai:primary-login";

@@ -439,22 +406,11 @@ describe("promoteAuthProfileInOrder", () => {

439406

backupProfileId,

440407

primaryProfileId,

441408

]);

442-

} finally {

443-

if (previousStateDir === undefined) {

444-

delete process.env.OPENCLAW_STATE_DIR;

445-

} else {

446-

process.env.OPENCLAW_STATE_DIR = previousStateDir;

447-

}

448-

fs.rmSync(stateDir, { recursive: true, force: true });

449-

}

409+

});

450410

});

451411452412

it("preserves config-only fallback ids when creating a relogin order", async () => {

453-

const stateDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-auth-order-config-only-"));

454-

const agentDir = path.join(stateDir, "agents", "main", "agent");

455-

const previousStateDir = process.env.OPENCLAW_STATE_DIR;

456-

process.env.OPENCLAW_STATE_DIR = stateDir;

457-

try {

413+

await withAuthProfileTestState("openclaw-auth-order-config-only-", async ({ agentDir }) => {

458414

fs.mkdirSync(agentDir, { recursive: true });

459415

const newProfileId = "openai:new-login";

460416

const existingProfileId = "openai:old-login";

@@ -501,22 +457,11 @@ describe("promoteAuthProfileInOrder", () => {

501457

existingProfileId,

502458

configOnlyProfileId,

503459

]);

504-

} finally {

505-

if (previousStateDir === undefined) {

506-

delete process.env.OPENCLAW_STATE_DIR;

507-

} else {

508-

process.env.OPENCLAW_STATE_DIR = previousStateDir;

509-

}

510-

fs.rmSync(stateDir, { recursive: true, force: true });

511-

}

460+

});

512461

});

513462514463

it("keeps implicit round-robin when relogin has no existing order by default", async () => {

515-

const stateDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-auth-order-implicit-"));

516-

const agentDir = path.join(stateDir, "agents", "main", "agent");

517-

const previousStateDir = process.env.OPENCLAW_STATE_DIR;

518-

process.env.OPENCLAW_STATE_DIR = stateDir;

519-

try {

464+

await withAuthProfileTestState("openclaw-auth-order-implicit-", async ({ agentDir }) => {

520465

fs.mkdirSync(agentDir, { recursive: true });

521466

const newProfileId = "openai:new-login";

522467

saveAuthProfileStore(

@@ -543,22 +488,11 @@ describe("promoteAuthProfileInOrder", () => {

543488544489

expect(updated?.order?.["openai"]).toBeUndefined();

545490

expect(loadAuthProfileStoreForRuntime(agentDir).order?.["openai"]).toBeUndefined();

546-

} finally {

547-

if (previousStateDir === undefined) {

548-

delete process.env.OPENCLAW_STATE_DIR;

549-

} else {

550-

process.env.OPENCLAW_STATE_DIR = previousStateDir;

551-

}

552-

fs.rmSync(stateDir, { recursive: true, force: true });

553-

}

491+

});

554492

});

555493556494

it("clears matching lastGood after a stale refresh_token_reused profile", async () => {

557-

const stateDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-auth-clear-lastgood-"));

558-

const agentDir = path.join(stateDir, "agents", "main", "agent");

559-

const previousStateDir = process.env.OPENCLAW_STATE_DIR;

560-

process.env.OPENCLAW_STATE_DIR = stateDir;

561-

try {

495+

await withAuthProfileTestState("openclaw-auth-clear-lastgood-", async ({ agentDir }) => {

562496

fs.mkdirSync(agentDir, { recursive: true });

563497

const staleProfileId = "openai:default";

564498

saveAuthProfileStore(

@@ -585,22 +519,11 @@ describe("promoteAuthProfileInOrder", () => {

585519

});

586520587521

expect(loadAuthProfileStoreForRuntime(agentDir).lastGood).toBeUndefined();

588-

} finally {

589-

if (previousStateDir === undefined) {

590-

delete process.env.OPENCLAW_STATE_DIR;

591-

} else {

592-

process.env.OPENCLAW_STATE_DIR = previousStateDir;

593-

}

594-

fs.rmSync(stateDir, { recursive: true, force: true });

595-

}

522+

});

596523

});

597524598525

it("does not clear lastGood when the failed profile is not the stored profile", async () => {

599-

const stateDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-auth-clear-lastgood-keep-"));

600-

const agentDir = path.join(stateDir, "agents", "main", "agent");

601-

const previousStateDir = process.env.OPENCLAW_STATE_DIR;

602-

process.env.OPENCLAW_STATE_DIR = stateDir;

603-

try {

526+

await withAuthProfileTestState("openclaw-auth-clear-lastgood-keep-", async ({ agentDir }) => {

604527

fs.mkdirSync(agentDir, { recursive: true });

605528

const goodProfileId = "openai:user@example.test";

606529

saveAuthProfileStore(

@@ -627,13 +550,6 @@ describe("promoteAuthProfileInOrder", () => {

627550

});

628551629552

expect(loadAuthProfileStoreForRuntime(agentDir).lastGood?.["openai"]).toBe(goodProfileId);

630-

} finally {

631-

if (previousStateDir === undefined) {

632-

delete process.env.OPENCLAW_STATE_DIR;

633-

} else {

634-

process.env.OPENCLAW_STATE_DIR = previousStateDir;

635-

}

636-

fs.rmSync(stateDir, { recursive: true, force: true });

637-

}

553+

});

638554

});

639555

});