From 833ae4be73f86c9bb387baed57ccbaa284be8c06 Mon Sep 17 00:00:00 2001 From: Julie Yaunches Date: Wed, 29 Jul 2026 09:51:11 -0400 Subject: [PATCH 1/6] ci(e2e): select post-reboot recovery for status --- .github/workflows/e2e.yaml | 11 ++++++- test/e2e/README.md | 4 +++ test/pr-e2e-gate-typed-target.test.ts | 15 +++++++++ test/pr-risk-plan.test.ts | 31 +++++++++++++++--- tools/advisors/risk-plan.mts | 37 ++++++++++++++++------ tools/e2e/operations-workflow-boundary.mts | 5 ++- tools/e2e/workflow-boundary.mts | 10 ++++-- 7 files changed, 94 insertions(+), 19 deletions(-) diff --git a/.github/workflows/e2e.yaml b/.github/workflows/e2e.yaml index f2ed802e5e..75065ba418 100644 --- a/.github/workflows/e2e.yaml +++ b/.github/workflows/e2e.yaml @@ -178,6 +178,12 @@ jobs: ubuntu-repo-cloud-langchain-deepagents-code) matrix='[{"id":"ubuntu-repo-cloud-langchain-deepagents-code","runner":"ubuntu-latest","label":"ubuntu-repo-cloud-langchain-deepagents-code"}]' ;; + ubuntu-repo-docker-post-reboot-recovery) + matrix='[{"id":"ubuntu-repo-docker-post-reboot-recovery","runner":"ubuntu-latest","label":"ubuntu-repo-docker-post-reboot-recovery"}]' + ;; + ubuntu-repo-cloud-langchain-deepagents-code,ubuntu-repo-docker-post-reboot-recovery) + matrix='[{"id":"ubuntu-repo-cloud-langchain-deepagents-code","runner":"ubuntu-latest","label":"ubuntu-repo-cloud-langchain-deepagents-code"},{"id":"ubuntu-repo-docker-post-reboot-recovery","runner":"ubuntu-latest","label":"ubuntu-repo-docker-post-reboot-recovery"}]' + ;; *) echo "::error::PR E2E target is not approved by the trusted controller" >&2 exit 1 @@ -305,7 +311,10 @@ jobs: [[ "$CORRELATION_ID" =~ ^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$ ]] || { echo "::error::correlation_id must be a lowercase UUIDv4"; exit 1; } [[ "$PR_NUMBER" =~ ^[1-9][0-9]*$ ]] || { echo "::error::pr_number must be a positive integer"; exit 1; } [[ -n "$JOBS" || -n "$TARGETS" ]] || { echo "::error::PR E2E runs require controller-selected jobs or targets"; exit 1; } - [[ -z "$TARGETS" || "$TARGETS" == "ubuntu-repo-cloud-langchain-deepagents-code" ]] || { echo "::error::PR E2E target is not approved by the trusted controller"; exit 1; } + case "$TARGETS" in + ""|ubuntu-repo-cloud-langchain-deepagents-code|ubuntu-repo-docker-post-reboot-recovery|ubuntu-repo-cloud-langchain-deepagents-code,ubuntu-repo-docker-post-reboot-recovery) ;; + *) echo "::error::PR E2E target is not approved by the trusted controller"; exit 1 ;; + esac pull_json="$(curl --fail --silent --show-error --proto '=https' \ --header "Authorization: Bearer ${GITHUB_TOKEN}" \ diff --git a/test/e2e/README.md b/test/e2e/README.md index a99078b25a..6a1da13ab5 100644 --- a/test/e2e/README.md +++ b/test/e2e/README.md @@ -577,6 +577,10 @@ both selector types in one correlated workflow run. Fork revisions whose plans select credential-bearing jobs or targets instead require explicit protected credentialed-E2E approval. Plans with no selected jobs or targets can complete without an E2E run. +Changes to `src/lib/actions/sandbox/status-snapshot.ts` select the exact +`ubuntu-repo-docker-post-reboot-recovery` typed target. This keeps status +delivery-recovery changes bound to the reboot simulation that independently +probes the restored gateway and host forward. An internal revision whose matched control-plane files are drawn only from the trusted controller and observer boundaries—`.github/workflows/pr-e2e-gate.yaml`, `tools/e2e/pr-e2e-gate.mts`, and `tools/e2e/pr-e2e-required.mts`—automatically diff --git a/test/pr-e2e-gate-typed-target.test.ts b/test/pr-e2e-gate-typed-target.test.ts index 895bb8205e..111e8a779e 100644 --- a/test/pr-e2e-gate-typed-target.test.ts +++ b/test/pr-e2e-gate-typed-target.test.ts @@ -17,6 +17,7 @@ const BASE_SHA = "b".repeat(40); const WORKFLOW_SHA = "d".repeat(40); const CORRELATION_ID = "12345678-1234-4123-8123-123456789abc"; const DCODE_TARGET = PR_E2E_TYPED_TARGET_IDS[0]; +const POST_REBOOT_TARGET = PR_E2E_TYPED_TARGET_IDS[1]; const DCODE_CHECK = "test/e2e/e2e-cloud-experimental/checks/07-deepagents-code-headless-inference.sh"; @@ -96,4 +97,18 @@ describe("PR E2E typed-target gate (#7031)", () => { }), ).rejects.toThrow(/Controller dispatch inputs are invalid/u); }); + + it("accepts the trusted post-reboot target in an exact-head plan (#7824)", () => { + const plan = buildRiskPlan({ + headSha: HEAD_SHA, + changedFiles: ["src/lib/actions/sandbox/status-snapshot.ts"], + }); + + expect(plan.requiredTargets).toEqual([ + expect.objectContaining({ + id: POST_REBOOT_TARGET, + matchedFiles: ["src/lib/actions/sandbox/status-snapshot.ts"], + }), + ]); + }); }); diff --git a/test/pr-risk-plan.test.ts b/test/pr-risk-plan.test.ts index 636ca5db37..377b01c2e9 100644 --- a/test/pr-risk-plan.test.ts +++ b/test/pr-risk-plan.test.ts @@ -28,7 +28,7 @@ describe("deterministic PR risk plan", () => { const second = plan("src/lib/onboard.ts", "src/lib/state/registry.ts"); expect(first).toEqual(second); - expect(first.version).toBe(7); + expect(first.version).toBe(8); expect(first.headSha).toBe(HEAD_SHA); expect(first.planHash).toMatch(/^[a-f0-9]{64}$/u); expect(first.changedFiles).toEqual(["src/lib/onboard.ts", "src/lib/state/registry.ts"]); @@ -150,8 +150,11 @@ describe("deterministic PR risk plan", () => { "test/e2e/e2e-cloud-experimental/checks/08-deepagents-code-secret-boundary.sh", ); - expect(PR_E2E_TYPED_TARGET_IDS).toEqual(["ubuntu-repo-cloud-langchain-deepagents-code"]); - expect(riskPlanRequiredTargetIds(result)).toEqual(PR_E2E_TYPED_TARGET_IDS); + expect(PR_E2E_TYPED_TARGET_IDS).toEqual([ + "ubuntu-repo-cloud-langchain-deepagents-code", + "ubuntu-repo-docker-post-reboot-recovery", + ]); + expect(riskPlanRequiredTargetIds(result)).toEqual([PR_E2E_TYPED_TARGET_IDS[0]]); expect(result.requiredTargets).toEqual([ expect.objectContaining({ id: PR_E2E_TYPED_TARGET_IDS[0], @@ -162,7 +165,7 @@ describe("deterministic PR risk plan", () => { expect(result.families).toContainEqual( expect.objectContaining({ id: "focused-e2e", - requiredTargets: [...PR_E2E_TYPED_TARGET_IDS], + requiredTargets: [PR_E2E_TYPED_TARGET_IDS[0]], }), ); expect(riskPlanRequiredTargetIds(adjacentCheck)).toEqual([]); @@ -185,7 +188,7 @@ describe("deterministic PR risk plan", () => { "test/langchain-deepagents-code-managed-model-params.test.ts", ); - expect(riskPlanRequiredTargetIds(result)).toEqual(PR_E2E_TYPED_TARGET_IDS); + expect(riskPlanRequiredTargetIds(result)).toEqual([PR_E2E_TYPED_TARGET_IDS[0]]); expect(result.requiredTargets).toEqual([ expect.objectContaining({ id: PR_E2E_TYPED_TARGET_IDS[0], @@ -197,6 +200,24 @@ describe("deterministic PR risk plan", () => { expect(riskPlanRequiredTargetIds(docsAndTestsOnly)).toEqual([]); }); + it("selects post-reboot recovery for status delivery recovery changes (#7824)", () => { + const changedFile = "src/lib/actions/sandbox/status-snapshot.ts"; + const result = plan(changedFile); + const adjacentStatusFile = plan("src/lib/actions/sandbox/status-text.ts"); + + expect(riskPlanRequiredTargetIds(result)).toEqual([PR_E2E_TYPED_TARGET_IDS[1]]); + expect(result.requiredTargets).toEqual([ + expect.objectContaining({ + id: PR_E2E_TYPED_TARGET_IDS[1], + families: ["focused-e2e"], + matchedFiles: [changedFile], + }), + ]); + expect(riskPlanRequiredTargetIds(adjacentStatusFile)).toEqual([]); + expect(result.planHash).not.toBe(adjacentStatusFile.planHash); + expect(requiresCredentialedE2eAuthorization(result)).toBe(false); + }); + it("does not infer security or inference risk from unrelated path substrings", () => { const result = plan("src/lib/actions/sandbox/mcp-bridge-provider.ts", "src/lib/secretary.ts"); diff --git a/tools/advisors/risk-plan.mts b/tools/advisors/risk-plan.mts index 6adbad8c72..71c00ec11d 100644 --- a/tools/advisors/risk-plan.mts +++ b/tools/advisors/risk-plan.mts @@ -3,14 +3,18 @@ import { createHash } from "node:crypto"; -export const RISK_PLAN_VERSION = 7 as const; +export const RISK_PLAN_VERSION = 8 as const; -export const PR_E2E_TYPED_TARGET_IDS = ["ubuntu-repo-cloud-langchain-deepagents-code"] as const; +export const PR_E2E_TYPED_TARGET_IDS = [ + "ubuntu-repo-cloud-langchain-deepagents-code", + "ubuntu-repo-docker-post-reboot-recovery", +] as const; const PR_E2E_TYPED_TARGET_ID_SET = new Set(PR_E2E_TYPED_TARGET_IDS); const DEEPAGENTS_HEADLESS_INFERENCE_CHECK = "test/e2e/e2e-cloud-experimental/checks/07-deepagents-code-headless-inference.sh"; const DEEPAGENTS_CODE_RUNTIME_ROOT = "agents/langchain-deepagents-code/"; +const POST_REBOOT_STATUS_RUNTIME = "src/lib/actions/sandbox/status-snapshot.ts"; export type RiskTier = 0 | 1 | 2 | 3; export type RiskFamilyId = @@ -122,21 +126,34 @@ export function isPrE2eTypedTargetId(value: string): boolean { export function focusedPrE2eTargetsForChangedFiles( changedFiles: readonly string[], ): TrustedFocusedE2eTarget[] { - const matchedFiles = stableUnique( + const deepAgentsMatchedFiles = stableUnique( changedFiles.filter( (file) => file === DEEPAGENTS_HEADLESS_INFERENCE_CHECK || (file.startsWith(DEEPAGENTS_CODE_RUNTIME_ROOT) && isRuntimeRelevant(file)), ), ); - return matchedFiles.length > 0 - ? [ - { - id: PR_E2E_TYPED_TARGET_IDS[0], - matchedFiles, - }, - ] + const postRebootMatchedFiles = changedFiles.includes(POST_REBOOT_STATUS_RUNTIME) + ? [POST_REBOOT_STATUS_RUNTIME] : []; + return [ + ...(deepAgentsMatchedFiles.length > 0 + ? [ + { + id: PR_E2E_TYPED_TARGET_IDS[0], + matchedFiles: deepAgentsMatchedFiles, + }, + ] + : []), + ...(postRebootMatchedFiles.length > 0 + ? [ + { + id: PR_E2E_TYPED_TARGET_IDS[1], + matchedFiles: postRebootMatchedFiles, + }, + ] + : []), + ]; } export const RISK_RULES: readonly RiskRule[] = [ diff --git a/tools/e2e/operations-workflow-boundary.mts b/tools/e2e/operations-workflow-boundary.mts index 5b2a34a5fb..adb12602b8 100644 --- a/tools/e2e/operations-workflow-boundary.mts +++ b/tools/e2e/operations-workflow-boundary.mts @@ -383,7 +383,10 @@ function validatePrGateDispatch(errors: string[], workflow: OperationsWorkflow): '"$CORRELATION_ID" =~ ^[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89ab][a-f0-9]{3}-[a-f0-9]{12}$', '"$PR_NUMBER" =~ ^[1-9][0-9]*$', '[[ -n "$JOBS" || -n "$TARGETS" ]]', - '[[ -z "$TARGETS" || "$TARGETS" == "ubuntu-repo-cloud-langchain-deepagents-code" ]]', + 'case "$TARGETS" in', + "ubuntu-repo-cloud-langchain-deepagents-code", + "ubuntu-repo-docker-post-reboot-recovery", + "PR E2E target is not approved by the trusted controller", "https://api.github.com/repos/${GITHUB_REPOSITORY}/pulls/${PR_NUMBER}", "'.state'", "'.head.repo.full_name // \"\"'", diff --git a/tools/e2e/workflow-boundary.mts b/tools/e2e/workflow-boundary.mts index 6a28cc4a32..8f9e74df27 100644 --- a/tools/e2e/workflow-boundary.mts +++ b/tools/e2e/workflow-boundary.mts @@ -4396,8 +4396,14 @@ export function validateE2eWorkflow(workflowValue: unknown): string[] { } requireRunContains(errors, controllerMatrix, 'case "${TARGETS}" in'); requireRunContains(errors, controllerMatrix, "matrix='[]'"); - requireRunContains(errors, controllerMatrix, "ubuntu-repo-cloud-langchain-deepagents-code"); - if (!stringValue(controllerMatrix?.run).includes('"runner":"ubuntu-latest"')) { + const controllerMatrixScript = stringValue(controllerMatrix?.run); + const trustedTargetMappings = [ + '{"id":"ubuntu-repo-cloud-langchain-deepagents-code","runner":"ubuntu-latest","label":"ubuntu-repo-cloud-langchain-deepagents-code"}', + '{"id":"ubuntu-repo-docker-post-reboot-recovery","runner":"ubuntu-latest","label":"ubuntu-repo-docker-post-reboot-recovery"}', + ]; + if ( + trustedTargetMappings.some((mapping) => controllerMatrixScript.split(mapping).length - 1 !== 2) + ) { errors.push("trusted controller matrix must pin typed target runner to ubuntu-latest"); } requireRunContains( From 713676e74aa51fb9b7ea6ab6d83f7512f4a2b815 Mon Sep 17 00:00:00 2001 From: Julie Yaunches Date: Wed, 29 Jul 2026 10:52:09 -0400 Subject: [PATCH 2/6] fix(e2e): validate trusted target case branches Signed-off-by: Julie Yaunches --- test/e2e/README.md | 2 +- test/e2e/support/e2e-workflow.test.ts | 23 ++++++++++++++++ tools/e2e/workflow-boundary.mts | 38 ++++++++++++++++++++++++--- 3 files changed, 58 insertions(+), 5 deletions(-) diff --git a/test/e2e/README.md b/test/e2e/README.md index 6a1da13ab5..8615fc86b8 100644 --- a/test/e2e/README.md +++ b/test/e2e/README.md @@ -580,7 +580,7 @@ without an E2E run. Changes to `src/lib/actions/sandbox/status-snapshot.ts` select the exact `ubuntu-repo-docker-post-reboot-recovery` typed target. This keeps status delivery-recovery changes bound to the reboot simulation that independently -probes the restored gateway and host forward. +probes the restored gateway and host forwarding. An internal revision whose matched control-plane files are drawn only from the trusted controller and observer boundaries—`.github/workflows/pr-e2e-gate.yaml`, `tools/e2e/pr-e2e-gate.mts`, and `tools/e2e/pr-e2e-required.mts`—automatically diff --git a/test/e2e/support/e2e-workflow.test.ts b/test/e2e/support/e2e-workflow.test.ts index ecebdd28c5..5ef4f09831 100644 --- a/test/e2e/support/e2e-workflow.test.ts +++ b/test/e2e/support/e2e-workflow.test.ts @@ -412,6 +412,29 @@ describe("e2e workflow boundary", () => { ); }); + it("rejects trusted target mappings outside their exact case branch (#7824)", () => { + const workflow = readWorkflow() as { + jobs: Record< + string, + { + steps: Array<{ id?: string; run?: string }>; + } + >; + }; + const controllerMatrix = workflow.jobs["generate-matrix"]!.steps.find( + (step) => step.id === "controller_matrix", + )!; + const trustedMapping = + '{"id":"ubuntu-repo-docker-post-reboot-recovery","runner":"ubuntu-latest","label":"ubuntu-repo-docker-post-reboot-recovery"}'; + controllerMatrix.run = controllerMatrix + .run!.replace(trustedMapping, trustedMapping.replace("ubuntu-latest", "self-hosted")) + .concat(`\n# ${trustedMapping}\n`); + + expect(validateE2eWorkflow(workflow)).toContain( + "trusted controller matrix must pin typed target runner to ubuntu-latest", + ); + }); + type RebuildWorkflowStep = { env?: Record; name?: string; diff --git a/tools/e2e/workflow-boundary.mts b/tools/e2e/workflow-boundary.mts index 8f9e74df27..7c4b736233 100644 --- a/tools/e2e/workflow-boundary.mts +++ b/tools/e2e/workflow-boundary.mts @@ -604,6 +604,25 @@ function stringValue(value: unknown): string { return typeof value === "string" ? value : ""; } +function shellCaseBranchCommands(script: string, selector: string): string[] | undefined { + const lines = script.split("\n"); + const caseStart = lines.findIndex((line) => line.trim() === 'case "${TARGETS}" in'); + const caseEnd = lines.findIndex((line, index) => index > caseStart && line.trim() === "esac"); + if (caseStart < 0 || caseEnd < 0) return undefined; + const branchStart = lines.findIndex( + (line, index) => index > caseStart && index < caseEnd && line.trim() === `${selector})`, + ); + if (branchStart < 0) return undefined; + const branchEnd = lines.findIndex( + (line, index) => index > branchStart && index < caseEnd && line.trim() === ";;", + ); + if (branchEnd < 0) return undefined; + return lines + .slice(branchStart + 1, branchEnd) + .map((line) => line.trim()) + .filter(Boolean); +} + function extractCallArguments(script: string, callStart: number): string { const openIndex = script.indexOf("(", callStart); if (openIndex < 0) return ""; @@ -4397,12 +4416,23 @@ export function validateE2eWorkflow(workflowValue: unknown): string[] { requireRunContains(errors, controllerMatrix, 'case "${TARGETS}" in'); requireRunContains(errors, controllerMatrix, "matrix='[]'"); const controllerMatrixScript = stringValue(controllerMatrix?.run); - const trustedTargetMappings = [ - '{"id":"ubuntu-repo-cloud-langchain-deepagents-code","runner":"ubuntu-latest","label":"ubuntu-repo-cloud-langchain-deepagents-code"}', - '{"id":"ubuntu-repo-docker-post-reboot-recovery","runner":"ubuntu-latest","label":"ubuntu-repo-docker-post-reboot-recovery"}', + const deepAgentsTarget = "ubuntu-repo-cloud-langchain-deepagents-code"; + const postRebootTarget = "ubuntu-repo-docker-post-reboot-recovery"; + const deepAgentsMapping = `{"id":"${deepAgentsTarget}","runner":"ubuntu-latest","label":"${deepAgentsTarget}"}`; + const postRebootMapping = `{"id":"${postRebootTarget}","runner":"ubuntu-latest","label":"${postRebootTarget}"}`; + const trustedTargetBranches = [ + [deepAgentsTarget, `matrix='[${deepAgentsMapping}]'`], + [postRebootTarget, `matrix='[${postRebootMapping}]'`], + [ + `${deepAgentsTarget},${postRebootTarget}`, + `matrix='[${deepAgentsMapping},${postRebootMapping}]'`, + ], ]; if ( - trustedTargetMappings.some((mapping) => controllerMatrixScript.split(mapping).length - 1 !== 2) + trustedTargetBranches.some( + ([selector, assignment]) => + !isDeepStrictEqual(shellCaseBranchCommands(controllerMatrixScript, selector), [assignment]), + ) ) { errors.push("trusted controller matrix must pin typed target runner to ubuntu-latest"); } From 1f2b89eef2483414541184b73e2003d29e9410fe Mon Sep 17 00:00:00 2001 From: Julie Yaunches Date: Wed, 29 Jul 2026 11:08:47 -0400 Subject: [PATCH 3/6] fix(e2e): reject duplicate trusted target cases Signed-off-by: Julie Yaunches --- test/e2e/support/e2e-workflow.test.ts | 36 +++++++++++++++++++++++++++ tools/e2e/workflow-boundary.mts | 11 +++++--- 2 files changed, 44 insertions(+), 3 deletions(-) diff --git a/test/e2e/support/e2e-workflow.test.ts b/test/e2e/support/e2e-workflow.test.ts index 5ef4f09831..389d60c444 100644 --- a/test/e2e/support/e2e-workflow.test.ts +++ b/test/e2e/support/e2e-workflow.test.ts @@ -426,10 +426,46 @@ describe("e2e workflow boundary", () => { )!; const trustedMapping = '{"id":"ubuntu-repo-docker-post-reboot-recovery","runner":"ubuntu-latest","label":"ubuntu-repo-docker-post-reboot-recovery"}'; + const expectedError = "trusted controller matrix must pin typed target runner to ubuntu-latest"; + expect(validateE2eWorkflow(workflow)).not.toContain(expectedError); + requireFixture( + controllerMatrix.run?.includes(trustedMapping), + "trusted target fixture mapping is missing", + ); + controllerMatrix.run = controllerMatrix .run!.replace(trustedMapping, trustedMapping.replace("ubuntu-latest", "self-hosted")) .concat(`\n# ${trustedMapping}\n`); + expect(validateE2eWorkflow(workflow)).toContain(expectedError); + }); + + it("rejects a dead approved case block before unsafe target routing (#7824)", () => { + const workflow = readWorkflow() as { + jobs: Record< + string, + { + steps: Array<{ id?: string; run?: string }>; + } + >; + }; + const controllerMatrix = workflow.jobs["generate-matrix"]!.steps.find( + (step) => step.id === "controller_matrix", + )!; + const trustedMapping = + '{"id":"ubuntu-repo-docker-post-reboot-recovery","runner":"ubuntu-latest","label":"ubuntu-repo-docker-post-reboot-recovery"}'; + const run = controllerMatrix.run!; + const caseStart = run.indexOf('case "${TARGETS}" in'); + const caseEnd = run.indexOf("\nesac", caseStart) + "\nesac".length; + requireFixture(caseStart >= 0, "trusted target fixture case is missing"); + requireFixture(caseEnd > caseStart, "trusted target fixture case terminator is missing"); + const deadApprovedCase = run.slice(caseStart, caseEnd); + const unsafeRouting = run.replace( + trustedMapping, + trustedMapping.replace("ubuntu-latest", "self-hosted"), + ); + controllerMatrix.run = `${deadApprovedCase}\n${unsafeRouting}`; + expect(validateE2eWorkflow(workflow)).toContain( "trusted controller matrix must pin typed target runner to ubuntu-latest", ); diff --git a/tools/e2e/workflow-boundary.mts b/tools/e2e/workflow-boundary.mts index 7c4b736233..07d1408f5a 100644 --- a/tools/e2e/workflow-boundary.mts +++ b/tools/e2e/workflow-boundary.mts @@ -606,9 +606,14 @@ function stringValue(value: unknown): string { function shellCaseBranchCommands(script: string, selector: string): string[] | undefined { const lines = script.split("\n"); - const caseStart = lines.findIndex((line) => line.trim() === 'case "${TARGETS}" in'); - const caseEnd = lines.findIndex((line, index) => index > caseStart && line.trim() === "esac"); - if (caseStart < 0 || caseEnd < 0) return undefined; + const caseStarts = lines.flatMap((line, index) => + line.trim() === 'case "${TARGETS}" in' ? [index] : [], + ); + const caseEnds = lines.flatMap((line, index) => (line.trim() === "esac" ? [index] : [])); + if (caseStarts.length !== 1 || caseEnds.length !== 1) return undefined; + const caseStart = caseStarts[0]!; + const caseEnd = caseEnds[0]!; + if (caseEnd <= caseStart) return undefined; const branchStart = lines.findIndex( (line, index) => index > caseStart && index < caseEnd && line.trim() === `${selector})`, ); From 3576f30979ba42e61059948769685fe671962f52 Mon Sep 17 00:00:00 2001 From: Julie Yaunches Date: Wed, 29 Jul 2026 11:36:59 -0400 Subject: [PATCH 4/6] fix(e2e): validate complete trusted target case --- test/e2e/support/e2e-workflow.test.ts | 59 -------------- ...d-target-routing-workflow-boundary.test.ts | 78 +++++++++++++++++++ tools/e2e/workflow-boundary.mts | 45 ++++++----- 3 files changed, 100 insertions(+), 82 deletions(-) create mode 100644 test/e2e/support/trusted-target-routing-workflow-boundary.test.ts diff --git a/test/e2e/support/e2e-workflow.test.ts b/test/e2e/support/e2e-workflow.test.ts index 389d60c444..ecebdd28c5 100644 --- a/test/e2e/support/e2e-workflow.test.ts +++ b/test/e2e/support/e2e-workflow.test.ts @@ -412,65 +412,6 @@ describe("e2e workflow boundary", () => { ); }); - it("rejects trusted target mappings outside their exact case branch (#7824)", () => { - const workflow = readWorkflow() as { - jobs: Record< - string, - { - steps: Array<{ id?: string; run?: string }>; - } - >; - }; - const controllerMatrix = workflow.jobs["generate-matrix"]!.steps.find( - (step) => step.id === "controller_matrix", - )!; - const trustedMapping = - '{"id":"ubuntu-repo-docker-post-reboot-recovery","runner":"ubuntu-latest","label":"ubuntu-repo-docker-post-reboot-recovery"}'; - const expectedError = "trusted controller matrix must pin typed target runner to ubuntu-latest"; - expect(validateE2eWorkflow(workflow)).not.toContain(expectedError); - requireFixture( - controllerMatrix.run?.includes(trustedMapping), - "trusted target fixture mapping is missing", - ); - - controllerMatrix.run = controllerMatrix - .run!.replace(trustedMapping, trustedMapping.replace("ubuntu-latest", "self-hosted")) - .concat(`\n# ${trustedMapping}\n`); - - expect(validateE2eWorkflow(workflow)).toContain(expectedError); - }); - - it("rejects a dead approved case block before unsafe target routing (#7824)", () => { - const workflow = readWorkflow() as { - jobs: Record< - string, - { - steps: Array<{ id?: string; run?: string }>; - } - >; - }; - const controllerMatrix = workflow.jobs["generate-matrix"]!.steps.find( - (step) => step.id === "controller_matrix", - )!; - const trustedMapping = - '{"id":"ubuntu-repo-docker-post-reboot-recovery","runner":"ubuntu-latest","label":"ubuntu-repo-docker-post-reboot-recovery"}'; - const run = controllerMatrix.run!; - const caseStart = run.indexOf('case "${TARGETS}" in'); - const caseEnd = run.indexOf("\nesac", caseStart) + "\nesac".length; - requireFixture(caseStart >= 0, "trusted target fixture case is missing"); - requireFixture(caseEnd > caseStart, "trusted target fixture case terminator is missing"); - const deadApprovedCase = run.slice(caseStart, caseEnd); - const unsafeRouting = run.replace( - trustedMapping, - trustedMapping.replace("ubuntu-latest", "self-hosted"), - ); - controllerMatrix.run = `${deadApprovedCase}\n${unsafeRouting}`; - - expect(validateE2eWorkflow(workflow)).toContain( - "trusted controller matrix must pin typed target runner to ubuntu-latest", - ); - }); - type RebuildWorkflowStep = { env?: Record; name?: string; diff --git a/test/e2e/support/trusted-target-routing-workflow-boundary.test.ts b/test/e2e/support/trusted-target-routing-workflow-boundary.test.ts new file mode 100644 index 0000000000..1d9570d6f4 --- /dev/null +++ b/test/e2e/support/trusted-target-routing-workflow-boundary.test.ts @@ -0,0 +1,78 @@ +// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 + +import { describe, expect, it } from "vitest"; +import { validateE2eWorkflow } from "../../../tools/e2e/workflow-boundary.mts"; +import { readWorkflow } from "../../helpers/e2e-workflow-contract"; +import { requireFixture } from "./require-fixture"; + +type ControllerWorkflow = { + jobs: Record }>; +}; + +const EXPECTED_ERROR = "trusted controller matrix must pin typed target runner to ubuntu-latest"; +const TRUSTED_MAPPING = + '{"id":"ubuntu-repo-docker-post-reboot-recovery","runner":"ubuntu-latest","label":"ubuntu-repo-docker-post-reboot-recovery"}'; + +function fixture() { + const workflow = readWorkflow() as ControllerWorkflow; + const controllerMatrix = workflow.jobs["generate-matrix"]!.steps.find( + (step) => step.id === "controller_matrix", + )!; + return { controllerMatrix, workflow }; +} + +describe("trusted E2E target routing boundary (#7824)", () => { + it("rejects trusted target mappings outside their exact case branch", () => { + const { controllerMatrix, workflow } = fixture(); + expect(validateE2eWorkflow(workflow)).not.toContain(EXPECTED_ERROR); + requireFixture( + controllerMatrix.run?.includes(TRUSTED_MAPPING), + "trusted target fixture mapping is missing", + ); + + controllerMatrix.run = controllerMatrix + .run!.replace(TRUSTED_MAPPING, TRUSTED_MAPPING.replace("ubuntu-latest", "self-hosted")) + .concat(`\n# ${TRUSTED_MAPPING}\n`); + + expect(validateE2eWorkflow(workflow)).toContain(EXPECTED_ERROR); + }); + + it("rejects a dead approved case block before unsafe target routing", () => { + const { controllerMatrix, workflow } = fixture(); + const run = controllerMatrix.run!; + const caseStart = run.indexOf('case "${TARGETS}" in'); + const caseEnd = run.indexOf("\nesac", caseStart) + "\nesac".length; + requireFixture(caseStart >= 0, "trusted target fixture case is missing"); + requireFixture(caseEnd > caseStart, "trusted target fixture case terminator is missing"); + const deadApprovedCase = run.slice(caseStart, caseEnd); + const unsafeRouting = run.replace( + TRUSTED_MAPPING, + TRUSTED_MAPPING.replace("ubuntu-latest", "self-hosted"), + ); + controllerMatrix.run = `${deadApprovedCase}\n${unsafeRouting}`; + + expect(validateE2eWorkflow(workflow)).toContain(EXPECTED_ERROR); + }); + + it("rejects an executable wildcard before approved target routing", () => { + const { controllerMatrix, workflow } = fixture(); + const caseStart = 'case "${TARGETS}" in'; + const unsafeWildcard = [ + "*)", + 'matrix=\'[{"id":"untrusted","runner":"self-hosted","label":"untrusted"}]\'', + ";;", + ].join("\n"); + requireFixture( + controllerMatrix.run?.includes(caseStart), + "trusted target fixture case is missing", + ); + + controllerMatrix.run = controllerMatrix.run!.replace( + caseStart, + `${caseStart}\n${unsafeWildcard}`, + ); + + expect(validateE2eWorkflow(workflow)).toContain(EXPECTED_ERROR); + }); +}); diff --git a/tools/e2e/workflow-boundary.mts b/tools/e2e/workflow-boundary.mts index 07d1408f5a..68b4c58600 100644 --- a/tools/e2e/workflow-boundary.mts +++ b/tools/e2e/workflow-boundary.mts @@ -604,7 +604,7 @@ function stringValue(value: unknown): string { return typeof value === "string" ? value : ""; } -function shellCaseBranchCommands(script: string, selector: string): string[] | undefined { +function shellTargetCaseLines(script: string): string[] | undefined { const lines = script.split("\n"); const caseStarts = lines.flatMap((line, index) => line.trim() === 'case "${TARGETS}" in' ? [index] : [], @@ -614,16 +614,8 @@ function shellCaseBranchCommands(script: string, selector: string): string[] | u const caseStart = caseStarts[0]!; const caseEnd = caseEnds[0]!; if (caseEnd <= caseStart) return undefined; - const branchStart = lines.findIndex( - (line, index) => index > caseStart && index < caseEnd && line.trim() === `${selector})`, - ); - if (branchStart < 0) return undefined; - const branchEnd = lines.findIndex( - (line, index) => index > branchStart && index < caseEnd && line.trim() === ";;", - ); - if (branchEnd < 0) return undefined; return lines - .slice(branchStart + 1, branchEnd) + .slice(caseStart, caseEnd + 1) .map((line) => line.trim()) .filter(Boolean); } @@ -4425,20 +4417,27 @@ export function validateE2eWorkflow(workflowValue: unknown): string[] { const postRebootTarget = "ubuntu-repo-docker-post-reboot-recovery"; const deepAgentsMapping = `{"id":"${deepAgentsTarget}","runner":"ubuntu-latest","label":"${deepAgentsTarget}"}`; const postRebootMapping = `{"id":"${postRebootTarget}","runner":"ubuntu-latest","label":"${postRebootTarget}"}`; - const trustedTargetBranches = [ - [deepAgentsTarget, `matrix='[${deepAgentsMapping}]'`], - [postRebootTarget, `matrix='[${postRebootMapping}]'`], - [ - `${deepAgentsTarget},${postRebootTarget}`, - `matrix='[${deepAgentsMapping},${postRebootMapping}]'`, - ], + const trustedTargetCase = [ + 'case "${TARGETS}" in', + '"")', + "matrix='[]'", + ";;", + `${deepAgentsTarget})`, + `matrix='[${deepAgentsMapping}]'`, + ";;", + `${postRebootTarget})`, + `matrix='[${postRebootMapping}]'`, + ";;", + `${deepAgentsTarget},${postRebootTarget})`, + `matrix='[${deepAgentsMapping},${postRebootMapping}]'`, + ";;", + "*)", + 'echo "::error::PR E2E target is not approved by the trusted controller" >&2', + "exit 1", + ";;", + "esac", ]; - if ( - trustedTargetBranches.some( - ([selector, assignment]) => - !isDeepStrictEqual(shellCaseBranchCommands(controllerMatrixScript, selector), [assignment]), - ) - ) { + if (!isDeepStrictEqual(shellTargetCaseLines(controllerMatrixScript), trustedTargetCase)) { errors.push("trusted controller matrix must pin typed target runner to ubuntu-latest"); } requireRunContains( From e7bb0dfc9b381b99f66b18def1045bfea9d4edad Mon Sep 17 00:00:00 2001 From: Julie Yaunches Date: Wed, 29 Jul 2026 11:49:41 -0400 Subject: [PATCH 5/6] fix(e2e): bind trusted matrix output Signed-off-by: Julie Yaunches --- ...d-target-routing-workflow-boundary.test.ts | 14 ++++++++++ tools/e2e/workflow-boundary.mts | 26 ++++++------------- 2 files changed, 22 insertions(+), 18 deletions(-) diff --git a/test/e2e/support/trusted-target-routing-workflow-boundary.test.ts b/test/e2e/support/trusted-target-routing-workflow-boundary.test.ts index 1d9570d6f4..9eb1591240 100644 --- a/test/e2e/support/trusted-target-routing-workflow-boundary.test.ts +++ b/test/e2e/support/trusted-target-routing-workflow-boundary.test.ts @@ -75,4 +75,18 @@ describe("trusted E2E target routing boundary (#7824)", () => { expect(validateE2eWorkflow(workflow)).toContain(EXPECTED_ERROR); }); + + it("rejects a matrix override after approved target routing", () => { + const { controllerMatrix, workflow } = fixture(); + const output = `printf 'matrix=%s\\n' "\${matrix}" >> "\${GITHUB_OUTPUT}"`; + requireFixture( + controllerMatrix.run?.includes(output), + "trusted target fixture output is missing", + ); + const unsafeOverride = + 'matrix=\'[{"id":"untrusted","runner":"self-hosted","label":"untrusted"}]\''; + controllerMatrix.run = controllerMatrix.run!.replace(output, `${unsafeOverride}\n${output}`); + + expect(validateE2eWorkflow(workflow)).toContain(EXPECTED_ERROR); + }); }); diff --git a/tools/e2e/workflow-boundary.mts b/tools/e2e/workflow-boundary.mts index 68b4c58600..dc95348e6a 100644 --- a/tools/e2e/workflow-boundary.mts +++ b/tools/e2e/workflow-boundary.mts @@ -604,22 +604,6 @@ function stringValue(value: unknown): string { return typeof value === "string" ? value : ""; } -function shellTargetCaseLines(script: string): string[] | undefined { - const lines = script.split("\n"); - const caseStarts = lines.flatMap((line, index) => - line.trim() === 'case "${TARGETS}" in' ? [index] : [], - ); - const caseEnds = lines.flatMap((line, index) => (line.trim() === "esac" ? [index] : [])); - if (caseStarts.length !== 1 || caseEnds.length !== 1) return undefined; - const caseStart = caseStarts[0]!; - const caseEnd = caseEnds[0]!; - if (caseEnd <= caseStart) return undefined; - return lines - .slice(caseStart, caseEnd + 1) - .map((line) => line.trim()) - .filter(Boolean); -} - function extractCallArguments(script: string, callStart: number): string { const openIndex = script.indexOf("(", callStart); if (openIndex < 0) return ""; @@ -4417,7 +4401,8 @@ export function validateE2eWorkflow(workflowValue: unknown): string[] { const postRebootTarget = "ubuntu-repo-docker-post-reboot-recovery"; const deepAgentsMapping = `{"id":"${deepAgentsTarget}","runner":"ubuntu-latest","label":"${deepAgentsTarget}"}`; const postRebootMapping = `{"id":"${postRebootTarget}","runner":"ubuntu-latest","label":"${postRebootTarget}"}`; - const trustedTargetCase = [ + const trustedControllerMatrixScript = [ + "set -euo pipefail", 'case "${TARGETS}" in', '"")', "matrix='[]'", @@ -4436,8 +4421,13 @@ export function validateE2eWorkflow(workflowValue: unknown): string[] { "exit 1", ";;", "esac", + `printf 'matrix=%s\\n' "\${matrix}" >> "\${GITHUB_OUTPUT}"`, ]; - if (!isDeepStrictEqual(shellTargetCaseLines(controllerMatrixScript), trustedTargetCase)) { + const controllerMatrixLines = controllerMatrixScript + .split("\n") + .map((line) => line.trim()) + .filter(Boolean); + if (!isDeepStrictEqual(controllerMatrixLines, trustedControllerMatrixScript)) { errors.push("trusted controller matrix must pin typed target runner to ubuntu-latest"); } requireRunContains( From 1be699e00f93192adf62bd9f5b7a36d25a3f44b0 Mon Sep 17 00:00:00 2001 From: Julie Yaunches Date: Wed, 29 Jul 2026 11:56:49 -0400 Subject: [PATCH 6/6] test(e2e): prove trusted matrix override rejection Signed-off-by: Julie Yaunches --- .../e2e/support/trusted-target-routing-workflow-boundary.test.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/test/e2e/support/trusted-target-routing-workflow-boundary.test.ts b/test/e2e/support/trusted-target-routing-workflow-boundary.test.ts index 9eb1591240..f44af1890c 100644 --- a/test/e2e/support/trusted-target-routing-workflow-boundary.test.ts +++ b/test/e2e/support/trusted-target-routing-workflow-boundary.test.ts @@ -78,6 +78,7 @@ describe("trusted E2E target routing boundary (#7824)", () => { it("rejects a matrix override after approved target routing", () => { const { controllerMatrix, workflow } = fixture(); + expect(validateE2eWorkflow(workflow)).not.toContain(EXPECTED_ERROR); const output = `printf 'matrix=%s\\n' "\${matrix}" >> "\${GITHUB_OUTPUT}"`; requireFixture( controllerMatrix.run?.includes(output),