diff --git a/scripts/e2e/lib/npm-onboard-channel-agent/assertions.mjs b/scripts/e2e/lib/npm-onboard-channel-agent/assertions.mjs index 70e1340d87df..1f12c2905a3d 100644 --- a/scripts/e2e/lib/npm-onboard-channel-agent/assertions.mjs +++ b/scripts/e2e/lib/npm-onboard-channel-agent/assertions.mjs @@ -77,8 +77,8 @@ function extractStatusSection(text, title) { return stripAnsi(section.join("\n")); } -function readAuthProfileStoreText(agentDir) { - const dbPath = path.join(agentDir, "openclaw-agent.sqlite"); +function readSharedAuthProfileStoreText(stateDir) { + const dbPath = path.join(stateDir, "state", "openclaw.sqlite"); if (!fs.existsSync(dbPath)) { return ""; } @@ -86,8 +86,8 @@ function readAuthProfileStoreText(agentDir) { try { db = new DatabaseSync(dbPath, { readOnly: true }); const row = db - .prepare("SELECT store_json FROM auth_profile_store WHERE store_key = ?") - .get("primary"); + .prepare("SELECT store_json FROM auth_profile_stores WHERE store_key = ?") + .get("shared"); return typeof row?.store_json === "string" ? row.store_json : ""; } catch { return ""; @@ -100,15 +100,21 @@ function assertOnboardState() { const home = process.argv[3]; const stateDir = path.join(home, ".openclaw"); const configPath = path.join(stateDir, "openclaw.json"); - const agentDir = path.join(stateDir, "agents", "main", "agent"); + const legacyAuthDatabase = path.join( + stateDir, + "agents", + "main", + "agent", + "openclaw-agent.sqlite", + ); if (!fs.existsSync(configPath)) { throw new Error("onboard did not write openclaw.json"); } - if (!fs.existsSync(agentDir)) { - throw new Error("onboard did not create main agent dir"); + if (fs.existsSync(legacyAuthDatabase)) { + throw new Error("onboard created the retired main-agent auth database"); } - const authStoreText = readAuthProfileStoreText(agentDir); + const authStoreText = readSharedAuthProfileStoreText(stateDir); if (!authStoreText) { throw new Error("onboard did not persist auth profile store"); } diff --git a/test/scripts/npm-onboard-channel-agent-assertions.test.ts b/test/scripts/npm-onboard-channel-agent-assertions.test.ts index 64c96e58b618..e725794f655f 100644 --- a/test/scripts/npm-onboard-channel-agent-assertions.test.ts +++ b/test/scripts/npm-onboard-channel-agent-assertions.test.ts @@ -37,12 +37,13 @@ function writeOnboardConfig(home: string): void { ); } -function writeAuthProfileStoreSqlite(agentDir: string, store: unknown): void { - fs.mkdirSync(agentDir, { recursive: true }); - const db = new DatabaseSync(path.join(agentDir, "openclaw-agent.sqlite")); +function writeSharedAuthProfileStoreSqlite(home: string, store: unknown): void { + const stateDir = path.join(home, ".openclaw", "state"); + fs.mkdirSync(stateDir, { recursive: true }); + const db = new DatabaseSync(path.join(stateDir, "openclaw.sqlite")); try { db.exec(` - CREATE TABLE IF NOT EXISTS auth_profile_store ( + CREATE TABLE IF NOT EXISTS auth_profile_stores ( store_key TEXT NOT NULL PRIMARY KEY, store_json TEXT NOT NULL, updated_at INTEGER NOT NULL @@ -50,10 +51,10 @@ function writeAuthProfileStoreSqlite(agentDir: string, store: unknown): void { `); db.prepare( ` - INSERT INTO auth_profile_store (store_key, store_json, updated_at) + INSERT INTO auth_profile_stores (store_key, store_json, updated_at) VALUES (?, ?, ?) `, - ).run("primary", JSON.stringify(store), Date.now()); + ).run("shared", JSON.stringify(store), Date.now()); } finally { db.close(); } @@ -217,13 +218,13 @@ describe("npm onboard channel agent assertions", () => { } }); - it("validates OpenAI env refs from the SQLite auth profile store", () => { + it("validates OpenAI env refs from the shared SQLite auth profile store", () => { const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-onboard-assertions-")); const agentDir = path.join(tempDir, ".openclaw", "agents", "main", "agent"); try { writeOnboardConfig(tempDir); - writeAuthProfileStoreSqlite(agentDir, { + writeSharedAuthProfileStoreSqlite(tempDir, { version: 1, profiles: { "openai:api-key": { @@ -238,6 +239,7 @@ describe("npm onboard channel agent assertions", () => { expect(result.status).toBe(0); expect(result.stderr).toBe(""); + expect(fs.existsSync(agentDir)).toBe(false); expect(fs.existsSync(path.join(agentDir, "auth-profiles.json"))).toBe(false); } finally { fs.rmSync(tempDir, { force: true, recursive: true }); @@ -257,11 +259,10 @@ describe("npm onboard channel agent assertions", () => { for (const store of cases) { const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-onboard-assertions-")); - const agentDir = path.join(tempDir, ".openclaw", "agents", "main", "agent"); try { writeOnboardConfig(tempDir); - writeAuthProfileStoreSqlite(agentDir, store); + writeSharedAuthProfileStoreSqlite(tempDir, store); const result = runOnboardAssert(tempDir); @@ -275,11 +276,9 @@ describe("npm onboard channel agent assertions", () => { it("rejects inline OpenAI keys in the SQLite auth profile store", () => { const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-onboard-assertions-")); - const agentDir = path.join(tempDir, ".openclaw", "agents", "main", "agent"); - try { writeOnboardConfig(tempDir); - writeAuthProfileStoreSqlite(agentDir, { + writeSharedAuthProfileStoreSqlite(tempDir, { version: 1, profiles: { "openai:api-key": { @@ -299,6 +298,34 @@ describe("npm onboard channel agent assertions", () => { } }); + it("rejects a fresh install that recreates the retired main-agent auth database", () => { + const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-onboard-assertions-")); + const legacyAgentDir = path.join(tempDir, ".openclaw", "agents", "main", "agent"); + + try { + writeOnboardConfig(tempDir); + writeSharedAuthProfileStoreSqlite(tempDir, { + version: 1, + profiles: { + "openai:api-key": { + type: "api_key", + provider: "openai", + keyRef: { source: "env", provider: "default", id: "OPENAI_API_KEY" }, + }, + }, + }); + fs.mkdirSync(legacyAgentDir, { recursive: true }); + new DatabaseSync(path.join(legacyAgentDir, "openclaw-agent.sqlite")).close(); + + const result = runOnboardAssert(tempDir); + + expect(result.status).not.toBe(0); + expect(result.stderr).toContain("onboard created the retired main-agent auth database"); + } finally { + fs.rmSync(tempDir, { force: true, recursive: true }); + } + }); + it("validates channel tokens in their canonical config fields", () => { const tempDir = fs.mkdtempSync(path.join(os.tmpdir(), "openclaw-channel-assertions-")); try {