diff --git a/test/e2e/live/rebuild-hermes-old-sandbox.ts b/test/e2e/live/rebuild-hermes-old-sandbox.ts index 228fe337f6c..f04ab22400f 100644 --- a/test/e2e/live/rebuild-hermes-old-sandbox.ts +++ b/test/e2e/live/rebuild-hermes-old-sandbox.ts @@ -7,6 +7,7 @@ import { formatSandboxBaseImageResolutionLabels } from "../../../src/lib/sandbox interface RebuildHermesOldSandboxDockerfileOptions { baseTag: string; baseResolutionMetadata: Parameters[0] | null; + apiServerKey: string; discordPlaceholder: string; kanbanTaskTitle: string; } @@ -47,6 +48,7 @@ export function buildRebuildHermesOldSandboxDockerfile( " && printf '%s\\n' \\", " 'API_SERVER_PORT=18642' \\", " 'API_SERVER_HOST=127.0.0.1' \\", + ` 'API_SERVER_KEY=${options.apiServerKey}' \\`, ` 'DISCORD_BOT_TOKEN=${options.discordPlaceholder}' \\`, " > /sandbox/.hermes/.env", "RUN /usr/local/bin/hermes kanban init \\", diff --git a/test/e2e/live/rebuild-hermes.test.ts b/test/e2e/live/rebuild-hermes.test.ts index aeef638a05d..9508739eada 100644 --- a/test/e2e/live/rebuild-hermes.test.ts +++ b/test/e2e/live/rebuild-hermes.test.ts @@ -90,6 +90,7 @@ const KANBAN_TASK_TITLE = `NEMOCLAW_REBUILD_KANBAN_${Date.now()}`; const EXCLUDED_KANBAN_FILE = "/sandbox/.hermes/kanban/excluded-rebuild-marker.txt"; const DISCORD_PLACEHOLDER = "openshell:resolve:env:DISCORD_BOT_TOKEN"; const DISCORD_FAKE_TOKEN = "test-fake-discord-token-rebuild-e2e"; +const PRE_REBUILD_API_SERVER_KEY = createHash("sha256").update(MARKER_CONTENT).digest("hex"); const REGISTRY_FILE = path.join(os.homedir(), ".nemoclaw", "sandboxes.json"); const SESSION_FILE = path.join(os.homedir(), ".nemoclaw", "onboard-session.json"); const BACKUP_ROOT = path.join(os.homedir(), ".nemoclaw", "rebuild-backups"); @@ -304,7 +305,7 @@ async function bestEffortPrecleanHermesResources( await host.nemoclaw([SANDBOX_NAME, "destroy", "--yes", "--cleanup-gateway"], { artifactName: `${artifactName}-nemoclaw-destroy`, env: testEnv(apiKey), - redactionValues: [apiKey ?? "", DISCORD_FAKE_TOKEN], + redactionValues: [apiKey ?? "", DISCORD_FAKE_TOKEN, PRE_REBUILD_API_SERVER_KEY], timeoutMs: 3 * 60_000, }); await host.command( @@ -328,7 +329,7 @@ async function bestEffortPrecleanHermesResources( CURRENT_BASE_REUSE_TAG, OLD_BASE_TAG, }), - redactionValues: [apiKey ?? "", DISCORD_FAKE_TOKEN], + redactionValues: [apiKey ?? "", DISCORD_FAKE_TOKEN, PRE_REBUILD_API_SERVER_KEY], timeoutMs: 3 * 60_000, }, ); @@ -343,7 +344,7 @@ function hermesCleanupEnv(apiKey: string | undefined): NodeJS.ProcessEnv { } function hermesCleanupRedactions(apiKey: string | undefined): string[] { - return [apiKey ?? "", DISCORD_FAKE_TOKEN]; + return [apiKey ?? "", DISCORD_FAKE_TOKEN, PRE_REBUILD_API_SERVER_KEY]; } async function cleanupHermesNemoClawSandbox( @@ -419,7 +420,7 @@ async function waitForSandboxReady( const list = await host.command("openshell", ["sandbox", "list"], { artifactName: `${artifactPrefix}-sandbox-list-${attempt}`, env: testEnv(apiKey), - redactionValues: [apiKey], + redactionValues: [apiKey, PRE_REBUILD_API_SERVER_KEY], timeoutMs: 30_000, }); switch (new RegExp(`${SANDBOX_NAME}.*Ready`).test(resultText(list))) { @@ -629,7 +630,7 @@ test(STALE_BASE_REBUILD timeout: LIVE_TIMEOUT_MS, }, async ({ artifacts, cleanup, host, sandbox, secrets, skip }) => { const apiKey = secrets.required("NVIDIA_INFERENCE_API_KEY"); - const redactionValues = [apiKey, DISCORD_FAKE_TOKEN]; + const redactionValues = [apiKey, DISCORD_FAKE_TOKEN, PRE_REBUILD_API_SERVER_KEY]; const expectedVersion = expectedHermesVersion(); const progress = startRebuildHermesProgress("setup"); cleanup.trackDisposable("stop Hermes rebuild progress", progress.stop); @@ -971,6 +972,7 @@ test(STALE_BASE_REBUILD buildRebuildHermesOldSandboxDockerfile({ baseTag: OLD_BASE_TAG, baseResolutionMetadata: STALE_BASE_REBUILD ? oldBaseResolutionMetadata : null, + apiServerKey: PRE_REBUILD_API_SERVER_KEY, discordPlaceholder: DISCORD_PLACEHOLDER, kanbanTaskTitle: KANBAN_TASK_TITLE, }), @@ -1473,7 +1475,7 @@ test(STALE_BASE_REBUILD true, ); const leaks = listCredentialLeakPaths(sandboxBackupRoot, { - extraSecrets: [apiKey, DISCORD_FAKE_TOKEN], + extraSecrets: [apiKey, DISCORD_FAKE_TOKEN, PRE_REBUILD_API_SERVER_KEY], }); await artifacts.writeJson("phase-7-backup-credential-scan.json", { backupRoot: sandboxBackupRoot, diff --git a/test/e2e/support/rebuild-hermes-old-base-fixture.test.ts b/test/e2e/support/rebuild-hermes-old-base-fixture.test.ts index aa09a135c29..1da8ff5b17a 100644 --- a/test/e2e/support/rebuild-hermes-old-base-fixture.test.ts +++ b/test/e2e/support/rebuild-hermes-old-base-fixture.test.ts @@ -21,6 +21,7 @@ describe("rebuild-Hermes historical base fixture", () => { const dockerfile = buildRebuildHermesOldSandboxDockerfile({ baseTag: "nemoclaw-hermes-old-base:test", baseResolutionMetadata: null, + apiServerKey: "a".repeat(64), discordPlaceholder: "openshell:resolve:env:DISCORD_BOT_TOKEN", kanbanTaskTitle: "NEMOCLAW_REBUILD_KANBAN_TEST", }); @@ -31,6 +32,7 @@ describe("rebuild-Hermes historical base fixture", () => { "&& /usr/local/bin/hermes kanban create 'NEMOCLAW_REBUILD_KANBAN_TEST' --initial-status blocked --json", ); expect(dockerfile).toContain("&& test -s /sandbox/.hermes/kanban.db"); + expect(dockerfile).toContain(`'API_SERVER_KEY=${"a".repeat(64)}'`); expect(dockerfile.indexOf("hermes kanban init")).toBeLessThan( dockerfile.indexOf('CMD ["/bin/bash"]'), );