Skip to content

Commit 2826da3

Browse files
committed
merge: synchronize current main
Signed-off-by: Senthil Ravichandran <senthilr@nvidia.com>
2 parents 9164222 + 70d3173 commit 2826da3

5 files changed

Lines changed: 47 additions & 24 deletions

File tree

.github/workflows/e2e.yaml

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -186,14 +186,11 @@ jobs:
186186
run: node --experimental-strip-types --no-warnings tools/e2e/dcode-base-image-contract.mts "${RUNNER_TEMP}/dcode-base-contract/contract.json"
187187

188188
generate-matrix:
189-
needs: base-image-publication
190189
runs-on: ubuntu-latest
191190
timeout-minutes: 10
192191
outputs:
193192
cli_artifact_provenance: ${{ steps.record_cli_artifact.outputs.provenance }}
194193
e2e_credentials_allowed: ${{ steps.e2e_credentials.outputs.allowed }}
195-
dcode_base_contract: ${{ needs.base-image-publication.outputs.dcode_base_contract }}
196-
dcode_base_ref: ${{ needs.base-image-publication.outputs.dcode_base_ref }}
197194
matrix: ${{ steps.matrix.outputs.matrix }}
198195
test_matrix: ${{ steps.matrix.outputs.test_matrix }}
199196
hermes_selected: ${{ steps.matrix.outputs.hermes_selected }}
@@ -907,7 +904,7 @@ jobs:
907904
${{ steps.workspace.outputs.work_dir }}/cleanup.json
908905
909906
live:
910-
needs: generate-matrix
907+
needs: [base-image-publication, generate-matrix]
911908
if: ${{ needs.generate-matrix.outputs.matrix != '[]' }}
912909
runs-on: ${{ matrix.runner }}
913910
timeout-minutes: 45
@@ -917,7 +914,7 @@ jobs:
917914
include: ${{ fromJSON(needs.generate-matrix.outputs.matrix) }}
918915
env:
919916
E2E_ARTIFACT_DIR: ${{ github.workspace }}/e2e-artifacts/live
920-
NEMOCLAW_LANGCHAIN_DEEPAGENTS_CODE_SANDBOX_BASE_IMAGE_REF: ${{ needs.generate-matrix.outputs.dcode_base_ref }}
917+
NEMOCLAW_LANGCHAIN_DEEPAGENTS_CODE_SANDBOX_BASE_IMAGE_REF: ${{ needs.base-image-publication.outputs.dcode_base_ref }}
921918
NEMOCLAW_CLI_BIN: ${{ github.workspace }}/bin/nemoclaw.js
922919
NEMOCLAW_RUN_LIVE_E2E: "1"
923920
NEMOCLAW_E2E_USE_HOSTED_INFERENCE: "1"
@@ -974,7 +971,7 @@ jobs:
974971
- name: Record immutable Deep Agents Code base evidence
975972
if: ${{ matrix.id == 'ubuntu-repo-cloud-langchain-deepagents-code' }}
976973
env:
977-
BASE_CONTRACT: ${{ needs.generate-matrix.outputs.dcode_base_contract }}
974+
BASE_CONTRACT: ${{ needs.base-image-publication.outputs.dcode_base_contract }}
978975
CANDIDATE_SHA: ${{ inputs.checkout_sha || github.sha }}
979976
TARGET_ID: ${{ matrix.id }}
980977
shell: bash

