Skip to content

fix(e2e): gate scenario fan-out by onboarding+secret support contract#4978

Closed
jyaunches wants to merge 1 commit into
mainfrom
feat/e2e-fanout-support-gate
Closed

fix(e2e): gate scenario fan-out by onboarding+secret support contract#4978
jyaunches wants to merge 1 commit into
mainfrom
feat/e2e-fanout-support-gate

Conversation

@jyaunches

@jyaunches jyaunches commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Why

Follow-up to #4380 addressing the two PR Review Advisor 🛠️ Needs-attention findings that were posted after the lgtm[] format fix landed but before the merge could re-fetch the advisor signal:

  1. "Live fan-out includes scenarios without onboarding and secret plumbing" — the typed scenario registry declares 12 scenarios whose onboarding profile has no case in nemoclaw_scenarios/onboard/dispatch.sh and/or whose required secrets are not declared in the scenario workflows. Live fan-out via e2e-scenarios-all.yaml would either fail at onboarding dispatch with unsupported onboarding profile (Mode A) or run without the credential boundary the registry declares.

  2. "No-docker negative onboarding truncates the framework-seeded context" — the no-docker negative worker called e2e_context_init, which opens with : > ctx and wipes seeded keys (E2E_SCENARIO, E2E_SANDBOX_NAME, E2E_GATEWAY_URL) before the state-validation phase's gateway-absent / sandbox-absent probes run. Mirrors a contract already documented in dispatch-action.sh.

What changed

Finding 1: scenario fan-out support gate

Path chosen (per advisor): filter the generated matrix to fully supported scenarios and add a static contract test.

  • New module test/e2e-scenario/scenarios/runtime-support.ts exporting:
    • SUPPORTED_ONBOARDING_IDS — mirrors the bash dispatcher case statement.
    • WORKFLOW_AVAILABLE_SECRETS — mirrors e2e-scenarios.yaml and e2e-scenarios-all.yaml secrets: blocks.
    • isScenarioFullyWired(scenario) — combines the two with the compiler's docker-missing onboarding-rewrite logic.
  • buildScenarioMatrix() in run.ts now filters via isScenarioFullyWired and writes a structured per-scenario explanation of skipped scenarios to stderr. The matrix went from 23 entries to 11; the 12 skipped scenarios stay in the registry as roadmap items.
  • New framework test e2e-scenario-fully-wired.test.ts locks the contract:
    • Parses dispatch.sh and the two scenario workflows.
    • Asserts SUPPORTED_ONBOARDING_IDS == dispatcher case set.
    • Asserts WORKFLOW_AVAILABLE_SECRETS == workflow secrets.
    • Every emitted matrix entry is fully wired.
    • Every filtered scenario has at least one structured reason.
  • Updated e2e-scenario-matrix.test.ts to assert matrix == fully-wired subset (was: matrix == every registered scenario).

Finding 2: no-docker context init removal

Removed the e2e_context_init call in cloud-openclaw-no-docker.sh. Added a comment block at the same site explaining why workers must not call e2e_context_init, mirroring the contract already documented in dispatch-action.sh.

Verification

  • vitest test/e2e-scenario/ — 374/374 (8 new contract tests added)
  • typecheck:cli — clean
  • npx tsx scenarios/run.ts --emit-matrix — produces 11 fully-wired entries with the 12 filtered scenarios reported on stderr
  • bash -n + shfmt clean on edited shell file

Out of scope

The 12 filtered scenarios are not removed from the typed registry — they stay as roadmap items. Adding their dispatcher cases + secret plumbing belongs to follow-up work scoped per integration (slack, discord, telegram, brave, openai-compatible, etc.). The framework test will fail-loud the moment any of them lands in the dispatcher without also being added to SUPPORTED_ONBOARDING_IDS.

Refs #4380.

Summary by CodeRabbit

  • Tests

    • Added comprehensive validation for end-to-end scenario configurations, ensuring all scenarios meet runtime requirements before execution.
    • Enhanced scenario matrix filtering to automatically exclude incomplete scenarios and provide detailed feedback on missing dependencies.
  • Bug Fixes

    • Corrected environment initialization sequencing in scenario setup to prevent data loss during context configuration.

