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
11 changes: 10 additions & 1 deletion .github/workflows/e2e.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -346,7 +352,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}" \
Expand Down
4 changes: 4 additions & 0 deletions test/e2e/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -601,6 +601,10 @@ both selector types in one correlated workflow run. Fork revisions whose plans
select credential-bearing jobs or targets instead require explicit maintainer
approval through the `approve-e2e` workflow operation. 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 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
Expand Down
93 changes: 93 additions & 0 deletions test/e2e/support/trusted-target-routing-workflow-boundary.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// 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<string, { steps: Array<{ id?: string; run?: string }> }>;
};

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);
});

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),
"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);
Comment thread
coderabbitai[bot] marked this conversation as resolved.
});
});
15 changes: 15 additions & 0 deletions test/pr-e2e-gate-typed-target.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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";

Expand Down Expand Up @@ -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"],
}),
]);
});
});
31 changes: 26 additions & 5 deletions test/pr-risk-plan.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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"]);
Expand Down Expand Up @@ -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],
Expand All @@ -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([]);
Expand All @@ -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],
Expand All @@ -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");

Expand Down
37 changes: 27 additions & 10 deletions tools/advisors/risk-plan.mts
Original file line number Diff line number Diff line change
Expand Up @@ -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<string>(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 =
Expand Down Expand Up @@ -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[] = [
Expand Down
5 changes: 4 additions & 1 deletion tools/e2e/operations-workflow-boundary.mts
Original file line number Diff line number Diff line change
Expand Up @@ -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 // \"\"'",
Expand Down
34 changes: 32 additions & 2 deletions tools/e2e/workflow-boundary.mts
Original file line number Diff line number Diff line change
Expand Up @@ -4500,8 +4500,38 @@ 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 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 trustedControllerMatrixScript = [
"set -euo pipefail",
'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",
`printf 'matrix=%s\\n' "\${matrix}" >> "\${GITHUB_OUTPUT}"`,
];
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(
Expand Down
Loading