Files
openclaw/extensions/migrate-hermes/secrets.test.ts
Peter Steinberger 694ca50e97 Revert "refactor: move runtime state to SQLite"
This reverts commit f91de52f0d.
2026-05-13 13:33:38 +01:00

188 lines
5.8 KiB
TypeScript

import fs from "node:fs/promises";
import path from "node:path";
import type { OpenClawConfig } from "openclaw/plugin-sdk/provider-auth";
import { afterEach, describe, expect, it } from "vitest";
import { HERMES_REASON_AUTH_PROFILE_EXISTS } from "./items.js";
import { buildHermesMigrationProvider } from "./provider.js";
import { cleanupTempRoots, makeContext, makeTempRoot, writeFile } from "./test/provider-helpers.js";
async function expectMissingPath(filePath: string): Promise<void> {
try {
await fs.access(filePath);
} catch (error) {
expect((error as NodeJS.ErrnoException).code).toBe("ENOENT");
return;
}
throw new Error(`expected missing path: ${filePath}`);
}
describe("Hermes migration secret items", () => {
afterEach(async () => {
await cleanupTempRoots();
});
it("uses configured agentDir for secret planning and imports without runtime helpers", async () => {
const root = await makeTempRoot();
const source = path.join(root, "hermes");
const workspaceDir = path.join(root, "workspace");
const stateDir = path.join(root, "state");
const customAgentDir = path.join(root, "custom-agent");
await writeFile(path.join(source, ".env"), "OPENAI_API_KEY=sk-hermes\n");
const config = {
agents: {
defaults: {
workspace: workspaceDir,
},
list: [
{
id: "custom",
default: true,
agentDir: customAgentDir,
},
],
},
} as OpenClawConfig;
const provider = buildHermesMigrationProvider();
const plan = await provider.plan(
makeContext({
source,
stateDir,
workspaceDir,
config,
includeSecrets: true,
}),
);
expect(plan.metadata?.agentDir).toBe(customAgentDir);
expect(plan.items).toEqual([
{
id: "secret:openai",
kind: "secret",
action: "create",
source: path.join(source, ".env"),
target: `${customAgentDir}/auth-profiles.json#openai:hermes-import`,
status: "planned",
sensitive: true,
details: {
envVar: "OPENAI_API_KEY",
provider: "openai",
profileId: "openai:hermes-import",
},
},
]);
const result = await provider.apply(
makeContext({
source,
stateDir,
workspaceDir,
config,
includeSecrets: true,
overwrite: true,
reportDir: path.join(root, "report"),
}),
);
expect(result.summary.errors).toBe(0);
const authStore = JSON.parse(
await fs.readFile(path.join(customAgentDir, "auth-profiles.json"), "utf8"),
) as {
profiles?: Record<
string,
{ displayName?: string; key?: string; provider?: string; type?: string }
>;
};
expect(authStore.profiles?.["openai:hermes-import"]).toEqual({
type: "api_key",
provider: "openai",
key: "sk-hermes",
displayName: "Hermes import",
});
await expectMissingPath(path.join(stateDir, "agents", "custom", "agent", "auth-profiles.json"));
});
it("keeps secret conflict checks read-only during planning", async () => {
const root = await makeTempRoot();
const source = path.join(root, "hermes");
const workspaceDir = path.join(root, "workspace");
const stateDir = path.join(root, "state");
const agentDir = path.join(stateDir, "agents", "main", "agent");
await writeFile(path.join(source, ".env"), "OPENAI_API_KEY=sk-hermes\n");
await writeFile(
path.join(agentDir, "auth.json"),
JSON.stringify({
openai: { type: "api_key", provider: "openai", key: "legacy-main-key" },
}),
);
const provider = buildHermesMigrationProvider();
await provider.plan(makeContext({ source, stateDir, workspaceDir, includeSecrets: true }));
await expect(fs.access(path.join(agentDir, "auth.json"))).resolves.toBeUndefined();
await expectMissingPath(path.join(agentDir, "auth-profiles.json"));
});
it("reports late-created auth profiles as conflicts without overwriting", async () => {
const root = await makeTempRoot();
const source = path.join(root, "hermes");
const workspaceDir = path.join(root, "workspace");
const stateDir = path.join(root, "state");
const reportDir = path.join(root, "report");
const agentDir = path.join(stateDir, "agents", "main", "agent");
await writeFile(path.join(source, ".env"), "OPENAI_API_KEY=sk-hermes\n");
const provider = buildHermesMigrationProvider();
const ctx = makeContext({
source,
stateDir,
workspaceDir,
includeSecrets: true,
reportDir,
});
const plan = await provider.plan(ctx);
await writeFile(
path.join(agentDir, "auth-profiles.json"),
JSON.stringify(
{
version: 1,
profiles: {
"openai:hermes-import": {
type: "api_key",
provider: "openai",
key: "sk-late",
},
},
},
null,
2,
),
);
const result = await provider.apply(ctx, plan);
expect(result.items).toEqual([
{
id: "secret:openai",
kind: "secret",
action: "create",
source: path.join(source, ".env"),
target: `${agentDir}/auth-profiles.json#openai:hermes-import`,
status: "conflict",
sensitive: true,
reason: HERMES_REASON_AUTH_PROFILE_EXISTS,
details: {
envVar: "OPENAI_API_KEY",
provider: "openai",
profileId: "openai:hermes-import",
},
},
]);
expect(result.summary.conflicts).toBe(1);
const authStore = JSON.parse(
await fs.readFile(path.join(agentDir, "auth-profiles.json"), "utf8"),
) as { profiles?: Record<string, { key?: string }> };
expect(authStore.profiles?.["openai:hermes-import"]?.key).toBe("sk-late");
});
});