Addresses two PR Review Advisor 🛠️ Needs-attention findings on
HEAD 70df051:

1. Live fan-out includes scenarios without onboarding and secret plumbing
   (test/e2e-scenario/nemoclaw_scenarios/onboard/dispatch.sh:32):
   The typed registry declares 12 scenarios whose onboarding profile has
   no case in dispatch.sh and/or whose requiredSecrets are not declared
   in the scenario workflows. Live fan-out via e2e-scenarios-all.yaml
   would either fail at onboarding dispatch ('unsupported onboarding
   profile') or run without the credential boundary the registry declares.

   Path chosen (per advisor): filter the generated matrix to fully
   supported scenarios + add a static contract test.

   Implementation:
   - New module test/e2e-scenario/scenarios/runtime-support.ts exporting
     SUPPORTED_ONBOARDING_IDS (mirrors dispatch.sh case statement),
     WORKFLOW_AVAILABLE_SECRETS (mirrors workflow secrets:), and
     isScenarioFullyWired(scenario) which combines them with the
     compiler's docker-missing onboarding rewrite logic.
   - buildScenarioMatrix() in run.ts now filters via isScenarioFullyWired
     and writes a structured per-scenario explanation of skipped
     scenarios to stderr. The matrix went from 23 entries to 11; the
     12 skipped scenarios stay in the registry as roadmap items.
   - New framework test e2e-scenario-fully-wired.test.ts locks the
     contract: parses dispatch.sh and the two scenario workflows,
     asserts SUPPORTED_ONBOARDING_IDS == dispatcher case set,
     WORKFLOW_AVAILABLE_SECRETS == workflow secrets, every emitted
     matrix entry is fully wired, every filtered scenario has at least
     one structured reason.
   - Updated e2e-scenario-matrix.test.ts to assert matrix == fully-wired
     subset (was: matrix == every registered scenario).

2. No-docker negative onboarding truncates the framework-seeded context
   (test/e2e-scenario/nemoclaw_scenarios/onboard/cloud-openclaw-no-docker.sh:35):
   The TS runner seeds context.env before phase actions, and
   dispatch-action.sh explicitly forbids workers from calling
   e2e_context_init because it opens with ': > ctx' and wipes seeded
   keys. The no-docker negative worker still called e2e_context_init,
   wiping E2E_SCENARIO/E2E_SANDBOX_NAME/E2E_GATEWAY_URL before
   state-validation probes (gateway-absent, sandbox-absent) need them.

   Removed the call. Added a comment block at the same site explaining
   why workers must not call e2e_context_init, mirroring the contract
   already documented in dispatch-action.sh.

Verified: vitest test/e2e-scenario/ 374/374 (8 new contract tests);
typecheck:cli clean; npx tsx scenarios/run.ts --emit-matrix produces
11 fully-wired entries with the 12 filtered scenarios reported on
stderr; bash -n + shfmt clean on edited shell file.
@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces a typed "fully-wired" contract for E2E scenarios that validates which scenarios can be executed given the supported onboarding profiles and workflow secrets, applies filtering to the scenario matrix, and enforces invariants bidirectionally across TypeScript constants, bash dispatcher logic, and GitHub workflow configurations.

Changes

E2E Scenario Fully-Wired Contract

Layer / File(s) Summary
Runtime wiring contract definition
test/e2e-scenario/scenarios/runtime-support.ts
Exports SUPPORTED_ONBOARDING_IDS (onboarding profiles from bash dispatcher), WORKFLOW_AVAILABLE_SECRETS (secrets from workflows), effectiveOnboardingId() (maps scenario runtime to invoked profile), WiredCheck type (discriminated result), and isScenarioFullyWired() (validates scenario support).
Scenario matrix filtering implementation
test/e2e-scenario/scenarios/run.ts
buildScenarioMatrix() now imports isScenarioFullyWired(), filters scenarios to only include fully-wired ones, and logs skipped scenario IDs with reasons to stderr.
Runtime-support contract validation tests
test/e2e-scenario/framework-tests/e2e-scenario-fully-wired.test.ts
Parses bash dispatcher and workflow YAML to validate SUPPORTED_ONBOARDING_IDS and WORKFLOW_AVAILABLE_SECRETS match their sources; asserts matrix-included scenarios pass wiring checks and filtered scenarios fail with non-empty reasons.
Matrix test assertions update
test/e2e-scenario/framework-tests/e2e-scenario-matrix.test.ts
Updates matrix contract tests to expect the fully-wired scenario subset instead of all registered scenarios; updates JSON matrix length and id assertions.
Scenario configuration adjustment
test/e2e-scenario/nemoclaw_scenarios/onboard/cloud-openclaw-no-docker.sh
Removes e2e_context_init call; documents that framework seeding owns context initialization and scenario should use e2e_context_set for additional keys.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

  • NVIDIA/NemoClaw#4862: Related to the E2E fully-wired contract via workflow secret management; gating live messaging secrets in nightly-e2e.yaml.

Suggested labels

area: e2e, bug-fix

Suggested reviewers

  • prekshivyas
  • sandl99
  • cjagwani

Poem

🐰 A wiring test hops through the dark,
Matching bash to types with structured marks,
Secrets known and profiles blessed,
Only fully wired scenarios pass the test!
No silent drops, just reasons clear—
The matrix runs without a fear. 🎯

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and specifically summarizes the main change: gating the e2e scenario fan-out by enforcing onboarding and secret support contracts.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/e2e-fanout-support-gate

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: None
Optional E2E: ubuntu-no-docker-preflight-negative, ubuntu-repo-cloud-openclaw, e2e-scenarios-all:generate-matrix

Dispatch hint: ubuntu-no-docker-preflight-negative,ubuntu-repo-cloud-openclaw

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • None. No merge-blocking live E2E is required because the PR is confined to E2E scenario harness/tests and does not change shipped installer, onboarding, sandbox, inference, policy, or credential runtime code. Optional live scenario runs are recommended to validate the harness changes themselves.

Optional E2E

  • ubuntu-no-docker-preflight-negative (moderate): Validates the changed cloud-openclaw-no-docker onboarding worker in the live scenario runner, including the expected preflight failure, preserved seeded context, and sandbox/gateway absence checks.
  • ubuntu-repo-cloud-openclaw (moderate): Baseline positive cloud OpenClaw scenario to sanity-check that normal typed scenario execution and NVIDIA_API_KEY passthrough still work after the scenario runner/runtime-support changes.
  • e2e-scenarios-all:generate-matrix (low for generate-matrix only; high if the full workflow is allowed to fan out): Targets the changed --emit-matrix path and runtime-support filtering contract used by the all-scenarios workflow; useful to confirm the fan-out matrix remains non-empty and only includes fully wired scenarios. Dispatching the full workflow will continue into all live matrix jobs, so use with care.

New E2E recommendations

  • e2e-scenario-matrix-fanout (medium): There is no existing PR-targeted E2E job that runs only the all-scenarios matrix generation/fully-wired gate without dispatching every live scenario. That makes runtime-support changes either under-validated or expensive to validate through the full fan-out workflow.
    • Suggested test: Add a lightweight PR or workflow_dispatch dry-run job that checks out the PR, runs npx tsx test/e2e-scenario/scenarios/run.ts --emit-matrix, validates non-empty JSON, and verifies each emitted id is routable by e2e-scenarios.yaml.

Dispatch hint

  • Workflow: .github/workflows/e2e-scenarios.yaml
  • jobs input: ubuntu-no-docker-preflight-negative,ubuntu-repo-cloud-openclaw

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

E2E Scenario Advisor Recommendation

Required scenario E2E: e2e-scenarios-all
Optional scenario E2E: None

Dispatch required scenario E2E:

  • gh workflow run e2e-scenarios-all.yaml --ref <pr-head-ref>

Workflow run

Full scenario advisor summary

E2E Scenario Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required scenario E2E

  • e2e-scenarios-all: Changes touch scenario runtime/matrix emission code under test/e2e-scenario/scenarios/ and add runtime-support gating that controls which scenarios fan out. This affects the scenario runner surface globally, so run the all-scenarios fan-out. The no-docker onboarding helper change is also covered by the fan-out negative scenario path.
    • Dispatch: gh workflow run e2e-scenarios-all.yaml --ref <pr-head-ref>

Optional scenario E2E

  • None.

Relevant changed files

  • test/e2e-scenario/framework-tests/e2e-scenario-fully-wired.test.ts
  • test/e2e-scenario/framework-tests/e2e-scenario-matrix.test.ts
  • test/e2e-scenario/nemoclaw_scenarios/onboard/cloud-openclaw-no-docker.sh
  • test/e2e-scenario/scenarios/run.ts
  • test/e2e-scenario/scenarios/runtime-support.ts

@github-actions

github-actions Bot commented Jun 8, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor

Findings: 0 needs attention, 2 worth checking, 1 nice ideas
Top item: Lock compiler secretEnv passthrough to the runtime-support credential contract

Review findings

🛠️ Needs attention

  • None.

🔎 Worth checking

  • Source-of-truth review needed: test/e2e-scenario/scenarios/runtime-support.ts fan-out support gate: The advisor marked localized patch analysis as needs_followup.
    • Recommendation: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
    • Evidence: runtime-support.ts documents dispatcher, workflow, and compiler secret allowlist plumbing, but its implementation and tests currently lock only dispatcher and workflow parity.
  • Runtime-support secret gate does not verify the compiler's actual secret passthrough (test/e2e-scenario/scenarios/runtime-support.ts:110): The new gate checks each scenario's requiredSecrets against workflow-declared secrets, but the actual child-process credential boundary is controlled separately by compiler.ts:ONBOARD_PROFILE_SECRET_ENV. Because that map is not exported or checked by the new contract test, future drift could let a matrix scenario receive a profile-level secret that is not declared on the scenario, or be considered fully wired even though the compiler does not pass a required credential to the onboarding action.
    • Recommendation: Add a contract test or shared source of truth that compiles every emitted matrix scenario and verifies the onboarding action's secretEnv is aligned with the scenario's declared requiredSecrets and workflow allowlist. At minimum, assert fully wired scenarios cannot receive secretEnv keys absent from their declared requiredSecrets, and that declared onboarding credentials needed by the effective profile are actually passed by the compiler.
    • Evidence: runtime-support.ts documents compiler.ts:ONBOARD_PROFILE_SECRET_ENV as part of the wiring contract, but isScenarioFullyWired only checks scenario.requiredSecrets against WORKFLOW_AVAILABLE_SECRETS. compiler.ts keeps ONBOARD_PROFILE_SECRET_ENV as an independent private map used to set PhaseAction.secretEnv.

🌱 Nice ideas

  • Consider locking the context ownership rule with a convention test (test/e2e-scenario/nemoclaw_scenarios/onboard/cloud-openclaw-no-docker.sh:35): This PR correctly removes the e2e_context_init call from the no-docker worker, but the rule that onboard workers must not truncate framework-seeded context.env is only documented in comments. A future worker could reintroduce e2e_context_init and silently wipe E2E_SCENARIO, E2E_SANDBOX_NAME, or E2E_GATEWAY_URL before state-validation probes.
    • Recommendation: Add a convention-lint or framework test such as onboard_workers_must_not_call_e2e_context_init_or_truncate_seeded_context_env that scans onboard workers and fails if they call e2e_context_init.
    • Evidence: cloud-openclaw-no-docker.sh now says 'Do NOT call e2e_context_init', and dispatch-action.sh documents the same contract, but existing convention lint does not appear to enforce this specific worker rule.
Consider writing more tests for
  • **Consider locking the context ownership rule with a convention test** — Add a convention-lint or framework test such as onboard_workers_must_not_call_e2e_context_init_or_truncate_seeded_context_env that scans onboard workers and fails if they call e2e_context_init.
  • **Acceptance clause:** "Live fan-out includes scenarios without onboarding and secret plumbing" — the typed scenario registry declares 12 scenarios whose onboarding profile has no case in `nemoclaw_scenarios/onboard/dispatch.sh` and/or whose required secrets are not declared in the scenario workflows. — add test evidence or identify existing coverage. run.ts filters buildScenarioMatrix through isScenarioFullyWired; runtime-support.ts checks effective onboarding IDs against SUPPORTED_ONBOARDING_IDS and requiredSecrets against WORKFLOW_AVAILABLE_SECRETS; e2e-scenario-fully-wired.test.ts verifies dispatcher/workflow parity and that emitted entries are fully wired. The remaining gap is that actual compiler secretEnv passthrough is not verified against this contract.
  • **Acceptance clause:** Live fan-out via `e2e-scenarios-all.yaml` would either fail at onboarding dispatch with `unsupported onboarding profile` (Mode A) or run without the credential boundary the registry declares. — add test evidence or identify existing coverage. The generated matrix now excludes unsupported onboarding profiles and undeclared workflow secrets before e2e-scenarios-all.yaml fans out. The workflow declaration side of the credential boundary is covered; the compiler secretEnv side is not yet locked by tests.
  • **Acceptance clause:** The matrix went from 23 entries to 11; the 12 skipped scenarios stay in the registry as roadmap items. — add test evidence or identify existing coverage. The code leaves listScenarios unchanged and filters only the emitted matrix. The new tests assert a non-empty filtered set with structured reasons, but they do not assert the exact 11/12 counts.
  • **test/e2e-scenario/scenarios/runtime-support.ts fan-out support gate** — e2e-scenario-fully-wired.test.ts covers dispatcher case parity, workflow secret parity, fully wired emitted matrix entries, and structured skip reasons.. runtime-support.ts documents dispatcher, workflow, and compiler secret allowlist plumbing, but its implementation and tests currently lock only dispatcher and workflow parity.

Workflow run details

This is an automated advisory review. A human maintainer must make the final merge decision.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
test/e2e-scenario/framework-tests/e2e-scenario-fully-wired.test.ts (1)

78-103: 💤 Low value

Consider clarifying blank-line handling in YAML parser.

The comment at line 92 states "De-dent or blank line ends the block," but the code only sets inSecrets = false for non-blank dedented lines (lines 93-95). Blank lines within a secrets block are skipped but don't terminate parsing. While this works for the documented "stable structure" use case, the implementation doesn't match the comment.

♻️ Consider clarifying the logic

Option 1: Update the comment to match the actual behavior:

-        // De-dent or blank line ends the block.
+        // Skip blank lines; dedent ends the block.

Option 2: Make blank lines actually end the block if that's the intent:

       if (line.trim() === "" || line.search(/\S/) <= secretsIndent) {
-        // De-dent or blank line ends the block.
-        if (line.search(/\S/) >= 0 && line.search(/\S/) <= secretsIndent) {
-          inSecrets = false;
-        }
+        // Blank line or dedent ends the secrets block.
+        inSecrets = false;
         continue;
       }

Given the stable YAML structure, the current implementation is acceptable.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@test/e2e-scenario/framework-tests/e2e-scenario-fully-wired.test.ts` around
lines 78 - 103, The comment in workflowSecretKeys describing "De-dent or blank
line ends the block" is inaccurate because the implementation only ends the
secrets block on de-dent, while blank lines are skipped; update the comment to
accurately describe the current behavior (i.e., blank lines inside the secrets
block are ignored and only a dedented non-blank line terminates the block) so
the code and comment match; locate the logic in function workflowSecretKeys
around the inSecrets/secretsIndent handling and adjust the inline comment
accordingly.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@test/e2e-scenario/framework-tests/e2e-scenario-fully-wired.test.ts`:
- Around line 78-103: The comment in workflowSecretKeys describing "De-dent or
blank line ends the block" is inaccurate because the implementation only ends
the secrets block on de-dent, while blank lines are skipped; update the comment
to accurately describe the current behavior (i.e., blank lines inside the
secrets block are ignored and only a dedented non-blank line terminates the
block) so the code and comment match; locate the logic in function
workflowSecretKeys around the inSecrets/secretsIndent handling and adjust the
inline comment accordingly.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 5fbd4f8f-4a04-48be-acdc-fca844059644

📥 Commits

Reviewing files that changed from the base of the PR and between 282876a and 27fadfc.

📒 Files selected for processing (5)
  • test/e2e-scenario/framework-tests/e2e-scenario-fully-wired.test.ts
  • test/e2e-scenario/framework-tests/e2e-scenario-matrix.test.ts
  • test/e2e-scenario/nemoclaw_scenarios/onboard/cloud-openclaw-no-docker.sh
  • test/e2e-scenario/scenarios/run.ts
  • test/e2e-scenario/scenarios/runtime-support.ts

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug-fix PR fixes a bug or regression

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants