Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 5 additions & 47 deletions test/e2e/live/hermes-discord.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,7 @@ async function rawTokenSurfaceProbe(
});
}

test("hermes-discord: Hermes Discord schema, credential isolation, native gateway rewrite, and rebuild credential reuse", {
test("hermes-discord: Hermes Discord schema, credential isolation, and native gateway rewrite", {
timeout: HERMES_DISCORD_TEST_TIMEOUT_MS,
meta: {
e2ePhases: [
Expand All @@ -366,7 +366,6 @@ test("hermes-discord: Hermes Discord schema, credential isolation, native gatewa
"validate Discord config and placeholders",
"exercise native Discord gateway rewrite",
"verify Discord token isolation and REST boundary",
"rebuild without host inference credentials",
"finalize Hermes Discord resources",
],
},
Expand All @@ -378,7 +377,7 @@ test("hermes-discord: Hermes Discord schema, credential isolation, native gatewa
await artifacts.target.declare({
id: "hermes-discord",
boundary:
"install.sh --non-interactive Hermes sandbox + Discord config + OpenShell provider rewrite + sandbox leak probes + rebuild credential reuse",
"install.sh --non-interactive Hermes sandbox + Discord config + OpenShell provider rewrite + sandbox leak probes",
sandboxName: SANDBOX_NAME,
discordServerIds: DISCORD_SERVER_IDS,
discordAllowedIds: DISCORD_ALLOWED_IDS,
Expand Down Expand Up @@ -723,46 +722,6 @@ done`,
expectExitZero(bridgeResidue, "no local Discord bridge residue probe");
expect(bridgeResidue.stdout.trim()).toBe("");

progress.phase("rebuild without host inference credentials");
await bestEffortLifecycleCleanup(() =>
host.command("docker", ["rm", "-f", fakeGateway.container], {
artifactName: "phase-8-remove-fake-discord-container-before-rebuild",
env,
redactionValues,
timeoutMs: 60_000,
}),
);
fs.rmSync(fakeGateway.dir, { recursive: true, force: true });
await bestEffortLifecycleCleanup(() =>
host.command(
"bash",
[
"-lc",
"sudo rm -rf .tmp/fake-discord.* 2>/dev/null || rm -rf .tmp/fake-discord.* 2>/dev/null || true",
],
{
artifactName: "phase-8-remove-fake-discord-scratch-before-rebuild",
cwd: REPO_ROOT,
env,
redactionValues,
timeoutMs: 60_000,
},
),
);

const rebuildEnv = commandEnv();
delete rebuildEnv.NVIDIA_INFERENCE_API_KEY;
delete rebuildEnv.NVIDIA_INFERENCE_API_KEY;
delete rebuildEnv.COMPATIBLE_API_KEY;
const rebuild = await host.command("nemoclaw", [SANDBOX_NAME, "rebuild", "--yes"], {
artifactName: "phase-8-rebuild-without-inference-env",
env: rebuildEnv,
redactionValues,
timeoutMs: 45 * 60_000,
});
expectExitZero(rebuild, "Hermes rebuild without NVIDIA_INFERENCE_API_KEY");
expect(resultText(rebuild)).not.toMatch(/provider credential not found/i);

progress.phase("finalize Hermes Discord resources");
await (async (): Promise<void> => {
switch (process.env.NEMOCLAW_E2E_KEEP_SANDBOX) {
Expand All @@ -771,15 +730,15 @@ done`,
default:
}
const destroy = await host.command("nemoclaw", [SANDBOX_NAME, "destroy", "--yes"], {
artifactName: "phase-9-nemoclaw-destroy",
artifactName: "phase-8-nemoclaw-destroy",
env,
redactionValues,
timeoutMs: 15 * 60_000,
});
expectExitZero(destroy, "destroy Hermes Discord sandbox");
await bestEffortLifecycleCleanup(() =>
host.command(host.openshellCommandPath, ["gateway", "destroy", "-g", "nemoclaw"], {
artifactName: "phase-9-openshell-gateway-destroy",
artifactName: "phase-8-openshell-gateway-destroy",
env,
redactionValues,
timeoutMs: 120_000,
Expand All @@ -792,7 +751,7 @@ done`,
`registry="$HOME/.nemoclaw/sandboxes.json"; if [ -f "$registry" ] && grep -Fq ${shellQuote(`"${SANDBOX_NAME}"`)} "$registry"; then echo FOUND; exit 1; else echo ABSENT; fi`,
],
{
artifactName: "phase-9-registry-removal-probe",
artifactName: "phase-8-registry-removal-probe",
env: sandboxAccessEnv(),
redactionValues,
timeoutMs: 30_000,
Expand All @@ -815,7 +774,6 @@ done`,
rawTokenAbsentFromConfigEnvProcessAndFilesystem: true,
discordRestBoundaryReachedOrSkippedOnTimeout: true,
noLocalDiscordBridgeResidue: true,
rebuildReusedGatewayCredentialWithoutInferenceEnv: true,
cleanupVerified: process.env.NEMOCLAW_E2E_KEEP_SANDBOX !== "1",
},
});
Expand Down
15 changes: 10 additions & 5 deletions test/e2e/live/rebuild-hermes.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -654,7 +654,7 @@ test(STALE_BASE_REBUILD
"phase 1 current Hermes base resolution plus immutable old Hermes base fixture",
"openshell provider create/update and sandbox create/exec/list",
"curated local ~/.nemoclaw registry and onboard-session rebuild metadata",
"real nemoclaw <sandbox> rebuild --yes --verbose",
"real nemoclaw <sandbox> rebuild --yes --verbose without host inference credentials",
"Hermes .env/config.yaml messaging placeholder preservation",
"backup credential leak scan under ~/.nemoclaw/rebuild-backups",
],
Expand Down Expand Up @@ -1208,12 +1208,16 @@ test(STALE_BASE_REBUILD
}

progress.phase("rebuild the Hermes sandbox");
const rebuildEnv = testEnv(undefined, {
NEMOCLAW_REBUILD_VERBOSE: "1",
...baseReusePlan?.childEnv,
});
expect(rebuildEnv).not.toHaveProperty("NVIDIA_INFERENCE_API_KEY");
expect(rebuildEnv).not.toHaveProperty("COMPATIBLE_API_KEY");
expect(rebuildEnv).not.toHaveProperty("NVIDIA_API_KEY");
const rebuild = await host.nemoclaw([SANDBOX_NAME, "rebuild", "--yes", "--verbose"], {
artifactName: "phase-6-nemoclaw-rebuild-hermes",
env: testEnv(apiKey, {
NEMOCLAW_REBUILD_VERBOSE: "1",
...baseReusePlan?.childEnv,
}),
env: rebuildEnv,
redactionValues,
timeoutMs: REBUILD_TIMEOUT_MS,
captureLimitBytes: LONG_COMMAND_CAPTURE_LIMIT_BYTES,
Expand All @@ -1225,6 +1229,7 @@ test(STALE_BASE_REBUILD
expect(rebuildOutput).toContain(`nemoclaw ${SANDBOX_NAME} gateway-token --quiet`);
expect(rebuildOutput).toContain(`Using Hermes Agent base image: ${phase1BaseResolution.ref}`);
expect(rebuildOutput).not.toContain("Rebuilding Hermes Agent base image");
expect(rebuildOutput).not.toMatch(/provider credential not found/i);
await waitForSandboxReady(host, apiKey, "phase-6-post-rebuild");

const backupPathText = rebuildOutput.match(/^\s*Backup:\s+(.+)$/mu)?.[1]?.trim();
Expand Down
4 changes: 4 additions & 0 deletions test/e2e/support/rebuild-hermes-env.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,16 +83,20 @@ describe("rebuild-Hermes base reuse", () => {
HOME: process.env.HOME,
PATH: process.env.PATH,
BUILDX_BUILDER: "external-builder",
COMPATIBLE_API_KEY: "must-not-reach-child",
NEMOCLAW_ACCEPT_DEV_UNVERIFIED_INSTALL: "1",
NEMOCLAW_OPENSHELL_CHANNEL: "dev",
NVIDIA_API_KEY: "must-not-reach-child",
NVIDIA_INFERENCE_API_KEY: "must-not-reach-child",
},
{},
);

expect(childEnv.NEMOCLAW_ACCEPT_DEV_UNVERIFIED_INSTALL).toBe("1");
expect(childEnv.NEMOCLAW_OPENSHELL_CHANNEL).toBe("dev");
expect(childEnv.COMPATIBLE_API_KEY).toBeUndefined();
expect(childEnv.NVIDIA_API_KEY).toBeUndefined();
expect(childEnv.NVIDIA_INFERENCE_API_KEY).toBeUndefined();
expect(childEnv.BUILDX_BUILDER).toBeUndefined();
});
});
Loading