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
2 changes: 2 additions & 0 deletions .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2589,7 +2589,9 @@ jobs:
E2E_WORKLOAD_SOURCE: "managed-image"
RELEASE_E2E_ACTIVATION_PATH: ci/protected-managed-image-runtime-activation-v1.json
NEMOCLAW_CLI_BIN: ${{ github.workspace }}/bin/nemoclaw.js
NEMOCLAW_E2E_EXPECTED_SHA: ${{ inputs.checkout_sha || github.sha }}
NEMOCLAW_E2E_SHARD: linux-amd64-gpu
NEMOCLAW_E2E_TESTED_ROOT: ${{ github.workspace }}/.candidate-runtime
NEMOCLAW_NON_INTERACTIVE: "1"
NEMOCLAW_PROTECTED_MANAGED_IMAGE_BASE_SHA: ${{ inputs.base_sha || github.event.before || github.sha }}
NEMOCLAW_PROTECTED_MANAGED_IMAGE_BUILD_CACHE: ${{ github.workspace }}/.protected-managed-image-build-cache/linux-amd64
Expand Down
31 changes: 31 additions & 0 deletions test/e2e-risk-signal-reporter.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,37 @@ describe("E2E risk signal reporter", () => {
expect(() => configuredEnvironment(env, () => "c".repeat(40))).toThrow(/checked-out HEAD/u);
});

it("attests an explicit tested root when trusted code runs beside the candidate checkout", () => {
const env = {
E2E_ARTIFACT_DIR: "/tmp/e2e-risk-signal-test",
E2E_TARGET_ID: "managed-image-protected-runtime",
GITHUB_WORKSPACE: "/workspace/trusted",
NEMOCLAW_E2E_EXPECTED_SHA: EXPECTED_SHA,
NEMOCLAW_E2E_CORRELATION_ID: CORRELATION_ID,
NEMOCLAW_E2E_SHARD: "linux-amd64-gpu",
NEMOCLAW_E2E_TESTED_ROOT: "/workspace/trusted/.candidate-runtime",
};
const resolveHead = vi.fn(() => EXPECTED_SHA);

expect(configuredEnvironment(env, resolveHead)?.testedSha).toBe(EXPECTED_SHA);
expect(resolveHead).toHaveBeenCalledWith("/workspace/trusted/.candidate-runtime");
});

it("rejects a relative tested root before resolving its HEAD", () => {
const env = {
E2E_ARTIFACT_DIR: "/tmp/e2e-risk-signal-test",
E2E_TARGET_ID: "managed-image-protected-runtime",
NEMOCLAW_E2E_EXPECTED_SHA: EXPECTED_SHA,
NEMOCLAW_E2E_CORRELATION_ID: CORRELATION_ID,
NEMOCLAW_E2E_SHARD: "linux-amd64-gpu",
NEMOCLAW_E2E_TESTED_ROOT: ".candidate-runtime",
};
const resolveHead = vi.fn(() => EXPECTED_SHA);

expect(() => configuredEnvironment(env, resolveHead)).toThrow(/absolute tested root/u);
expect(resolveHead).not.toHaveBeenCalled();
});

it("writes pass, failure, skip, and pending counts for the tested commit", () => {
const dir = fs.mkdtempSync(path.join(os.tmpdir(), "nemoclaw-risk-signal-"));
try {
Expand Down
20 changes: 20 additions & 0 deletions test/e2e/support/managed-image-protected-runtime-workflow.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,26 @@ describe("protected managed-image runtime workflow boundary", () => {
expect(validateManagedImageProtectedRuntimeWorkflow(value)).toEqual([]);
});

it("binds protected risk evidence to the isolated exact candidate checkout", () => {
const value = workflow();
const jobEnv = runtimeJob(value).env as Record<string, unknown>;
jobEnv.NEMOCLAW_E2E_TESTED_ROOT = "${{ github.workspace }}";

expect(validateManagedImageProtectedRuntimeWorkflow(value)).toContain(
"managed-image-protected-runtime env must bind NEMOCLAW_E2E_TESTED_ROOT to ${{ github.workspace }}/.candidate-runtime",
);
});

it("binds protected candidate identity on ordinary main runs", () => {
const value = workflow();
const jobEnv = runtimeJob(value).env as Record<string, unknown>;
jobEnv.NEMOCLAW_E2E_EXPECTED_SHA = "${{ inputs.checkout_sha }}";

expect(validateManagedImageProtectedRuntimeWorkflow(value)).toContain(
"managed-image-protected-runtime env must bind NEMOCLAW_E2E_EXPECTED_SHA to ${{ inputs.checkout_sha || github.sha }}",
);
});

it("does not record manual PR risk signals on main pushes", () => {
const value = workflow();
const jobEnv = multiarchJob(value).env as Record<string, unknown>;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,9 @@ export function validateManagedImageProtectedRuntimeWorkflow(workflow: WorkflowR
E2E_TARGET_ID: JOB_ID,
E2E_WORKLOAD_SOURCE: "managed-image",
RELEASE_E2E_ACTIVATION_PATH: ACTIVATION_PATH,
NEMOCLAW_E2E_EXPECTED_SHA: "${{ inputs.checkout_sha || github.sha }}",
NEMOCLAW_E2E_SHARD: "linux-amd64-gpu",
NEMOCLAW_E2E_TESTED_ROOT: "${{ github.workspace }}/.candidate-runtime",
NEMOCLAW_NON_INTERACTIVE: "1",
NEMOCLAW_PROTECTED_MANAGED_IMAGE_BASE_SHA:
"${{ inputs.base_sha || github.event.before || github.sha }}",
Expand Down
7 changes: 6 additions & 1 deletion tools/e2e/risk-signal.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: Apache-2.0

import { execFileSync } from "node:child_process";
import path from "node:path";

export const RISK_SIGNAL_FILE = "risk-signal.json";

Expand Down Expand Up @@ -73,7 +74,11 @@ export function configuredRiskSignalEnvironment(
if (!CORRELATION_PATTERN.test(values.correlationId)) {
throw new Error("risk signal requires a lowercase UUIDv4 correlation id");
}
const testedSha = resolveHead(env.GITHUB_WORKSPACE ?? process.cwd());
const testedRoot = env.NEMOCLAW_E2E_TESTED_ROOT ?? env.GITHUB_WORKSPACE ?? process.cwd();
if (!path.isAbsolute(testedRoot)) {
throw new Error("risk signal requires an absolute tested root");
}
const testedSha = resolveHead(testedRoot);
if (!SHA_PATTERN.test(testedSha) || testedSha !== values.expectedSha) {
throw new Error("risk signal checked-out HEAD does not match the expected SHA");
}
Expand Down
Loading