test/e2e/support/base-image-publication-workflow-boundary.test.ts

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,12 @@ function runClassifier(environment: {
9393
}
9494

9595
describe("base-image publication workflow boundary (#7372)", () => {
96+
it("keeps Launchable off the base-image publication critical path", () => {
97+
const value = workflow();
98+
99+
expect(validate(value)).toEqual([]);
100+
});
101+
96102
// source-shape-contract: security -- Immutable base contracts must outlive the qualification interval so later E2E cannot fall back to a mutable alias.
97103
it("retains immutable base contracts for later qualification (#9049)", () => {
98104
const action = YAML.parse(
@@ -209,7 +215,19 @@ describe("base-image publication workflow boundary (#7372)", () => {
209215
(gateSteps(value)[5].run = "node tools/e2e/dcode-base-image-contract.mts contract.json"),
210216
],
211217
["step count", (value) => gateSteps(value).push({ name: "Unreviewed step", run: "true" })],
212-
["fanout dependency", (value) => (value.jobs["generate-matrix"].needs = [])],
218+
[
219+
"matrix publication dependency",
220+
(value) => (value.jobs["generate-matrix"].needs = "base-image-publication"),
221+
],
222+
["live publication dependency", (value) => (value.jobs.live.needs = ["generate-matrix"])],
223+
[
224+
"Launchable publication dependency",
225+
(value) =>
226+
(value.jobs["staging-brev-launchable"].needs = [
227+
"base-image-publication",
228+
"generate-matrix",
229+
]),
230+
],
213231
[
214232
"matrix base output",
215233
(value) => {

tools/e2e/cli-artifact-workflow-boundary.mts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -340,10 +340,12 @@ function validateConsumer(
340340
job: WorkflowRecord,
341341
jobSteps: WorkflowStep[],
342342
): void {
343-
const expectedNeeds =
344-
jobName === "mcp-bridge-dev"
345-
? [CLI_ARTIFACT_PRODUCER_JOB, "openshell-dev-artifact"]
346-
: CLI_ARTIFACT_PRODUCER_JOB;
343+
let expectedNeeds: string | string[] = CLI_ARTIFACT_PRODUCER_JOB;
344+
if (jobName === "mcp-bridge-dev") {
345+
expectedNeeds = [CLI_ARTIFACT_PRODUCER_JOB, "openshell-dev-artifact"];
346+
} else if (jobName === "live") {
347+
expectedNeeds = ["base-image-publication", CLI_ARTIFACT_PRODUCER_JOB];
348+
}
347349
if (!isDeepStrictEqual(job.needs, expectedNeeds)) {
348350
errors.push(`${jobName} must depend directly on the CLI artifact producer`);
349351
}

tools/e2e/operations-workflow-boundary.mts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -578,21 +578,21 @@ export function validateBaseImagePublicationGate(workflow: OperationsWorkflow):
578578
"base-image-publication job must preserve its exact trusted-mode classifier, minimal permissions, pinned checkout, and verifier boundary",
579579
);
580580
}
581-
if (!needs(workflow.jobs["generate-matrix"] ?? {}).includes("base-image-publication")) {
582-
errors.push("generate-matrix must wait for base-image-publication");
581+
const matrix = workflow.jobs["generate-matrix"] ?? {};
582+
if (needs(matrix).includes("base-image-publication")) {
583+
errors.push("generate-matrix must not wait for base-image-publication");
583584
}
584-
const matrixOutputs = workflow.jobs["generate-matrix"]?.outputs ?? {};
585-
if (
586-
matrixOutputs.dcode_base_contract !==
587-
"${{ needs.base-image-publication.outputs.dcode_base_contract }}" ||
588-
matrixOutputs.dcode_base_ref !== "${{ needs.base-image-publication.outputs.dcode_base_ref }}"
589-
) {
590-
errors.push("generate-matrix must preserve the immutable Deep Agents Code base outputs");
585+
const matrixOutputs = matrix.outputs ?? {};
586+
if ("dcode_base_contract" in matrixOutputs || "dcode_base_ref" in matrixOutputs) {
587+
errors.push("generate-matrix must not relay Deep Agents Code base outputs");
591588
}
592589
const live = workflow.jobs.live ?? {};
590+
if (!sameMembers(needs(live), ["base-image-publication", "generate-matrix"])) {
591+
errors.push("live E2E must wait for matrix generation and base-image publication");
592+
}
593593
if (
594594
live.env?.NEMOCLAW_LANGCHAIN_DEEPAGENTS_CODE_SANDBOX_BASE_IMAGE_REF !==
595-
"${{ needs.generate-matrix.outputs.dcode_base_ref }}"
595+
"${{ needs.base-image-publication.outputs.dcode_base_ref }}"
596596
) {
597597
errors.push("live DCode must use the selected immutable base reference");
598598
}
@@ -601,13 +601,17 @@ export function validateBaseImagePublicationGate(workflow: OperationsWorkflow):
601601
const liveSteps = live.steps ?? [];
602602
if (
603603
evidence.if !== "${{ matrix.id == 'ubuntu-repo-cloud-langchain-deepagents-code' }}" ||
604-
evidence.env?.BASE_CONTRACT !== "${{ needs.generate-matrix.outputs.dcode_base_contract }}" ||
604+
evidence.env?.BASE_CONTRACT !==
605+
"${{ needs.base-image-publication.outputs.dcode_base_contract }}" ||
605606
!String(evidence.run ?? "").includes("dcode-base-image.json") ||
606607
liveSteps.indexOf(evidence) >= liveSteps.indexOf(findStep(live, "Run live E2E tests")) ||
607608
!String(upload.with?.path ?? "").includes("dcode-base-image.json")
608609
) {
609610
errors.push("live DCode must record its immutable base contract before E2E execution");
610611
}
612+
if (!sameMembers(needs(workflow.jobs["staging-brev-launchable"] ?? {}), ["generate-matrix"])) {
613+
errors.push("staging-brev-launchable must wait only for generate-matrix");
614+
}
611615
return errors;
612616
}
613617

tools/e2e/workflow-boundary.mts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2443,8 +2443,10 @@ export function validateE2eWorkflow(workflowValue: unknown): string[] {
24432443
if (liveTargets["runs-on"] !== "${{ matrix.runner }}") {
24442444
errors.push("live job must run on the matrix runner");
24452445
}
2446-
if (liveTargets.needs !== "generate-matrix") {
2447-
errors.push("live job must depend on generate-matrix");
2446+
if (
2447+
!isDeepStrictEqual(liveTargets.needs, ["base-image-publication", "generate-matrix"])
2448+
) {
2449+
errors.push("live job must depend on base-image-publication and generate-matrix");
24482450
}
24492451
if (liveTargets.if !== "${{ needs.generate-matrix.outputs.matrix != '[]' }}") {
24502452
errors.push("live job must run whenever the trusted planner emits typed targets");

0 commit comments

Comments
 (0)