From bb236f13938de6d8ec6fd6b4695200f1d52721b0 Mon Sep 17 00:00:00 2001 From: Carlos Villela Date: Fri, 26 Jun 2026 21:28:34 -0700 Subject: [PATCH 1/2] fix(e2e): use hosted validation models in Vitest lanes Signed-off-by: Carlos Villela --- .github/workflows/e2e-vitest-scenarios.yaml | 1 - .../live/cron-preflight-inference-local.test.ts | 7 +++++-- test/e2e-scenario/live/diagnostics.test.ts | 11 ++++++++--- test/e2e-scenario/live/hermes-e2e.test.ts | 15 +++++++++------ .../live/upgrade-stale-sandbox-helpers.ts | 13 ++++++------- .../live/upgrade-stale-sandbox.test.ts | 17 +++++++++-------- 6 files changed, 37 insertions(+), 27 deletions(-) diff --git a/.github/workflows/e2e-vitest-scenarios.yaml b/.github/workflows/e2e-vitest-scenarios.yaml index 43aedc2501..74fac99206 100644 --- a/.github/workflows/e2e-vitest-scenarios.yaml +++ b/.github/workflows/e2e-vitest-scenarios.yaml @@ -1719,7 +1719,6 @@ jobs: NEMOCLAW_NON_INTERACTIVE: "1" NEMOCLAW_RECREATE_SANDBOX: "1" NEMOCLAW_SANDBOX_NAME: e2e-hermes - NEMOCLAW_MODEL: minimaxai/minimax-m2.7 NEMOCLAW_ONBOARD_VALIDATION_TIMEOUT_SECONDS: "60" steps: - uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6.0.3 diff --git a/test/e2e-scenario/live/cron-preflight-inference-local.test.ts b/test/e2e-scenario/live/cron-preflight-inference-local.test.ts index 8d30e3390b..6323ec39c5 100644 --- a/test/e2e-scenario/live/cron-preflight-inference-local.test.ts +++ b/test/e2e-scenario/live/cron-preflight-inference-local.test.ts @@ -18,14 +18,17 @@ import { resultText } from "../fixtures/clients/index.ts"; import { type SandboxClient, validateSandboxName } from "../fixtures/clients/sandbox.ts"; import { expect, test } from "../fixtures/e2e-test.ts"; import { shouldRunLiveE2EScenarios } from "../fixtures/live-project-gate.ts"; -import { requireHostedInferenceConfig } from "../fixtures/hosted-inference.ts"; +import { + DEFAULT_HOSTED_INFERENCE_MODEL, + requireHostedInferenceConfig, +} from "../fixtures/hosted-inference.ts"; import type { ShellProbeResult } from "../fixtures/shell-probe.ts"; import { isTransientProviderValidationFailure } from "./network-policy-transient-provider.ts"; const REPO_ROOT = path.resolve(import.meta.dirname, "../../.."); const SANDBOX_NAME = process.env.NEMOCLAW_SANDBOX_NAME ?? "e2e-cron-preflight"; validateSandboxName(SANDBOX_NAME); -const MODEL = process.env.NEMOCLAW_CRON_PREFLIGHT_MODEL ?? "nvidia/nemotron-3-super-120b-a12b"; +const MODEL = process.env.NEMOCLAW_CRON_PREFLIGHT_MODEL ?? DEFAULT_HOSTED_INFERENCE_MODEL; const INSTALL_ATTEMPTS = process.env.CI === "true" || process.env.GITHUB_ACTIONS === "true" ? 3 : 1; const LIVE_TIMEOUT_MS = 35 * 60_000; const PROBE_SOURCE = String.raw` diff --git a/test/e2e-scenario/live/diagnostics.test.ts b/test/e2e-scenario/live/diagnostics.test.ts index c94fb2af9d..a566a487e9 100644 --- a/test/e2e-scenario/live/diagnostics.test.ts +++ b/test/e2e-scenario/live/diagnostics.test.ts @@ -18,13 +18,17 @@ import path from "node:path"; import { buildAvailabilityProbeEnv } from "../fixtures/availability-env.ts"; import { validateSandboxName } from "../fixtures/clients/sandbox.ts"; import { expect, test } from "../fixtures/e2e-test.ts"; +import { + DEFAULT_HOSTED_INFERENCE_MODEL, + requireHostedInferenceConfig, +} from "../fixtures/hosted-inference.ts"; import { shouldRunLiveE2EScenarios } from "../fixtures/live-project-gate.ts"; import type { ShellProbeResult } from "../fixtures/shell-probe.ts"; const REPO_ROOT = path.resolve(import.meta.dirname, "../../.."); const CLI_ENTRYPOINT = path.join(REPO_ROOT, "bin", "nemoclaw.js"); const SANDBOX_NAME = process.env.NEMOCLAW_SANDBOX_NAME ?? `e2e-diag-${process.pid}`; -const DIAGNOSTICS_MODEL = process.env.NEMOCLAW_MODEL ?? "openai/gpt-oss-120b"; +const DIAGNOSTICS_MODEL = process.env.NEMOCLAW_MODEL ?? DEFAULT_HOSTED_INFERENCE_MODEL; const DEBUG_QUICK_TIMEOUT_MS = 30_000; const INSTALL_TIMEOUT_MS = 35 * 60_000; const TEST_TIMEOUT_MS = 55 * 60_000; @@ -138,7 +142,8 @@ runDiagnosticsTest( "run `npm run build:cli` before live repo CLI scenarios", ).toBe(true); - const apiKey = secrets.required("NVIDIA_INFERENCE_API_KEY"); + const hosted = requireHostedInferenceConfig(secrets, process.env, { model: DIAGNOSTICS_MODEL }); + const apiKey = hosted.apiKey; await artifacts.writeJson("scenario.json", { id: "diagnostics", runner: "vitest", @@ -195,7 +200,7 @@ runDiagnosticsTest( fs.rmSync(home, { recursive: true, force: true }); }); - const env = testEnv(home, { NVIDIA_INFERENCE_API_KEY: apiKey }); + const env = testEnv(home, hosted.env); await bestEffort(() => host.command("node", [CLI_ENTRYPOINT, SANDBOX_NAME, "destroy", "--yes"], { artifactName: "pre-cleanup-nemoclaw-destroy-diagnostics", diff --git a/test/e2e-scenario/live/hermes-e2e.test.ts b/test/e2e-scenario/live/hermes-e2e.test.ts index b295943193..7bcba780f4 100644 --- a/test/e2e-scenario/live/hermes-e2e.test.ts +++ b/test/e2e-scenario/live/hermes-e2e.test.ts @@ -11,7 +11,10 @@ import { trustedProviderEndpoint } from "../fixtures/clients/provider.ts"; import { trustedSandboxShellScript, validateSandboxName } from "../fixtures/clients/sandbox.ts"; import { expect, test } from "../fixtures/e2e-test.ts"; import { shouldRunLiveE2EScenarios } from "../fixtures/live-project-gate.ts"; -import { requireHostedInferenceConfig } from "../fixtures/hosted-inference.ts"; +import { + DEFAULT_HOSTED_INFERENCE_MODEL, + requireHostedInferenceConfig, +} from "../fixtures/hosted-inference.ts"; import type { ShellProbeResult } from "../fixtures/shell-probe.ts"; // Migrated from test/e2e/test-hermes-e2e.sh. @@ -33,7 +36,7 @@ const HERMES_DASHBOARD_INTERNAL_PORT = const SESSION_FILE = path.join(os.homedir(), ".nemoclaw", "onboard-session.json"); const REGISTRY_FILE = path.join(os.homedir(), ".nemoclaw", "sandboxes.json"); const LIVE_TIMEOUT_MS = 70 * 60_000; -const CHAT_MODEL = process.env.NEMOCLAW_MODEL ?? "nvidia/nemotron-3-super-120b-a12b"; +const CHAT_MODEL = process.env.NEMOCLAW_MODEL ?? DEFAULT_HOSTED_INFERENCE_MODEL; const ONBOARD_VALIDATION_TIMEOUT_SECONDS = process.env.NEMOCLAW_ONBOARD_VALIDATION_TIMEOUT_SECONDS ?? "60"; @@ -65,18 +68,18 @@ function hermesDashboardE2eEnabled(): boolean { ); } -function commandEnv(apiKey?: string): NodeJS.ProcessEnv { +function commandEnv(hostedEnv: NodeJS.ProcessEnv = {}): NodeJS.ProcessEnv { const env: NodeJS.ProcessEnv = { ...buildAvailabilityProbeEnv(), + ...hostedEnv, NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE: "1", NEMOCLAW_AGENT: "hermes", NEMOCLAW_NON_INTERACTIVE: "1", NEMOCLAW_RECREATE_SANDBOX: "1", - NEMOCLAW_MODEL: CHAT_MODEL, + NEMOCLAW_MODEL: hostedEnv.NEMOCLAW_MODEL ?? CHAT_MODEL, NEMOCLAW_ONBOARD_VALIDATION_TIMEOUT_SECONDS: ONBOARD_VALIDATION_TIMEOUT_SECONDS, NEMOCLAW_SANDBOX_NAME: SANDBOX_NAME, }; - if (apiKey) env.NVIDIA_INFERENCE_API_KEY = apiKey; if (process.env.NEMOCLAW_E2E_HERMES_DASHBOARD) { env.NEMOCLAW_E2E_HERMES_DASHBOARD = process.env.NEMOCLAW_E2E_HERMES_DASHBOARD; } @@ -232,7 +235,7 @@ test.skipIf(!shouldRunLiveE2EScenarios())( dashboardEnabled: hermesDashboardE2eEnabled(), }); - const env = commandEnv(apiKey); + const env = commandEnv(hosted.env); const redactionValues = [apiKey]; const cleanupHermes = async (label: string) => { diff --git a/test/e2e-scenario/live/upgrade-stale-sandbox-helpers.ts b/test/e2e-scenario/live/upgrade-stale-sandbox-helpers.ts index b14d4bc39a..600964296c 100644 --- a/test/e2e-scenario/live/upgrade-stale-sandbox-helpers.ts +++ b/test/e2e-scenario/live/upgrade-stale-sandbox-helpers.ts @@ -43,9 +43,10 @@ function assertSafeSandboxName(): void { } } -export function commandEnv(apiKey?: string): NodeJS.ProcessEnv { - const env: NodeJS.ProcessEnv = { +export function commandEnv(extra: NodeJS.ProcessEnv = {}): NodeJS.ProcessEnv { + return { ...buildAvailabilityProbeEnv(), + ...extra, NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE: "1", NEMOCLAW_NON_INTERACTIVE: "1", NEMOCLAW_REBUILD_VERBOSE: "1", @@ -53,8 +54,6 @@ export function commandEnv(apiKey?: string): NodeJS.ProcessEnv { NEMOCLAW_SANDBOX_NAME: SANDBOX_NAME, OPENSHELL_GATEWAY: process.env.OPENSHELL_GATEWAY ?? "nemoclaw", }; - apiKey && Object.assign(env, { NVIDIA_INFERENCE_API_KEY: apiKey }); - return env; } export async function bestEffort(run: () => Promise): Promise { @@ -201,7 +200,7 @@ export async function cleanupOldImage(host: HostCliClient): Promise { export async function installCurrentNemoclaw( host: HostCliClient, - apiKey: string, + hosted: { apiKey: string; env: NodeJS.ProcessEnv }, ): Promise { let install: ShellProbeResult | undefined; for (let attempt = 1; attempt <= INSTALL_ATTEMPTS; attempt += 1) { @@ -211,8 +210,8 @@ export async function installCurrentNemoclaw( ? "phase-1-install-current-nemoclaw" : `phase-1-install-current-nemoclaw-attempt-${attempt}`, cwd: REPO_ROOT, - env: commandEnv(apiKey), - redactionValues: [apiKey], + env: commandEnv(hosted.env), + redactionValues: [hosted.apiKey], timeoutMs: 20 * 60_000, }); const retry = diff --git a/test/e2e-scenario/live/upgrade-stale-sandbox.test.ts b/test/e2e-scenario/live/upgrade-stale-sandbox.test.ts index 0b796fe38b..1c758398d3 100644 --- a/test/e2e-scenario/live/upgrade-stale-sandbox.test.ts +++ b/test/e2e-scenario/live/upgrade-stale-sandbox.test.ts @@ -13,6 +13,7 @@ import { buildAvailabilityProbeEnv } from "../fixtures/availability-env.ts"; import { resultText } from "../fixtures/clients/index.ts"; import { expect, test } from "../fixtures/e2e-test.ts"; +import { requireHostedInferenceConfig } from "../fixtures/hosted-inference.ts"; import { shouldRunLiveE2EScenarios } from "../fixtures/live-project-gate.ts"; import { assertDeleteInstalledSandboxAllowed, @@ -37,7 +38,7 @@ test.skipIf(!shouldRunLiveE2EScenarios())( "upgrade-sandboxes detects and rebuilds stale OpenClaw sandboxes (#1904)", { timeout: LIVE_TIMEOUT_MS }, async ({ artifacts, cleanup, host, sandbox, secrets, skip }) => { - const apiKey = secrets.required("NVIDIA_INFERENCE_API_KEY"); + const hosted = requireHostedInferenceConfig(secrets); await artifacts.writeJson("scenario.json", { id: "upgrade-stale-sandbox", @@ -67,7 +68,7 @@ test.skipIf(!shouldRunLiveE2EScenarios())( cleanup.add("remove stale OpenClaw test image", () => cleanupOldImage(host)); await cleanupStaleSandbox(host, sandbox); - const install = await installCurrentNemoclaw(host, apiKey); + const install = await installCurrentNemoclaw(host, hosted); expect(install.exitCode, resultText(install)).toBe(0); const deleteInstalledSandbox = await sandbox.openshell(["sandbox", "delete", SANDBOX_NAME], { @@ -119,8 +120,8 @@ test.skipIf(!shouldRunLiveE2EScenarios())( const staleCheck = await host.nemoclaw(["upgrade-sandboxes", "--check"], { artifactName: "phase-5-upgrade-sandboxes-check-stale", - env: commandEnv(apiKey), - redactionValues: [apiKey], + env: commandEnv(hosted.env), + redactionValues: [hosted.apiKey], timeoutMs: 120_000, }); expect(staleCheck.exitCode, resultText(staleCheck)).toBe(0); @@ -129,8 +130,8 @@ test.skipIf(!shouldRunLiveE2EScenarios())( const rebuild = await host.nemoclaw([SANDBOX_NAME, "rebuild", "--yes"], { artifactName: "phase-6-rebuild-stale-sandbox", - env: commandEnv(apiKey), - redactionValues: [apiKey], + env: commandEnv(hosted.env), + redactionValues: [hosted.apiKey], timeoutMs: 25 * 60_000, }); expect(rebuild.exitCode, resultText(rebuild)).toBe(0); @@ -148,8 +149,8 @@ test.skipIf(!shouldRunLiveE2EScenarios())( const cleanCheck = await host.nemoclaw(["upgrade-sandboxes", "--check"], { artifactName: "phase-7-upgrade-sandboxes-check-clean", - env: commandEnv(apiKey), - redactionValues: [apiKey], + env: commandEnv(hosted.env), + redactionValues: [hosted.apiKey], timeoutMs: 120_000, }); expect(cleanCheck.exitCode, resultText(cleanCheck)).toBe(0); From 1fe54b49fb704af5ea7a96373d2e6a14ac03f07d Mon Sep 17 00:00:00 2001 From: Carlos Villela Date: Fri, 26 Jun 2026 21:39:55 -0700 Subject: [PATCH 2/2] fix(e2e): use hosted validation models in Vitest lanes Signed-off-by: Carlos Villela --- tools/e2e-scenarios/workflow-boundary.mts | 4175 +++++---------------- 1 file changed, 837 insertions(+), 3338 deletions(-) diff --git a/tools/e2e-scenarios/workflow-boundary.mts b/tools/e2e-scenarios/workflow-boundary.mts index dd17b0e7ba..4cd1fa3c87 100644 --- a/tools/e2e-scenarios/workflow-boundary.mts +++ b/tools/e2e-scenarios/workflow-boundary.mts @@ -95,9 +95,7 @@ function deriveFreeStandingJobsInventoryFromJobs(jobs: WorkflowRecord): { if (!hasJobMarker && !hasScenarioMarker) continue; if (!SELECTOR_ID_PATTERN.test(jobId)) { - errors.push( - `free-standing workflow metadata contains invalid job id: ${jobId}`, - ); + errors.push(`free-standing workflow metadata contains invalid job id: ${jobId}`); } if (!hasJobMarker) { errors.push( @@ -115,9 +113,7 @@ function deriveFreeStandingJobsInventoryFromJobs(jobs: WorkflowRecord): { const scenario = env[FREE_STANDING_SCENARIO_MARKER]; if (typeof scenario !== "string" || !SELECTOR_ID_PATTERN.test(scenario)) { - errors.push( - `${jobId} job ${FREE_STANDING_SCENARIO_MARKER} must be a selector id`, - ); + errors.push(`${jobId} job ${FREE_STANDING_SCENARIO_MARKER} must be a selector id`); continue; } freeStandingScenarios.push(scenario); @@ -125,17 +121,13 @@ function deriveFreeStandingJobsInventoryFromJobs(jobs: WorkflowRecord): { } if (allowedJobs.length === 0) { - errors.push( - "free-standing workflow metadata must declare at least one job", - ); + errors.push("free-standing workflow metadata must declare at least one job"); } for (const duplicate of findDuplicates(allowedJobs)) { errors.push(`free-standing workflow metadata repeats job id: ${duplicate}`); } for (const duplicate of findDuplicates(freeStandingScenarios)) { - errors.push( - `free-standing workflow metadata repeats scenario id: ${duplicate}`, - ); + errors.push(`free-standing workflow metadata repeats scenario id: ${duplicate}`); } return { @@ -148,10 +140,7 @@ function deriveFreeStandingJobsInventoryFromJobs(jobs: WorkflowRecord): { }; } -const freeStandingJobsInventoryCache = new Map< - string, - CachedFreeStandingJobsInventory ->(); +const freeStandingJobsInventoryCache = new Map(); function readWorkflowRecord(workflowPath: string): WorkflowRecord { return asRecord(YAML.parse(readFileSync(workflowPath, "utf-8"))); @@ -171,8 +160,7 @@ export function validateFreeStandingWorkflowInventory( workflowPath = DEFAULT_VITEST_WORKFLOW_PATH, ): string[] { const workflow = readWorkflowRecord(workflowPath); - return deriveFreeStandingJobsInventoryFromJobs(asRecord(workflow.jobs)) - .errors; + return deriveFreeStandingJobsInventoryFromJobs(asRecord(workflow.jobs)).errors; } export function readFreeStandingJobsInventory( @@ -180,22 +168,14 @@ export function readFreeStandingJobsInventory( ): FreeStandingJobsInventory { const stats = statSync(workflowPath); const cached = freeStandingJobsInventoryCache.get(workflowPath); - if ( - cached && - cached.mtimeMs === stats.mtimeMs && - cached.size === stats.size - ) { + if (cached && cached.mtimeMs === stats.mtimeMs && cached.size === stats.size) { return cloneFreeStandingJobsInventory(cached.inventory); } const workflow = readWorkflowRecord(workflowPath); - const { errors, inventory } = deriveFreeStandingJobsInventoryFromJobs( - asRecord(workflow.jobs), - ); + const { errors, inventory } = deriveFreeStandingJobsInventoryFromJobs(asRecord(workflow.jobs)); if (errors.length > 0) { - throw new Error( - `Invalid free-standing workflow inventory:\n${errors.join("\n")}`, - ); + throw new Error(`Invalid free-standing workflow inventory:\n${errors.join("\n")}`); } freeStandingJobsInventoryCache.set(workflowPath, { mtimeMs: stats.mtimeMs, @@ -321,18 +301,11 @@ export function evaluateE2eVitestWorkflowDispatchSelectors(input: { }; } -function namedStep( - steps: readonly WorkflowStep[], - name: string, -): WorkflowStep | undefined { +function namedStep(steps: readonly WorkflowStep[], name: string): WorkflowStep | undefined { return steps.find((step) => step.name === name); } -function requireInput( - errors: string[], - inputs: WorkflowRecord, - name: string, -): WorkflowRecord { +function requireInput(errors: string[], inputs: WorkflowRecord, name: string): WorkflowRecord { if (!Object.hasOwn(inputs, name)) { errors.push(`workflow_dispatch missing input: ${name}`); return {}; @@ -368,9 +341,7 @@ function requireRunContains( ): void { if (!step) return; if (!stringValue(step.run).includes(expected)) { - errors.push( - `step '${step.name ?? ""}' run script must include ${expected}`, - ); + errors.push(`step '${step.name ?? ""}' run script must include ${expected}`); } } @@ -381,17 +352,11 @@ function requireRunDoesNotContain( ): void { if (!step) return; if (stringValue(step.run).includes(forbidden)) { - errors.push( - `step '${step.name ?? ""}' run script must not include ${forbidden}`, - ); + errors.push(`step '${step.name ?? ""}' run script must not include ${forbidden}`); } } -function requireUploadPathContains( - errors: string[], - uploadPath: string, - expected: string, -): void { +function requireUploadPathContains(errors: string[], uploadPath: string, expected: string): void { if (!uploadPath.includes(expected)) { errors.push(`artifact upload path must include ${expected}`); } @@ -408,28 +373,16 @@ function requireEnvDoesNotExposeSecret( } } -function requireWorkflowDispatch( - errors: string[], - triggers: WorkflowRecord, -): WorkflowRecord { +function requireWorkflowDispatch(errors: string[], triggers: WorkflowRecord): WorkflowRecord { const workflowDispatch = asRecord(triggers.workflow_dispatch); if (Object.keys(workflowDispatch).length === 0) errors.push("workflow must support workflow_dispatch"); return workflowDispatch; } -function rejectAutomaticTriggers( - errors: string[], - triggers: WorkflowRecord, -): void { - for (const unsafe of [ - "push", - "pull_request", - "pull_request_target", - "schedule", - ]) { - if (Object.hasOwn(triggers, unsafe)) - errors.push(`workflow must not run on ${unsafe}`); +function rejectAutomaticTriggers(errors: string[], triggers: WorkflowRecord): void { + for (const unsafe of ["push", "pull_request", "pull_request_target", "schedule"]) { + if (Object.hasOwn(triggers, unsafe)) errors.push(`workflow must not run on ${unsafe}`); } } @@ -448,8 +401,7 @@ function requireNoDispatchInputInterpolation( errors: string[], steps: readonly WorkflowStep[], ): void { - const expressionPattern = - /\$\{\{\s*(?:inputs|github\.event\.inputs)\s*(?:\.|\[)/; + const expressionPattern = /\$\{\{\s*(?:inputs|github\.event\.inputs)\s*(?:\.|\[)/; for (const step of steps) { if (expressionPattern.test(stringValue(step.run))) { errors.push( @@ -528,19 +480,11 @@ function validateFreeStandingInventoryBoundary( if (Object.keys(job).length === 0) continue; if (!FREE_STANDING_SELECTOR_SPECIAL_CASES.has(jobName)) { - validateFreeStandingJobSelector( - errors, - jobs, - jobName, - scenarioByJob.get(jobName), - ); + validateFreeStandingJobSelector(errors, jobs, jobName, scenarioByJob.get(jobName)); } const jobEnv = asRecord(job.env); - if ( - jobEnv.NEMOCLAW_RUN_E2E_SCENARIOS === "1" && - jobPassesNvidiaInferenceSecret(job) - ) { + if (jobEnv.NEMOCLAW_RUN_E2E_SCENARIOS === "1" && jobPassesNvidiaInferenceSecret(job)) { validateHostedCompatibleInferenceFlag(errors, jobName, jobEnv); } for (const secret of COMMON_SECRET_ENV_NAMES) { @@ -551,11 +495,7 @@ function validateFreeStandingInventoryBoundary( requireNoDispatchInputInterpolation(errors, steps); for (const step of steps) { if (step.uses) { - requireFullShaAction( - errors, - step, - `${jobName} step '${step.name ?? step.uses}'`, - ); + requireFullShaAction(errors, step, `${jobName} step '${step.name ?? step.uses}'`); } if (/\$\{\{\s*secrets\./.test(stringValue(step.run))) { errors.push( @@ -582,9 +522,7 @@ function validateFreeStandingInventoryCoverage( } for (const [scenario, jobId] of inventory.scenarioToJob) { if (!inventory.allowedJobs.includes(jobId)) { - errors.push( - `free-standing inventory maps ${scenario} to unknown job ${jobId}`, - ); + errors.push(`free-standing inventory maps ${scenario} to unknown job ${jobId}`); continue; } const job = asRecord(jobs[jobId]); @@ -602,10 +540,7 @@ function validateFreeStandingInventoryCoverage( } } -function validateOpenShellVersionPinVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateOpenShellVersionPinVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "openshell-version-pin-vitest"; const job = asRecord(jobs[jobName]); if (Object.keys(job).length === 0) { @@ -616,22 +551,14 @@ function validateOpenShellVersionPinVitestJob( if (job["runs-on"] !== "ubuntu-latest") { errors.push("openshell-version-pin-vitest job must run on ubuntu-latest"); } - validateFreeStandingJobSelector( - errors, - jobs, - jobName, - "openshell-version-pin", - ); + validateFreeStandingJobSelector(errors, jobs, jobName, "openshell-version-pin"); const jobEnv = asRecord(job.env); if (jobEnv.NEMOCLAW_RUN_E2E_SCENARIOS !== "1") { - errors.push( - "openshell-version-pin-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1", - ); + errors.push("openshell-version-pin-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1"); } if ( - jobEnv.E2E_ARTIFACT_DIR !== - "${{ github.workspace }}/e2e-artifacts/vitest/openshell-version-pin" + jobEnv.E2E_ARTIFACT_DIR !== "${{ github.workspace }}/e2e-artifacts/vitest/openshell-version-pin" ) { errors.push( "openshell-version-pin-vitest job must write artifacts under e2e-artifacts/vitest/openshell-version-pin", @@ -655,30 +582,16 @@ function validateOpenShellVersionPinVitestJob( ); } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); - if (!checkout) - errors.push("openshell-version-pin-vitest job missing checkout step"); - requireFullShaAction( - errors, - checkout, - "openshell-version-pin-vitest checkout", - ); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); + if (!checkout) errors.push("openshell-version-pin-vitest job missing checkout step"); + requireFullShaAction(errors, checkout, "openshell-version-pin-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { - errors.push( - "openshell-version-pin-vitest checkout step must set persist-credentials=false", - ); + errors.push("openshell-version-pin-vitest checkout step must set persist-credentials=false"); } const setupNode = namedStep(steps, "Set up Node"); - if (!setupNode) - errors.push("openshell-version-pin-vitest job missing step: Set up Node"); - requireFullShaAction( - errors, - setupNode, - "openshell-version-pin-vitest setup-node", - ); + if (!setupNode) errors.push("openshell-version-pin-vitest job missing step: Set up Node"); + requireFullShaAction(errors, setupNode, "openshell-version-pin-vitest setup-node"); const installRootDependencies = requireJobStep( errors, @@ -686,52 +599,20 @@ function validateOpenShellVersionPinVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); - const runVitest = requireJobStep( - errors, - jobName, - steps, - "Run OpenShell version-pin live test", - ); - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/openshell-version-pin.test.ts", - ); + const runVitest = requireJobStep(errors, jobName, steps, "Run OpenShell version-pin live test"); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/openshell-version-pin.test.ts"); - const upload = requireJobStep( - errors, - jobName, - steps, - "Upload OpenShell version-pin artifacts", - ); - requireFullShaAction( - errors, - upload, - "openshell-version-pin-vitest upload-artifact", - ); + const upload = requireJobStep(errors, jobName, steps, "Upload OpenShell version-pin artifacts"); + requireFullShaAction(errors, upload, "openshell-version-pin-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); if (uploadWith.name !== "e2e-vitest-scenarios-openshell-version-pin") { - errors.push( - "openshell-version-pin-vitest artifact upload name must be stable", - ); + errors.push("openshell-version-pin-vitest artifact upload name must be stable"); } const uploadPath = stringValue(uploadWith.path); - requireUploadPathContains( - errors, - uploadPath, - "e2e-artifacts/vitest/openshell-version-pin/", - ); + requireUploadPathContains(errors, uploadPath, "e2e-artifacts/vitest/openshell-version-pin/"); if (uploadWith["include-hidden-files"] !== false) { errors.push( "openshell-version-pin-vitest artifact upload must set include-hidden-files: false", @@ -743,16 +624,11 @@ function validateOpenShellVersionPinVitestJob( ); } if (uploadWith["retention-days"] !== 14) { - errors.push( - "openshell-version-pin-vitest artifact upload retention-days must be 14", - ); + errors.push("openshell-version-pin-vitest artifact upload retention-days must be 14"); } } -function validateSkillAgentVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateSkillAgentVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "skill-agent-vitest"; const job = asRecord(jobs[jobName]); if (Object.keys(job).length === 0) { @@ -769,18 +645,13 @@ function validateSkillAgentVitestJob( if (jobEnv.NEMOCLAW_RUN_E2E_SCENARIOS !== "1") { errors.push("skill-agent-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1"); } - if ( - jobEnv.E2E_ARTIFACT_DIR !== - "${{ github.workspace }}/e2e-artifacts/vitest/skill-agent" - ) { + if (jobEnv.E2E_ARTIFACT_DIR !== "${{ github.workspace }}/e2e-artifacts/vitest/skill-agent") { errors.push( "skill-agent-vitest job must write artifacts under e2e-artifacts/vitest/skill-agent", ); } if (!stringValue(jobEnv.NEMOCLAW_CLI_BIN).includes("bin/nemoclaw.js")) { - errors.push( - "skill-agent-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI", - ); + errors.push("skill-agent-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI"); } requireEnvDoesNotExposeSecret( errors, @@ -802,20 +673,15 @@ function validateSkillAgentVitestJob( } } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); if (!checkout) errors.push("skill-agent-vitest job missing checkout step"); requireFullShaAction(errors, checkout, "skill-agent-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { - errors.push( - "skill-agent-vitest checkout step must set persist-credentials=false", - ); + errors.push("skill-agent-vitest checkout step must set persist-credentials=false"); } const setupNode = namedStep(steps, "Set up Node"); - if (!setupNode) - errors.push("skill-agent-vitest job missing step: Set up Node"); + if (!setupNode) errors.push("skill-agent-vitest job missing step: Set up Node"); requireFullShaAction(errors, setupNode, "skill-agent-vitest setup-node"); const installRootDependencies = requireJobStep( @@ -824,70 +690,30 @@ function validateSkillAgentVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); const buildCli = requireJobStep(errors, jobName, steps, "Build CLI"); requireRunContains(errors, buildCli, "npm run build:cli"); - const installOpenShell = requireJobStep( - errors, - jobName, - steps, - "Install OpenShell CLI", - ); - requireRunContains( - errors, - installOpenShell, - "bash scripts/install-openshell.sh", - ); + const installOpenShell = requireJobStep(errors, jobName, steps, "Install OpenShell CLI"); + requireRunContains(errors, installOpenShell, "bash scripts/install-openshell.sh"); - const runVitest = requireJobStep( - errors, - jobName, - steps, - "Run skill-agent live test", - ); + const runVitest = requireJobStep(errors, jobName, steps, "Run skill-agent live test"); const runEnv = asRecord(runVitest?.env); - if ( - runEnv.NVIDIA_INFERENCE_API_KEY !== - "${{ secrets.NVIDIA_INFERENCE_API_KEY }}" - ) { - errors.push( - "skill-agent-vitest run step must receive NVIDIA_INFERENCE_API_KEY from secrets", - ); + if (runEnv.NVIDIA_INFERENCE_API_KEY !== "${{ secrets.NVIDIA_INFERENCE_API_KEY }}") { + errors.push("skill-agent-vitest run step must receive NVIDIA_INFERENCE_API_KEY from secrets"); } requireRunContains( errors, runVitest, 'export PATH="$HOME/.local/bin:$HOME/.npm-global/bin:$PATH"', ); - requireRunContains( - errors, - runVitest, - 'OPENSHELL_BIN="$(command -v openshell)"', - ); + requireRunContains(errors, runVitest, 'OPENSHELL_BIN="$(command -v openshell)"'); requireRunContains(errors, runVitest, "export OPENSHELL_BIN"); - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/skill-agent.test.ts", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/skill-agent.test.ts"); - const upload = requireJobStep( - errors, - jobName, - steps, - "Upload skill-agent artifacts", - ); + const upload = requireJobStep(errors, jobName, steps, "Upload skill-agent artifacts"); requireFullShaAction(errors, upload, "skill-agent-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); if (uploadWith.name !== "e2e-vitest-scenarios-skill-agent") { @@ -914,24 +740,17 @@ function validateSkillAgentVitestJob( } } if (uploadWith["include-hidden-files"] !== false) { - errors.push( - "skill-agent-vitest artifact upload must set include-hidden-files: false", - ); + errors.push("skill-agent-vitest artifact upload must set include-hidden-files: false"); } if (uploadWith["if-no-files-found"] !== "ignore") { - errors.push( - "skill-agent-vitest artifact upload must ignore missing fixture artifacts", - ); + errors.push("skill-agent-vitest artifact upload must ignore missing fixture artifacts"); } if (uploadWith["retention-days"] !== 14) { errors.push("skill-agent-vitest artifact upload retention-days must be 14"); } } -function validateNetworkPolicyVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateNetworkPolicyVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "network-policy-vitest"; const job = asRecord(jobs[jobName]); if (Object.keys(job).length === 0) { @@ -952,27 +771,18 @@ function validateNetworkPolicyVitestJob( const jobEnv = asRecord(job.env); if (jobEnv.NEMOCLAW_RUN_E2E_SCENARIOS !== "1") { - errors.push( - "network-policy-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1", - ); + errors.push("network-policy-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1"); } - if ( - jobEnv.E2E_ARTIFACT_DIR !== - "${{ github.workspace }}/e2e-artifacts/vitest/network-policy" - ) { + if (jobEnv.E2E_ARTIFACT_DIR !== "${{ github.workspace }}/e2e-artifacts/vitest/network-policy") { errors.push( "network-policy-vitest job must write artifacts under e2e-artifacts/vitest/network-policy", ); } if (!stringValue(jobEnv.NEMOCLAW_CLI_BIN).includes("bin/nemoclaw.js")) { - errors.push( - "network-policy-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI", - ); + errors.push("network-policy-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI"); } if (jobEnv.OPENSHELL_GATEWAY !== "nemoclaw") { - errors.push( - "network-policy-vitest job must force OPENSHELL_GATEWAY=nemoclaw", - ); + errors.push("network-policy-vitest job must force OPENSHELL_GATEWAY=nemoclaw"); } for (const secret of [ "NVIDIA_INFERENCE_API_KEY", @@ -980,12 +790,7 @@ function validateNetworkPolicyVitestJob( "DOCKERHUB_TOKEN", "GITHUB_TOKEN", ]) { - requireEnvDoesNotExposeSecret( - errors, - "network-policy-vitest job", - jobEnv, - secret, - ); + requireEnvDoesNotExposeSecret(errors, "network-policy-vitest job", jobEnv, secret); } const steps = asSteps(job.steps); @@ -1023,20 +828,15 @@ function validateNetworkPolicyVitestJob( ); } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); if (!checkout) errors.push("network-policy-vitest job missing checkout step"); requireFullShaAction(errors, checkout, "network-policy-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { - errors.push( - "network-policy-vitest checkout step must set persist-credentials=false", - ); + errors.push("network-policy-vitest checkout step must set persist-credentials=false"); } const setupNode = namedStep(steps, "Set up Node"); - if (!setupNode) - errors.push("network-policy-vitest job missing step: Set up Node"); + if (!setupNode) errors.push("network-policy-vitest job missing step: Set up Node"); requireFullShaAction(errors, setupNode, "network-policy-vitest setup-node"); const installRootDependencies = requireJobStep( @@ -1045,102 +845,53 @@ function validateNetworkPolicyVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); const buildCli = requireJobStep(errors, jobName, steps, "Build CLI"); requireRunContains(errors, buildCli, "npm run build:cli"); if (namedStep(steps, "Authenticate to Docker Hub")) { - errors.push( - "network-policy-vitest must not include unused Docker Hub authentication", - ); + errors.push("network-policy-vitest must not include unused Docker Hub authentication"); } - const installOpenShell = requireJobStep( - errors, - jobName, - steps, - "Install OpenShell", - ); - requireRunContains( - errors, - installOpenShell, - "bash scripts/install-openshell.sh", - ); + const installOpenShell = requireJobStep(errors, jobName, steps, "Install OpenShell"); + requireRunContains(errors, installOpenShell, "bash scripts/install-openshell.sh"); requireRunContains(errors, installOpenShell, "env -u DOCKER_CONFIG"); requireRunContains(errors, installOpenShell, "-u DOCKERHUB_USERNAME"); requireRunContains(errors, installOpenShell, "-u DOCKERHUB_TOKEN"); requireRunContains(errors, installOpenShell, "-u NVIDIA_INFERENCE_API_KEY"); requireRunContains(errors, installOpenShell, "-u GITHUB_TOKEN"); - const runVitest = requireJobStep( - errors, - jobName, - steps, - "Run network-policy live test", - ); + const runVitest = requireJobStep(errors, jobName, steps, "Run network-policy live test"); const runVitestEnv = asRecord(runVitest?.env); - if ( - runVitestEnv.NVIDIA_INFERENCE_API_KEY !== - "${{ secrets.NVIDIA_INFERENCE_API_KEY }}" - ) { + if (runVitestEnv.NVIDIA_INFERENCE_API_KEY !== "${{ secrets.NVIDIA_INFERENCE_API_KEY }}") { errors.push( "network-policy-vitest Vitest step must receive NVIDIA_INFERENCE_API_KEY from secrets", ); } - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/network-policy.test.ts", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/network-policy.test.ts"); - const upload = requireJobStep( - errors, - jobName, - steps, - "Upload network-policy artifacts", - ); + const upload = requireJobStep(errors, jobName, steps, "Upload network-policy artifacts"); requireFullShaAction(errors, upload, "network-policy-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); if (uploadWith.name !== "e2e-vitest-scenarios-network-policy") { errors.push("network-policy-vitest artifact upload name must be stable"); } const uploadPath = stringValue(uploadWith.path); - requireUploadPathContains( - errors, - uploadPath, - "e2e-artifacts/vitest/network-policy/", - ); + requireUploadPathContains(errors, uploadPath, "e2e-artifacts/vitest/network-policy/"); if (uploadWith["include-hidden-files"] !== false) { - errors.push( - "network-policy-vitest artifact upload must set include-hidden-files: false", - ); + errors.push("network-policy-vitest artifact upload must set include-hidden-files: false"); } if (uploadWith["if-no-files-found"] !== "ignore") { - errors.push( - "network-policy-vitest artifact upload must ignore missing fixture artifacts", - ); + errors.push("network-policy-vitest artifact upload must ignore missing fixture artifacts"); } if (uploadWith["retention-days"] !== 14) { - errors.push( - "network-policy-vitest artifact upload retention-days must be 14", - ); + errors.push("network-policy-vitest artifact upload retention-days must be 14"); } } -function validateCommonEgressAgentVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateCommonEgressAgentVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "common-egress-agent-vitest"; const job = asRecord(jobs[jobName]); if (Object.keys(job).length === 0) { @@ -1153,49 +904,34 @@ function validateCommonEgressAgentVitestJob( } validateFreeStandingJobSelector(errors, jobs, jobName, "common-egress-agent"); if (job["timeout-minutes"] !== 120) { - errors.push( - "common-egress-agent-vitest job must keep the legacy 120 minute timeout", - ); + errors.push("common-egress-agent-vitest job must keep the legacy 120 minute timeout"); } const jobEnv = asRecord(job.env); if (jobEnv.NEMOCLAW_RUN_E2E_SCENARIOS !== "1") { - errors.push( - "common-egress-agent-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1", - ); + errors.push("common-egress-agent-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1"); } if ( - jobEnv.E2E_ARTIFACT_DIR !== - "${{ github.workspace }}/e2e-artifacts/vitest/common-egress-agent" + jobEnv.E2E_ARTIFACT_DIR !== "${{ github.workspace }}/e2e-artifacts/vitest/common-egress-agent" ) { errors.push( "common-egress-agent-vitest job must write artifacts under e2e-artifacts/vitest/common-egress-agent", ); } if (!stringValue(jobEnv.NEMOCLAW_CLI_BIN).includes("bin/nemoclaw.js")) { - errors.push( - "common-egress-agent-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI", - ); + errors.push("common-egress-agent-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI"); } if (jobEnv.NEMOCLAW_NON_INTERACTIVE !== "1") { - errors.push( - "common-egress-agent-vitest job must set NEMOCLAW_NON_INTERACTIVE=1", - ); + errors.push("common-egress-agent-vitest job must set NEMOCLAW_NON_INTERACTIVE=1"); } if (jobEnv.NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE !== "1") { - errors.push( - "common-egress-agent-vitest job must set NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1", - ); + errors.push("common-egress-agent-vitest job must set NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1"); } if (jobEnv.NEMOCLAW_RECREATE_SANDBOX !== "1") { - errors.push( - "common-egress-agent-vitest job must set NEMOCLAW_RECREATE_SANDBOX=1", - ); + errors.push("common-egress-agent-vitest job must set NEMOCLAW_RECREATE_SANDBOX=1"); } if (jobEnv.OPENSHELL_GATEWAY !== "nemoclaw") { - errors.push( - "common-egress-agent-vitest job must force OPENSHELL_GATEWAY=nemoclaw", - ); + errors.push("common-egress-agent-vitest job must force OPENSHELL_GATEWAY=nemoclaw"); } for (const secret of [ "NVIDIA_INFERENCE_API_KEY", @@ -1203,12 +939,7 @@ function validateCommonEgressAgentVitestJob( "DOCKERHUB_TOKEN", "GITHUB_TOKEN", ]) { - requireEnvDoesNotExposeSecret( - errors, - "common-egress-agent-vitest job", - jobEnv, - secret, - ); + requireEnvDoesNotExposeSecret(errors, "common-egress-agent-vitest job", jobEnv, secret); } const steps = asSteps(job.steps); @@ -1224,11 +955,7 @@ function validateCommonEgressAgentVitestJob( "NVIDIA_INFERENCE_API_KEY", ); } - for (const secret of [ - "DOCKERHUB_USERNAME", - "DOCKERHUB_TOKEN", - "GITHUB_TOKEN", - ]) { + for (const secret of ["DOCKERHUB_USERNAME", "DOCKERHUB_TOKEN", "GITHUB_TOKEN"]) { requireEnvDoesNotExposeSecret( errors, `common-egress-agent-vitest step '${stepName}'`, @@ -1238,26 +965,16 @@ function validateCommonEgressAgentVitestJob( } } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); - if (!checkout) - errors.push("common-egress-agent-vitest job missing checkout step"); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); + if (!checkout) errors.push("common-egress-agent-vitest job missing checkout step"); requireFullShaAction(errors, checkout, "common-egress-agent-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { - errors.push( - "common-egress-agent-vitest checkout step must set persist-credentials=false", - ); + errors.push("common-egress-agent-vitest checkout step must set persist-credentials=false"); } const setupNode = namedStep(steps, "Set up Node"); - if (!setupNode) - errors.push("common-egress-agent-vitest job missing step: Set up Node"); - requireFullShaAction( - errors, - setupNode, - "common-egress-agent-vitest setup-node", - ); + if (!setupNode) errors.push("common-egress-agent-vitest job missing step: Set up Node"); + requireFullShaAction(errors, setupNode, "common-egress-agent-vitest setup-node"); const installRootDependencies = requireJobStep( errors, @@ -1265,38 +982,20 @@ function validateCommonEgressAgentVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); const buildCli = requireJobStep(errors, jobName, steps, "Build CLI"); requireRunContains(errors, buildCli, "npm run build:cli"); - const installOpenShell = requireJobStep( - errors, - jobName, - steps, - "Install OpenShell", - ); - requireRunContains( - errors, - installOpenShell, - "bash scripts/install-openshell.sh", - ); + const installOpenShell = requireJobStep(errors, jobName, steps, "Install OpenShell"); + requireRunContains(errors, installOpenShell, "bash scripts/install-openshell.sh"); requireRunContains(errors, installOpenShell, "env -u DOCKER_CONFIG"); requireRunContains(errors, installOpenShell, "-u DOCKERHUB_USERNAME"); requireRunContains(errors, installOpenShell, "-u DOCKERHUB_TOKEN"); requireRunContains(errors, installOpenShell, "-u NVIDIA_INFERENCE_API_KEY"); requireRunContains(errors, installOpenShell, "-u GITHUB_TOKEN"); - const runVitest = requireJobStep( - errors, - jobName, - steps, - "Run common-egress agent live test", - ); + const runVitest = requireJobStep(errors, jobName, steps, "Run common-egress agent live test"); const runVitestEnv = asRecord(runVitest?.env); if (runVitestEnv.NVIDIA_INFERENCE_API_KEY !== "${{ secrets.NVIDIA_INFERENCE_API_KEY }}") { errors.push( @@ -1304,61 +1003,29 @@ function validateCommonEgressAgentVitestJob( ); } requireRunContains(errors, runVitest, "OPENSHELL_BIN"); - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/common-egress-agent.test.ts", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/common-egress-agent.test.ts"); - const upload = requireJobStep( - errors, - jobName, - steps, - "Upload common-egress agent artifacts", - ); - requireFullShaAction( - errors, - upload, - "common-egress-agent-vitest upload-artifact", - ); + const upload = requireJobStep(errors, jobName, steps, "Upload common-egress agent artifacts"); + requireFullShaAction(errors, upload, "common-egress-agent-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); if (uploadWith.name !== "e2e-vitest-scenarios-common-egress-agent") { - errors.push( - "common-egress-agent-vitest artifact upload name must be stable", - ); + errors.push("common-egress-agent-vitest artifact upload name must be stable"); } const uploadPath = stringValue(uploadWith.path); - requireUploadPathContains( - errors, - uploadPath, - "e2e-artifacts/vitest/common-egress-agent/", - ); + requireUploadPathContains(errors, uploadPath, "e2e-artifacts/vitest/common-egress-agent/"); if (uploadWith["include-hidden-files"] !== false) { - errors.push( - "common-egress-agent-vitest artifact upload must set include-hidden-files: false", - ); + errors.push("common-egress-agent-vitest artifact upload must set include-hidden-files: false"); } if (uploadWith["if-no-files-found"] !== "ignore") { - errors.push( - "common-egress-agent-vitest artifact upload must ignore missing fixture artifacts", - ); + errors.push("common-egress-agent-vitest artifact upload must ignore missing fixture artifacts"); } if (uploadWith["retention-days"] !== 14) { - errors.push( - "common-egress-agent-vitest artifact upload retention-days must be 14", - ); + errors.push("common-egress-agent-vitest artifact upload retention-days must be 14"); } } -function validateShieldsConfigVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateShieldsConfigVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "shields-config-vitest"; const job = asRecord(jobs[jobName]); if (Object.keys(job).length === 0) { @@ -1371,43 +1038,28 @@ function validateShieldsConfigVitestJob( } validateFreeStandingJobSelector(errors, jobs, jobName, "shields-config"); if (job["timeout-minutes"] !== 45) { - errors.push( - "shields-config-vitest job must keep the legacy 45 minute timeout", - ); + errors.push("shields-config-vitest job must keep the legacy 45 minute timeout"); } const jobEnv = asRecord(job.env); if (jobEnv.NEMOCLAW_RUN_E2E_SCENARIOS !== "1") { - errors.push( - "shields-config-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1", - ); + errors.push("shields-config-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1"); } - if ( - jobEnv.E2E_ARTIFACT_DIR !== - "${{ github.workspace }}/e2e-artifacts/vitest/shields-config" - ) { + if (jobEnv.E2E_ARTIFACT_DIR !== "${{ github.workspace }}/e2e-artifacts/vitest/shields-config") { errors.push( "shields-config-vitest job must write artifacts under e2e-artifacts/vitest/shields-config", ); } if (jobEnv.OPENSHELL_GATEWAY !== "nemoclaw") { - errors.push( - "shields-config-vitest job must force OPENSHELL_GATEWAY=nemoclaw", - ); + errors.push("shields-config-vitest job must force OPENSHELL_GATEWAY=nemoclaw"); } if (jobEnv.NEMOCLAW_NON_INTERACTIVE !== "1") { - errors.push( - "shields-config-vitest job must set NEMOCLAW_NON_INTERACTIVE=1", - ); + errors.push("shields-config-vitest job must set NEMOCLAW_NON_INTERACTIVE=1"); } if (jobEnv.NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE !== "1") { - errors.push( - "shields-config-vitest job must set NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1", - ); + errors.push("shields-config-vitest job must set NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1"); } if (jobEnv.NEMOCLAW_SANDBOX_NAME !== "e2e-shields") { - errors.push( - "shields-config-vitest job must set NEMOCLAW_SANDBOX_NAME=e2e-shields", - ); + errors.push("shields-config-vitest job must set NEMOCLAW_SANDBOX_NAME=e2e-shields"); } requireEnvDoesNotExposeSecret( errors, @@ -1415,18 +1067,8 @@ function validateShieldsConfigVitestJob( jobEnv, "NVIDIA_INFERENCE_API_KEY", ); - requireEnvDoesNotExposeSecret( - errors, - "shields-config-vitest job", - jobEnv, - "DOCKERHUB_USERNAME", - ); - requireEnvDoesNotExposeSecret( - errors, - "shields-config-vitest job", - jobEnv, - "DOCKERHUB_TOKEN", - ); + requireEnvDoesNotExposeSecret(errors, "shields-config-vitest job", jobEnv, "DOCKERHUB_USERNAME"); + requireEnvDoesNotExposeSecret(errors, "shields-config-vitest job", jobEnv, "DOCKERHUB_TOKEN"); const steps = asSteps(job.steps); requireNoDispatchInputInterpolation(errors, steps); @@ -1457,23 +1099,14 @@ function validateShieldsConfigVitestJob( } } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); if (!checkout) errors.push("shields-config-vitest job missing checkout step"); requireFullShaAction(errors, checkout, "shields-config-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { - errors.push( - "shields-config-vitest checkout step must set persist-credentials=false", - ); + errors.push("shields-config-vitest checkout step must set persist-credentials=false"); } - const dockerHubAuth = requireJobStep( - errors, - jobName, - steps, - "Authenticate to Docker Hub", - ); + const dockerHubAuth = requireJobStep(errors, jobName, steps, "Authenticate to Docker Hub"); const dockerHubEnv = asRecord(dockerHubAuth?.env); if (dockerHubEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}") { errors.push( @@ -1481,15 +1114,12 @@ function validateShieldsConfigVitestJob( ); } if (dockerHubEnv.DOCKERHUB_TOKEN !== "${{ secrets.DOCKERHUB_TOKEN }}") { - errors.push( - "shields-config-vitest Docker Hub auth must receive DOCKERHUB_TOKEN from secrets", - ); + errors.push("shields-config-vitest Docker Hub auth must receive DOCKERHUB_TOKEN from secrets"); } requireRunContains(errors, dockerHubAuth, "docker login docker.io"); const setupNode = namedStep(steps, "Set up Node"); - if (!setupNode) - errors.push("shields-config-vitest job missing step: Set up Node"); + if (!setupNode) errors.push("shields-config-vitest job missing step: Set up Node"); requireFullShaAction(errors, setupNode, "shields-config-vitest setup-node"); const installRootDependencies = requireJobStep( @@ -1498,81 +1128,37 @@ function validateShieldsConfigVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); - const runVitest = requireJobStep( - errors, - jobName, - steps, - "Run shields-config live test", - ); + const runVitest = requireJobStep(errors, jobName, steps, "Run shields-config live test"); const runVitestEnv = asRecord(runVitest?.env); - if ( - runVitestEnv.NVIDIA_INFERENCE_API_KEY !== - "${{ secrets.NVIDIA_INFERENCE_API_KEY }}" - ) { - errors.push( - "shields-config-vitest step must receive NVIDIA_INFERENCE_API_KEY from secrets", - ); + if (runVitestEnv.NVIDIA_INFERENCE_API_KEY !== "${{ secrets.NVIDIA_INFERENCE_API_KEY }}") { + errors.push("shields-config-vitest step must receive NVIDIA_INFERENCE_API_KEY from secrets"); } - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/shields-config.test.ts", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/shields-config.test.ts"); - const upload = requireJobStep( - errors, - jobName, - steps, - "Upload shields-config artifacts", - ); + const upload = requireJobStep(errors, jobName, steps, "Upload shields-config artifacts"); requireFullShaAction(errors, upload, "shields-config-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); if (uploadWith.name !== "e2e-vitest-scenarios-shields-config") { errors.push("shields-config-vitest artifact upload name must be stable"); } const uploadPath = stringValue(uploadWith.path); - requireUploadPathContains( - errors, - uploadPath, - "e2e-artifacts/vitest/shields-config/", - ); - requireUploadPathContains( - errors, - uploadPath, - "/tmp/nemoclaw-e2e-shields-install.log", - ); + requireUploadPathContains(errors, uploadPath, "e2e-artifacts/vitest/shields-config/"); + requireUploadPathContains(errors, uploadPath, "/tmp/nemoclaw-e2e-shields-install.log"); if (uploadWith["include-hidden-files"] !== false) { - errors.push( - "shields-config-vitest artifact upload must set include-hidden-files: false", - ); + errors.push("shields-config-vitest artifact upload must set include-hidden-files: false"); } if (uploadWith["if-no-files-found"] !== "ignore") { - errors.push( - "shields-config-vitest artifact upload must ignore missing fixture artifacts", - ); + errors.push("shields-config-vitest artifact upload must ignore missing fixture artifacts"); } if (uploadWith["retention-days"] !== 14) { - errors.push( - "shields-config-vitest artifact upload retention-days must be 14", - ); + errors.push("shields-config-vitest artifact upload retention-days must be 14"); } } -function validateRebuildOpenClawVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateRebuildOpenClawVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "rebuild-openclaw-vitest"; const job = asRecord(jobs[jobName]); if (Object.keys(job).length === 0) { @@ -1585,28 +1171,19 @@ function validateRebuildOpenClawVitestJob( } validateFreeStandingJobSelector(errors, jobs, jobName, "rebuild-openclaw"); if (job["timeout-minutes"] !== 130) { - errors.push( - "rebuild-openclaw-vitest job must keep the legacy 130 minute timeout", - ); + errors.push("rebuild-openclaw-vitest job must keep the legacy 130 minute timeout"); } const jobEnv = asRecord(job.env); if (jobEnv.NEMOCLAW_RUN_E2E_SCENARIOS !== "1") { - errors.push( - "rebuild-openclaw-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1", - ); + errors.push("rebuild-openclaw-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1"); } - if ( - jobEnv.E2E_ARTIFACT_DIR !== - "${{ github.workspace }}/e2e-artifacts/vitest/rebuild-openclaw" - ) { + if (jobEnv.E2E_ARTIFACT_DIR !== "${{ github.workspace }}/e2e-artifacts/vitest/rebuild-openclaw") { errors.push( "rebuild-openclaw-vitest job must write artifacts under e2e-artifacts/vitest/rebuild-openclaw", ); } if (!stringValue(jobEnv.NEMOCLAW_CLI_BIN).includes("bin/nemoclaw.js")) { - errors.push( - "rebuild-openclaw-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI", - ); + errors.push("rebuild-openclaw-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI"); } requireEnvDoesNotExposeSecret( errors, @@ -1628,24 +1205,14 @@ function validateRebuildOpenClawVitestJob( } } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); - if (!checkout) - errors.push("rebuild-openclaw-vitest job missing checkout step"); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); + if (!checkout) errors.push("rebuild-openclaw-vitest job missing checkout step"); requireFullShaAction(errors, checkout, "rebuild-openclaw-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { - errors.push( - "rebuild-openclaw-vitest checkout step must set persist-credentials=false", - ); + errors.push("rebuild-openclaw-vitest checkout step must set persist-credentials=false"); } - const dockerHubAuth = requireJobStep( - errors, - jobName, - steps, - "Authenticate to Docker Hub", - ); + const dockerHubAuth = requireJobStep(errors, jobName, steps, "Authenticate to Docker Hub"); const dockerHubEnv = asRecord(dockerHubAuth?.env); if (dockerHubEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}") { errors.push( @@ -1660,8 +1227,7 @@ function validateRebuildOpenClawVitestJob( requireRunContains(errors, dockerHubAuth, "docker login docker.io"); const setupNode = namedStep(steps, "Set up Node"); - if (!setupNode) - errors.push("rebuild-openclaw-vitest job missing step: Set up Node"); + if (!setupNode) errors.push("rebuild-openclaw-vitest job missing step: Set up Node"); requireFullShaAction(errors, setupNode, "rebuild-openclaw-vitest setup-node"); const installRootDependencies = requireJobStep( @@ -1670,100 +1236,50 @@ function validateRebuildOpenClawVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); const buildCli = requireJobStep(errors, jobName, steps, "Build CLI"); requireRunContains(errors, buildCli, "npm run build:cli"); - const installOpenShell = requireJobStep( - errors, - jobName, - steps, - "Install OpenShell", - ); + const installOpenShell = requireJobStep(errors, jobName, steps, "Install OpenShell"); requireEnvDoesNotExposeSecret( errors, "rebuild-openclaw-vitest step 'Install OpenShell'", asRecord(installOpenShell?.env), "GITHUB_TOKEN", ); - requireRunContains( - errors, - installOpenShell, - "bash scripts/install-openshell.sh", - ); + requireRunContains(errors, installOpenShell, "bash scripts/install-openshell.sh"); requireRunContains(errors, installOpenShell, "env -u DOCKER_CONFIG"); requireRunContains(errors, installOpenShell, "-u DOCKERHUB_USERNAME"); requireRunContains(errors, installOpenShell, "-u DOCKERHUB_TOKEN"); requireRunContains(errors, installOpenShell, "-u NVIDIA_INFERENCE_API_KEY"); requireRunContains(errors, installOpenShell, "-u GITHUB_TOKEN"); - const runVitest = requireJobStep( - errors, - jobName, - steps, - "Run OpenClaw rebuild live test", - ); + const runVitest = requireJobStep(errors, jobName, steps, "Run OpenClaw rebuild live test"); const runVitestEnv = asRecord(runVitest?.env); - if ( - runVitestEnv.NVIDIA_INFERENCE_API_KEY !== - "${{ secrets.NVIDIA_INFERENCE_API_KEY }}" - ) { - errors.push( - "rebuild-openclaw-vitest step must receive NVIDIA_INFERENCE_API_KEY from secrets", - ); + if (runVitestEnv.NVIDIA_INFERENCE_API_KEY !== "${{ secrets.NVIDIA_INFERENCE_API_KEY }}") { + errors.push("rebuild-openclaw-vitest step must receive NVIDIA_INFERENCE_API_KEY from secrets"); } requireRunContains(errors, runVitest, "OPENSHELL_BIN"); - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/rebuild-openclaw.test.ts", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/rebuild-openclaw.test.ts"); - const upload = requireJobStep( - errors, - jobName, - steps, - "Upload OpenClaw rebuild artifacts", - ); - requireFullShaAction( - errors, - upload, - "rebuild-openclaw-vitest upload-artifact", - ); + const upload = requireJobStep(errors, jobName, steps, "Upload OpenClaw rebuild artifacts"); + requireFullShaAction(errors, upload, "rebuild-openclaw-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); if (uploadWith.name !== "e2e-vitest-scenarios-rebuild-openclaw") { errors.push("rebuild-openclaw-vitest artifact upload name must be stable"); } const uploadPath = stringValue(uploadWith.path); - requireUploadPathContains( - errors, - uploadPath, - "e2e-artifacts/vitest/rebuild-openclaw/", - ); + requireUploadPathContains(errors, uploadPath, "e2e-artifacts/vitest/rebuild-openclaw/"); if (uploadWith["include-hidden-files"] !== false) { - errors.push( - "rebuild-openclaw-vitest artifact upload must set include-hidden-files: false", - ); + errors.push("rebuild-openclaw-vitest artifact upload must set include-hidden-files: false"); } if (uploadWith["if-no-files-found"] !== "ignore") { - errors.push( - "rebuild-openclaw-vitest artifact upload must ignore missing fixture artifacts", - ); + errors.push("rebuild-openclaw-vitest artifact upload must ignore missing fixture artifacts"); } if (uploadWith["retention-days"] !== 14) { - errors.push( - "rebuild-openclaw-vitest artifact upload retention-days must be 14", - ); + errors.push("rebuild-openclaw-vitest artifact upload retention-days must be 14"); } } @@ -1772,12 +1288,8 @@ function validateRebuildHermesVitestJob( jobs: WorkflowRecord, options: { staleBase: boolean }, ): void { - const jobName = options.staleBase - ? "rebuild-hermes-stale-base-vitest" - : "rebuild-hermes-vitest"; - const scenarioName = options.staleBase - ? "rebuild-hermes-stale-base" - : "rebuild-hermes"; + const jobName = options.staleBase ? "rebuild-hermes-stale-base-vitest" : "rebuild-hermes-vitest"; + const scenarioName = options.staleBase ? "rebuild-hermes-stale-base" : "rebuild-hermes"; const job = asRecord(jobs[jobName]); if (Object.keys(job).length === 0) { errors.push(`workflow missing ${jobName} job`); @@ -1805,9 +1317,7 @@ function validateRebuildHermesVitestJob( errors.push(`${jobName} job must set NEMOCLAW_AGENT=hermes`); } if (jobEnv.NEMOCLAW_PROVIDER !== "custom") { - errors.push( - `${jobName} job must use the hosted compatible endpoint provider`, - ); + errors.push(`${jobName} job must use the hosted compatible endpoint provider`); } if (jobEnv.NEMOCLAW_ENDPOINT_URL !== "https://inference-api.nvidia.com/v1") { errors.push(`${jobName} job must target hosted CI inference endpoint`); @@ -1823,19 +1333,13 @@ function validateRebuildHermesVitestJob( } if (options.staleBase) { if (jobEnv.NEMOCLAW_HERMES_STALE_BASE_REBUILD_E2E !== "1") { - errors.push( - `${jobName} job must enable NEMOCLAW_HERMES_STALE_BASE_REBUILD_E2E=1`, - ); + errors.push(`${jobName} job must enable NEMOCLAW_HERMES_STALE_BASE_REBUILD_E2E=1`); } if (jobEnv.NEMOCLAW_SANDBOX_NAME !== "e2e-rebuild-hermes-base") { - errors.push( - `${jobName} job must set NEMOCLAW_SANDBOX_NAME=e2e-rebuild-hermes-base`, - ); + errors.push(`${jobName} job must set NEMOCLAW_SANDBOX_NAME=e2e-rebuild-hermes-base`); } } else if (jobEnv.NEMOCLAW_SANDBOX_NAME !== "e2e-rebuild-hermes") { - errors.push( - `${jobName} job must set NEMOCLAW_SANDBOX_NAME=e2e-rebuild-hermes`, - ); + errors.push(`${jobName} job must set NEMOCLAW_SANDBOX_NAME=e2e-rebuild-hermes`); } for (const secret of [ "NVIDIA_INFERENCE_API_KEY", @@ -1852,56 +1356,30 @@ function validateRebuildHermesVitestJob( const stepName = `${jobName} step '${step.name ?? step.uses ?? ""}'`; const stepEnv = asRecord(step.env); if (!step.name?.startsWith("Run Hermes")) { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "NVIDIA_INFERENCE_API_KEY", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "NVIDIA_INFERENCE_API_KEY"); } if (step.name !== "Authenticate to Docker Hub") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_USERNAME", - ); - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_TOKEN", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_USERNAME"); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_TOKEN"); requireNoDockerHubAuthInRun(errors, stepName, stringValue(step.run)); } requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "GITHUB_TOKEN"); } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); if (!checkout) errors.push(`${jobName} job missing checkout step`); requireFullShaAction(errors, checkout, `${jobName} checkout`); if (asRecord(checkout?.with)["persist-credentials"] !== false) { errors.push(`${jobName} checkout step must set persist-credentials=false`); } - const dockerHubAuth = requireJobStep( - errors, - jobName, - steps, - "Authenticate to Docker Hub", - ); + const dockerHubAuth = requireJobStep(errors, jobName, steps, "Authenticate to Docker Hub"); const dockerHubEnv = asRecord(dockerHubAuth?.env); if (dockerHubEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}") { - errors.push( - `${jobName} Docker Hub auth must receive DOCKERHUB_USERNAME from secrets`, - ); + errors.push(`${jobName} Docker Hub auth must receive DOCKERHUB_USERNAME from secrets`); } if (dockerHubEnv.DOCKERHUB_TOKEN !== "${{ secrets.DOCKERHUB_TOKEN }}") { - errors.push( - `${jobName} Docker Hub auth must receive DOCKERHUB_TOKEN from secrets`, - ); + errors.push(`${jobName} Docker Hub auth must receive DOCKERHUB_TOKEN from secrets`); } requireRunContains(errors, dockerHubAuth, "docker login docker.io"); requireRunContains(errors, dockerHubAuth, "continuing with anonymous pulls"); @@ -1916,39 +1394,20 @@ function validateRebuildHermesVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); const runVitest = requireJobStep( errors, jobName, steps, - options.staleBase - ? "Run Hermes stale-base rebuild live test" - : "Run Hermes rebuild live test", + options.staleBase ? "Run Hermes stale-base rebuild live test" : "Run Hermes rebuild live test", ); const runVitestEnv = asRecord(runVitest?.env); - if ( - runVitestEnv.NVIDIA_INFERENCE_API_KEY !== - "${{ secrets.NVIDIA_INFERENCE_API_KEY }}" - ) { - errors.push( - `${jobName} step must receive NVIDIA_INFERENCE_API_KEY from secrets`, - ); + if (runVitestEnv.NVIDIA_INFERENCE_API_KEY !== "${{ secrets.NVIDIA_INFERENCE_API_KEY }}") { + errors.push(`${jobName} step must receive NVIDIA_INFERENCE_API_KEY from secrets`); } - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/rebuild-hermes.test.ts", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/rebuild-hermes.test.ts"); const upload = requireJobStep( errors, @@ -1975,24 +1434,17 @@ function validateRebuildHermesVitestJob( : "e2e-artifacts/vitest/rebuild-hermes/", ); if (uploadWith["include-hidden-files"] !== false) { - errors.push( - `${jobName} artifact upload must set include-hidden-files: false`, - ); + errors.push(`${jobName} artifact upload must set include-hidden-files: false`); } if (uploadWith["if-no-files-found"] !== "ignore") { - errors.push( - `${jobName} artifact upload must ignore missing fixture artifacts`, - ); + errors.push(`${jobName} artifact upload must ignore missing fixture artifacts`); } if (uploadWith["retention-days"] !== 14) { errors.push(`${jobName} artifact upload retention-days must be 14`); } } -function validateSandboxRebuildVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateSandboxRebuildVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "sandbox-rebuild-vitest"; const scenarioName = "sandbox-rebuild"; const job = asRecord(jobs[jobName]); @@ -2006,33 +1458,22 @@ function validateSandboxRebuildVitestJob( } validateFreeStandingJobSelector(errors, jobs, jobName, scenarioName); if (job["timeout-minutes"] !== 90) { - errors.push( - "sandbox-rebuild-vitest job must keep the legacy 90 minute timeout", - ); + errors.push("sandbox-rebuild-vitest job must keep the legacy 90 minute timeout"); } const jobEnv = asRecord(job.env); if (jobEnv.NEMOCLAW_RUN_E2E_SCENARIOS !== "1") { - errors.push( - "sandbox-rebuild-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1", - ); + errors.push("sandbox-rebuild-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1"); } - if ( - jobEnv.E2E_ARTIFACT_DIR !== - "${{ github.workspace }}/e2e-artifacts/vitest/sandbox-rebuild" - ) { + if (jobEnv.E2E_ARTIFACT_DIR !== "${{ github.workspace }}/e2e-artifacts/vitest/sandbox-rebuild") { errors.push( "sandbox-rebuild-vitest job must write artifacts under e2e-artifacts/vitest/sandbox-rebuild", ); } if (jobEnv.NEMOCLAW_CLI_BIN !== "${{ github.workspace }}/bin/nemoclaw.js") { - errors.push( - "sandbox-rebuild-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI", - ); + errors.push("sandbox-rebuild-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI"); } if (jobEnv.OPENSHELL_GATEWAY !== "nemoclaw") { - errors.push( - "sandbox-rebuild-vitest job must force OPENSHELL_GATEWAY=nemoclaw", - ); + errors.push("sandbox-rebuild-vitest job must force OPENSHELL_GATEWAY=nemoclaw"); } for (const secret of [ "NVIDIA_INFERENCE_API_KEY", @@ -2040,12 +1481,7 @@ function validateSandboxRebuildVitestJob( "DOCKERHUB_TOKEN", "GITHUB_TOKEN", ]) { - requireEnvDoesNotExposeSecret( - errors, - "sandbox-rebuild-vitest job", - jobEnv, - secret, - ); + requireEnvDoesNotExposeSecret(errors, "sandbox-rebuild-vitest job", jobEnv, secret); } const steps = asSteps(job.steps); @@ -2054,49 +1490,24 @@ function validateSandboxRebuildVitestJob( const stepName = `sandbox-rebuild-vitest step '${step.name ?? step.uses ?? ""}'`; const stepEnv = asRecord(step.env); if (step.name !== "Run sandbox rebuild live test") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "NVIDIA_INFERENCE_API_KEY", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "NVIDIA_INFERENCE_API_KEY"); } if (step.name !== "Authenticate to Docker Hub") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_USERNAME", - ); - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_TOKEN", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_USERNAME"); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_TOKEN"); requireNoDockerHubAuthInRun(errors, stepName, stringValue(step.run)); } requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "GITHUB_TOKEN"); } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); - if (!checkout) - errors.push("sandbox-rebuild-vitest job missing checkout step"); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); + if (!checkout) errors.push("sandbox-rebuild-vitest job missing checkout step"); requireFullShaAction(errors, checkout, "sandbox-rebuild-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { - errors.push( - "sandbox-rebuild-vitest checkout step must set persist-credentials=false", - ); + errors.push("sandbox-rebuild-vitest checkout step must set persist-credentials=false"); } - const dockerHubAuth = requireJobStep( - errors, - jobName, - steps, - "Authenticate to Docker Hub", - ); + const dockerHubAuth = requireJobStep(errors, jobName, steps, "Authenticate to Docker Hub"); const dockerHubEnv = asRecord(dockerHubAuth?.env); if (dockerHubEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}") { errors.push( @@ -2104,16 +1515,13 @@ function validateSandboxRebuildVitestJob( ); } if (dockerHubEnv.DOCKERHUB_TOKEN !== "${{ secrets.DOCKERHUB_TOKEN }}") { - errors.push( - "sandbox-rebuild-vitest Docker Hub auth must receive DOCKERHUB_TOKEN from secrets", - ); + errors.push("sandbox-rebuild-vitest Docker Hub auth must receive DOCKERHUB_TOKEN from secrets"); } requireRunContains(errors, dockerHubAuth, "docker login docker.io"); requireRunContains(errors, dockerHubAuth, "continuing with anonymous pulls"); const setupNode = namedStep(steps, "Set up Node"); - if (!setupNode) - errors.push("sandbox-rebuild-vitest job missing step: Set up Node"); + if (!setupNode) errors.push("sandbox-rebuild-vitest job missing step: Set up Node"); requireFullShaAction(errors, setupNode, "sandbox-rebuild-vitest setup-node"); const installRootDependencies = requireJobStep( @@ -2122,101 +1530,48 @@ function validateSandboxRebuildVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); const buildCli = requireJobStep(errors, jobName, steps, "Build CLI"); requireRunContains(errors, buildCli, "npm run build:cli"); - const installOpenShell = requireJobStep( - errors, - jobName, - steps, - "Install OpenShell", - ); - requireRunContains( - errors, - installOpenShell, - "bash scripts/install-openshell.sh", - ); + const installOpenShell = requireJobStep(errors, jobName, steps, "Install OpenShell"); + requireRunContains(errors, installOpenShell, "bash scripts/install-openshell.sh"); requireRunContains(errors, installOpenShell, "env -u DOCKER_CONFIG"); requireRunContains(errors, installOpenShell, "-u DOCKERHUB_USERNAME"); requireRunContains(errors, installOpenShell, "-u DOCKERHUB_TOKEN"); requireRunContains(errors, installOpenShell, "-u NVIDIA_INFERENCE_API_KEY"); requireRunContains(errors, installOpenShell, "-u GITHUB_TOKEN"); - const runVitest = requireJobStep( - errors, - jobName, - steps, - "Run sandbox rebuild live test", - ); + const runVitest = requireJobStep(errors, jobName, steps, "Run sandbox rebuild live test"); const runVitestEnv = asRecord(runVitest?.env); - if ( - runVitestEnv.NVIDIA_INFERENCE_API_KEY !== - "${{ secrets.NVIDIA_INFERENCE_API_KEY }}" - ) { - errors.push( - "sandbox-rebuild-vitest step must receive NVIDIA_INFERENCE_API_KEY from secrets", - ); + if (runVitestEnv.NVIDIA_INFERENCE_API_KEY !== "${{ secrets.NVIDIA_INFERENCE_API_KEY }}") { + errors.push("sandbox-rebuild-vitest step must receive NVIDIA_INFERENCE_API_KEY from secrets"); } requireRunContains(errors, runVitest, "OPENSHELL_BIN"); - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/sandbox-rebuild.test.ts", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/sandbox-rebuild.test.ts"); - const upload = requireJobStep( - errors, - jobName, - steps, - "Upload sandbox rebuild artifacts", - ); - requireFullShaAction( - errors, - upload, - "sandbox-rebuild-vitest upload-artifact", - ); + const upload = requireJobStep(errors, jobName, steps, "Upload sandbox rebuild artifacts"); + requireFullShaAction(errors, upload, "sandbox-rebuild-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); if (uploadWith.name !== "e2e-vitest-scenarios-sandbox-rebuild") { errors.push("sandbox-rebuild-vitest artifact upload name must be stable"); } const uploadPath = stringValue(uploadWith.path); - requireUploadPathContains( - errors, - uploadPath, - "e2e-artifacts/vitest/sandbox-rebuild/", - ); + requireUploadPathContains(errors, uploadPath, "e2e-artifacts/vitest/sandbox-rebuild/"); if (uploadWith["include-hidden-files"] !== false) { - errors.push( - "sandbox-rebuild-vitest artifact upload must set include-hidden-files: false", - ); + errors.push("sandbox-rebuild-vitest artifact upload must set include-hidden-files: false"); } if (uploadWith["if-no-files-found"] !== "ignore") { - errors.push( - "sandbox-rebuild-vitest artifact upload must ignore missing fixture artifacts", - ); + errors.push("sandbox-rebuild-vitest artifact upload must ignore missing fixture artifacts"); } if (uploadWith["retention-days"] !== 14) { - errors.push( - "sandbox-rebuild-vitest artifact upload retention-days must be 14", - ); + errors.push("sandbox-rebuild-vitest artifact upload retention-days must be 14"); } } -function validateStateBackupRestoreVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateStateBackupRestoreVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "state-backup-restore-vitest"; const scenarioName = "state-backup-restore"; const job = asRecord(jobs[jobName]); @@ -2230,48 +1585,33 @@ function validateStateBackupRestoreVitestJob( } validateFreeStandingJobSelector(errors, jobs, jobName, scenarioName); if (job["timeout-minutes"] !== 60) { - errors.push( - "state-backup-restore-vitest job must keep the legacy 60 minute timeout", - ); + errors.push("state-backup-restore-vitest job must keep the legacy 60 minute timeout"); } const jobEnv = asRecord(job.env); if (jobEnv.NEMOCLAW_RUN_E2E_SCENARIOS !== "1") { - errors.push( - "state-backup-restore-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1", - ); + errors.push("state-backup-restore-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1"); } if ( - jobEnv.E2E_ARTIFACT_DIR !== - "${{ github.workspace }}/e2e-artifacts/vitest/state-backup-restore" + jobEnv.E2E_ARTIFACT_DIR !== "${{ github.workspace }}/e2e-artifacts/vitest/state-backup-restore" ) { errors.push( "state-backup-restore-vitest job must write artifacts under e2e-artifacts/vitest/state-backup-restore", ); } if (jobEnv.NEMOCLAW_CLI_BIN !== "${{ github.workspace }}/bin/nemoclaw.js") { - errors.push( - "state-backup-restore-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI", - ); + errors.push("state-backup-restore-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI"); } if (jobEnv.OPENSHELL_GATEWAY !== "nemoclaw") { - errors.push( - "state-backup-restore-vitest job must force OPENSHELL_GATEWAY=nemoclaw", - ); + errors.push("state-backup-restore-vitest job must force OPENSHELL_GATEWAY=nemoclaw"); } if (jobEnv.NEMOCLAW_NON_INTERACTIVE !== "1") { - errors.push( - "state-backup-restore-vitest job must set NEMOCLAW_NON_INTERACTIVE=1", - ); + errors.push("state-backup-restore-vitest job must set NEMOCLAW_NON_INTERACTIVE=1"); } if (jobEnv.NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE !== "1") { - errors.push( - "state-backup-restore-vitest job must set NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1", - ); + errors.push("state-backup-restore-vitest job must set NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1"); } if (jobEnv.NEMOCLAW_SANDBOX_NAME !== "e2e-state-backup") { - errors.push( - "state-backup-restore-vitest job must set NEMOCLAW_SANDBOX_NAME=e2e-state-backup", - ); + errors.push("state-backup-restore-vitest job must set NEMOCLAW_SANDBOX_NAME=e2e-state-backup"); } for (const secret of [ "NVIDIA_INFERENCE_API_KEY", @@ -2279,12 +1619,7 @@ function validateStateBackupRestoreVitestJob( "DOCKERHUB_TOKEN", "GITHUB_TOKEN", ]) { - requireEnvDoesNotExposeSecret( - errors, - "state-backup-restore-vitest job", - jobEnv, - secret, - ); + requireEnvDoesNotExposeSecret(errors, "state-backup-restore-vitest job", jobEnv, secret); } const steps = asSteps(job.steps); @@ -2293,53 +1628,24 @@ function validateStateBackupRestoreVitestJob( const stepName = `state-backup-restore-vitest step '${step.name ?? step.uses ?? ""}'`; const stepEnv = asRecord(step.env); if (step.name !== "Run state backup restore live test") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "NVIDIA_INFERENCE_API_KEY", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "NVIDIA_INFERENCE_API_KEY"); } if (step.name !== "Authenticate to Docker Hub") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_USERNAME", - ); - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_TOKEN", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_USERNAME"); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_TOKEN"); requireNoDockerHubAuthInRun(errors, stepName, stringValue(step.run)); } requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "GITHUB_TOKEN"); } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); - if (!checkout) - errors.push("state-backup-restore-vitest job missing checkout step"); - requireFullShaAction( - errors, - checkout, - "state-backup-restore-vitest checkout", - ); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); + if (!checkout) errors.push("state-backup-restore-vitest job missing checkout step"); + requireFullShaAction(errors, checkout, "state-backup-restore-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { - errors.push( - "state-backup-restore-vitest checkout step must set persist-credentials=false", - ); + errors.push("state-backup-restore-vitest checkout step must set persist-credentials=false"); } - const dockerHubAuth = requireJobStep( - errors, - jobName, - steps, - "Authenticate to Docker Hub", - ); + const dockerHubAuth = requireJobStep(errors, jobName, steps, "Authenticate to Docker Hub"); const dockerHubEnv = asRecord(dockerHubAuth?.env); if (dockerHubEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}") { errors.push( @@ -2355,13 +1661,8 @@ function validateStateBackupRestoreVitestJob( requireRunContains(errors, dockerHubAuth, "continuing with anonymous pulls"); const setupNode = namedStep(steps, "Set up Node"); - if (!setupNode) - errors.push("state-backup-restore-vitest job missing step: Set up Node"); - requireFullShaAction( - errors, - setupNode, - "state-backup-restore-vitest setup-node", - ); + if (!setupNode) errors.push("state-backup-restore-vitest job missing step: Set up Node"); + requireFullShaAction(errors, setupNode, "state-backup-restore-vitest setup-node"); const installRootDependencies = requireJobStep( errors, @@ -2369,38 +1670,20 @@ function validateStateBackupRestoreVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); const buildCli = requireJobStep(errors, jobName, steps, "Build CLI"); requireRunContains(errors, buildCli, "npm run build:cli"); - const installOpenShell = requireJobStep( - errors, - jobName, - steps, - "Install OpenShell", - ); - requireRunContains( - errors, - installOpenShell, - "bash scripts/install-openshell.sh", - ); + const installOpenShell = requireJobStep(errors, jobName, steps, "Install OpenShell"); + requireRunContains(errors, installOpenShell, "bash scripts/install-openshell.sh"); requireRunContains(errors, installOpenShell, "env -u DOCKER_CONFIG"); requireRunContains(errors, installOpenShell, "-u DOCKERHUB_USERNAME"); requireRunContains(errors, installOpenShell, "-u DOCKERHUB_TOKEN"); requireRunContains(errors, installOpenShell, "-u NVIDIA_INFERENCE_API_KEY"); requireRunContains(errors, installOpenShell, "-u GITHUB_TOKEN"); - const runVitest = requireJobStep( - errors, - jobName, - steps, - "Run state backup restore live test", - ); + const runVitest = requireJobStep(errors, jobName, steps, "Run state backup restore live test"); const runVitestEnv = asRecord(runVitest?.env); if (runVitestEnv.NVIDIA_INFERENCE_API_KEY !== "${{ secrets.NVIDIA_INFERENCE_API_KEY }}") { errors.push( @@ -2408,44 +1691,19 @@ function validateStateBackupRestoreVitestJob( ); } requireRunContains(errors, runVitest, "OPENSHELL_BIN"); - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/state-backup-restore.test.ts", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/state-backup-restore.test.ts"); - const upload = requireJobStep( - errors, - jobName, - steps, - "Upload state backup restore artifacts", - ); - requireFullShaAction( - errors, - upload, - "state-backup-restore-vitest upload-artifact", - ); + const upload = requireJobStep(errors, jobName, steps, "Upload state backup restore artifacts"); + requireFullShaAction(errors, upload, "state-backup-restore-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); if (uploadWith.name !== "e2e-vitest-scenarios-state-backup-restore") { - errors.push( - "state-backup-restore-vitest artifact upload name must be stable", - ); + errors.push("state-backup-restore-vitest artifact upload name must be stable"); } const uploadPath = stringValue(uploadWith.path); - requireUploadPathContains( - errors, - uploadPath, - "e2e-artifacts/vitest/state-backup-restore/", - ); + requireUploadPathContains(errors, uploadPath, "e2e-artifacts/vitest/state-backup-restore/"); if (uploadWith["include-hidden-files"] !== false) { - errors.push( - "state-backup-restore-vitest artifact upload must set include-hidden-files: false", - ); + errors.push("state-backup-restore-vitest artifact upload must set include-hidden-files: false"); } if (uploadWith["if-no-files-found"] !== "ignore") { errors.push( @@ -2453,16 +1711,11 @@ function validateStateBackupRestoreVitestJob( ); } if (uploadWith["retention-days"] !== 14) { - errors.push( - "state-backup-restore-vitest artifact upload retention-days must be 14", - ); + errors.push("state-backup-restore-vitest artifact upload retention-days must be 14"); } } -function validateUpgradeStaleSandboxVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateUpgradeStaleSandboxVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "upgrade-stale-sandbox-vitest"; const scenarioName = "upgrade-stale-sandbox"; const job = asRecord(jobs[jobName]); @@ -2476,34 +1729,25 @@ function validateUpgradeStaleSandboxVitestJob( } validateFreeStandingJobSelector(errors, jobs, jobName, scenarioName); if (job["timeout-minutes"] !== 55) { - errors.push( - "upgrade-stale-sandbox-vitest job must keep the legacy 55 minute timeout", - ); + errors.push("upgrade-stale-sandbox-vitest job must keep the legacy 55 minute timeout"); } const jobEnv = asRecord(job.env); if (jobEnv.NEMOCLAW_RUN_E2E_SCENARIOS !== "1") { - errors.push( - "upgrade-stale-sandbox-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1", - ); + errors.push("upgrade-stale-sandbox-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1"); } if ( - jobEnv.E2E_ARTIFACT_DIR !== - "${{ github.workspace }}/e2e-artifacts/vitest/upgrade-stale-sandbox" + jobEnv.E2E_ARTIFACT_DIR !== "${{ github.workspace }}/e2e-artifacts/vitest/upgrade-stale-sandbox" ) { errors.push( "upgrade-stale-sandbox-vitest job must write artifacts under e2e-artifacts/vitest/upgrade-stale-sandbox", ); } if (jobEnv.NEMOCLAW_CLI_BIN !== "${{ github.workspace }}/bin/nemoclaw.js") { - errors.push( - "upgrade-stale-sandbox-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI", - ); + errors.push("upgrade-stale-sandbox-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI"); } if (jobEnv.OPENSHELL_GATEWAY !== "nemoclaw") { - errors.push( - "upgrade-stale-sandbox-vitest job must force OPENSHELL_GATEWAY=nemoclaw", - ); + errors.push("upgrade-stale-sandbox-vitest job must force OPENSHELL_GATEWAY=nemoclaw"); } if (jobEnv.NEMOCLAW_SANDBOX_NAME !== "e2e-upgrade-stale") { errors.push( @@ -2511,19 +1755,10 @@ function validateUpgradeStaleSandboxVitestJob( ); } if ("DOCKER_CONFIG" in jobEnv) { - errors.push( - "upgrade-stale-sandbox-vitest job must not set DOCKER_CONFIG at job level", - ); + errors.push("upgrade-stale-sandbox-vitest job must not set DOCKER_CONFIG at job level"); } - for (const secret of [ - ...COMMON_SECRET_ENV_NAMES, - ]) { - requireEnvDoesNotExposeSecret( - errors, - "upgrade-stale-sandbox-vitest job", - jobEnv, - secret, - ); + for (const secret of [...COMMON_SECRET_ENV_NAMES]) { + requireEnvDoesNotExposeSecret(errors, "upgrade-stale-sandbox-vitest job", jobEnv, secret); } const steps = asSteps(job.steps); @@ -2532,51 +1767,22 @@ function validateUpgradeStaleSandboxVitestJob( const stepName = `upgrade-stale-sandbox-vitest step '${step.name ?? step.uses ?? ""}'`; const stepEnv = asRecord(step.env); if (step.name !== "Run upgrade stale sandbox live Vitest test") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "NVIDIA_INFERENCE_API_KEY", - ); - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "NVIDIA_INFERENCE_API_KEY", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "NVIDIA_INFERENCE_API_KEY"); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "NVIDIA_INFERENCE_API_KEY"); } if (step.name !== "Authenticate to Docker Hub") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_USERNAME", - ); - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_TOKEN", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_USERNAME"); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_TOKEN"); requireNoDockerHubAuthInRun(errors, stepName, stringValue(step.run)); } requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "GITHUB_TOKEN"); } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); - if (!checkout) - errors.push("upgrade-stale-sandbox-vitest job missing checkout step"); - requireFullShaAction( - errors, - checkout, - "upgrade-stale-sandbox-vitest checkout", - ); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); + if (!checkout) errors.push("upgrade-stale-sandbox-vitest job missing checkout step"); + requireFullShaAction(errors, checkout, "upgrade-stale-sandbox-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { - errors.push( - "upgrade-stale-sandbox-vitest checkout step must set persist-credentials=false", - ); + errors.push("upgrade-stale-sandbox-vitest checkout step must set persist-credentials=false"); } const configureDockerAuth = requireJobStep( @@ -2591,12 +1797,7 @@ function validateUpgradeStaleSandboxVitestJob( 'echo "DOCKER_CONFIG=${RUNNER_TEMP}/docker-config-upgrade-stale-sandbox" >> "$GITHUB_ENV"', ); - const dockerHubAuth = requireJobStep( - errors, - jobName, - steps, - "Authenticate to Docker Hub", - ); + const dockerHubAuth = requireJobStep(errors, jobName, steps, "Authenticate to Docker Hub"); const dockerHubEnv = asRecord(dockerHubAuth?.env); if (dockerHubEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}") { errors.push( @@ -2614,13 +1815,8 @@ function validateUpgradeStaleSandboxVitestJob( requireRunContains(errors, dockerHubAuth, "continuing with anonymous pulls"); const setupNode = namedStep(steps, "Set up Node"); - if (!setupNode) - errors.push("upgrade-stale-sandbox-vitest job missing step: Set up Node"); - requireFullShaAction( - errors, - setupNode, - "upgrade-stale-sandbox-vitest setup-node", - ); + if (!setupNode) errors.push("upgrade-stale-sandbox-vitest job missing step: Set up Node"); + requireFullShaAction(errors, setupNode, "upgrade-stale-sandbox-vitest setup-node"); const installRootDependencies = requireJobStep( errors, @@ -2628,26 +1824,13 @@ function validateUpgradeStaleSandboxVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); const buildCli = requireJobStep(errors, jobName, steps, "Build CLI"); requireRunContains(errors, buildCli, "npm run build:cli"); - const installOpenShell = requireJobStep( - errors, - jobName, - steps, - "Install OpenShell CLI", - ); - requireRunContains( - errors, - installOpenShell, - "bash scripts/install-openshell.sh", - ); + const installOpenShell = requireJobStep(errors, jobName, steps, "Install OpenShell CLI"); + requireRunContains(errors, installOpenShell, "bash scripts/install-openshell.sh"); requireRunContains(errors, installOpenShell, "env -u DOCKER_CONFIG"); requireRunContains(errors, installOpenShell, "-u DOCKERHUB_USERNAME"); requireRunContains(errors, installOpenShell, "-u DOCKERHUB_TOKEN"); @@ -2661,49 +1844,23 @@ function validateUpgradeStaleSandboxVitestJob( "Run upgrade stale sandbox live Vitest test", ); const runVitestEnv = asRecord(runVitest?.env); - if ( - runVitestEnv.NVIDIA_INFERENCE_API_KEY !== - "${{ secrets.NVIDIA_INFERENCE_API_KEY }}" - ) { + if (runVitestEnv.NVIDIA_INFERENCE_API_KEY !== "${{ secrets.NVIDIA_INFERENCE_API_KEY }}") { errors.push( "upgrade-stale-sandbox-vitest step must receive NVIDIA_INFERENCE_API_KEY from secrets", ); } requireRunContains(errors, runVitest, "OPENSHELL_BIN"); - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/upgrade-stale-sandbox.test.ts", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/upgrade-stale-sandbox.test.ts"); - const upload = requireJobStep( - errors, - jobName, - steps, - "Upload upgrade stale sandbox artifacts", - ); - requireFullShaAction( - errors, - upload, - "upgrade-stale-sandbox-vitest upload-artifact", - ); + const upload = requireJobStep(errors, jobName, steps, "Upload upgrade stale sandbox artifacts"); + requireFullShaAction(errors, upload, "upgrade-stale-sandbox-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); if (uploadWith.name !== "e2e-vitest-scenarios-upgrade-stale-sandbox") { - errors.push( - "upgrade-stale-sandbox-vitest artifact upload name must be stable", - ); + errors.push("upgrade-stale-sandbox-vitest artifact upload name must be stable"); } const uploadPath = stringValue(uploadWith.path); - requireUploadPathContains( - errors, - uploadPath, - "e2e-artifacts/vitest/upgrade-stale-sandbox/", - ); + requireUploadPathContains(errors, uploadPath, "e2e-artifacts/vitest/upgrade-stale-sandbox/"); if (uploadWith["include-hidden-files"] !== false) { errors.push( "upgrade-stale-sandbox-vitest artifact upload must set include-hidden-files: false", @@ -2715,25 +1872,15 @@ function validateUpgradeStaleSandboxVitestJob( ); } if (uploadWith["retention-days"] !== 14) { - errors.push( - "upgrade-stale-sandbox-vitest artifact upload retention-days must be 14", - ); + errors.push("upgrade-stale-sandbox-vitest artifact upload retention-days must be 14"); } - const cleanup = requireJobStep( - errors, - jobName, - steps, - "Clean up Docker auth", - ); + const cleanup = requireJobStep(errors, jobName, steps, "Clean up Docker auth"); requireRunContains(errors, cleanup, "docker logout docker.io"); requireRunContains(errors, cleanup, 'rm -rf "${DOCKER_CONFIG}"'); } -function validateTokenRotationVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateTokenRotationVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "token-rotation-vitest"; const job = asRecord(jobs[jobName]); if (Object.keys(job).length === 0) { @@ -2746,28 +1893,19 @@ function validateTokenRotationVitestJob( } validateFreeStandingJobSelector(errors, jobs, jobName, "token-rotation"); if (job["timeout-minutes"] !== 45) { - errors.push( - "token-rotation-vitest job must keep the legacy 45 minute timeout", - ); + errors.push("token-rotation-vitest job must keep the legacy 45 minute timeout"); } const jobEnv = asRecord(job.env); if (jobEnv.NEMOCLAW_RUN_E2E_SCENARIOS !== "1") { - errors.push( - "token-rotation-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1", - ); + errors.push("token-rotation-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1"); } - if ( - jobEnv.E2E_ARTIFACT_DIR !== - "${{ github.workspace }}/e2e-artifacts/vitest/token-rotation" - ) { + if (jobEnv.E2E_ARTIFACT_DIR !== "${{ github.workspace }}/e2e-artifacts/vitest/token-rotation") { errors.push( "token-rotation-vitest job must write artifacts under e2e-artifacts/vitest/token-rotation", ); } if (!stringValue(jobEnv.NEMOCLAW_CLI_BIN).includes("bin/nemoclaw.js")) { - errors.push( - "token-rotation-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI", - ); + errors.push("token-rotation-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI"); } requireEnvDoesNotExposeSecret( errors, @@ -2789,23 +1927,14 @@ function validateTokenRotationVitestJob( } } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); if (!checkout) errors.push("token-rotation-vitest job missing checkout step"); requireFullShaAction(errors, checkout, "token-rotation-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { - errors.push( - "token-rotation-vitest checkout step must set persist-credentials=false", - ); + errors.push("token-rotation-vitest checkout step must set persist-credentials=false"); } - const dockerHubAuth = requireJobStep( - errors, - jobName, - steps, - "Authenticate to Docker Hub", - ); + const dockerHubAuth = requireJobStep(errors, jobName, steps, "Authenticate to Docker Hub"); const dockerHubEnv = asRecord(dockerHubAuth?.env); if (dockerHubEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}") { errors.push( @@ -2813,15 +1942,12 @@ function validateTokenRotationVitestJob( ); } if (dockerHubEnv.DOCKERHUB_TOKEN !== "${{ secrets.DOCKERHUB_TOKEN }}") { - errors.push( - "token-rotation-vitest Docker Hub auth must receive DOCKERHUB_TOKEN from secrets", - ); + errors.push("token-rotation-vitest Docker Hub auth must receive DOCKERHUB_TOKEN from secrets"); } requireRunContains(errors, dockerHubAuth, "docker login docker.io"); const setupNode = namedStep(steps, "Set up Node"); - if (!setupNode) - errors.push("token-rotation-vitest job missing step: Set up Node"); + if (!setupNode) errors.push("token-rotation-vitest job missing step: Set up Node"); requireFullShaAction(errors, setupNode, "token-rotation-vitest setup-node"); const installRootDependencies = requireJobStep( @@ -2830,21 +1956,12 @@ function validateTokenRotationVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); const buildCli = requireJobStep(errors, jobName, steps, "Build CLI"); requireRunContains(errors, buildCli, "npm run build:cli"); - const runVitest = requireJobStep( - errors, - jobName, - steps, - "Run token rotation live test", - ); + const runVitest = requireJobStep(errors, jobName, steps, "Run token rotation live test"); const runVitestEnv = asRecord(runVitest?.env); requireEnvDoesNotExposeSecret( errors, @@ -2853,9 +1970,7 @@ function validateTokenRotationVitestJob( "NVIDIA_INFERENCE_API_KEY", ); if (runVitestEnv.GITHUB_TOKEN !== "${{ github.token }}") { - errors.push( - "token-rotation-vitest step must receive GITHUB_TOKEN from github.token", - ); + errors.push("token-rotation-vitest step must receive GITHUB_TOKEN from github.token"); } for (const tokenName of [ "TELEGRAM_BOT_TOKEN_A", @@ -2876,48 +1991,25 @@ function validateTokenRotationVitestJob( errors.push(`token-rotation-vitest step must set ${tokenName}`); } } - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/token-rotation.test.ts", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/token-rotation.test.ts"); - const upload = requireJobStep( - errors, - jobName, - steps, - "Upload token rotation artifacts", - ); + const upload = requireJobStep(errors, jobName, steps, "Upload token rotation artifacts"); requireFullShaAction(errors, upload, "token-rotation-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); if (uploadWith.name !== "e2e-vitest-scenarios-token-rotation") { errors.push("token-rotation-vitest artifact upload name must be stable"); } const uploadPath = stringValue(uploadWith.path); - requireUploadPathContains( - errors, - uploadPath, - "e2e-artifacts/vitest/token-rotation/", - ); + requireUploadPathContains(errors, uploadPath, "e2e-artifacts/vitest/token-rotation/"); if (uploadWith["include-hidden-files"] !== false) { - errors.push( - "token-rotation-vitest artifact upload must set include-hidden-files: false", - ); + errors.push("token-rotation-vitest artifact upload must set include-hidden-files: false"); } if (uploadWith["if-no-files-found"] !== "ignore") { - errors.push( - "token-rotation-vitest artifact upload must ignore missing fixture artifacts", - ); + errors.push("token-rotation-vitest artifact upload must ignore missing fixture artifacts"); } if (uploadWith["retention-days"] !== 14) { - errors.push( - "token-rotation-vitest artifact upload retention-days must be 14", - ); + errors.push("token-rotation-vitest artifact upload retention-days must be 14"); } } @@ -2933,20 +2025,11 @@ function validateMessagingCompatibleEndpointVitestJob( } if (job["runs-on"] !== "ubuntu-latest") { - errors.push( - "messaging-compatible-endpoint-vitest job must run on ubuntu-latest", - ); + errors.push("messaging-compatible-endpoint-vitest job must run on ubuntu-latest"); } - validateFreeStandingJobSelector( - errors, - jobs, - jobName, - "messaging-compatible-endpoint", - ); + validateFreeStandingJobSelector(errors, jobs, jobName, "messaging-compatible-endpoint"); if (job["timeout-minutes"] !== 45) { - errors.push( - "messaging-compatible-endpoint-vitest job must keep the legacy 45 minute timeout", - ); + errors.push("messaging-compatible-endpoint-vitest job must keep the legacy 45 minute timeout"); } const jobEnv = asRecord(job.env); @@ -2964,19 +2047,13 @@ function validateMessagingCompatibleEndpointVitestJob( ); } if (jobEnv.NEMOCLAW_RUN_E2E_SCENARIOS !== "1") { - errors.push( - "messaging-compatible-endpoint-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1", - ); + errors.push("messaging-compatible-endpoint-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1"); } if (jobEnv.NEMOCLAW_SANDBOX_NAME !== "e2e-msg-compat") { - errors.push( - "messaging-compatible-endpoint-vitest job must pin the legacy sandbox name", - ); + errors.push("messaging-compatible-endpoint-vitest job must pin the legacy sandbox name"); } if (jobEnv.OPENSHELL_GATEWAY !== "nemoclaw") { - errors.push( - "messaging-compatible-endpoint-vitest job must force OPENSHELL_GATEWAY=nemoclaw", - ); + errors.push("messaging-compatible-endpoint-vitest job must force OPENSHELL_GATEWAY=nemoclaw"); } requireEnvDoesNotExposeSecret( errors, @@ -3033,18 +2110,9 @@ function validateMessagingCompatibleEndpointVitestJob( ); } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); - if (!checkout) - errors.push( - "messaging-compatible-endpoint-vitest job missing checkout step", - ); - requireFullShaAction( - errors, - checkout, - "messaging-compatible-endpoint-vitest checkout", - ); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); + if (!checkout) errors.push("messaging-compatible-endpoint-vitest job missing checkout step"); + requireFullShaAction(errors, checkout, "messaging-compatible-endpoint-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { errors.push( "messaging-compatible-endpoint-vitest checkout step must set persist-credentials=false", @@ -3052,15 +2120,8 @@ function validateMessagingCompatibleEndpointVitestJob( } const setupNode = namedStep(steps, "Set up Node"); - if (!setupNode) - errors.push( - "messaging-compatible-endpoint-vitest job missing step: Set up Node", - ); - requireFullShaAction( - errors, - setupNode, - "messaging-compatible-endpoint-vitest setup-node", - ); + if (!setupNode) errors.push("messaging-compatible-endpoint-vitest job missing step: Set up Node"); + requireFullShaAction(errors, setupNode, "messaging-compatible-endpoint-vitest setup-node"); const installRootDependencies = requireJobStep( errors, @@ -3068,11 +2129,7 @@ function validateMessagingCompatibleEndpointVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); const buildCli = requireJobStep(errors, jobName, steps, "Build CLI"); requireRunContains(errors, buildCli, "npm run build:cli"); @@ -3096,20 +2153,12 @@ function validateMessagingCompatibleEndpointVitestJob( ); } if (runVitestEnv.TELEGRAM_BOT_TOKEN !== "test-fake-telegram-token-e2e") { - errors.push( - "messaging-compatible-endpoint-vitest step must set a fake Telegram token", - ); + errors.push("messaging-compatible-endpoint-vitest step must set a fake Telegram token"); } if (runVitestEnv.TELEGRAM_ALLOWED_IDS !== "123456789") { - errors.push( - "messaging-compatible-endpoint-vitest step must set fake Telegram allowed ids", - ); + errors.push("messaging-compatible-endpoint-vitest step must set fake Telegram allowed ids"); } - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); requireRunContains( errors, runVitest, @@ -3122,18 +2171,10 @@ function validateMessagingCompatibleEndpointVitestJob( steps, "Upload messaging compatible endpoint artifacts", ); - requireFullShaAction( - errors, - upload, - "messaging-compatible-endpoint-vitest upload-artifact", - ); + requireFullShaAction(errors, upload, "messaging-compatible-endpoint-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); - if ( - uploadWith.name !== "e2e-vitest-scenarios-messaging-compatible-endpoint" - ) { - errors.push( - "messaging-compatible-endpoint-vitest artifact upload name must be stable", - ); + if (uploadWith.name !== "e2e-vitest-scenarios-messaging-compatible-endpoint") { + errors.push("messaging-compatible-endpoint-vitest artifact upload name must be stable"); } const uploadPath = stringValue(uploadWith.path); requireUploadPathContains( @@ -3152,16 +2193,11 @@ function validateMessagingCompatibleEndpointVitestJob( ); } if (uploadWith["retention-days"] !== 14) { - errors.push( - "messaging-compatible-endpoint-vitest artifact upload retention-days must be 14", - ); + errors.push("messaging-compatible-endpoint-vitest artifact upload retention-days must be 14"); } } -function validateOnboardNegativePathsVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateOnboardNegativePathsVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "onboard-negative-paths-vitest"; const job = asRecord(jobs[jobName]); if (Object.keys(job).length === 0) { @@ -3172,18 +2208,11 @@ function validateOnboardNegativePathsVitestJob( if (job["runs-on"] !== "ubuntu-latest") { errors.push("onboard-negative-paths-vitest job must run on ubuntu-latest"); } - validateFreeStandingJobSelector( - errors, - jobs, - jobName, - "onboard-negative-paths", - ); + validateFreeStandingJobSelector(errors, jobs, jobName, "onboard-negative-paths"); const jobEnv = asRecord(job.env); if (jobEnv.NEMOCLAW_RUN_E2E_SCENARIOS !== "1") { - errors.push( - "onboard-negative-paths-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1", - ); + errors.push("onboard-negative-paths-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1"); } if ( jobEnv.E2E_ARTIFACT_DIR !== @@ -3211,30 +2240,16 @@ function validateOnboardNegativePathsVitestJob( ); } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); - if (!checkout) - errors.push("onboard-negative-paths-vitest job missing checkout step"); - requireFullShaAction( - errors, - checkout, - "onboard-negative-paths-vitest checkout", - ); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); + if (!checkout) errors.push("onboard-negative-paths-vitest job missing checkout step"); + requireFullShaAction(errors, checkout, "onboard-negative-paths-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { - errors.push( - "onboard-negative-paths-vitest checkout step must set persist-credentials=false", - ); + errors.push("onboard-negative-paths-vitest checkout step must set persist-credentials=false"); } const setupNode = namedStep(steps, "Set up Node"); - if (!setupNode) - errors.push("onboard-negative-paths-vitest job missing step: Set up Node"); - requireFullShaAction( - errors, - setupNode, - "onboard-negative-paths-vitest setup-node", - ); + if (!setupNode) errors.push("onboard-negative-paths-vitest job missing step: Set up Node"); + requireFullShaAction(errors, setupNode, "onboard-negative-paths-vitest setup-node"); const installRootDependencies = requireJobStep( errors, @@ -3242,55 +2257,23 @@ function validateOnboardNegativePathsVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); const buildCli = requireJobStep(errors, jobName, steps, "Build CLI"); requireRunContains(errors, buildCli, "npm run build:cli"); - const runVitest = requireJobStep( - errors, - jobName, - steps, - "Run onboard negative-paths live test", - ); - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/onboard-negative-paths.test.ts", - ); + const runVitest = requireJobStep(errors, jobName, steps, "Run onboard negative-paths live test"); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/onboard-negative-paths.test.ts"); - const upload = requireJobStep( - errors, - jobName, - steps, - "Upload onboard negative-paths artifacts", - ); - requireFullShaAction( - errors, - upload, - "onboard-negative-paths-vitest upload-artifact", - ); + const upload = requireJobStep(errors, jobName, steps, "Upload onboard negative-paths artifacts"); + requireFullShaAction(errors, upload, "onboard-negative-paths-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); if (uploadWith.name !== "e2e-vitest-scenarios-onboard-negative-paths") { - errors.push( - "onboard-negative-paths-vitest artifact upload name must be stable", - ); + errors.push("onboard-negative-paths-vitest artifact upload name must be stable"); } const uploadPath = stringValue(uploadWith.path); - requireUploadPathContains( - errors, - uploadPath, - "e2e-artifacts/vitest/onboard-negative-paths/", - ); + requireUploadPathContains(errors, uploadPath, "e2e-artifacts/vitest/onboard-negative-paths/"); if (uploadWith["include-hidden-files"] !== false) { errors.push( "onboard-negative-paths-vitest artifact upload must set include-hidden-files: false", @@ -3302,16 +2285,11 @@ function validateOnboardNegativePathsVitestJob( ); } if (uploadWith["retention-days"] !== 14) { - errors.push( - "onboard-negative-paths-vitest artifact upload retention-days must be 14", - ); + errors.push("onboard-negative-paths-vitest artifact upload retention-days must be 14"); } } -function validateCloudInferenceVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateCloudInferenceVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "cloud-inference-vitest"; const job = asRecord(jobs[jobName]); if (Object.keys(job).length === 0) { @@ -3328,33 +2306,22 @@ function validateCloudInferenceVitestJob( } const jobEnv = asRecord(job.env); - if ( - jobEnv.E2E_ARTIFACT_DIR !== - "${{ github.workspace }}/e2e-artifacts/vitest/cloud-inference" - ) { + if (jobEnv.E2E_ARTIFACT_DIR !== "${{ github.workspace }}/e2e-artifacts/vitest/cloud-inference") { errors.push( "cloud-inference-vitest job must write artifacts under e2e-artifacts/vitest/cloud-inference", ); } if (jobEnv.NEMOCLAW_CLI_BIN !== "${{ github.workspace }}/bin/nemoclaw.js") { - errors.push( - "cloud-inference-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI", - ); + errors.push("cloud-inference-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI"); } if (jobEnv.NEMOCLAW_RUN_E2E_SCENARIOS !== "1") { - errors.push( - "cloud-inference-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1", - ); + errors.push("cloud-inference-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1"); } if (jobEnv.NEMOCLAW_SANDBOX_NAME !== "e2e-cloud-inference") { - errors.push( - "cloud-inference-vitest job must set NEMOCLAW_SANDBOX_NAME=e2e-cloud-inference", - ); + errors.push("cloud-inference-vitest job must set NEMOCLAW_SANDBOX_NAME=e2e-cloud-inference"); } if (jobEnv.OPENSHELL_GATEWAY !== "nemoclaw") { - errors.push( - "cloud-inference-vitest job must force OPENSHELL_GATEWAY=nemoclaw", - ); + errors.push("cloud-inference-vitest job must force OPENSHELL_GATEWAY=nemoclaw"); } requireEnvDoesNotExposeSecret( errors, @@ -3376,21 +2343,15 @@ function validateCloudInferenceVitestJob( } } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); - if (!checkout) - errors.push("cloud-inference-vitest job missing checkout step"); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); + if (!checkout) errors.push("cloud-inference-vitest job missing checkout step"); requireFullShaAction(errors, checkout, "cloud-inference-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { - errors.push( - "cloud-inference-vitest checkout step must set persist-credentials=false", - ); + errors.push("cloud-inference-vitest checkout step must set persist-credentials=false"); } const setupNode = namedStep(steps, "Set up Node"); - if (!setupNode) - errors.push("cloud-inference-vitest job missing step: Set up Node"); + if (!setupNode) errors.push("cloud-inference-vitest job missing step: Set up Node"); requireFullShaAction(errors, setupNode, "cloud-inference-vitest setup-node"); const installRootDependencies = requireJobStep( @@ -3399,96 +2360,50 @@ function validateCloudInferenceVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); const buildCli = requireJobStep(errors, jobName, steps, "Build CLI"); requireRunContains(errors, buildCli, "npm run build:cli"); - const runVitest = requireJobStep( - errors, - jobName, - steps, - "Run cloud inference live test", - ); + const runVitest = requireJobStep(errors, jobName, steps, "Run cloud inference live test"); const runVitestEnv = asRecord(runVitest?.env); if (runVitestEnv.NVIDIA_INFERENCE_API_KEY !== "${{ secrets.NVIDIA_INFERENCE_API_KEY }}") { errors.push( "cloud-inference-vitest run step must receive NVIDIA_INFERENCE_API_KEY from secrets", ); } - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/cloud-inference.test.ts", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/cloud-inference.test.ts"); - const upload = requireJobStep( - errors, - jobName, - steps, - "Upload cloud inference artifacts", - ); - requireFullShaAction( - errors, - upload, - "cloud-inference-vitest upload-artifact", - ); + const upload = requireJobStep(errors, jobName, steps, "Upload cloud inference artifacts"); + requireFullShaAction(errors, upload, "cloud-inference-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); if (uploadWith.name !== "e2e-vitest-scenarios-cloud-inference") { errors.push("cloud-inference-vitest artifact upload name must be stable"); } const uploadPath = stringValue(uploadWith.path); - requireUploadPathContains( - errors, - uploadPath, - "e2e-artifacts/vitest/cloud-inference/", - ); + requireUploadPathContains(errors, uploadPath, "e2e-artifacts/vitest/cloud-inference/"); if (uploadWith["include-hidden-files"] !== false) { - errors.push( - "cloud-inference-vitest artifact upload must set include-hidden-files: false", - ); + errors.push("cloud-inference-vitest artifact upload must set include-hidden-files: false"); } if (uploadWith["if-no-files-found"] !== "ignore") { - errors.push( - "cloud-inference-vitest artifact upload must ignore missing fixture artifacts", - ); + errors.push("cloud-inference-vitest artifact upload must ignore missing fixture artifacts"); } if (uploadWith["retention-days"] !== 14) { - errors.push( - "cloud-inference-vitest artifact upload retention-days must be 14", - ); + errors.push("cloud-inference-vitest artifact upload retention-days must be 14"); } } -function requireNoDockerHubAuthInRun( - errors: string[], - owner: string, - runScript: string, -): void { +function requireNoDockerHubAuthInRun(errors: string[], owner: string, runScript: string): void { if (!runScript) return; const usesDockerLogin = /\bdocker\s+login\b/i.test(runScript); - const referencesSecret = - /\bsecrets\.[A-Za-z0-9_]+\b|\$\{\{\s*secrets\.[^}]+\}\}/.test(runScript); + const referencesSecret = /\bsecrets\.[A-Za-z0-9_]+\b|\$\{\{\s*secrets\.[^}]+\}\}/.test(runScript); if (usesDockerLogin || referencesSecret) { - errors.push( - `${owner} run script must not use docker login or inline secret interpolation`, - ); + errors.push(`${owner} run script must not use docker login or inline secret interpolation`); } } -function validateDoubleOnboardVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateDoubleOnboardVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "double-onboard-vitest"; const job = asRecord(jobs[jobName]); if (Object.keys(job).length === 0) { @@ -3503,19 +2418,12 @@ function validateDoubleOnboardVitestJob( const jobEnv = asRecord(job.env); if (jobEnv.NEMOCLAW_RUN_E2E_SCENARIOS !== "1") { - errors.push( - "double-onboard-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1", - ); + errors.push("double-onboard-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1"); } if (jobEnv.NEMOCLAW_CLI_BIN !== "${{ github.workspace }}/bin/nemoclaw.js") { - errors.push( - "double-onboard-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI", - ); + errors.push("double-onboard-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI"); } - if ( - jobEnv.E2E_ARTIFACT_DIR !== - "${{ github.workspace }}/e2e-artifacts/vitest/double-onboard" - ) { + if (jobEnv.E2E_ARTIFACT_DIR !== "${{ github.workspace }}/e2e-artifacts/vitest/double-onboard") { errors.push( "double-onboard-vitest job must write artifacts under e2e-artifacts/vitest/double-onboard", ); @@ -3526,12 +2434,7 @@ function validateDoubleOnboardVitestJob( jobEnv, "NVIDIA_INFERENCE_API_KEY", ); - requireEnvDoesNotExposeSecret( - errors, - "double-onboard-vitest job", - jobEnv, - "DOCKERHUB_TOKEN", - ); + requireEnvDoesNotExposeSecret(errors, "double-onboard-vitest job", jobEnv, "DOCKERHUB_TOKEN"); const steps = asSteps(job.steps); requireNoDispatchInputInterpolation(errors, steps); @@ -3552,42 +2455,28 @@ function validateDoubleOnboardVitestJob( ); } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); if (!checkout) errors.push("double-onboard-vitest job missing checkout step"); requireFullShaAction(errors, checkout, "double-onboard-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { - errors.push( - "double-onboard-vitest checkout step must set persist-credentials=false", - ); + errors.push("double-onboard-vitest checkout step must set persist-credentials=false"); } - const dockerLogin = requireJobStep( - errors, - jobName, - steps, - "Authenticate to Docker Hub", - ); + const dockerLogin = requireJobStep(errors, jobName, steps, "Authenticate to Docker Hub"); const dockerLoginEnv = asRecord(dockerLogin?.env); - if ( - dockerLoginEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}" - ) { + if (dockerLoginEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}") { errors.push( "double-onboard-vitest Docker login step must read DOCKERHUB_USERNAME from secrets", ); } if (dockerLoginEnv.DOCKERHUB_TOKEN !== "${{ secrets.DOCKERHUB_TOKEN }}") { - errors.push( - "double-onboard-vitest Docker login step must read DOCKERHUB_TOKEN from secrets", - ); + errors.push("double-onboard-vitest Docker login step must read DOCKERHUB_TOKEN from secrets"); } requireRunContains(errors, dockerLogin, "docker login docker.io"); requireRunContains(errors, dockerLogin, "continuing with anonymous pulls"); const setupNode = namedStep(steps, "Set up Node"); - if (!setupNode) - errors.push("double-onboard-vitest job missing step: Set up Node"); + if (!setupNode) errors.push("double-onboard-vitest job missing step: Set up Node"); requireFullShaAction(errors, setupNode, "double-onboard-vitest setup-node"); const installRootDependencies = requireJobStep( @@ -3596,78 +2485,38 @@ function validateDoubleOnboardVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); const buildCli = requireJobStep(errors, jobName, steps, "Build CLI"); requireRunContains(errors, buildCli, "npm run build:cli"); - const installTools = requireJobStep( - errors, - jobName, - steps, - "Install OpenShell CLI", - ); + const installTools = requireJobStep(errors, jobName, steps, "Install OpenShell CLI"); requireRunContains(errors, installTools, "bash scripts/install-openshell.sh"); - const runVitest = requireJobStep( - errors, - jobName, - steps, - "Run double-onboard live Vitest test", - ); + const runVitest = requireJobStep(errors, jobName, steps, "Run double-onboard live Vitest test"); requireRunContains(errors, runVitest, "OPENSHELL_BIN"); - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/double-onboard.test.ts", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/double-onboard.test.ts"); - const upload = requireJobStep( - errors, - jobName, - steps, - "Upload double-onboard Vitest artifacts", - ); + const upload = requireJobStep(errors, jobName, steps, "Upload double-onboard Vitest artifacts"); requireFullShaAction(errors, upload, "double-onboard-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); if (uploadWith.name !== "e2e-vitest-scenarios-double-onboard") { errors.push("double-onboard-vitest artifact upload name must be stable"); } const uploadPath = stringValue(uploadWith.path); - requireUploadPathContains( - errors, - uploadPath, - "e2e-artifacts/vitest/double-onboard/", - ); + requireUploadPathContains(errors, uploadPath, "e2e-artifacts/vitest/double-onboard/"); if (uploadWith["include-hidden-files"] !== false) { - errors.push( - "double-onboard-vitest artifact upload must set include-hidden-files: false", - ); + errors.push("double-onboard-vitest artifact upload must set include-hidden-files: false"); } if (uploadWith["if-no-files-found"] !== "ignore") { - errors.push( - "double-onboard-vitest artifact upload must ignore missing fixture artifacts", - ); + errors.push("double-onboard-vitest artifact upload must ignore missing fixture artifacts"); } if (uploadWith["retention-days"] !== 14) { - errors.push( - "double-onboard-vitest artifact upload retention-days must be 14", - ); + errors.push("double-onboard-vitest artifact upload retention-days must be 14"); } } -function validateRuntimeOverridesVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateRuntimeOverridesVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "runtime-overrides-vitest"; const job = asRecord(jobs[jobName]); if (Object.keys(job).length === 0) { @@ -3682,13 +2531,10 @@ function validateRuntimeOverridesVitestJob( const jobEnv = asRecord(job.env); if (jobEnv.NEMOCLAW_RUN_E2E_SCENARIOS !== "1") { - errors.push( - "runtime-overrides-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1", - ); + errors.push("runtime-overrides-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1"); } if ( - jobEnv.E2E_ARTIFACT_DIR !== - "${{ github.workspace }}/e2e-artifacts/vitest/runtime-overrides" + jobEnv.E2E_ARTIFACT_DIR !== "${{ github.workspace }}/e2e-artifacts/vitest/runtime-overrides" ) { errors.push( "runtime-overrides-vitest job must write artifacts under e2e-artifacts/vitest/runtime-overrides", @@ -3706,54 +2552,29 @@ function validateRuntimeOverridesVitestJob( jobEnv, "DOCKERHUB_USERNAME", ); - requireEnvDoesNotExposeSecret( - errors, - "runtime-overrides-vitest job", - jobEnv, - "DOCKERHUB_TOKEN", - ); + requireEnvDoesNotExposeSecret(errors, "runtime-overrides-vitest job", jobEnv, "DOCKERHUB_TOKEN"); const steps = asSteps(job.steps); requireNoDispatchInputInterpolation(errors, steps); for (const step of steps) { const stepName = `runtime-overrides-vitest step '${step.name ?? step.uses ?? ""}'`; const stepEnv = asRecord(step.env); - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "NVIDIA_INFERENCE_API_KEY", - ); - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_USERNAME", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "NVIDIA_INFERENCE_API_KEY"); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_USERNAME"); requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_TOKEN"); requireNoDockerHubAuthInRun(errors, stepName, stringValue(step.run)); } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); - if (!checkout) - errors.push("runtime-overrides-vitest job missing checkout step"); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); + if (!checkout) errors.push("runtime-overrides-vitest job missing checkout step"); requireFullShaAction(errors, checkout, "runtime-overrides-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { - errors.push( - "runtime-overrides-vitest checkout step must set persist-credentials=false", - ); + errors.push("runtime-overrides-vitest checkout step must set persist-credentials=false"); } const setupNode = namedStep(steps, "Set up Node"); - if (!setupNode) - errors.push("runtime-overrides-vitest job missing step: Set up Node"); - requireFullShaAction( - errors, - setupNode, - "runtime-overrides-vitest setup-node", - ); + if (!setupNode) errors.push("runtime-overrides-vitest job missing step: Set up Node"); + requireFullShaAction(errors, setupNode, "runtime-overrides-vitest setup-node"); const installRootDependencies = requireJobStep( errors, @@ -3761,71 +2582,32 @@ function validateRuntimeOverridesVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); - const runVitest = requireJobStep( - errors, - jobName, - steps, - "Run runtime overrides live test", - ); - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/runtime-overrides.test.ts", - ); + const runVitest = requireJobStep(errors, jobName, steps, "Run runtime overrides live test"); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/runtime-overrides.test.ts"); - const upload = requireJobStep( - errors, - jobName, - steps, - "Upload runtime overrides artifacts", - ); - requireFullShaAction( - errors, - upload, - "runtime-overrides-vitest upload-artifact", - ); + const upload = requireJobStep(errors, jobName, steps, "Upload runtime overrides artifacts"); + requireFullShaAction(errors, upload, "runtime-overrides-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); if (uploadWith.name !== "e2e-vitest-scenarios-runtime-overrides") { errors.push("runtime-overrides-vitest artifact upload name must be stable"); } const uploadPath = stringValue(uploadWith.path); - requireUploadPathContains( - errors, - uploadPath, - "e2e-artifacts/vitest/runtime-overrides/", - ); + requireUploadPathContains(errors, uploadPath, "e2e-artifacts/vitest/runtime-overrides/"); if (uploadWith["include-hidden-files"] !== false) { - errors.push( - "runtime-overrides-vitest artifact upload must set include-hidden-files: false", - ); + errors.push("runtime-overrides-vitest artifact upload must set include-hidden-files: false"); } if (uploadWith["if-no-files-found"] !== "ignore") { - errors.push( - "runtime-overrides-vitest artifact upload must ignore missing fixture artifacts", - ); + errors.push("runtime-overrides-vitest artifact upload must ignore missing fixture artifacts"); } if (uploadWith["retention-days"] !== 14) { - errors.push( - "runtime-overrides-vitest artifact upload retention-days must be 14", - ); + errors.push("runtime-overrides-vitest artifact upload retention-days must be 14"); } } -function validateHermesE2EVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateHermesE2EVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "hermes-e2e-vitest"; const job = asRecord(jobs[jobName]); if (Object.keys(job).length === 0) { @@ -3837,21 +2619,13 @@ function validateHermesE2EVitestJob( errors.push("hermes-e2e-vitest job must run on ubuntu-latest"); } if (job.needs !== "generate-matrix") { - errors.push( - "hermes-e2e-vitest job must depend on generate-matrix validation", - ); + errors.push("hermes-e2e-vitest job must depend on generate-matrix validation"); } - if ( - job.if !== "${{ needs.generate-matrix.outputs.hermes_selected == 'true' }}" - ) { - errors.push( - "hermes-e2e-vitest job must use validated hermes_selected output", - ); + if (job.if !== "${{ needs.generate-matrix.outputs.hermes_selected == 'true' }}") { + errors.push("hermes-e2e-vitest job must use validated hermes_selected output"); } if (stringValue(job.if).includes("inputs.scenarios")) { - errors.push( - "hermes-e2e-vitest job must not inspect raw workflow dispatch scenarios", - ); + errors.push("hermes-e2e-vitest job must not inspect raw workflow dispatch scenarios"); } const jobEnv = asRecord(job.env); @@ -3859,28 +2633,19 @@ function validateHermesE2EVitestJob( errors.push("hermes-e2e-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1"); } if (jobEnv.NEMOCLAW_CLI_BIN !== "${{ github.workspace }}/bin/nemoclaw.js") { - errors.push( - "hermes-e2e-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI", - ); + errors.push("hermes-e2e-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI"); } - if ( - jobEnv.E2E_ARTIFACT_DIR !== - "${{ github.workspace }}/e2e-artifacts/vitest/hermes-e2e" - ) { - errors.push( - "hermes-e2e-vitest job must write artifacts under e2e-artifacts/vitest/hermes-e2e", - ); + if (jobEnv.E2E_ARTIFACT_DIR !== "${{ github.workspace }}/e2e-artifacts/vitest/hermes-e2e") { + errors.push("hermes-e2e-vitest job must write artifacts under e2e-artifacts/vitest/hermes-e2e"); } if (jobEnv.NEMOCLAW_AGENT !== "hermes") { errors.push("hermes-e2e-vitest job must set NEMOCLAW_AGENT=hermes"); } - if (jobEnv.NEMOCLAW_MODEL !== "minimaxai/minimax-m2.7") { - errors.push("hermes-e2e-vitest job must pin the CI-safe Hermes model"); + if (jobEnv.NEMOCLAW_MODEL !== undefined) { + errors.push("hermes-e2e-vitest job must use the shared hosted-compatible model default"); } if (jobEnv.NEMOCLAW_ONBOARD_VALIDATION_TIMEOUT_SECONDS !== "60") { - errors.push( - "hermes-e2e-vitest job must give hosted endpoint validation a CI-safe timeout", - ); + errors.push("hermes-e2e-vitest job must give hosted endpoint validation a CI-safe timeout"); } requireEnvDoesNotExposeSecret( errors, @@ -3902,20 +2667,15 @@ function validateHermesE2EVitestJob( } } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); if (!checkout) errors.push("hermes-e2e-vitest job missing checkout step"); requireFullShaAction(errors, checkout, "hermes-e2e-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { - errors.push( - "hermes-e2e-vitest checkout step must set persist-credentials=false", - ); + errors.push("hermes-e2e-vitest checkout step must set persist-credentials=false"); } const setupNode = namedStep(steps, "Set up Node"); - if (!setupNode) - errors.push("hermes-e2e-vitest job missing step: Set up Node"); + if (!setupNode) errors.push("hermes-e2e-vitest job missing step: Set up Node"); requireFullShaAction(errors, setupNode, "hermes-e2e-vitest setup-node"); const installRootDependencies = requireJobStep( @@ -3924,78 +2684,40 @@ function validateHermesE2EVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); const buildCli = requireJobStep(errors, jobName, steps, "Build CLI"); requireRunContains(errors, buildCli, "npm run build:cli"); - const runVitest = requireJobStep( - errors, - jobName, - steps, - "Run Hermes live Vitest test", - ); + const runVitest = requireJobStep(errors, jobName, steps, "Run Hermes live Vitest test"); const runVitestEnv = asRecord(runVitest?.env); - if ( - runVitestEnv.NVIDIA_INFERENCE_API_KEY !== - "${{ secrets.NVIDIA_INFERENCE_API_KEY }}" - ) { - errors.push( - "hermes-e2e-vitest Vitest step must receive NVIDIA_INFERENCE_API_KEY from secrets", - ); + if (runVitestEnv.NVIDIA_INFERENCE_API_KEY !== "${{ secrets.NVIDIA_INFERENCE_API_KEY }}") { + errors.push("hermes-e2e-vitest Vitest step must receive NVIDIA_INFERENCE_API_KEY from secrets"); } - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/hermes-e2e.test.ts", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/hermes-e2e.test.ts"); requireRunDoesNotContain(errors, runVitest, "${{ inputs."); - const upload = requireJobStep( - errors, - jobName, - steps, - "Upload Hermes live Vitest artifacts", - ); + const upload = requireJobStep(errors, jobName, steps, "Upload Hermes live Vitest artifacts"); requireFullShaAction(errors, upload, "hermes-e2e-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); if (uploadWith.name !== "e2e-vitest-scenarios-hermes-e2e") { errors.push("hermes-e2e-vitest artifact upload name must be stable"); } const uploadPath = stringValue(uploadWith.path); - requireUploadPathContains( - errors, - uploadPath, - "e2e-artifacts/vitest/hermes-e2e/", - ); + requireUploadPathContains(errors, uploadPath, "e2e-artifacts/vitest/hermes-e2e/"); if (uploadWith["include-hidden-files"] !== false) { - errors.push( - "hermes-e2e-vitest artifact upload must set include-hidden-files: false", - ); + errors.push("hermes-e2e-vitest artifact upload must set include-hidden-files: false"); } if (uploadWith["if-no-files-found"] !== "ignore") { - errors.push( - "hermes-e2e-vitest artifact upload must ignore missing fixture artifacts", - ); + errors.push("hermes-e2e-vitest artifact upload must ignore missing fixture artifacts"); } if (uploadWith["retention-days"] !== 14) { errors.push("hermes-e2e-vitest artifact upload retention-days must be 14"); } } -function validateHermesRootEntrypointSmokeVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateHermesRootEntrypointSmokeVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "hermes-root-entrypoint-smoke-vitest"; const job = asRecord(jobs[jobName]); if (Object.keys(job).length === 0) { @@ -4004,14 +2726,10 @@ function validateHermesRootEntrypointSmokeVitestJob( } if (job["runs-on"] !== "ubuntu-latest") { - errors.push( - "hermes-root-entrypoint-smoke-vitest job must run on ubuntu-latest", - ); + errors.push("hermes-root-entrypoint-smoke-vitest job must run on ubuntu-latest"); } if (job.needs !== "generate-matrix") { - errors.push( - "hermes-root-entrypoint-smoke-vitest job must depend on generate-matrix", - ); + errors.push("hermes-root-entrypoint-smoke-vitest job must depend on generate-matrix"); } const expectedIf = "${{ needs.generate-matrix.result == 'success' && ((inputs.jobs == '' && inputs.scenarios == '') || contains(format(',{0},', inputs.jobs), ',hermes-root-entrypoint-smoke-vitest,') || contains(format(',{0},', inputs.scenarios), ',hermes-root-entrypoint-smoke,')) }}"; @@ -4021,16 +2739,12 @@ function validateHermesRootEntrypointSmokeVitestJob( ); } if (job["timeout-minutes"] !== 45) { - errors.push( - "hermes-root-entrypoint-smoke-vitest job must keep the 45 minute timeout", - ); + errors.push("hermes-root-entrypoint-smoke-vitest job must keep the 45 minute timeout"); } const jobEnv = asRecord(job.env); if (jobEnv.NEMOCLAW_RUN_E2E_SCENARIOS !== "1") { - errors.push( - "hermes-root-entrypoint-smoke-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1", - ); + errors.push("hermes-root-entrypoint-smoke-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1"); } if ( jobEnv.E2E_ARTIFACT_DIR !== @@ -4095,18 +2809,9 @@ function validateHermesRootEntrypointSmokeVitestJob( ); } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); - if (!checkout) - errors.push( - "hermes-root-entrypoint-smoke-vitest job missing checkout step", - ); - requireFullShaAction( - errors, - checkout, - "hermes-root-entrypoint-smoke-vitest checkout", - ); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); + if (!checkout) errors.push("hermes-root-entrypoint-smoke-vitest job missing checkout step"); + requireFullShaAction(errors, checkout, "hermes-root-entrypoint-smoke-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { errors.push( "hermes-root-entrypoint-smoke-vitest checkout step must set persist-credentials=false", @@ -4114,15 +2819,8 @@ function validateHermesRootEntrypointSmokeVitestJob( } const setupNode = namedStep(steps, "Set up Node"); - if (!setupNode) - errors.push( - "hermes-root-entrypoint-smoke-vitest job missing step: Set up Node", - ); - requireFullShaAction( - errors, - setupNode, - "hermes-root-entrypoint-smoke-vitest setup-node", - ); + if (!setupNode) errors.push("hermes-root-entrypoint-smoke-vitest job missing step: Set up Node"); + requireFullShaAction(errors, setupNode, "hermes-root-entrypoint-smoke-vitest setup-node"); const installRootDependencies = requireJobStep( errors, @@ -4130,11 +2828,7 @@ function validateHermesRootEntrypointSmokeVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); const runVitest = requireJobStep( errors, @@ -4142,11 +2836,7 @@ function validateHermesRootEntrypointSmokeVitestJob( steps, "Run Hermes root entrypoint smoke live test", ); - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); requireRunContains( errors, runVitest, @@ -4160,16 +2850,10 @@ function validateHermesRootEntrypointSmokeVitestJob( steps, "Upload Hermes root entrypoint smoke artifacts", ); - requireFullShaAction( - errors, - upload, - "hermes-root-entrypoint-smoke-vitest upload-artifact", - ); + requireFullShaAction(errors, upload, "hermes-root-entrypoint-smoke-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); if (uploadWith.name !== "e2e-vitest-scenarios-hermes-root-entrypoint-smoke") { - errors.push( - "hermes-root-entrypoint-smoke-vitest artifact upload name must be stable", - ); + errors.push("hermes-root-entrypoint-smoke-vitest artifact upload name must be stable"); } const uploadPath = stringValue(uploadWith.path); requireUploadPathContains( @@ -4188,9 +2872,7 @@ function validateHermesRootEntrypointSmokeVitestJob( ); } if (uploadWith["retention-days"] !== 14) { - errors.push( - "hermes-root-entrypoint-smoke-vitest artifact upload retention-days must be 14", - ); + errors.push("hermes-root-entrypoint-smoke-vitest artifact upload retention-days must be 14"); } } @@ -4322,11 +3004,7 @@ function validateHermesSandboxSecretBoundaryVitestJob( } } - -function validateDiagnosticsVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateDiagnosticsVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "diagnostics-vitest"; const scenarioName = "diagnostics"; const job = asRecord(jobs[jobName]); @@ -4345,22 +3023,15 @@ function validateDiagnosticsVitestJob( const jobEnv = asRecord(job.env); if ("DOCKER_CONFIG" in jobEnv) { - errors.push( - "diagnostics-vitest job must not expose Docker auth to branch-controlled steps", - ); + errors.push("diagnostics-vitest job must not expose Docker auth to branch-controlled steps"); } - if ( - jobEnv.E2E_ARTIFACT_DIR !== - "${{ github.workspace }}/e2e-artifacts/vitest/diagnostics" - ) { + if (jobEnv.E2E_ARTIFACT_DIR !== "${{ github.workspace }}/e2e-artifacts/vitest/diagnostics") { errors.push( "diagnostics-vitest job must write artifacts under e2e-artifacts/vitest/diagnostics", ); } if (jobEnv.NEMOCLAW_CLI_BIN !== "${{ github.workspace }}/bin/nemoclaw.js") { - errors.push( - "diagnostics-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI", - ); + errors.push("diagnostics-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI"); } if (jobEnv.NEMOCLAW_RUN_E2E_SCENARIOS !== "1") { errors.push("diagnostics-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1"); @@ -4369,14 +3040,10 @@ function validateDiagnosticsVitestJob( errors.push("diagnostics-vitest job must set NEMOCLAW_NON_INTERACTIVE=1"); } if (jobEnv.NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE !== "1") { - errors.push( - "diagnostics-vitest job must set NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1", - ); + errors.push("diagnostics-vitest job must set NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1"); } if (jobEnv.NEMOCLAW_SANDBOX_NAME !== "e2e-diag") { - errors.push( - "diagnostics-vitest job must use the stable e2e-diag sandbox name", - ); + errors.push("diagnostics-vitest job must use the stable e2e-diag sandbox name"); } if (jobEnv.OPENSHELL_GATEWAY !== "nemoclaw") { errors.push("diagnostics-vitest job must force OPENSHELL_GATEWAY=nemoclaw"); @@ -4387,12 +3054,7 @@ function validateDiagnosticsVitestJob( "DOCKERHUB_TOKEN", "GITHUB_TOKEN", ]) { - requireEnvDoesNotExposeSecret( - errors, - "diagnostics-vitest job", - jobEnv, - secret, - ); + requireEnvDoesNotExposeSecret(errors, "diagnostics-vitest job", jobEnv, secret); } const steps = asSteps(job.steps); @@ -4401,19 +3063,9 @@ function validateDiagnosticsVitestJob( const stepName = `diagnostics-vitest step '${step.name ?? step.uses ?? ""}'`; const stepEnv = asRecord(step.env); if (step.name !== "Run diagnostics live test") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "NVIDIA_INFERENCE_API_KEY", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "NVIDIA_INFERENCE_API_KEY"); } - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_USERNAME", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_USERNAME"); requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_TOKEN"); requireNoDockerHubAuthInRun(errors, stepName, stringValue(step.run)); requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "GITHUB_TOKEN"); @@ -4425,20 +3077,15 @@ function validateDiagnosticsVitestJob( ); } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); if (!checkout) errors.push("diagnostics-vitest job missing checkout step"); requireFullShaAction(errors, checkout, "diagnostics-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { - errors.push( - "diagnostics-vitest checkout step must set persist-credentials=false", - ); + errors.push("diagnostics-vitest checkout step must set persist-credentials=false"); } const setupNode = namedStep(steps, "Set up Node"); - if (!setupNode) - errors.push("diagnostics-vitest job missing step: Set up Node"); + if (!setupNode) errors.push("diagnostics-vitest job missing step: Set up Node"); requireFullShaAction(errors, setupNode, "diagnostics-vitest setup-node"); const installRootDependencies = requireJobStep( @@ -4447,75 +3094,42 @@ function validateDiagnosticsVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); const buildCli = requireJobStep(errors, jobName, steps, "Build CLI"); requireRunContains(errors, buildCli, "npm run build:cli"); - const runVitest = requireJobStep( - errors, - jobName, - steps, - "Run diagnostics live test", - ); + const runVitest = requireJobStep(errors, jobName, steps, "Run diagnostics live test"); const runVitestEnv = asRecord(runVitest?.env); if (runVitestEnv.NVIDIA_INFERENCE_API_KEY !== "${{ secrets.NVIDIA_INFERENCE_API_KEY }}") { errors.push( "diagnostics-vitest Vitest step must receive NVIDIA_INFERENCE_API_KEY from secrets", ); } - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/diagnostics.test.ts", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/diagnostics.test.ts"); requireRunDoesNotContain(errors, runVitest, "${{ inputs."); - const upload = requireJobStep( - errors, - jobName, - steps, - "Upload diagnostics artifacts", - ); + const upload = requireJobStep(errors, jobName, steps, "Upload diagnostics artifacts"); requireFullShaAction(errors, upload, "diagnostics-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); if (uploadWith.name !== "e2e-vitest-scenarios-diagnostics") { errors.push("diagnostics-vitest artifact upload name must be stable"); } const uploadPath = stringValue(uploadWith.path); - requireUploadPathContains( - errors, - uploadPath, - "e2e-artifacts/vitest/diagnostics/", - ); + requireUploadPathContains(errors, uploadPath, "e2e-artifacts/vitest/diagnostics/"); if (uploadWith["include-hidden-files"] !== false) { - errors.push( - "diagnostics-vitest artifact upload must set include-hidden-files: false", - ); + errors.push("diagnostics-vitest artifact upload must set include-hidden-files: false"); } if (uploadWith["if-no-files-found"] !== "ignore") { - errors.push( - "diagnostics-vitest artifact upload must ignore missing fixture artifacts", - ); + errors.push("diagnostics-vitest artifact upload must ignore missing fixture artifacts"); } if (uploadWith["retention-days"] !== 14) { errors.push("diagnostics-vitest artifact upload retention-days must be 14"); } } -function validateSparkInstallVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateSparkInstallVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "spark-install-vitest"; const scenarioName = "spark-install"; const job = asRecord(jobs[jobName]); @@ -4533,31 +3147,22 @@ function validateSparkInstallVitestJob( validateFreeStandingJobSelector(errors, jobs, jobName, scenarioName); const jobEnv = asRecord(job.env); - if ( - jobEnv.E2E_ARTIFACT_DIR !== - "${{ github.workspace }}/e2e-artifacts/vitest/spark-install" - ) { + if (jobEnv.E2E_ARTIFACT_DIR !== "${{ github.workspace }}/e2e-artifacts/vitest/spark-install") { errors.push( "spark-install-vitest job must write artifacts under e2e-artifacts/vitest/spark-install", ); } if (jobEnv.NEMOCLAW_CLI_BIN !== "${{ github.workspace }}/bin/nemoclaw.js") { - errors.push( - "spark-install-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI", - ); + errors.push("spark-install-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI"); } if (jobEnv.NEMOCLAW_RUN_E2E_SCENARIOS !== "1") { - errors.push( - "spark-install-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1", - ); + errors.push("spark-install-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1"); } if (jobEnv.NEMOCLAW_NON_INTERACTIVE !== "1") { errors.push("spark-install-vitest job must set NEMOCLAW_NON_INTERACTIVE=1"); } if (jobEnv.NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE !== "1") { - errors.push( - "spark-install-vitest job must accept third-party software non-interactively", - ); + errors.push("spark-install-vitest job must accept third-party software non-interactively"); } if (jobEnv.NEMOCLAW_FRESH !== "1") { errors.push("spark-install-vitest job must set NEMOCLAW_FRESH=1"); @@ -4571,17 +3176,10 @@ function validateSparkInstallVitestJob( errors.push("spark-install-vitest job must use the cloud provider"); } if (jobEnv.OPENSHELL_GATEWAY !== "nemoclaw") { - errors.push( - "spark-install-vitest job must force OPENSHELL_GATEWAY=nemoclaw", - ); + errors.push("spark-install-vitest job must force OPENSHELL_GATEWAY=nemoclaw"); } for (const secret of COMMON_SECRET_ENV_NAMES) { - requireEnvDoesNotExposeSecret( - errors, - "spark-install-vitest job", - jobEnv, - secret, - ); + requireEnvDoesNotExposeSecret(errors, "spark-install-vitest job", jobEnv, secret); } const steps = asSteps(job.steps); @@ -4590,34 +3188,20 @@ function validateSparkInstallVitestJob( const stepName = `spark-install-vitest step '${step.name ?? step.uses ?? ""}'`; const stepEnv = asRecord(step.env); if (step.name !== "Run Spark install live test") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "NVIDIA_INFERENCE_API_KEY", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "NVIDIA_INFERENCE_API_KEY"); } - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_USERNAME", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_USERNAME"); requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_TOKEN"); requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "GITHUB_TOKEN"); } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); if (!checkout) { errors.push("spark-install-vitest job missing checkout step"); } requireFullShaAction(errors, checkout, "spark-install-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { - errors.push( - "spark-install-vitest checkout step must set persist-credentials=false", - ); + errors.push("spark-install-vitest checkout step must set persist-credentials=false"); } const setupNode = namedStep(steps, "Set up Node"); @@ -4632,18 +3216,9 @@ function validateSparkInstallVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); - const runVitest = requireJobStep( - errors, - jobName, - steps, - "Run Spark install live test", - ); + const runVitest = requireJobStep(errors, jobName, steps, "Run Spark install live test"); const runVitestEnv = asRecord(runVitest?.env); if (runVitestEnv.NVIDIA_INFERENCE_API_KEY !== "${{ secrets.NVIDIA_INFERENCE_API_KEY }}") { errors.push( @@ -4651,55 +3226,29 @@ function validateSparkInstallVitestJob( ); } requireRunContains(errors, runVitest, "set -euo pipefail"); - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/spark-install.test.ts", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/spark-install.test.ts"); - const upload = requireJobStep( - errors, - jobName, - steps, - "Upload Spark install artifacts", - ); + const upload = requireJobStep(errors, jobName, steps, "Upload Spark install artifacts"); requireFullShaAction(errors, upload, "spark-install-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); if (uploadWith.name !== "e2e-vitest-scenarios-spark-install") { errors.push("spark-install-vitest artifact upload name must be stable"); } const uploadPath = stringValue(uploadWith.path); - requireUploadPathContains( - errors, - uploadPath, - "e2e-artifacts/vitest/spark-install/", - ); + requireUploadPathContains(errors, uploadPath, "e2e-artifacts/vitest/spark-install/"); if (uploadWith["include-hidden-files"] !== false) { - errors.push( - "spark-install-vitest artifact upload must set include-hidden-files: false", - ); + errors.push("spark-install-vitest artifact upload must set include-hidden-files: false"); } if (uploadWith["if-no-files-found"] !== "ignore") { - errors.push( - "spark-install-vitest artifact upload must ignore missing fixture artifacts", - ); + errors.push("spark-install-vitest artifact upload must ignore missing fixture artifacts"); } if (uploadWith["retention-days"] !== 14) { - errors.push( - "spark-install-vitest artifact upload retention-days must be 14", - ); + errors.push("spark-install-vitest artifact upload retention-days must be 14"); } } -function validateSnapshotCommandsVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateSnapshotCommandsVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "snapshot-commands-vitest"; const scenarioName = "snapshot-commands"; const job = asRecord(jobs[jobName]); @@ -4718,42 +3267,29 @@ function validateSnapshotCommandsVitestJob( const jobEnv = asRecord(job.env); if ("DOCKER_CONFIG" in jobEnv) { - errors.push( - "snapshot-commands-vitest job must not set DOCKER_CONFIG at job level", - ); + errors.push("snapshot-commands-vitest job must not set DOCKER_CONFIG at job level"); } if ( - jobEnv.E2E_ARTIFACT_DIR !== - "${{ github.workspace }}/e2e-artifacts/vitest/snapshot-commands" + jobEnv.E2E_ARTIFACT_DIR !== "${{ github.workspace }}/e2e-artifacts/vitest/snapshot-commands" ) { errors.push( "snapshot-commands-vitest job must write artifacts under e2e-artifacts/vitest/snapshot-commands", ); } if (jobEnv.NEMOCLAW_RUN_E2E_SCENARIOS !== "1") { - errors.push( - "snapshot-commands-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1", - ); + errors.push("snapshot-commands-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1"); } if (jobEnv.NEMOCLAW_NON_INTERACTIVE !== "1") { - errors.push( - "snapshot-commands-vitest job must set NEMOCLAW_NON_INTERACTIVE=1", - ); + errors.push("snapshot-commands-vitest job must set NEMOCLAW_NON_INTERACTIVE=1"); } if (jobEnv.NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE !== "1") { - errors.push( - "snapshot-commands-vitest job must accept third-party software non-interactively", - ); + errors.push("snapshot-commands-vitest job must accept third-party software non-interactively"); } if (jobEnv.NEMOCLAW_SANDBOX_NAME !== "e2e-snapshot") { - errors.push( - "snapshot-commands-vitest job must use the stable e2e-snapshot sandbox name", - ); + errors.push("snapshot-commands-vitest job must use the stable e2e-snapshot sandbox name"); } if (jobEnv.OPENSHELL_GATEWAY !== "nemoclaw") { - errors.push( - "snapshot-commands-vitest job must force OPENSHELL_GATEWAY=nemoclaw", - ); + errors.push("snapshot-commands-vitest job must force OPENSHELL_GATEWAY=nemoclaw"); } for (const secret of [ "NVIDIA_INFERENCE_API_KEY", @@ -4761,12 +3297,7 @@ function validateSnapshotCommandsVitestJob( "DOCKERHUB_TOKEN", "GITHUB_TOKEN", ]) { - requireEnvDoesNotExposeSecret( - errors, - "snapshot-commands-vitest job", - jobEnv, - secret, - ); + requireEnvDoesNotExposeSecret(errors, "snapshot-commands-vitest job", jobEnv, secret); } const steps = asSteps(job.steps); @@ -4775,42 +3306,23 @@ function validateSnapshotCommandsVitestJob( const stepName = `snapshot-commands-vitest step '${step.name ?? step.uses ?? ""}'`; const stepEnv = asRecord(step.env); if (step.name !== "Run snapshot commands live test") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "NVIDIA_INFERENCE_API_KEY", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "NVIDIA_INFERENCE_API_KEY"); } if (step.name !== "Authenticate to Docker Hub") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_USERNAME", - ); - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_TOKEN", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_USERNAME"); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_TOKEN"); requireNoDockerHubAuthInRun(errors, stepName, stringValue(step.run)); } requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "GITHUB_TOKEN"); } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); if (!checkout) { errors.push("snapshot-commands-vitest job missing checkout step"); } requireFullShaAction(errors, checkout, "snapshot-commands-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { - errors.push( - "snapshot-commands-vitest checkout step must set persist-credentials=false", - ); + errors.push("snapshot-commands-vitest checkout step must set persist-credentials=false"); } const configureDockerAuth = requireJobStep( @@ -4826,16 +3338,9 @@ function validateSnapshotCommandsVitestJob( ); requireRunDoesNotContain(errors, configureDockerAuth, "${{ runner.temp }}"); - const dockerLogin = requireJobStep( - errors, - jobName, - steps, - "Authenticate to Docker Hub", - ); + const dockerLogin = requireJobStep(errors, jobName, steps, "Authenticate to Docker Hub"); const dockerLoginEnv = asRecord(dockerLogin?.env); - if ( - dockerLoginEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}" - ) { + if (dockerLoginEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}") { errors.push( "snapshot-commands-vitest Docker Hub auth must receive DOCKERHUB_USERNAME from secrets", ); @@ -4855,11 +3360,7 @@ function validateSnapshotCommandsVitestJob( if (!setupNode) { errors.push("snapshot-commands-vitest job missing step: Set up Node"); } - requireFullShaAction( - errors, - setupNode, - "snapshot-commands-vitest setup-node", - ); + requireFullShaAction(errors, setupNode, "snapshot-commands-vitest setup-node"); const installRootDependencies = requireJobStep( errors, @@ -4867,78 +3368,37 @@ function validateSnapshotCommandsVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); - const runVitest = requireJobStep( - errors, - jobName, - steps, - "Run snapshot commands live test", - ); + const runVitest = requireJobStep(errors, jobName, steps, "Run snapshot commands live test"); const runVitestEnv = asRecord(runVitest?.env); if (runVitestEnv.NVIDIA_INFERENCE_API_KEY !== "${{ secrets.NVIDIA_INFERENCE_API_KEY }}") { errors.push( "snapshot-commands-vitest Vitest step must receive NVIDIA_INFERENCE_API_KEY from secrets", ); } - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/snapshot-commands.test.ts", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/snapshot-commands.test.ts"); - const upload = requireJobStep( - errors, - jobName, - steps, - "Upload snapshot commands artifacts", - ); - requireFullShaAction( - errors, - upload, - "snapshot-commands-vitest upload-artifact", - ); + const upload = requireJobStep(errors, jobName, steps, "Upload snapshot commands artifacts"); + requireFullShaAction(errors, upload, "snapshot-commands-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); if (uploadWith.name !== "e2e-vitest-scenarios-snapshot-commands") { errors.push("snapshot-commands-vitest artifact upload name must be stable"); } const uploadPath = stringValue(uploadWith.path); - requireUploadPathContains( - errors, - uploadPath, - "e2e-artifacts/vitest/snapshot-commands/", - ); + requireUploadPathContains(errors, uploadPath, "e2e-artifacts/vitest/snapshot-commands/"); if (uploadWith["include-hidden-files"] !== false) { - errors.push( - "snapshot-commands-vitest artifact upload must set include-hidden-files: false", - ); + errors.push("snapshot-commands-vitest artifact upload must set include-hidden-files: false"); } if (uploadWith["if-no-files-found"] !== "ignore") { - errors.push( - "snapshot-commands-vitest artifact upload must ignore missing fixture artifacts", - ); + errors.push("snapshot-commands-vitest artifact upload must ignore missing fixture artifacts"); } if (uploadWith["retention-days"] !== 14) { - errors.push( - "snapshot-commands-vitest artifact upload retention-days must be 14", - ); + errors.push("snapshot-commands-vitest artifact upload retention-days must be 14"); } - const cleanup = requireJobStep( - errors, - jobName, - steps, - "Clean up Docker auth", - ); + const cleanup = requireJobStep(errors, jobName, steps, "Clean up Docker auth"); if (cleanup?.if !== "always()") { errors.push("snapshot-commands-vitest Docker auth cleanup must always run"); } @@ -4954,16 +3414,12 @@ function validateModelRouterProviderRoutedInferenceVitestJob( const scenarioName = "model-router-provider-routed-inference"; const job = asRecord(jobs[jobName]); if (Object.keys(job).length === 0) { - errors.push( - "workflow missing model-router-provider-routed-inference-vitest job", - ); + errors.push("workflow missing model-router-provider-routed-inference-vitest job"); return; } if (job["runs-on"] !== "ubuntu-latest") { - errors.push( - "model-router-provider-routed-inference-vitest job must run on ubuntu-latest", - ); + errors.push("model-router-provider-routed-inference-vitest job must run on ubuntu-latest"); } validateFreeStandingJobSelector(errors, jobs, jobName, scenarioName); @@ -5016,47 +3472,24 @@ function validateModelRouterProviderRoutedInferenceVitestJob( const stepName = `model-router-provider-routed-inference-vitest step '${step.name ?? step.uses ?? ""}'`; const stepEnv = asRecord(step.env); if (step.name !== "Run Model Router provider-routed inference live test") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "NVIDIA_INFERENCE_API_KEY", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "NVIDIA_INFERENCE_API_KEY"); } if (step.name !== "Authenticate to Docker Hub") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_USERNAME", - ); - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_TOKEN", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_USERNAME"); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_TOKEN"); requireNoDockerHubAuthInRun(errors, stepName, stringValue(step.run)); } requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "GITHUB_TOKEN"); } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); if (!checkout) { + errors.push("model-router-provider-routed-inference-vitest job missing checkout step"); + } + requireFullShaAction(errors, checkout, "model-router-provider-routed-inference-vitest checkout"); + if (asRecord(checkout?.with)["persist-credentials"] !== false) { errors.push( - "model-router-provider-routed-inference-vitest job missing checkout step", - ); - } - requireFullShaAction( - errors, - checkout, - "model-router-provider-routed-inference-vitest checkout", - ); - if (asRecord(checkout?.with)["persist-credentials"] !== false) { - errors.push( - "model-router-provider-routed-inference-vitest checkout step must set persist-credentials=false", + "model-router-provider-routed-inference-vitest checkout step must set persist-credentials=false", ); } @@ -5073,16 +3506,9 @@ function validateModelRouterProviderRoutedInferenceVitestJob( ); requireRunDoesNotContain(errors, configureDockerAuth, "${{ runner.temp }}"); - const dockerLogin = requireJobStep( - errors, - jobName, - steps, - "Authenticate to Docker Hub", - ); + const dockerLogin = requireJobStep(errors, jobName, steps, "Authenticate to Docker Hub"); const dockerLoginEnv = asRecord(dockerLogin?.env); - if ( - dockerLoginEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}" - ) { + if (dockerLoginEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}") { errors.push( "model-router-provider-routed-inference-vitest Docker Hub auth must receive DOCKERHUB_USERNAME from secrets", ); @@ -5100,9 +3526,7 @@ function validateModelRouterProviderRoutedInferenceVitestJob( const setupNode = namedStep(steps, "Set up Node"); if (!setupNode) { - errors.push( - "model-router-provider-routed-inference-vitest job missing step: Set up Node", - ); + errors.push("model-router-provider-routed-inference-vitest job missing step: Set up Node"); } requireFullShaAction( errors, @@ -5116,11 +3540,7 @@ function validateModelRouterProviderRoutedInferenceVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); const buildCli = requireJobStep(errors, jobName, steps, "Build CLI"); requireRunContains(errors, buildCli, "npm run build:cli"); @@ -5132,19 +3552,12 @@ function validateModelRouterProviderRoutedInferenceVitestJob( "Run Model Router provider-routed inference live test", ); const runVitestEnv = asRecord(runVitest?.env); - if ( - runVitestEnv.NVIDIA_INFERENCE_API_KEY !== - "${{ secrets.NVIDIA_INFERENCE_API_KEY }}" - ) { + if (runVitestEnv.NVIDIA_INFERENCE_API_KEY !== "${{ secrets.NVIDIA_INFERENCE_API_KEY }}") { errors.push( "model-router-provider-routed-inference-vitest Vitest step must receive NVIDIA_INFERENCE_API_KEY from secrets", ); } - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); requireRunContains( errors, runVitest, @@ -5163,10 +3576,7 @@ function validateModelRouterProviderRoutedInferenceVitestJob( "model-router-provider-routed-inference-vitest upload-artifact", ); const uploadWith = asRecord(upload?.with); - if ( - uploadWith.name !== - "e2e-vitest-scenarios-model-router-provider-routed-inference" - ) { + if (uploadWith.name !== "e2e-vitest-scenarios-model-router-provider-routed-inference") { errors.push( "model-router-provider-routed-inference-vitest artifact upload name must be stable", ); @@ -5193,12 +3603,7 @@ function validateModelRouterProviderRoutedInferenceVitestJob( ); } - const cleanup = requireJobStep( - errors, - jobName, - steps, - "Clean up Docker auth", - ); + const cleanup = requireJobStep(errors, jobName, steps, "Clean up Docker auth"); if (cleanup?.if !== "always()") { errors.push( "model-router-provider-routed-inference-vitest Docker auth cleanup must always run", @@ -5214,10 +3619,7 @@ function runContainsCloudflaredAptInstall(run: string): boolean { ); } -function validateTunnelLifecycleVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateTunnelLifecycleVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "tunnel-lifecycle-vitest"; const scenarioName = "tunnel-lifecycle"; const job = asRecord(jobs[jobName]); @@ -5236,29 +3638,19 @@ function validateTunnelLifecycleVitestJob( const jobEnv = asRecord(job.env); if ("DOCKER_CONFIG" in jobEnv) { - errors.push( - "tunnel-lifecycle-vitest job must not set DOCKER_CONFIG at job level", - ); + errors.push("tunnel-lifecycle-vitest job must not set DOCKER_CONFIG at job level"); } if (jobEnv.NEMOCLAW_CLI_BIN !== "${{ github.workspace }}/bin/nemoclaw.js") { - errors.push( - "tunnel-lifecycle-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI", - ); + errors.push("tunnel-lifecycle-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI"); } if (jobEnv.FREE_STANDING_VITEST_JOB !== "1") { - errors.push( - "tunnel-lifecycle-vitest job must set FREE_STANDING_VITEST_JOB=1", - ); + errors.push("tunnel-lifecycle-vitest job must set FREE_STANDING_VITEST_JOB=1"); } if (jobEnv.FREE_STANDING_SCENARIO_ID !== scenarioName) { - errors.push( - `tunnel-lifecycle-vitest job must set FREE_STANDING_SCENARIO_ID=${scenarioName}`, - ); + errors.push(`tunnel-lifecycle-vitest job must set FREE_STANDING_SCENARIO_ID=${scenarioName}`); } if (jobEnv.NEMOCLAW_RUN_E2E_SCENARIOS !== "1") { - errors.push( - "tunnel-lifecycle-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1", - ); + errors.push("tunnel-lifecycle-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1"); } requireEnvDoesNotExposeSecret( errors, @@ -5274,47 +3666,23 @@ function validateTunnelLifecycleVitestJob( const stepEnv = asRecord(step.env); requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "GITHUB_TOKEN"); if (step.name !== "Run tunnel lifecycle live test") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "NVIDIA_INFERENCE_API_KEY", - ); - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "NVIDIA_INFERENCE_API_KEY", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "NVIDIA_INFERENCE_API_KEY"); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "NVIDIA_INFERENCE_API_KEY"); } if (step.name !== "Authenticate to Docker Hub") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_USERNAME", - ); - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_TOKEN", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_USERNAME"); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_TOKEN"); requireNoDockerHubAuthInRun(errors, stepName, stringValue(step.run)); } } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); if (!checkout) { errors.push("tunnel-lifecycle-vitest job missing checkout step"); } requireFullShaAction(errors, checkout, "tunnel-lifecycle-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { - errors.push( - "tunnel-lifecycle-vitest checkout step must set persist-credentials=false", - ); + errors.push("tunnel-lifecycle-vitest checkout step must set persist-credentials=false"); } const configureDockerAuth = requireJobStep( @@ -5329,22 +3697,11 @@ function validateTunnelLifecycleVitestJob( 'echo "DOCKER_CONFIG=${RUNNER_TEMP}/docker-config-tunnel-lifecycle" >> "$GITHUB_ENV"', ); requireRunDoesNotContain(errors, configureDockerAuth, "${{ runner.temp }}"); - requireRunDoesNotContain( - errors, - configureDockerAuth, - "${{ github.workspace }}", - ); + requireRunDoesNotContain(errors, configureDockerAuth, "${{ github.workspace }}"); - const dockerLogin = requireJobStep( - errors, - jobName, - steps, - "Authenticate to Docker Hub", - ); + const dockerLogin = requireJobStep(errors, jobName, steps, "Authenticate to Docker Hub"); const dockerLoginEnv = asRecord(dockerLogin?.env); - if ( - dockerLoginEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}" - ) { + if (dockerLoginEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}") { errors.push( "tunnel-lifecycle-vitest Docker Hub auth must receive DOCKERHUB_USERNAME from secrets", ); @@ -5372,11 +3729,7 @@ function validateTunnelLifecycleVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); const buildCli = requireJobStep(errors, jobName, steps, "Build CLI"); requireRunContains(errors, buildCli, "npm run build:cli"); @@ -5401,25 +3754,13 @@ function validateTunnelLifecycleVitestJob( "NVIDIA_INFERENCE_API_KEY", ); requireRunContains(errors, cloudflaredPrereq, "cloudflared --version"); - requireRunContains( - errors, - cloudflaredPrereq, - "test/e2e/lib/cloudflared-version-resolver.sh", - ); + requireRunContains(errors, cloudflaredPrereq, "test/e2e/lib/cloudflared-version-resolver.sh"); requireRunContains(errors, cloudflaredPrereq, "sudo apt-get install -y"); requireRunContains(errors, cloudflaredPrereq, "cloudflared=${cf_version}"); - const runVitest = requireJobStep( - errors, - jobName, - steps, - "Run tunnel lifecycle live test", - ); + const runVitest = requireJobStep(errors, jobName, steps, "Run tunnel lifecycle live test"); const runVitestEnv = asRecord(runVitest?.env); - if ( - runVitestEnv.NVIDIA_INFERENCE_API_KEY !== - "${{ secrets.NVIDIA_INFERENCE_API_KEY }}" - ) { + if (runVitestEnv.NVIDIA_INFERENCE_API_KEY !== "${{ secrets.NVIDIA_INFERENCE_API_KEY }}") { errors.push( "tunnel-lifecycle-vitest Vitest step must receive NVIDIA_INFERENCE_API_KEY from secrets", ); @@ -5429,60 +3770,28 @@ function validateTunnelLifecycleVitestJob( "tunnel-lifecycle-vitest Vitest step must not run cloudflared APT installation with NVIDIA_INFERENCE_API_KEY in scope", ); } - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/tunnel-lifecycle.test.ts", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/tunnel-lifecycle.test.ts"); - const upload = requireJobStep( - errors, - jobName, - steps, - "Upload tunnel lifecycle artifacts", - ); - requireFullShaAction( - errors, - upload, - "tunnel-lifecycle-vitest upload-artifact", - ); + const upload = requireJobStep(errors, jobName, steps, "Upload tunnel lifecycle artifacts"); + requireFullShaAction(errors, upload, "tunnel-lifecycle-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); if (uploadWith.name !== "e2e-vitest-scenarios-tunnel-lifecycle") { errors.push("tunnel-lifecycle-vitest artifact upload name must be stable"); } const uploadPath = stringValue(uploadWith.path); - requireUploadPathContains( - errors, - uploadPath, - "e2e-artifacts/vitest/tunnel-lifecycle/", - ); + requireUploadPathContains(errors, uploadPath, "e2e-artifacts/vitest/tunnel-lifecycle/"); if (uploadWith["include-hidden-files"] !== false) { - errors.push( - "tunnel-lifecycle-vitest artifact upload must set include-hidden-files: false", - ); + errors.push("tunnel-lifecycle-vitest artifact upload must set include-hidden-files: false"); } if (uploadWith["if-no-files-found"] !== "ignore") { - errors.push( - "tunnel-lifecycle-vitest artifact upload must ignore missing fixture artifacts", - ); + errors.push("tunnel-lifecycle-vitest artifact upload must ignore missing fixture artifacts"); } if (uploadWith["retention-days"] !== 14) { - errors.push( - "tunnel-lifecycle-vitest artifact upload retention-days must be 14", - ); + errors.push("tunnel-lifecycle-vitest artifact upload retention-days must be 14"); } - const cleanup = requireJobStep( - errors, - jobName, - steps, - "Clean up Docker auth", - ); + const cleanup = requireJobStep(errors, jobName, steps, "Clean up Docker auth"); if (cleanup?.if !== "always()") { errors.push("tunnel-lifecycle-vitest Docker auth cleanup must always run"); } @@ -5490,10 +3799,7 @@ function validateTunnelLifecycleVitestJob( requireRunContains(errors, cleanup, 'rm -rf "${DOCKER_CONFIG}"'); } -function validateIssue2478CrashLoopRecoveryVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateIssue2478CrashLoopRecoveryVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "issue-2478-crash-loop-recovery-vitest"; const scenarioName = "issue-2478-crash-loop-recovery"; const job = asRecord(jobs[jobName]); @@ -5503,14 +3809,10 @@ function validateIssue2478CrashLoopRecoveryVitestJob( } if (job["runs-on"] !== "ubuntu-latest") { - errors.push( - "issue-2478-crash-loop-recovery-vitest job must run on ubuntu-latest", - ); + errors.push("issue-2478-crash-loop-recovery-vitest job must run on ubuntu-latest"); } if (job["timeout-minutes"] !== 30) { - errors.push( - "issue-2478-crash-loop-recovery-vitest job must keep the 30 minute timeout", - ); + errors.push("issue-2478-crash-loop-recovery-vitest job must keep the 30 minute timeout"); } validateFreeStandingJobSelector(errors, jobs, jobName, scenarioName); @@ -5523,8 +3825,7 @@ function validateIssue2478CrashLoopRecoveryVitestJob( const expectedEnv: Record = { FREE_STANDING_VITEST_JOB: "1", FREE_STANDING_SCENARIO_ID: scenarioName, - E2E_ARTIFACT_DIR: - "${{ github.workspace }}/e2e-artifacts/vitest/issue-2478-crash-loop-recovery", + E2E_ARTIFACT_DIR: "${{ github.workspace }}/e2e-artifacts/vitest/issue-2478-crash-loop-recovery", NEMOCLAW_CLI_BIN: "${{ github.workspace }}/bin/nemoclaw.js", NEMOCLAW_RUN_E2E_SCENARIOS: "1", NEMOCLAW_NON_INTERACTIVE: "1", @@ -5534,14 +3835,10 @@ function validateIssue2478CrashLoopRecoveryVitestJob( }; for (const [key, value] of Object.entries(expectedEnv)) { if (jobEnv[key] !== value) { - errors.push( - `issue-2478-crash-loop-recovery-vitest job env ${key} must be ${value}`, - ); + errors.push(`issue-2478-crash-loop-recovery-vitest job env ${key} must be ${value}`); } } - for (const secret of [ - ...COMMON_SECRET_ENV_NAMES, - ]) { + for (const secret of [...COMMON_SECRET_ENV_NAMES]) { requireEnvDoesNotExposeSecret( errors, "issue-2478-crash-loop-recovery-vitest job", @@ -5555,44 +3852,21 @@ function validateIssue2478CrashLoopRecoveryVitestJob( for (const step of steps) { const stepName = `issue-2478-crash-loop-recovery-vitest step '${step.name ?? step.uses ?? ""}'`; const stepEnv = asRecord(step.env); - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "NVIDIA_INFERENCE_API_KEY", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "NVIDIA_INFERENCE_API_KEY"); requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "NVIDIA_INFERENCE_API_KEY"); if (step.name !== "Authenticate to Docker Hub") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_USERNAME", - ); - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_TOKEN", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_USERNAME"); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_TOKEN"); requireNoDockerHubAuthInRun(errors, stepName, stringValue(step.run)); } requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "GITHUB_TOKEN"); } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); if (!checkout) { - errors.push( - "issue-2478-crash-loop-recovery-vitest job missing checkout step", - ); + errors.push("issue-2478-crash-loop-recovery-vitest job missing checkout step"); } - requireFullShaAction( - errors, - checkout, - "issue-2478-crash-loop-recovery-vitest checkout", - ); + requireFullShaAction(errors, checkout, "issue-2478-crash-loop-recovery-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { errors.push( "issue-2478-crash-loop-recovery-vitest checkout step must set persist-credentials=false", @@ -5611,22 +3885,11 @@ function validateIssue2478CrashLoopRecoveryVitestJob( 'echo "DOCKER_CONFIG=${RUNNER_TEMP}/docker-config-issue-2478-crash-loop-recovery" >> "$GITHUB_ENV"', ); requireRunDoesNotContain(errors, configureDockerAuth, "${{ runner.temp }}"); - requireRunDoesNotContain( - errors, - configureDockerAuth, - "${{ github.workspace }}", - ); + requireRunDoesNotContain(errors, configureDockerAuth, "${{ github.workspace }}"); - const dockerLogin = requireJobStep( - errors, - jobName, - steps, - "Authenticate to Docker Hub", - ); + const dockerLogin = requireJobStep(errors, jobName, steps, "Authenticate to Docker Hub"); const dockerLoginEnv = asRecord(dockerLogin?.env); - if ( - dockerLoginEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}" - ) { + if (dockerLoginEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}") { errors.push( "issue-2478-crash-loop-recovery-vitest Docker Hub auth must receive DOCKERHUB_USERNAME from secrets", ); @@ -5644,15 +3907,9 @@ function validateIssue2478CrashLoopRecoveryVitestJob( const setupNode = namedStep(steps, "Set up Node"); if (!setupNode) { - errors.push( - "issue-2478-crash-loop-recovery-vitest job missing step: Set up Node", - ); + errors.push("issue-2478-crash-loop-recovery-vitest job missing step: Set up Node"); } - requireFullShaAction( - errors, - setupNode, - "issue-2478-crash-loop-recovery-vitest setup-node", - ); + requireFullShaAction(errors, setupNode, "issue-2478-crash-loop-recovery-vitest setup-node"); const installRootDependencies = requireJobStep( errors, @@ -5660,26 +3917,13 @@ function validateIssue2478CrashLoopRecoveryVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); const buildCli = requireJobStep(errors, jobName, steps, "Build CLI"); requireRunContains(errors, buildCli, "npm run build:cli"); - const installOpenShell = requireJobStep( - errors, - jobName, - steps, - "Install OpenShell CLI", - ); - requireRunContains( - errors, - installOpenShell, - "bash scripts/install-openshell.sh", - ); + const installOpenShell = requireJobStep(errors, jobName, steps, "Install OpenShell CLI"); + requireRunContains(errors, installOpenShell, "bash scripts/install-openshell.sh"); const runVitest = requireJobStep( errors, @@ -5694,11 +3938,7 @@ function validateIssue2478CrashLoopRecoveryVitestJob( runVitestEnv, "NVIDIA_INFERENCE_API_KEY", ); - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); requireRunContains( errors, runVitest, @@ -5711,18 +3951,10 @@ function validateIssue2478CrashLoopRecoveryVitestJob( steps, "Upload issue #2478 crash-loop recovery artifacts", ); - requireFullShaAction( - errors, - upload, - "issue-2478-crash-loop-recovery-vitest upload-artifact", - ); + requireFullShaAction(errors, upload, "issue-2478-crash-loop-recovery-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); - if ( - uploadWith.name !== "e2e-vitest-scenarios-issue-2478-crash-loop-recovery" - ) { - errors.push( - "issue-2478-crash-loop-recovery-vitest artifact upload name must be stable", - ); + if (uploadWith.name !== "e2e-vitest-scenarios-issue-2478-crash-loop-recovery") { + errors.push("issue-2478-crash-loop-recovery-vitest artifact upload name must be stable"); } const uploadPath = stringValue(uploadWith.path); requireUploadPathContains( @@ -5741,30 +3973,18 @@ function validateIssue2478CrashLoopRecoveryVitestJob( ); } if (uploadWith["retention-days"] !== 14) { - errors.push( - "issue-2478-crash-loop-recovery-vitest artifact upload retention-days must be 14", - ); + errors.push("issue-2478-crash-loop-recovery-vitest artifact upload retention-days must be 14"); } - const cleanup = requireJobStep( - errors, - jobName, - steps, - "Clean up Docker auth", - ); + const cleanup = requireJobStep(errors, jobName, steps, "Clean up Docker auth"); if (cleanup?.if !== "always()") { - errors.push( - "issue-2478-crash-loop-recovery-vitest Docker auth cleanup must always run", - ); + errors.push("issue-2478-crash-loop-recovery-vitest Docker auth cleanup must always run"); } requireRunContains(errors, cleanup, "docker logout docker.io"); requireRunContains(errors, cleanup, 'rm -rf "${DOCKER_CONFIG}"'); } -function validateChannelsAddRemoveVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateChannelsAddRemoveVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "channels-add-remove-vitest"; const scenarioName = "channels-add-remove"; const job = asRecord(jobs[jobName]); @@ -5778,28 +3998,21 @@ function validateChannelsAddRemoveVitestJob( } validateFreeStandingJobSelector(errors, jobs, jobName, scenarioName); if (job["timeout-minutes"] !== 75) { - errors.push( - "channels-add-remove-vitest job must keep the legacy 75 minute timeout", - ); + errors.push("channels-add-remove-vitest job must keep the legacy 75 minute timeout"); } const jobEnv = asRecord(job.env); if (jobEnv.NEMOCLAW_RUN_E2E_SCENARIOS !== "1") { - errors.push( - "channels-add-remove-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1", - ); + errors.push("channels-add-remove-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1"); } if ( - jobEnv.E2E_ARTIFACT_DIR !== - "${{ github.workspace }}/e2e-artifacts/vitest/channels-add-remove" + jobEnv.E2E_ARTIFACT_DIR !== "${{ github.workspace }}/e2e-artifacts/vitest/channels-add-remove" ) { errors.push( "channels-add-remove-vitest job must write artifacts under e2e-artifacts/vitest/channels-add-remove", ); } if (jobEnv.NEMOCLAW_CLI_BIN !== "${{ github.workspace }}/bin/nemoclaw.js") { - errors.push( - "channels-add-remove-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI", - ); + errors.push("channels-add-remove-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI"); } if (jobEnv.NEMOCLAW_SANDBOX_NAME !== "e2e-channels-add-remove") { errors.push( @@ -5807,24 +4020,16 @@ function validateChannelsAddRemoveVitestJob( ); } if (jobEnv.NEMOCLAW_NON_INTERACTIVE !== "1") { - errors.push( - "channels-add-remove-vitest job must set NEMOCLAW_NON_INTERACTIVE=1", - ); + errors.push("channels-add-remove-vitest job must set NEMOCLAW_NON_INTERACTIVE=1"); } if (jobEnv.NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE !== "1") { - errors.push( - "channels-add-remove-vitest job must set NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1", - ); + errors.push("channels-add-remove-vitest job must set NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1"); } if (jobEnv.OPENSHELL_GATEWAY !== "nemoclaw") { - errors.push( - "channels-add-remove-vitest job must force OPENSHELL_GATEWAY=nemoclaw", - ); + errors.push("channels-add-remove-vitest job must force OPENSHELL_GATEWAY=nemoclaw"); } if (jobEnv.NEMOCLAW_E2E_USE_HOSTED_INFERENCE !== "1") { - errors.push( - "channels-add-remove-vitest job must enable hosted-compatible inference mode", - ); + errors.push("channels-add-remove-vitest job must enable hosted-compatible inference mode"); } if (jobEnv.NEMOCLAW_PROVIDER !== "custom") { errors.push( @@ -5832,14 +4037,10 @@ function validateChannelsAddRemoveVitestJob( ); } if (jobEnv.NEMOCLAW_ENDPOINT_URL !== "https://inference-api.nvidia.com/v1") { - errors.push( - "channels-add-remove-vitest job must use the hosted compatible inference endpoint", - ); + errors.push("channels-add-remove-vitest job must use the hosted compatible inference endpoint"); } if (jobEnv.NEMOCLAW_MODEL !== "nvidia/nvidia/nemotron-3-ultra") { - errors.push( - "channels-add-remove-vitest job must use the hosted Inference Hub model id", - ); + errors.push("channels-add-remove-vitest job must use the hosted Inference Hub model id"); } if (jobEnv.NEMOCLAW_COMPAT_MODEL !== "nvidia/nvidia/nemotron-3-ultra") { errors.push( @@ -5858,12 +4059,7 @@ function validateChannelsAddRemoveVitestJob( "DOCKERHUB_TOKEN", "GITHUB_TOKEN", ]) { - requireEnvDoesNotExposeSecret( - errors, - "channels-add-remove-vitest job", - jobEnv, - secret, - ); + requireEnvDoesNotExposeSecret(errors, "channels-add-remove-vitest job", jobEnv, secret); } const steps = asSteps(job.steps); @@ -5872,55 +4068,25 @@ function validateChannelsAddRemoveVitestJob( const stepName = `channels-add-remove-vitest step '${step.name ?? step.uses ?? ""}'`; const stepEnv = asRecord(step.env); if (step.name !== "Run channels add/remove live test") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "NVIDIA_INFERENCE_API_KEY", - ); - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "COMPATIBLE_API_KEY", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "NVIDIA_INFERENCE_API_KEY"); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "COMPATIBLE_API_KEY"); } if (step.name !== "Authenticate to Docker Hub") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_USERNAME", - ); - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_TOKEN", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_USERNAME"); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_TOKEN"); requireNoDockerHubAuthInRun(errors, stepName, stringValue(step.run)); } requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "GITHUB_TOKEN"); } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); - if (!checkout) - errors.push("channels-add-remove-vitest job missing checkout step"); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); + if (!checkout) errors.push("channels-add-remove-vitest job missing checkout step"); requireFullShaAction(errors, checkout, "channels-add-remove-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { - errors.push( - "channels-add-remove-vitest checkout step must set persist-credentials=false", - ); + errors.push("channels-add-remove-vitest checkout step must set persist-credentials=false"); } - const dockerHubAuth = requireJobStep( - errors, - jobName, - steps, - "Authenticate to Docker Hub", - ); + const dockerHubAuth = requireJobStep(errors, jobName, steps, "Authenticate to Docker Hub"); const dockerHubEnv = asRecord(dockerHubAuth?.env); if (dockerHubEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}") { errors.push( @@ -5936,13 +4102,8 @@ function validateChannelsAddRemoveVitestJob( requireRunContains(errors, dockerHubAuth, "continuing with anonymous pulls"); const setupNode = namedStep(steps, "Set up Node"); - if (!setupNode) - errors.push("channels-add-remove-vitest job missing step: Set up Node"); - requireFullShaAction( - errors, - setupNode, - "channels-add-remove-vitest setup-node", - ); + if (!setupNode) errors.push("channels-add-remove-vitest job missing step: Set up Node"); + requireFullShaAction(errors, setupNode, "channels-add-remove-vitest setup-node"); const installRootDependencies = requireJobStep( errors, @@ -5950,38 +4111,20 @@ function validateChannelsAddRemoveVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); const buildCli = requireJobStep(errors, jobName, steps, "Build CLI"); requireRunContains(errors, buildCli, "npm run build:cli"); - const installOpenShell = requireJobStep( - errors, - jobName, - steps, - "Install OpenShell", - ); - requireRunContains( - errors, - installOpenShell, - "bash scripts/install-openshell.sh", - ); + const installOpenShell = requireJobStep(errors, jobName, steps, "Install OpenShell"); + requireRunContains(errors, installOpenShell, "bash scripts/install-openshell.sh"); requireRunContains(errors, installOpenShell, "env -u DOCKER_CONFIG"); requireRunContains(errors, installOpenShell, "-u DOCKERHUB_USERNAME"); requireRunContains(errors, installOpenShell, "-u DOCKERHUB_TOKEN"); requireRunContains(errors, installOpenShell, "-u NVIDIA_INFERENCE_API_KEY"); requireRunContains(errors, installOpenShell, "-u GITHUB_TOKEN"); - const runVitest = requireJobStep( - errors, - jobName, - steps, - "Run channels add/remove live test", - ); + const runVitest = requireJobStep(errors, jobName, steps, "Run channels add/remove live test"); const runVitestEnv = asRecord(runVitest?.env); if (runVitestEnv.NVIDIA_INFERENCE_API_KEY !== "${{ secrets.NVIDIA_INFERENCE_API_KEY }}") { errors.push( @@ -5993,80 +4136,39 @@ function validateChannelsAddRemoveVitestJob( "channels-add-remove-vitest step must stage NVIDIA_INFERENCE_API_KEY as COMPATIBLE_API_KEY", ); } - if ( - runVitestEnv.TELEGRAM_BOT_TOKEN !== - "test-fake-telegram-token-add-remove-e2e" - ) { - errors.push( - "channels-add-remove-vitest step must set the fake Telegram token", - ); + if (runVitestEnv.TELEGRAM_BOT_TOKEN !== "test-fake-telegram-token-add-remove-e2e") { + errors.push("channels-add-remove-vitest step must set the fake Telegram token"); } if (runVitestEnv.TELEGRAM_ALLOWED_IDS !== "123456789") { - errors.push( - "channels-add-remove-vitest step must set TELEGRAM_ALLOWED_IDS", - ); + errors.push("channels-add-remove-vitest step must set TELEGRAM_ALLOWED_IDS"); } if (runVitestEnv.TELEGRAM_REQUIRE_MENTION !== "0") { - errors.push( - "channels-add-remove-vitest step must set TELEGRAM_REQUIRE_MENTION", - ); + errors.push("channels-add-remove-vitest step must set TELEGRAM_REQUIRE_MENTION"); } requireRunContains(errors, runVitest, "OPENSHELL_BIN"); - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/channels-add-remove.test.ts", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/channels-add-remove.test.ts"); - const upload = requireJobStep( - errors, - jobName, - steps, - "Upload channels add/remove artifacts", - ); - requireFullShaAction( - errors, - upload, - "channels-add-remove-vitest upload-artifact", - ); + const upload = requireJobStep(errors, jobName, steps, "Upload channels add/remove artifacts"); + requireFullShaAction(errors, upload, "channels-add-remove-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); if (uploadWith.name !== "e2e-vitest-scenarios-channels-add-remove") { - errors.push( - "channels-add-remove-vitest artifact upload name must be stable", - ); + errors.push("channels-add-remove-vitest artifact upload name must be stable"); } const uploadPath = stringValue(uploadWith.path); - requireUploadPathContains( - errors, - uploadPath, - "e2e-artifacts/vitest/channels-add-remove/", - ); + requireUploadPathContains(errors, uploadPath, "e2e-artifacts/vitest/channels-add-remove/"); if (uploadWith["include-hidden-files"] !== false) { - errors.push( - "channels-add-remove-vitest artifact upload must set include-hidden-files: false", - ); + errors.push("channels-add-remove-vitest artifact upload must set include-hidden-files: false"); } if (uploadWith["if-no-files-found"] !== "ignore") { - errors.push( - "channels-add-remove-vitest artifact upload must ignore missing fixture artifacts", - ); + errors.push("channels-add-remove-vitest artifact upload must ignore missing fixture artifacts"); } if (uploadWith["retention-days"] !== 14) { - errors.push( - "channels-add-remove-vitest artifact upload retention-days must be 14", - ); + errors.push("channels-add-remove-vitest artifact upload retention-days must be 14"); } } -function validateOpenClawDiscordPairingVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateOpenClawDiscordPairingVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "openclaw-discord-pairing-vitest"; const scenarioName = "openclaw-discord-pairing"; const job = asRecord(jobs[jobName]); @@ -6076,32 +4178,19 @@ function validateOpenClawDiscordPairingVitestJob( } if (job["runs-on"] !== "ubuntu-latest") { - errors.push( - "openclaw-discord-pairing-vitest job must run on ubuntu-latest", - ); + errors.push("openclaw-discord-pairing-vitest job must run on ubuntu-latest"); } if (job["timeout-minutes"] !== 60) { - errors.push( - "openclaw-discord-pairing-vitest job must keep the 60 minute timeout", - ); + errors.push("openclaw-discord-pairing-vitest job must keep the 60 minute timeout"); } validateFreeStandingJobSelector(errors, jobs, jobName, scenarioName); const jobEnv = asRecord(job.env); if ("DOCKER_CONFIG" in jobEnv) { - errors.push( - "openclaw-discord-pairing-vitest job must not set DOCKER_CONFIG at job level", - ); + errors.push("openclaw-discord-pairing-vitest job must not set DOCKER_CONFIG at job level"); } - for (const secret of [ - ...COMMON_SECRET_ENV_NAMES, - ]) { - requireEnvDoesNotExposeSecret( - errors, - "openclaw-discord-pairing-vitest job", - jobEnv, - secret, - ); + for (const secret of [...COMMON_SECRET_ENV_NAMES]) { + requireEnvDoesNotExposeSecret(errors, "openclaw-discord-pairing-vitest job", jobEnv, secret); } const steps = asSteps(job.steps); @@ -6110,57 +4199,26 @@ function validateOpenClawDiscordPairingVitestJob( const stepName = `openclaw-discord-pairing-vitest step '${step.name ?? step.uses ?? ""}'`; const stepEnv = asRecord(step.env); if (step.name !== "Run OpenClaw Discord pairing live test") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "NVIDIA_INFERENCE_API_KEY", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "NVIDIA_INFERENCE_API_KEY"); } if (step.name !== "Authenticate to Docker Hub") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_USERNAME", - ); - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_TOKEN", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_USERNAME"); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_TOKEN"); requireNoDockerHubAuthInRun(errors, stepName, stringValue(step.run)); } requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "GITHUB_TOKEN"); } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); - if (!checkout) - errors.push("openclaw-discord-pairing-vitest job missing checkout step"); - requireFullShaAction( - errors, - checkout, - "openclaw-discord-pairing-vitest checkout", - ); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); + if (!checkout) errors.push("openclaw-discord-pairing-vitest job missing checkout step"); + requireFullShaAction(errors, checkout, "openclaw-discord-pairing-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { - errors.push( - "openclaw-discord-pairing-vitest checkout step must set persist-credentials=false", - ); + errors.push("openclaw-discord-pairing-vitest checkout step must set persist-credentials=false"); } const setupNode = namedStep(steps, "Set up Node"); - if (!setupNode) - errors.push( - "openclaw-discord-pairing-vitest job missing step: Set up Node", - ); - requireFullShaAction( - errors, - setupNode, - "openclaw-discord-pairing-vitest setup-node", - ); + if (!setupNode) errors.push("openclaw-discord-pairing-vitest job missing step: Set up Node"); + requireFullShaAction(errors, setupNode, "openclaw-discord-pairing-vitest setup-node"); const installRootDependencies = requireJobStep( errors, @@ -6168,11 +4226,7 @@ function validateOpenClawDiscordPairingVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); const buildCli = requireJobStep(errors, jobName, steps, "Build CLI"); requireRunContains(errors, buildCli, "npm run build:cli"); @@ -6189,22 +4243,11 @@ function validateOpenClawDiscordPairingVitestJob( 'echo "DOCKER_CONFIG=${RUNNER_TEMP}/docker-config-openclaw-discord-pairing" >> "$GITHUB_ENV"', ); requireRunDoesNotContain(errors, configureDockerAuth, "${{ runner.temp }}"); - requireRunDoesNotContain( - errors, - configureDockerAuth, - "${{ github.workspace }}", - ); + requireRunDoesNotContain(errors, configureDockerAuth, "${{ github.workspace }}"); - const dockerLogin = requireJobStep( - errors, - jobName, - steps, - "Authenticate to Docker Hub", - ); + const dockerLogin = requireJobStep(errors, jobName, steps, "Authenticate to Docker Hub"); const dockerLoginEnv = asRecord(dockerLogin?.env); - if ( - dockerLoginEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}" - ) { + if (dockerLoginEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}") { errors.push( "openclaw-discord-pairing-vitest Docker Hub auth must receive DOCKERHUB_USERNAME from secrets", ); @@ -6219,17 +4262,8 @@ function validateOpenClawDiscordPairingVitestJob( requireRunContains(errors, dockerLogin, "docker login docker.io"); requireRunContains(errors, dockerLogin, "--password-stdin"); - const installOpenShell = requireJobStep( - errors, - jobName, - steps, - "Install OpenShell CLI", - ); - requireRunContains( - errors, - installOpenShell, - "bash scripts/install-openshell.sh", - ); + const installOpenShell = requireJobStep(errors, jobName, steps, "Install OpenShell CLI"); + requireRunContains(errors, installOpenShell, "bash scripts/install-openshell.sh"); requireRunContains(errors, installOpenShell, "env -u DOCKER_CONFIG"); requireRunContains(errors, installOpenShell, "-u DOCKERHUB_USERNAME"); requireRunContains(errors, installOpenShell, "-u DOCKERHUB_TOKEN"); @@ -6243,29 +4277,16 @@ function validateOpenClawDiscordPairingVitestJob( "Run OpenClaw Discord pairing live test", ); const runVitestEnv = asRecord(runVitest?.env); - if ( - runVitestEnv.NVIDIA_INFERENCE_API_KEY !== - "${{ secrets.NVIDIA_INFERENCE_API_KEY }}" - ) { + if (runVitestEnv.NVIDIA_INFERENCE_API_KEY !== "${{ secrets.NVIDIA_INFERENCE_API_KEY }}") { errors.push( "openclaw-discord-pairing-vitest step must receive NVIDIA_INFERENCE_API_KEY from secrets", ); } if (runVitestEnv.DISCORD_BOT_TOKEN !== "test-fake-discord-pairing-e2e") { - errors.push( - "openclaw-discord-pairing-vitest step must use fake Discord token", - ); + errors.push("openclaw-discord-pairing-vitest step must use fake Discord token"); } - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/openclaw-discord-pairing.test.ts", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/openclaw-discord-pairing.test.ts"); const upload = requireJobStep( errors, @@ -6273,18 +4294,10 @@ function validateOpenClawDiscordPairingVitestJob( steps, "Upload OpenClaw Discord pairing artifacts", ); - requireFullShaAction( - errors, - upload, - "openclaw-discord-pairing-vitest upload-artifact", - ); + requireFullShaAction(errors, upload, "openclaw-discord-pairing-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); const uploadPath = stringValue(uploadWith.path); - requireUploadPathContains( - errors, - uploadPath, - "e2e-artifacts/vitest/openclaw-discord-pairing/", - ); + requireUploadPathContains(errors, uploadPath, "e2e-artifacts/vitest/openclaw-discord-pairing/"); if (uploadWith["include-hidden-files"] !== false) { errors.push( "openclaw-discord-pairing-vitest artifact upload must set include-hidden-files: false", @@ -6296,30 +4309,18 @@ function validateOpenClawDiscordPairingVitestJob( ); } if (uploadWith["retention-days"] !== 14) { - errors.push( - "openclaw-discord-pairing-vitest artifact upload retention-days must be 14", - ); + errors.push("openclaw-discord-pairing-vitest artifact upload retention-days must be 14"); } - const cleanup = requireJobStep( - errors, - jobName, - steps, - "Clean up Docker auth", - ); + const cleanup = requireJobStep(errors, jobName, steps, "Clean up Docker auth"); if (cleanup?.if !== "always()") { - errors.push( - "openclaw-discord-pairing-vitest Docker auth cleanup must always run", - ); + errors.push("openclaw-discord-pairing-vitest Docker auth cleanup must always run"); } requireRunContains(errors, cleanup, "docker logout docker.io"); requireRunContains(errors, cleanup, 'rm -rf "${DOCKER_CONFIG}"'); } -function validateOpenClawSlackPairingVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateOpenClawSlackPairingVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "openclaw-slack-pairing-vitest"; const scenarioName = "openclaw-slack-pairing"; const job = asRecord(jobs[jobName]); @@ -6332,27 +4333,16 @@ function validateOpenClawSlackPairingVitestJob( errors.push("openclaw-slack-pairing-vitest job must run on ubuntu-latest"); } if (job["timeout-minutes"] !== 60) { - errors.push( - "openclaw-slack-pairing-vitest job must keep the 60 minute timeout", - ); + errors.push("openclaw-slack-pairing-vitest job must keep the 60 minute timeout"); } validateFreeStandingJobSelector(errors, jobs, jobName, scenarioName); const jobEnv = asRecord(job.env); if ("DOCKER_CONFIG" in jobEnv) { - errors.push( - "openclaw-slack-pairing-vitest job must not set DOCKER_CONFIG at job level", - ); + errors.push("openclaw-slack-pairing-vitest job must not set DOCKER_CONFIG at job level"); } - for (const secret of [ - ...COMMON_SECRET_ENV_NAMES, - ]) { - requireEnvDoesNotExposeSecret( - errors, - "openclaw-slack-pairing-vitest job", - jobEnv, - secret, - ); + for (const secret of [...COMMON_SECRET_ENV_NAMES]) { + requireEnvDoesNotExposeSecret(errors, "openclaw-slack-pairing-vitest job", jobEnv, secret); } const steps = asSteps(job.steps); @@ -6361,55 +4351,26 @@ function validateOpenClawSlackPairingVitestJob( const stepName = `openclaw-slack-pairing-vitest step '${step.name ?? step.uses ?? ""}'`; const stepEnv = asRecord(step.env); if (step.name !== "Run OpenClaw Slack pairing live test") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "NVIDIA_INFERENCE_API_KEY", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "NVIDIA_INFERENCE_API_KEY"); } if (step.name !== "Authenticate to Docker Hub") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_USERNAME", - ); - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_TOKEN", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_USERNAME"); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_TOKEN"); requireNoDockerHubAuthInRun(errors, stepName, stringValue(step.run)); } requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "GITHUB_TOKEN"); } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); - if (!checkout) - errors.push("openclaw-slack-pairing-vitest job missing checkout step"); - requireFullShaAction( - errors, - checkout, - "openclaw-slack-pairing-vitest checkout", - ); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); + if (!checkout) errors.push("openclaw-slack-pairing-vitest job missing checkout step"); + requireFullShaAction(errors, checkout, "openclaw-slack-pairing-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { - errors.push( - "openclaw-slack-pairing-vitest checkout step must set persist-credentials=false", - ); + errors.push("openclaw-slack-pairing-vitest checkout step must set persist-credentials=false"); } const setupNode = namedStep(steps, "Set up Node"); - if (!setupNode) - errors.push("openclaw-slack-pairing-vitest job missing step: Set up Node"); - requireFullShaAction( - errors, - setupNode, - "openclaw-slack-pairing-vitest setup-node", - ); + if (!setupNode) errors.push("openclaw-slack-pairing-vitest job missing step: Set up Node"); + requireFullShaAction(errors, setupNode, "openclaw-slack-pairing-vitest setup-node"); const installRootDependencies = requireJobStep( errors, @@ -6417,11 +4378,7 @@ function validateOpenClawSlackPairingVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); const buildCli = requireJobStep(errors, jobName, steps, "Build CLI"); requireRunContains(errors, buildCli, "npm run build:cli"); @@ -6438,22 +4395,11 @@ function validateOpenClawSlackPairingVitestJob( 'echo "DOCKER_CONFIG=${RUNNER_TEMP}/docker-config-openclaw-slack-pairing" >> "$GITHUB_ENV"', ); requireRunDoesNotContain(errors, configureDockerAuth, "${{ runner.temp }}"); - requireRunDoesNotContain( - errors, - configureDockerAuth, - "${{ github.workspace }}", - ); + requireRunDoesNotContain(errors, configureDockerAuth, "${{ github.workspace }}"); - const dockerLogin = requireJobStep( - errors, - jobName, - steps, - "Authenticate to Docker Hub", - ); + const dockerLogin = requireJobStep(errors, jobName, steps, "Authenticate to Docker Hub"); const dockerLoginEnv = asRecord(dockerLogin?.env); - if ( - dockerLoginEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}" - ) { + if (dockerLoginEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}") { errors.push( "openclaw-slack-pairing-vitest Docker Hub auth must receive DOCKERHUB_USERNAME from secrets", ); @@ -6468,77 +4414,35 @@ function validateOpenClawSlackPairingVitestJob( requireRunContains(errors, dockerLogin, "docker login docker.io"); requireRunContains(errors, dockerLogin, "--password-stdin"); - const installOpenShell = requireJobStep( - errors, - jobName, - steps, - "Install OpenShell CLI", - ); - requireRunContains( - errors, - installOpenShell, - "bash scripts/install-openshell.sh", - ); + const installOpenShell = requireJobStep(errors, jobName, steps, "Install OpenShell CLI"); + requireRunContains(errors, installOpenShell, "bash scripts/install-openshell.sh"); requireRunContains(errors, installOpenShell, "env -u DOCKER_CONFIG"); requireRunContains(errors, installOpenShell, "-u DOCKERHUB_USERNAME"); requireRunContains(errors, installOpenShell, "-u DOCKERHUB_TOKEN"); requireRunContains(errors, installOpenShell, "-u NVIDIA_INFERENCE_API_KEY"); requireRunContains(errors, installOpenShell, "-u GITHUB_TOKEN"); - const runVitest = requireJobStep( - errors, - jobName, - steps, - "Run OpenClaw Slack pairing live test", - ); + const runVitest = requireJobStep(errors, jobName, steps, "Run OpenClaw Slack pairing live test"); const runVitestEnv = asRecord(runVitest?.env); - if ( - runVitestEnv.NVIDIA_INFERENCE_API_KEY !== - "${{ secrets.NVIDIA_INFERENCE_API_KEY }}" - ) { + if (runVitestEnv.NVIDIA_INFERENCE_API_KEY !== "${{ secrets.NVIDIA_INFERENCE_API_KEY }}") { errors.push( "openclaw-slack-pairing-vitest step must receive NVIDIA_INFERENCE_API_KEY from secrets", ); } if (runVitestEnv.SLACK_BOT_TOKEN !== "xoxb-fake-slack-pairing-e2e") { - errors.push( - "openclaw-slack-pairing-vitest step must use fake Slack bot token", - ); + errors.push("openclaw-slack-pairing-vitest step must use fake Slack bot token"); } if (runVitestEnv.SLACK_APP_TOKEN !== "xapp-fake-slack-pairing-e2e") { - errors.push( - "openclaw-slack-pairing-vitest step must use fake Slack app token", - ); + errors.push("openclaw-slack-pairing-vitest step must use fake Slack app token"); } - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/openclaw-slack-pairing.test.ts", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/openclaw-slack-pairing.test.ts"); - const upload = requireJobStep( - errors, - jobName, - steps, - "Upload OpenClaw Slack pairing artifacts", - ); - requireFullShaAction( - errors, - upload, - "openclaw-slack-pairing-vitest upload-artifact", - ); + const upload = requireJobStep(errors, jobName, steps, "Upload OpenClaw Slack pairing artifacts"); + requireFullShaAction(errors, upload, "openclaw-slack-pairing-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); const uploadPath = stringValue(uploadWith.path); - requireUploadPathContains( - errors, - uploadPath, - "e2e-artifacts/vitest/openclaw-slack-pairing/", - ); + requireUploadPathContains(errors, uploadPath, "e2e-artifacts/vitest/openclaw-slack-pairing/"); if (uploadWith["include-hidden-files"] !== false) { errors.push( "openclaw-slack-pairing-vitest artifact upload must set include-hidden-files: false", @@ -6550,30 +4454,18 @@ function validateOpenClawSlackPairingVitestJob( ); } if (uploadWith["retention-days"] !== 14) { - errors.push( - "openclaw-slack-pairing-vitest artifact upload retention-days must be 14", - ); + errors.push("openclaw-slack-pairing-vitest artifact upload retention-days must be 14"); } - const cleanup = requireJobStep( - errors, - jobName, - steps, - "Clean up Docker auth", - ); + const cleanup = requireJobStep(errors, jobName, steps, "Clean up Docker auth"); if (cleanup?.if !== "always()") { - errors.push( - "openclaw-slack-pairing-vitest Docker auth cleanup must always run", - ); + errors.push("openclaw-slack-pairing-vitest Docker auth cleanup must always run"); } requireRunContains(errors, cleanup, "docker logout docker.io"); requireRunContains(errors, cleanup, 'rm -rf "${DOCKER_CONFIG}"'); } -function validateChannelsStopStartVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateChannelsStopStartVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "channels-stop-start-vitest"; const scenarioName = "channels-stop-start"; const job = asRecord(jobs[jobName]); @@ -6587,29 +4479,20 @@ function validateChannelsStopStartVitestJob( } validateFreeStandingJobSelector(errors, jobs, jobName, scenarioName); if (job["timeout-minutes"] !== 90) { - errors.push( - "channels-stop-start-vitest job must keep the 90 minute timeout", - ); + errors.push("channels-stop-start-vitest job must keep the 90 minute timeout"); } const strategy = asRecord(job.strategy); if (strategy["fail-fast"] !== false) { errors.push("channels-stop-start-vitest strategy.fail-fast must be false"); } const matrix = asRecord(strategy.matrix); - if ( - !Array.isArray(matrix.agent) || - matrix.agent.join(",") !== "openclaw,hermes" - ) { - errors.push( - "channels-stop-start-vitest matrix.agent must be openclaw,hermes", - ); + if (!Array.isArray(matrix.agent) || matrix.agent.join(",") !== "openclaw,hermes") { + errors.push("channels-stop-start-vitest matrix.agent must be openclaw,hermes"); } const jobEnv = asRecord(job.env); if (jobEnv.NEMOCLAW_RUN_E2E_SCENARIOS !== "1") { - errors.push( - "channels-stop-start-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1", - ); + errors.push("channels-stop-start-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1"); } if ( jobEnv.E2E_ARTIFACT_DIR !== @@ -6620,22 +4503,15 @@ function validateChannelsStopStartVitestJob( ); } if (jobEnv.NEMOCLAW_CLI_BIN !== "${{ github.workspace }}/bin/nemoclaw.js") { - errors.push( - "channels-stop-start-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI", - ); + errors.push("channels-stop-start-vitest job must point NEMOCLAW_CLI_BIN at the repo CLI"); } - if ( - jobEnv.NEMOCLAW_SANDBOX_NAME !== - "e2e-channels-stop-start-${{ matrix.agent }}" - ) { + if (jobEnv.NEMOCLAW_SANDBOX_NAME !== "e2e-channels-stop-start-${{ matrix.agent }}") { errors.push( "channels-stop-start-vitest job must derive NEMOCLAW_SANDBOX_NAME from matrix.agent with the e2e-channels-stop-start- prefix", ); } if (jobEnv.NEMOCLAW_AGENT !== "${{ matrix.agent }}") { - errors.push( - "channels-stop-start-vitest job must pass matrix.agent through NEMOCLAW_AGENT", - ); + errors.push("channels-stop-start-vitest job must pass matrix.agent through NEMOCLAW_AGENT"); } if (jobEnv.NEMOCLAW_CHANNELS_STOP_START_AGENT !== "${{ matrix.agent }}") { errors.push( @@ -6643,27 +4519,19 @@ function validateChannelsStopStartVitestJob( ); } if (jobEnv.NEMOCLAW_NON_INTERACTIVE !== "1") { - errors.push( - "channels-stop-start-vitest job must set NEMOCLAW_NON_INTERACTIVE=1", - ); + errors.push("channels-stop-start-vitest job must set NEMOCLAW_NON_INTERACTIVE=1"); } if (jobEnv.NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE !== "1") { - errors.push( - "channels-stop-start-vitest job must set NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1", - ); + errors.push("channels-stop-start-vitest job must set NEMOCLAW_ACCEPT_THIRD_PARTY_SOFTWARE=1"); } if (jobEnv.OPENSHELL_GATEWAY !== "nemoclaw") { - errors.push( - "channels-stop-start-vitest job must force OPENSHELL_GATEWAY=nemoclaw", - ); + errors.push("channels-stop-start-vitest job must force OPENSHELL_GATEWAY=nemoclaw"); } if ( jobEnv.DOCKER_CONFIG !== "${{ github.workspace }}/.docker-config-channels-stop-start-${{ matrix.agent }}" ) { - errors.push( - "channels-stop-start-vitest job must isolate Docker auth by matrix agent", - ); + errors.push("channels-stop-start-vitest job must isolate Docker auth by matrix agent"); } for (const secret of [ "NVIDIA_INFERENCE_API_KEY", @@ -6671,12 +4539,7 @@ function validateChannelsStopStartVitestJob( "DOCKERHUB_TOKEN", "GITHUB_TOKEN", ]) { - requireEnvDoesNotExposeSecret( - errors, - "channels-stop-start-vitest job", - jobEnv, - secret, - ); + requireEnvDoesNotExposeSecret(errors, "channels-stop-start-vitest job", jobEnv, secret); } const steps = asSteps(job.steps); @@ -6685,49 +4548,24 @@ function validateChannelsStopStartVitestJob( const stepName = `channels-stop-start-vitest step '${step.name ?? step.uses ?? ""}'`; const stepEnv = asRecord(step.env); if (step.name !== "Run channels stop/start live test") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "NVIDIA_INFERENCE_API_KEY", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "NVIDIA_INFERENCE_API_KEY"); } if (step.name !== "Authenticate to Docker Hub") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_USERNAME", - ); - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_TOKEN", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_USERNAME"); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_TOKEN"); requireNoDockerHubAuthInRun(errors, stepName, stringValue(step.run)); } requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "GITHUB_TOKEN"); } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); - if (!checkout) - errors.push("channels-stop-start-vitest job missing checkout step"); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); + if (!checkout) errors.push("channels-stop-start-vitest job missing checkout step"); requireFullShaAction(errors, checkout, "channels-stop-start-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { - errors.push( - "channels-stop-start-vitest checkout step must set persist-credentials=false", - ); + errors.push("channels-stop-start-vitest checkout step must set persist-credentials=false"); } - const dockerHubAuth = requireJobStep( - errors, - jobName, - steps, - "Authenticate to Docker Hub", - ); + const dockerHubAuth = requireJobStep(errors, jobName, steps, "Authenticate to Docker Hub"); const dockerHubEnv = asRecord(dockerHubAuth?.env); if (dockerHubEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}") { errors.push( @@ -6746,13 +4584,8 @@ function validateChannelsStopStartVitestJob( requireRunContains(errors, dockerHubAuth, "continuing with anonymous pulls"); const setupNode = namedStep(steps, "Set up Node"); - if (!setupNode) - errors.push("channels-stop-start-vitest job missing step: Set up Node"); - requireFullShaAction( - errors, - setupNode, - "channels-stop-start-vitest setup-node", - ); + if (!setupNode) errors.push("channels-stop-start-vitest job missing step: Set up Node"); + requireFullShaAction(errors, setupNode, "channels-stop-start-vitest setup-node"); const installRootDependencies = requireJobStep( errors, @@ -6760,118 +4593,52 @@ function validateChannelsStopStartVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); const buildCli = requireJobStep(errors, jobName, steps, "Build CLI"); requireRunContains(errors, buildCli, "npm run build:cli"); - const installOpenShell = requireJobStep( - errors, - jobName, - steps, - "Install OpenShell", - ); - requireRunContains( - errors, - installOpenShell, - "bash scripts/install-openshell.sh", - ); + const installOpenShell = requireJobStep(errors, jobName, steps, "Install OpenShell"); + requireRunContains(errors, installOpenShell, "bash scripts/install-openshell.sh"); requireRunContains(errors, installOpenShell, "env -u DOCKER_CONFIG"); requireRunContains(errors, installOpenShell, "-u DOCKERHUB_USERNAME"); requireRunContains(errors, installOpenShell, "-u DOCKERHUB_TOKEN"); requireRunContains(errors, installOpenShell, "-u NVIDIA_INFERENCE_API_KEY"); requireRunContains(errors, installOpenShell, "-u GITHUB_TOKEN"); - const runVitest = requireJobStep( - errors, - jobName, - steps, - "Run channels stop/start live test", - ); + const runVitest = requireJobStep(errors, jobName, steps, "Run channels stop/start live test"); const runVitestEnv = asRecord(runVitest?.env); - if ( - runVitestEnv.NVIDIA_INFERENCE_API_KEY !== - "${{ secrets.NVIDIA_INFERENCE_API_KEY }}" - ) { + if (runVitestEnv.NVIDIA_INFERENCE_API_KEY !== "${{ secrets.NVIDIA_INFERENCE_API_KEY }}") { errors.push( "channels-stop-start-vitest step must receive NVIDIA_INFERENCE_API_KEY from secrets", ); } if ( - runVitestEnv.TELEGRAM_BOT_TOKEN !== - "test-fake-telegram-token-stop-start-${{ matrix.agent }}" + runVitestEnv.TELEGRAM_BOT_TOKEN !== "test-fake-telegram-token-stop-start-${{ matrix.agent }}" ) { - errors.push( - "channels-stop-start-vitest step must set the fake Telegram token", - ); + errors.push("channels-stop-start-vitest step must set the fake Telegram token"); } - if ( - runVitestEnv.DISCORD_BOT_TOKEN !== - "test-fake-discord-token-stop-start-${{ matrix.agent }}" - ) { - errors.push( - "channels-stop-start-vitest step must set the fake Discord token", - ); + if (runVitestEnv.DISCORD_BOT_TOKEN !== "test-fake-discord-token-stop-start-${{ matrix.agent }}") { + errors.push("channels-stop-start-vitest step must set the fake Discord token"); } - if ( - runVitestEnv.SLACK_BOT_TOKEN !== - "xoxb-fake-slack-token-stop-start-${{ matrix.agent }}" - ) { - errors.push( - "channels-stop-start-vitest step must set the fake Slack bot token", - ); + if (runVitestEnv.SLACK_BOT_TOKEN !== "xoxb-fake-slack-token-stop-start-${{ matrix.agent }}") { + errors.push("channels-stop-start-vitest step must set the fake Slack bot token"); } - if ( - runVitestEnv.SLACK_APP_TOKEN !== - "xapp-fake-slack-token-stop-start-${{ matrix.agent }}" - ) { - errors.push( - "channels-stop-start-vitest step must set the fake Slack app token", - ); + if (runVitestEnv.SLACK_APP_TOKEN !== "xapp-fake-slack-token-stop-start-${{ matrix.agent }}") { + errors.push("channels-stop-start-vitest step must set the fake Slack app token"); } - if ( - runVitestEnv.WECHAT_BOT_TOKEN !== - "test-fake-wechat-token-stop-start-${{ matrix.agent }}" - ) { - errors.push( - "channels-stop-start-vitest step must set the fake WeChat token", - ); + if (runVitestEnv.WECHAT_BOT_TOKEN !== "test-fake-wechat-token-stop-start-${{ matrix.agent }}") { + errors.push("channels-stop-start-vitest step must set the fake WeChat token"); } requireRunContains(errors, runVitest, "OPENSHELL_BIN"); - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/channels-stop-start.test.ts", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/channels-stop-start.test.ts"); - const upload = requireJobStep( - errors, - jobName, - steps, - "Upload channels stop/start artifacts", - ); - requireFullShaAction( - errors, - upload, - "channels-stop-start-vitest upload-artifact", - ); + const upload = requireJobStep(errors, jobName, steps, "Upload channels stop/start artifacts"); + requireFullShaAction(errors, upload, "channels-stop-start-vitest upload-artifact"); const uploadWith = asRecord(upload?.with); - if ( - uploadWith.name !== - "e2e-vitest-scenarios-channels-stop-start-${{ matrix.agent }}" - ) { - errors.push( - "channels-stop-start-vitest artifact upload name must include matrix.agent", - ); + if (uploadWith.name !== "e2e-vitest-scenarios-channels-stop-start-${{ matrix.agent }}") { + errors.push("channels-stop-start-vitest artifact upload name must include matrix.agent"); } const uploadPath = stringValue(uploadWith.path); requireUploadPathContains( @@ -6880,40 +4647,24 @@ function validateChannelsStopStartVitestJob( "e2e-artifacts/vitest/channels-stop-start/${{ matrix.agent }}/", ); if (uploadWith["include-hidden-files"] !== false) { - errors.push( - "channels-stop-start-vitest artifact upload must set include-hidden-files: false", - ); + errors.push("channels-stop-start-vitest artifact upload must set include-hidden-files: false"); } if (uploadWith["if-no-files-found"] !== "ignore") { - errors.push( - "channels-stop-start-vitest artifact upload must ignore missing fixture artifacts", - ); + errors.push("channels-stop-start-vitest artifact upload must ignore missing fixture artifacts"); } if (uploadWith["retention-days"] !== 14) { - errors.push( - "channels-stop-start-vitest artifact upload retention-days must be 14", - ); + errors.push("channels-stop-start-vitest artifact upload retention-days must be 14"); } - const cleanup = requireJobStep( - errors, - jobName, - steps, - "Clean up Docker auth", - ); - if (cleanup?.if !== "always()") { - errors.push( - "channels-stop-start-vitest Docker auth cleanup must always run", - ); + const cleanup = requireJobStep(errors, jobName, steps, "Clean up Docker auth"); + if (cleanup?.if !== "always()") { + errors.push("channels-stop-start-vitest Docker auth cleanup must always run"); } requireRunContains(errors, cleanup, "docker logout docker.io"); requireRunContains(errors, cleanup, 'rm -rf "${DOCKER_CONFIG}"'); } -function validateTelegramInjectionVitestJob( - errors: string[], - jobs: WorkflowRecord, -): void { +function validateTelegramInjectionVitestJob(errors: string[], jobs: WorkflowRecord): void { const jobName = "telegram-injection-vitest"; const scenarioName = "telegram-injection"; const job = asRecord(jobs[jobName]); @@ -6926,27 +4677,16 @@ function validateTelegramInjectionVitestJob( errors.push("telegram-injection-vitest job must run on ubuntu-latest"); } if (job["timeout-minutes"] !== 45) { - errors.push( - "telegram-injection-vitest job must keep the 45 minute timeout", - ); + errors.push("telegram-injection-vitest job must keep the 45 minute timeout"); } validateFreeStandingJobSelector(errors, jobs, jobName, scenarioName); const jobEnv = asRecord(job.env); if ("DOCKER_CONFIG" in jobEnv) { - errors.push( - "telegram-injection-vitest job must not set DOCKER_CONFIG at job level", - ); + errors.push("telegram-injection-vitest job must not set DOCKER_CONFIG at job level"); } - for (const secret of [ - ...COMMON_SECRET_ENV_NAMES, - ]) { - requireEnvDoesNotExposeSecret( - errors, - "telegram-injection-vitest job", - jobEnv, - secret, - ); + for (const secret of [...COMMON_SECRET_ENV_NAMES]) { + requireEnvDoesNotExposeSecret(errors, "telegram-injection-vitest job", jobEnv, secret); } const steps = asSteps(job.steps); @@ -6955,32 +4695,12 @@ function validateTelegramInjectionVitestJob( const stepName = `telegram-injection-vitest step '${step.name ?? step.uses ?? ""}'`; const stepEnv = asRecord(step.env); if (step.name !== "Run Telegram injection live test") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "NVIDIA_INFERENCE_API_KEY", - ); - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "NVIDIA_INFERENCE_API_KEY", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "NVIDIA_INFERENCE_API_KEY"); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "NVIDIA_INFERENCE_API_KEY"); } if (step.name !== "Authenticate to Docker Hub") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_USERNAME", - ); - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_TOKEN", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_USERNAME"); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_TOKEN"); requireNoDockerHubAuthInRun(errors, stepName, stringValue(step.run)); } requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "GITHUB_TOKEN"); @@ -6998,22 +4718,11 @@ function validateTelegramInjectionVitestJob( 'echo "DOCKER_CONFIG=${RUNNER_TEMP}/docker-config-telegram-injection" >> "$GITHUB_ENV"', ); requireRunDoesNotContain(errors, configureDockerAuth, "${{ runner.temp }}"); - requireRunDoesNotContain( - errors, - configureDockerAuth, - "${{ github.workspace }}", - ); + requireRunDoesNotContain(errors, configureDockerAuth, "${{ github.workspace }}"); - const dockerLogin = requireJobStep( - errors, - jobName, - steps, - "Authenticate to Docker Hub", - ); + const dockerLogin = requireJobStep(errors, jobName, steps, "Authenticate to Docker Hub"); const dockerLoginEnv = asRecord(dockerLogin?.env); - if ( - dockerLoginEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}" - ) { + if (dockerLoginEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}") { errors.push( "telegram-injection-vitest Docker Hub auth must receive DOCKERHUB_USERNAME from secrets", ); @@ -7028,88 +4737,41 @@ function validateTelegramInjectionVitestJob( requireRunContains(errors, dockerLogin, "docker login docker.io"); requireRunContains(errors, dockerLogin, "--password-stdin"); - const installOpenShell = requireJobStep( - errors, - jobName, - steps, - "Install OpenShell", - ); - requireRunContains( - errors, - installOpenShell, - "bash scripts/install-openshell.sh", - ); + const installOpenShell = requireJobStep(errors, jobName, steps, "Install OpenShell"); + requireRunContains(errors, installOpenShell, "bash scripts/install-openshell.sh"); requireRunContains(errors, installOpenShell, "env -u DOCKER_CONFIG"); requireRunContains(errors, installOpenShell, "-u DOCKERHUB_USERNAME"); requireRunContains(errors, installOpenShell, "-u DOCKERHUB_TOKEN"); requireRunContains(errors, installOpenShell, "-u NVIDIA_INFERENCE_API_KEY"); requireRunContains(errors, installOpenShell, "-u GITHUB_TOKEN"); - const runVitest = requireJobStep( - errors, - jobName, - steps, - "Run Telegram injection live test", - ); + const runVitest = requireJobStep(errors, jobName, steps, "Run Telegram injection live test"); const runVitestEnv = asRecord(runVitest?.env); - if ( - runVitestEnv.NVIDIA_INFERENCE_API_KEY !== - "${{ secrets.NVIDIA_INFERENCE_API_KEY }}" - ) { + if (runVitestEnv.NVIDIA_INFERENCE_API_KEY !== "${{ secrets.NVIDIA_INFERENCE_API_KEY }}") { errors.push( "telegram-injection-vitest step must receive NVIDIA_INFERENCE_API_KEY from secrets", ); } - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/telegram-injection.test.ts", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/telegram-injection.test.ts"); - const upload = requireJobStep( - errors, - jobName, - steps, - "Upload Telegram injection artifacts", - ); + const upload = requireJobStep(errors, jobName, steps, "Upload Telegram injection artifacts"); const uploadWith = asRecord(upload?.with); const uploadPath = stringValue(uploadWith.path); - requireUploadPathContains( - errors, - uploadPath, - "e2e-artifacts/vitest/telegram-injection/", - ); + requireUploadPathContains(errors, uploadPath, "e2e-artifacts/vitest/telegram-injection/"); if (uploadWith["include-hidden-files"] !== false) { - errors.push( - "telegram-injection-vitest artifact upload must set include-hidden-files: false", - ); + errors.push("telegram-injection-vitest artifact upload must set include-hidden-files: false"); } if (uploadWith["if-no-files-found"] !== "ignore") { - errors.push( - "telegram-injection-vitest artifact upload must ignore missing fixture artifacts", - ); + errors.push("telegram-injection-vitest artifact upload must ignore missing fixture artifacts"); } if (uploadWith["retention-days"] !== 14) { - errors.push( - "telegram-injection-vitest artifact upload retention-days must be 14", - ); + errors.push("telegram-injection-vitest artifact upload retention-days must be 14"); } - const cleanup = requireJobStep( - errors, - jobName, - steps, - "Clean up Docker auth", - ); + const cleanup = requireJobStep(errors, jobName, steps, "Clean up Docker auth"); if (cleanup?.if !== "always()") { - errors.push( - "telegram-injection-vitest Docker auth cleanup must always run", - ); + errors.push("telegram-injection-vitest Docker auth cleanup must always run"); } requireRunContains(errors, cleanup, "docker logout docker.io"); requireRunContains(errors, cleanup, 'rm -rf "${DOCKER_CONFIG}"'); @@ -7123,38 +4785,25 @@ function validateBedrockRuntimeCompatibleAnthropicVitestJob( const scenarioName = "bedrock-runtime-compatible-anthropic"; const job = asRecord(jobs[jobName]); if (Object.keys(job).length === 0) { - errors.push( - "workflow missing bedrock-runtime-compatible-anthropic-vitest job", - ); + errors.push("workflow missing bedrock-runtime-compatible-anthropic-vitest job"); return; } if (job["runs-on"] !== "ubuntu-latest") { - errors.push( - "bedrock-runtime-compatible-anthropic-vitest job must run on ubuntu-latest", - ); + errors.push("bedrock-runtime-compatible-anthropic-vitest job must run on ubuntu-latest"); } if (job["timeout-minutes"] !== 60) { - errors.push( - "bedrock-runtime-compatible-anthropic-vitest timeout-minutes must be 60", - ); + errors.push("bedrock-runtime-compatible-anthropic-vitest timeout-minutes must be 60"); } validateFreeStandingJobSelector(errors, jobs, jobName, scenarioName); const strategy = asRecord(job.strategy); if (strategy["fail-fast"] !== false) { - errors.push( - "bedrock-runtime-compatible-anthropic-vitest strategy.fail-fast must be false", - ); + errors.push("bedrock-runtime-compatible-anthropic-vitest strategy.fail-fast must be false"); } const matrix = asRecord(strategy.matrix); - if ( - !Array.isArray(matrix.agent) || - matrix.agent.join(",") !== "openclaw,hermes" - ) { - errors.push( - "bedrock-runtime-compatible-anthropic-vitest matrix.agent must be openclaw,hermes", - ); + if (!Array.isArray(matrix.agent) || matrix.agent.join(",") !== "openclaw,hermes") { + errors.push("bedrock-runtime-compatible-anthropic-vitest matrix.agent must be openclaw,hermes"); } const jobEnv = asRecord(job.env); @@ -7233,35 +4882,17 @@ function validateBedrockRuntimeCompatibleAnthropicVitestJob( requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "NVIDIA_INFERENCE_API_KEY"); requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "GITHUB_TOKEN"); if (step.name !== "Authenticate to Docker Hub") { - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_USERNAME", - ); - requireEnvDoesNotExposeSecret( - errors, - stepName, - stepEnv, - "DOCKERHUB_TOKEN", - ); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_USERNAME"); + requireEnvDoesNotExposeSecret(errors, stepName, stepEnv, "DOCKERHUB_TOKEN"); requireNoDockerHubAuthInRun(errors, stepName, stringValue(step.run)); } } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); if (!checkout) { - errors.push( - "bedrock-runtime-compatible-anthropic-vitest job missing checkout step", - ); + errors.push("bedrock-runtime-compatible-anthropic-vitest job missing checkout step"); } - requireFullShaAction( - errors, - checkout, - "bedrock-runtime-compatible-anthropic-vitest checkout", - ); + requireFullShaAction(errors, checkout, "bedrock-runtime-compatible-anthropic-vitest checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { errors.push( "bedrock-runtime-compatible-anthropic-vitest checkout step must set persist-credentials=false", @@ -7281,16 +4912,9 @@ function validateBedrockRuntimeCompatibleAnthropicVitestJob( ); requireRunDoesNotContain(errors, configureDockerAuth, "${{ runner.temp }}"); - const dockerLogin = requireJobStep( - errors, - jobName, - steps, - "Authenticate to Docker Hub", - ); + const dockerLogin = requireJobStep(errors, jobName, steps, "Authenticate to Docker Hub"); const dockerLoginEnv = asRecord(dockerLogin?.env); - if ( - dockerLoginEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}" - ) { + if (dockerLoginEnv.DOCKERHUB_USERNAME !== "${{ secrets.DOCKERHUB_USERNAME }}") { errors.push( "bedrock-runtime-compatible-anthropic-vitest Docker Hub auth must receive DOCKERHUB_USERNAME from secrets", ); @@ -7308,15 +4932,9 @@ function validateBedrockRuntimeCompatibleAnthropicVitestJob( const setupNode = namedStep(steps, "Set up Node"); if (!setupNode) { - errors.push( - "bedrock-runtime-compatible-anthropic-vitest job missing step: Set up Node", - ); + errors.push("bedrock-runtime-compatible-anthropic-vitest job missing step: Set up Node"); } - requireFullShaAction( - errors, - setupNode, - "bedrock-runtime-compatible-anthropic-vitest setup-node", - ); + requireFullShaAction(errors, setupNode, "bedrock-runtime-compatible-anthropic-vitest setup-node"); const installRootDependencies = requireJobStep( errors, @@ -7324,11 +4942,7 @@ function validateBedrockRuntimeCompatibleAnthropicVitestJob( steps, "Install root dependencies", ); - requireRunContains( - errors, - installRootDependencies, - "npm ci --ignore-scripts", - ); + requireRunContains(errors, installRootDependencies, "npm ci --ignore-scripts"); const buildCli = requireJobStep(errors, jobName, steps, "Build CLI"); requireRunContains(errors, buildCli, "npm run build:cli"); @@ -7339,11 +4953,7 @@ function validateBedrockRuntimeCompatibleAnthropicVitestJob( steps, "Run Bedrock Runtime compatible Anthropic live test", ); - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); requireRunContains( errors, runVitest, @@ -7393,16 +5003,9 @@ function validateBedrockRuntimeCompatibleAnthropicVitestJob( ); } - const cleanup = requireJobStep( - errors, - jobName, - steps, - "Clean up Docker auth", - ); + const cleanup = requireJobStep(errors, jobName, steps, "Clean up Docker auth"); if (cleanup?.if !== "always()") { - errors.push( - "bedrock-runtime-compatible-anthropic-vitest Docker auth cleanup must always run", - ); + errors.push("bedrock-runtime-compatible-anthropic-vitest Docker auth cleanup must always run"); } requireRunContains(errors, cleanup, "docker logout docker.io"); requireRunContains(errors, cleanup, 'rm -rf "${DOCKER_CONFIG}"'); @@ -7437,8 +5040,7 @@ export function validateE2eVitestScenariosWorkflowBoundary( } const permissions = asRecord(workflow.permissions); - if (permissions.contents !== "read") - errors.push("workflow permissions.contents must be read"); + if (permissions.contents !== "read") errors.push("workflow permissions.contents must be read"); const jobs = asRecord(workflow.jobs); const { errors: inventoryErrors, inventory: freeStandingInventory } = @@ -7446,8 +5048,7 @@ export function validateE2eVitestScenariosWorkflowBoundary( errors.push(...inventoryErrors); validateFreeStandingInventoryBoundary(errors, jobs, freeStandingInventory); const generateMatrix = asRecord(jobs["generate-matrix"]); - if (Object.keys(generateMatrix).length === 0) - errors.push("workflow missing generate-matrix job"); + if (Object.keys(generateMatrix).length === 0) errors.push("workflow missing generate-matrix job"); if (generateMatrix["runs-on"] !== "ubuntu-latest") { errors.push("generate-matrix job must run on ubuntu-latest"); } @@ -7455,10 +5056,7 @@ export function validateE2eVitestScenariosWorkflowBoundary( if (generateOutputs.matrix !== "${{ steps.matrix.outputs.matrix }}") { errors.push("generate-matrix job must expose matrix output"); } - if ( - generateOutputs.hermes_selected !== - "${{ steps.matrix.outputs.hermes_selected }}" - ) { + if (generateOutputs.hermes_selected !== "${{ steps.matrix.outputs.hermes_selected }}") { errors.push("generate-matrix job must expose hermes_selected output"); } const generateSteps = asSteps(generateMatrix.steps); @@ -7466,31 +5064,21 @@ export function validateE2eVitestScenariosWorkflowBoundary( const generateCheckout = generateSteps.find((step) => stringValue(step.uses).startsWith("actions/checkout@"), ); - if (!generateCheckout) - errors.push("generate-matrix job missing checkout step"); + if (!generateCheckout) errors.push("generate-matrix job missing checkout step"); requireFullShaAction(errors, generateCheckout, "generate-matrix checkout"); if (asRecord(generateCheckout?.with)["persist-credentials"] !== false) { - errors.push( - "generate-matrix checkout step must set persist-credentials=false", - ); + errors.push("generate-matrix checkout step must set persist-credentials=false"); } const generateSetupNode = namedStep(generateSteps, "Set up Node"); - if (!generateSetupNode) - errors.push("generate-matrix job missing step: Set up Node"); + if (!generateSetupNode) errors.push("generate-matrix job missing step: Set up Node"); requireFullShaAction(errors, generateSetupNode, "generate-matrix setup-node"); - const generate = requireStep( - errors, - generateSteps, - "Generate Vitest scenario matrix", - ); + const generate = requireStep(errors, generateSteps, "Generate Vitest scenario matrix"); const generateEnv = asRecord(generate?.env); if (generateEnv.JOBS !== "${{ inputs.jobs }}") { errors.push("matrix generation step must pass jobs through JOBS env"); } if (generateEnv.SCENARIOS !== "${{ inputs.scenarios }}") { - errors.push( - "matrix generation step must pass scenarios through SCENARIOS env", - ); + errors.push("matrix generation step must pass scenarios through SCENARIOS env"); } requireRunContains(errors, generate, FREE_STANDING_WORKFLOW_INVENTORY_SCRIPT); requireRunContains( @@ -7503,42 +5091,18 @@ export function validateE2eVitestScenariosWorkflowBoundary( generate, "free_standing_scenarios_csv must match scenario mapping keys", ); - requireRunContains( - errors, - generate, - "Free-standing scenario maps to unknown job", - ); - requireRunContains( - errors, - generate, - "Use either scenarios or jobs, not both", - ); + requireRunContains(errors, generate, "Free-standing scenario maps to unknown job"); + requireRunContains(errors, generate, "Use either scenarios or jobs, not both"); requireRunContains(errors, generate, "Unknown free-standing Vitest job"); requireRunContains(errors, generate, 'matrix="[]"'); - requireRunContains( - errors, - generate, - "npx tsx test/e2e-scenario/scenarios/run.ts", - ); + requireRunContains(errors, generate, "npx tsx test/e2e-scenario/scenarios/run.ts"); requireRunContains(errors, generate, "--emit-live-matrix"); requireRunContains(errors, generate, "--scenarios"); requireRunContains(errors, generate, "^[A-Za-z0-9_-]+(,[A-Za-z0-9_-]+)*$"); - requireRunContains( - errors, - generate, - "Invalid scenario input; use comma-separated scenario ids", - ); - requireRunContains( - errors, - generate, - "Invalid jobs input; use comma-separated job ids", - ); + requireRunContains(errors, generate, "Invalid scenario input; use comma-separated scenario ids"); + requireRunContains(errors, generate, "Invalid jobs input; use comma-separated job ids"); requireRunDoesNotContain(errors, generate, "Invalid jobs input: ${JOBS}"); - requireRunDoesNotContain( - errors, - generate, - "Invalid scenario input: ${SCENARIOS}", - ); + requireRunDoesNotContain(errors, generate, "Invalid scenario input: ${SCENARIOS}"); requireRunDoesNotContain(errors, generate, "^[A-Za-z0-9._-]+"); requireRunContains(errors, generate, "hermes_selected=false"); requireRunContains(errors, generate, "hermes_selected=true"); @@ -7551,8 +5115,7 @@ export function validateE2eVitestScenariosWorkflowBoundary( requireRunContains(errors, generate, "| Scenario | Runner | Label |"); const liveScenarios = asRecord(jobs["live-scenarios"]); - if (Object.keys(liveScenarios).length === 0) - errors.push("workflow missing live-scenarios job"); + if (Object.keys(liveScenarios).length === 0) errors.push("workflow missing live-scenarios job"); if (liveScenarios["runs-on"] !== "${{ matrix.runner }}") { errors.push("live-scenarios job must run on the matrix runner"); } @@ -7560,24 +5123,17 @@ export function validateE2eVitestScenariosWorkflowBoundary( errors.push("live-scenarios job must depend on generate-matrix"); } if ( - liveScenarios.if !== - "${{ inputs.jobs == '' && needs.generate-matrix.outputs.matrix != '[]' }}" + liveScenarios.if !== "${{ inputs.jobs == '' && needs.generate-matrix.outputs.matrix != '[]' }}" ) { - errors.push( - "live-scenarios job must not run when a free-standing jobs selector is supplied", - ); + errors.push("live-scenarios job must not run when a free-standing jobs selector is supplied"); } const strategy = asRecord(liveScenarios.strategy); if (strategy["fail-fast"] !== false) { errors.push("live-scenarios strategy.fail-fast must be false"); } const matrix = asRecord(strategy.matrix); - if ( - matrix.include !== "${{ fromJSON(needs.generate-matrix.outputs.matrix) }}" - ) { - errors.push( - "live-scenarios matrix.include must come from generate-matrix output", - ); + if (matrix.include !== "${{ fromJSON(needs.generate-matrix.outputs.matrix) }}") { + errors.push("live-scenarios matrix.include must come from generate-matrix output"); } const jobEnv = asRecord(liveScenarios.env); @@ -7586,26 +5142,15 @@ export function validateE2eVitestScenariosWorkflowBoundary( } validateHostedCompatibleInferenceFlag(errors, "live-scenarios", jobEnv); if (!stringValue(jobEnv.E2E_ARTIFACT_DIR).includes("e2e-artifacts/vitest")) { - errors.push( - "live-scenarios job must write artifacts under e2e-artifacts/vitest", - ); + errors.push("live-scenarios job must write artifacts under e2e-artifacts/vitest"); } if (stringValue(jobEnv.E2E_ARTIFACT_DIR).includes("${{ matrix.id }}")) { - errors.push( - "live-scenarios job E2E_ARTIFACT_DIR must be the Vitest artifact parent", - ); + errors.push("live-scenarios job E2E_ARTIFACT_DIR must be the Vitest artifact parent"); } if (!stringValue(jobEnv.NEMOCLAW_CLI_BIN).includes("bin/nemoclaw.js")) { - errors.push( - "live-scenarios job must point NEMOCLAW_CLI_BIN at the repo CLI", - ); + errors.push("live-scenarios job must point NEMOCLAW_CLI_BIN at the repo CLI"); } - requireEnvDoesNotExposeSecret( - errors, - "live-scenarios job", - jobEnv, - "NVIDIA_INFERENCE_API_KEY", - ); + requireEnvDoesNotExposeSecret(errors, "live-scenarios job", jobEnv, "NVIDIA_INFERENCE_API_KEY"); const steps = asSteps(liveScenarios.steps); requireNoDispatchInputInterpolation(errors, steps); @@ -7620,9 +5165,7 @@ export function validateE2eVitestScenariosWorkflowBoundary( } } - const checkout = steps.find((step) => - stringValue(step.uses).startsWith("actions/checkout@"), - ); + const checkout = steps.find((step) => stringValue(step.uses).startsWith("actions/checkout@")); if (!checkout) errors.push("live-scenarios job missing checkout step"); requireFullShaAction(errors, checkout, "checkout"); if (asRecord(checkout?.with)["persist-credentials"] !== false) { @@ -7641,24 +5184,11 @@ export function validateE2eVitestScenariosWorkflowBoundary( if (runVitestEnv.SCENARIO_ID !== "${{ matrix.id }}") { errors.push("Vitest step must pass matrix.id through SCENARIO_ID env"); } - if ( - runVitestEnv.NVIDIA_INFERENCE_API_KEY !== - "${{ secrets.NVIDIA_INFERENCE_API_KEY }}" - ) { - errors.push( - "Vitest step must receive NVIDIA_INFERENCE_API_KEY from secrets", - ); + if (runVitestEnv.NVIDIA_INFERENCE_API_KEY !== "${{ secrets.NVIDIA_INFERENCE_API_KEY }}") { + errors.push("Vitest step must receive NVIDIA_INFERENCE_API_KEY from secrets"); } - requireRunContains( - errors, - runVitest, - "npx vitest run --project e2e-scenarios-live", - ); - requireRunContains( - errors, - runVitest, - "test/e2e-scenario/live/registry-scenarios.test.ts", - ); + requireRunContains(errors, runVitest, "npx vitest run --project e2e-scenarios-live"); + requireRunContains(errors, runVitest, "test/e2e-scenario/live/registry-scenarios.test.ts"); requireRunContains(errors, runVitest, '"^${SCENARIO_ID}$"'); const summary = requireStep(errors, steps, "Summarize artifacts"); @@ -7667,9 +5197,7 @@ export function validateE2eVitestScenariosWorkflowBoundary( errors.push("summary step must pass matrix.id through SCENARIO_ID env"); } if (summaryEnv.SCENARIO_LABEL !== "${{ matrix.label }}") { - errors.push( - "summary step must pass matrix.label through SCENARIO_LABEL env", - ); + errors.push("summary step must pass matrix.label through SCENARIO_LABEL env"); } requireRunContains(errors, summary, "run-plan.json"); requireRunContains( @@ -7677,11 +5205,7 @@ export function validateE2eVitestScenariosWorkflowBoundary( summary, 'Path(os.environ["E2E_ARTIFACT_DIR"]) / os.environ["SCENARIO_ID"]', ); - requireRunContains( - errors, - summary, - "| Scenario | Manifest | Expected state | Suites | Phases |", - ); + requireRunContains(errors, summary, "| Scenario | Manifest | Expected state | Suites | Phases |"); requireRunContains(errors, summary, "SCENARIO_ID"); const upload = requireStep(errors, steps, "Upload Vitest E2E artifacts"); @@ -7721,26 +5245,12 @@ export function validateE2eVitestScenariosWorkflowBoundary( uploadPath, "e2e-artifacts/vitest/${{ matrix.id }}/state-validation.result.json", ); - requireUploadPathContains( - errors, - uploadPath, - "e2e-artifacts/vitest/${{ matrix.id }}/actions/", - ); - requireUploadPathContains( - errors, - uploadPath, - "e2e-artifacts/vitest/${{ matrix.id }}/logs/", - ); - requireUploadPathContains( - errors, - uploadPath, - "e2e-artifacts/vitest/${{ matrix.id }}/shell/", - ); + requireUploadPathContains(errors, uploadPath, "e2e-artifacts/vitest/${{ matrix.id }}/actions/"); + requireUploadPathContains(errors, uploadPath, "e2e-artifacts/vitest/${{ matrix.id }}/logs/"); + requireUploadPathContains(errors, uploadPath, "e2e-artifacts/vitest/${{ matrix.id }}/shell/"); for (const line of uploadPath.split("\n")) { if (line.trim() === "e2e-artifacts/vitest/${{ matrix.id }}/") { - errors.push( - "artifact upload path must not list the whole matrix artifact directory", - ); + errors.push("artifact upload path must not list the whole matrix artifact directory"); } } if (uploadWith["include-hidden-files"] !== false) { @@ -7763,12 +5273,7 @@ export function validateE2eVitestScenariosWorkflowBoundary( "sessions-agents-cli-vitest", "sessions-agents-cli", ); - validateFreeStandingJobSelector( - errors, - jobs, - "inference-routing-vitest", - "inference-routing", - ); + validateFreeStandingJobSelector(errors, jobs, "inference-routing-vitest", "inference-routing"); validateCloudInferenceVitestJob(errors, jobs); validateRuntimeOverridesVitestJob(errors, jobs); validateDoubleOnboardVitestJob(errors, jobs); @@ -7836,7 +5341,9 @@ export function validateE2eVitestScenariosWorkflowBoundary( if (jetsonJob.needs !== "generate-matrix") { errors.push("jetson-nvmap-gpu-vitest job must depend on generate-matrix"); } - if (jetsonJob.if !== explicitOnlyFreeStandingJobIf("jetson-nvmap-gpu-vitest", "jetson-nvmap-gpu")) { + if ( + jetsonJob.if !== explicitOnlyFreeStandingJobIf("jetson-nvmap-gpu-vitest", "jetson-nvmap-gpu") + ) { errors.push("jetson-nvmap-gpu-vitest job must run only when explicitly selected"); } @@ -7846,10 +5353,7 @@ export function validateE2eVitestScenariosWorkflowBoundary( } if ( sandboxRlimitConnectJob.if !== - explicitOnlyFreeStandingJobIf( - "sandbox-rlimits-connect-vitest", - "sandbox-rlimits-connect", - ) + explicitOnlyFreeStandingJobIf("sandbox-rlimits-connect-vitest", "sandbox-rlimits-connect") ) { errors.push("sandbox-rlimits-connect-vitest job must run only when explicitly selected"); } @@ -7858,13 +5362,17 @@ export function validateE2eVitestScenariosWorkflowBoundary( errors.push("sandbox-rlimits-connect-vitest job must set NEMOCLAW_RUN_E2E_SCENARIOS=1"); } if (sandboxRlimitConnectEnv.NEMOCLAW_E2E_CONNECT_RLIMITS !== "1") { - errors.push("sandbox-rlimits-connect-vitest job must opt in with NEMOCLAW_E2E_CONNECT_RLIMITS=1"); + errors.push( + "sandbox-rlimits-connect-vitest job must opt in with NEMOCLAW_E2E_CONNECT_RLIMITS=1", + ); } if ( sandboxRlimitConnectEnv.E2E_ARTIFACT_DIR !== "${{ github.workspace }}/e2e-artifacts/vitest/sandbox-rlimits-connect" ) { - errors.push("sandbox-rlimits-connect-vitest job must write artifacts under e2e-artifacts/vitest/sandbox-rlimits-connect"); + errors.push( + "sandbox-rlimits-connect-vitest job must write artifacts under e2e-artifacts/vitest/sandbox-rlimits-connect", + ); } const sandboxRlimitConnectSteps = asSteps(sandboxRlimitConnectJob.steps); const sandboxRlimitConnectRun = namedStep( @@ -7872,7 +5380,9 @@ export function validateE2eVitestScenariosWorkflowBoundary( "Run sandbox rlimit connect live test", ); if (!sandboxRlimitConnectRun) { - errors.push("sandbox-rlimits-connect-vitest job missing step: Run sandbox rlimit connect live test"); + errors.push( + "sandbox-rlimits-connect-vitest job missing step: Run sandbox rlimit connect live test", + ); } else { const runScript = stringValue(sandboxRlimitConnectRun.run); if (!runScript.includes("test/e2e-scenario/live/sandbox-rlimits-connect.test.ts")) { @@ -7902,15 +5412,9 @@ export function validateE2eVitestScenariosWorkflowBoundary( } else { const needs = Array.isArray(reportToPr.needs) ? reportToPr.needs : []; for (const required of ["generate-matrix", "live-scenarios"]) { - if (!needs.includes(required)) - errors.push(`report-to-pr job must wait for ${required}`); + if (!needs.includes(required)) errors.push(`report-to-pr job must wait for ${required}`); } - validateFreeStandingInventoryCoverage( - errors, - jobs, - needs, - freeStandingInventory, - ); + validateFreeStandingInventoryCoverage(errors, jobs, needs, freeStandingInventory); const reportSteps = asSteps(reportToPr.steps); const report = requireJobStep( errors, @@ -7923,18 +5427,12 @@ export function validateE2eVitestScenariosWorkflowBoundary( errors.push("report-to-pr step must pass jobs through JOBS env"); } if (reportEnv.JOB_PR_NUMBER !== "${{ inputs.pr_number }}") { - errors.push( - "report-to-pr step must pass pr_number through JOB_PR_NUMBER env", - ); + errors.push("report-to-pr step must pass pr_number through JOB_PR_NUMBER env"); } if (reportEnv.JOB_SCENARIOS !== "${{ inputs.scenarios }}") { - errors.push( - "report-to-pr step must pass scenarios through JOB_SCENARIOS env", - ); + errors.push("report-to-pr step must pass scenarios through JOB_SCENARIOS env"); } - const reportScript = stringValue( - asRecord(report?.with).script ?? report?.run, - ); + const reportScript = stringValue(asRecord(report?.with).script ?? report?.run); if (!reportScript.includes("process.env.JOBS")) { errors.push( "step 'Post Vitest scenario results to PR' run script must include process.env.JOBS", @@ -7971,9 +5469,7 @@ export function validateE2eVitestScenariosWorkflowBoundary( ); } if (!reportScript.includes("cancelled")) { - errors.push( - "step 'Post Vitest scenario results to PR' run script must count cancelled jobs", - ); + errors.push("step 'Post Vitest scenario results to PR' run script must count cancelled jobs"); } if (!reportScript.includes("**Requested jobs:**")) { errors.push( @@ -8000,12 +5496,18 @@ export function validateE2eVitestScenariosWorkflowBoundary( "step 'Post Vitest scenario results to PR' run script must list explicit-only skipped jobs on default dispatch", ); } - if (!reportScript.includes("jobs=${job}") || !reportScript.includes("jetson-nvmap-gpu-vitest")) { + if ( + !reportScript.includes("jobs=${job}") || + !reportScript.includes("jetson-nvmap-gpu-vitest") + ) { errors.push( "step 'Post Vitest scenario results to PR' run script must document the explicit Jetson jobs selector", ); } - if (!reportScript.includes("scenarios=${scenario}") || !reportScript.includes("jetson-nvmap-gpu")) { + if ( + !reportScript.includes("scenarios=${scenario}") || + !reportScript.includes("jetson-nvmap-gpu") + ) { errors.push( "step 'Post Vitest scenario results to PR' run script must document the explicit Jetson scenario selector", ); @@ -8020,10 +5522,7 @@ export function validateE2eVitestScenariosWorkflowBoundary( "step 'Post Vitest scenario results to PR' run script must document the explicit rlimit scenario selector", ); } - for (const forbidden of [ - "toJSON(inputs.pr_number)", - "toJSON(inputs.scenarios)", - ]) { + for (const forbidden of ["toJSON(inputs.pr_number)", "toJSON(inputs.scenarios)"]) { if (reportScript.includes(forbidden)) { errors.push( `step 'Post Vitest scenario results to PR' run script must not include ${forbidden}`,