Skip to content

ci: add blueprint/policy validation job and scheduled E2E workflow - #395

Closed
hulynn wants to merge 1 commit into
NVIDIA:mainfrom
hulynn:qa/add-ci-validation
Closed

ci: add blueprint/policy validation job and scheduled E2E workflow#395
hulynn wants to merge 1 commit into
NVIDIA:mainfrom
hulynn:qa/add-ci-validation

Conversation

@hulynn

@hulynn hulynn commented Mar 19, 2026

Copy link
Copy Markdown
Contributor

Add validate-profiles job to pr.yaml that checks:

  • All 4 inference profiles exist in blueprint.yaml
  • All policy preset YAMLs have valid structure
  • Base sandbox policy has required fields

Add e2e-scheduled.yaml for daily live inference E2E:

  • Runs test/e2e/test-full-e2e.sh on weekday mornings
  • Auto-creates GitHub issue on failure
  • Requires NVIDIA_API_KEY secret (not yet configured)

Summary by CodeRabbit

  • Chores
    • Added a scheduled end-to-end test workflow that runs on weekdays, can be triggered manually, collects logs on failures, and automatically files an issue when runs fail.
    • Added pull-request validation checks for configuration blueprints and policy presets to ensure required inference profiles and network policy fields are present.

@coderabbitai

coderabbitai Bot commented Mar 19, 2026

Copy link
Copy Markdown
Contributor

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: f35b1985-983a-4896-8029-4d6094f65b1f

📥 Commits

Reviewing files that changed from the base of the PR and between 3cf3497 and 2a609d5.

📒 Files selected for processing (2)
  • .github/workflows/e2e-scheduled.yaml
  • .github/workflows/pr.yaml
✅ Files skipped from review due to trivial changes (2)
  • .github/workflows/pr.yaml
  • .github/workflows/e2e-scheduled.yaml

📝 Walkthrough

Walkthrough

Added two GitHub Actions workflow changes: a scheduled weekday E2E workflow that runs full inference tests and notifies on failure, and a PR-time YAML validator that checks blueprint profiles and network policy files. (49 words)

Changes

Cohort / File(s) Summary
GitHub Actions workflows
\.github/workflows/e2e-scheduled.yaml, \.github/workflows/pr.yaml
Added e2e-scheduled.yaml to run weekday cron E2E tests (Node.js setup, install/build nemoclaw, install OpenShell, run full E2E script, upload logs on failure, use NVIDIA_API_KEY secret, concurrency). Appended validate-profiles job in pr.yaml to run Python/YAML checks validating inference profiles and network policy presets.

Sequence Diagram(s)

sequenceDiagram
    participant GitHub as GitHub Actions
    participant Runner as CI Runner
    participant Repo as Repository (code)
    participant Nemoclaw as Nemoclaw build
    participant OpenShell as OpenShell installer
    participant NVIDIA as NVIDIA API (secret)
    participant GitHubAPI as GitHub Issue API

    GitHub->>Runner: schedule/run workflow (cron or dispatch)
    Runner->>Repo: checkout code
    Runner->>Runner: setup Node.js, npm cache
    Runner->>Nemoclaw: install deps & build `nemoclaw`
    Runner->>OpenShell: run `scripts/install-openshell.sh`
    Runner->>Runner: run `test/e2e/test-full-e2e.sh` (uses NVIDIA secret)
    Runner->>NVIDIA: (secret used by test) request inference
    alt tests succeed
      Runner->>GitHub: finish workflow (success)
    else tests fail
      Runner->>Runner: collect `/tmp/nemoclaw-*.log`
      Runner->>GitHub: upload artifact (e2e-full-logs)
      GitHub->>GitHubAPI: create issue with run link & labels
    end
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Poem

🐰 I hopped through cron at eight each day,
Built nemoworks and chased bugs away,
If logs explode or tests go wrong,
An issue sings its failure song,
I nibble YAML, neat and bright—hooray!

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main changes: adding a blueprint/policy validation job to pr.yaml and a scheduled E2E workflow in e2e-scheduled.yaml.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
📝 Coding Plan
  • Generate coding plan for human review comments

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

Tip

You can disable poems in the walkthrough.

Disable the reviews.poem setting to disable the poems in the walkthrough.

@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.

Actionable comments posted: 1

🧹 Nitpick comments (3)
.github/workflows/e2e-scheduled.yaml (2)

53-70: Potential for duplicate issues on same-day failures.

If the workflow is triggered multiple times on the same day (e.g., via workflow_dispatch or if cron runs overlap), issues with identical titles will be created since the title only includes the date. Also, ensure the bug and ci labels exist in the repository, otherwise issue creation will fail.

Consider searching for an existing open issue before creating a new one:

♻️ Optional: Check for existing issue before creating
       - name: Create issue on failure
         uses: actions/github-script@v7
         with:
           script: |
             const title = `E2E Full pipeline failed — ${new Date().toISOString().split('T')[0]}`;
+            const { data: issues } = await github.rest.issues.listForRepo({
+              owner: context.repo.owner,
+              repo: context.repo.repo,
+              state: 'open',
+              labels: 'ci',
+              per_page: 100
+            });
+            if (issues.some(i => i.title === title)) {
+              console.log('Issue already exists for today, skipping creation');
+              return;
+            }
             const body = `The scheduled full E2E pipeline failed.\n\nRun: ${context.serverUrl}/${context.repo.owner}/${context.repo.repo}/actions/runs/${context.runId}`;
             await github.rest.issues.create({
               owner: context.repo.owner,
               repo: context.repo.repo,
               title,
               body,
               labels: ['bug', 'ci']
             });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/e2e-scheduled.yaml around lines 53 - 70, The
notify-on-failure job currently creates issues with a date-only title causing
duplicate issues and may fail if labels 'bug' and 'ci' don't exist; update the
actions/github-script block to first search for an open issue matching the same
day's title using github.rest.issues.list or the search API (refer to the
existing title variable), and only call github.rest.issues.create if no matching
open issue is found, and additionally either append a unique suffix (e.g.,
${context.runId} or timestamp) to the title variable to guarantee uniqueness;
also validate or create the 'bug' and 'ci' labels via
github.rest.issues.getLabel / createLabel (or handle label-not-found errors)
before creating the issue so creation cannot fail due to missing labels.

40-43: Verify the workflow behavior when NVIDIA_API_KEY is not configured.

The PR description notes this secret is "not yet configured." If the secret is empty/missing, the E2E test script will run with an empty NVIDIA_API_KEY environment variable, which could lead to unclear failures.

Consider adding a pre-check step that fails fast with a clear message if the secret is not set:

♻️ Optional: Add secret presence check
+     - name: Verify API key is configured
+       run: |
+         if [ -z "${{ secrets.NVIDIA_API_KEY }}" ]; then
+           echo "::error::NVIDIA_API_KEY secret is not configured"
+           exit 1
+         fi
+
       - name: Run full E2E
         env:
           NVIDIA_API_KEY: ${{ secrets.NVIDIA_API_KEY }}
         run: bash test/e2e/test-full-e2e.sh
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/e2e-scheduled.yaml around lines 40 - 43, Add a pre-check
step before the "Run full E2E" job to fail fast when the NVIDIA_API_KEY secret
is missing or empty: create a new step (e.g., "Check NVIDIA_API_KEY") that runs
a shell check against the NVIDIA_API_KEY environment variable (the same env name
used in the "Run full E2E" step) and prints a clear error and exits non‑zero if
it's unset/empty; ensure the existing run of test/e2e/test-full-e2e.sh only
proceeds when that check passes so failures are explicit and informative.
.github/workflows/pr.yaml (1)

77-97: Consider using context managers for file operations.

The inline script uses bare open() calls without context managers (with statements), which can leave file handles unclosed. While this is a short-lived CI script so it's unlikely to cause real issues, using context managers is a best practice.

Additionally, if any file doesn't exist, the error message will be a raw Python traceback rather than a clear CI message.

♻️ Suggested improvement with context managers and clearer errors
       - name: Validate blueprint and policy presets
         run: |
           python3 -c "
           import yaml, os, sys

-          bp = yaml.safe_load(open('nemoclaw-blueprint/blueprint.yaml'))
+          with open('nemoclaw-blueprint/blueprint.yaml') as f:
+              bp = yaml.safe_load(f)
           for p in ['default', 'ncp', 'nim-local', 'vllm']:
               assert p in bp['components']['inference']['profiles'], f'Missing profile: {p}'
               cfg = bp['components']['inference']['profiles'][p]
               assert 'provider_type' in cfg and 'model' in cfg
           print('Blueprint: 4/4 profiles OK')

           for f in sorted(os.listdir('nemoclaw-blueprint/policies/presets')):
               if f.endswith('.yaml'):
-                  data = yaml.safe_load(open(f'nemoclaw-blueprint/policies/presets/{f}'))
-                  assert data and 'network_policies' in data, f'{f}: invalid'
+                  with open(f'nemoclaw-blueprint/policies/presets/{f}') as fp:
+                      data = yaml.safe_load(fp)
+                  assert data, f'{f}: empty or invalid YAML'
+                  assert 'network_policies' in data, f'{f}: missing network_policies'
           print('Policy presets: all OK')

-          policy = yaml.safe_load(open('nemoclaw-blueprint/policies/openclaw-sandbox.yaml'))
+          with open('nemoclaw-blueprint/policies/openclaw-sandbox.yaml') as f:
+              policy = yaml.safe_load(f)
           assert 'version' in policy, 'Base policy missing version'
           assert 'network_policies' in policy, 'Base policy missing network_policies'
           print('Base policy: OK')
           "
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/pr.yaml around lines 77 - 97, Replace the bare open(...)
calls with context managers and add clearer error handling: use "with open(...)"
when loading files for bp, each preset file, and policy (references: bp =
yaml.safe_load(...), cfg, the for loops iterating presets, and policy =
yaml.safe_load(...)); wrap each load in try/except to catch
FileNotFoundError/IOError and yaml errors and print a concise, actionable CI
message (and exit nonzero) rather than a raw traceback; ensure you still assert
the required keys ('components'/'inference'/'profiles', 'provider_type'/'model',
'network_policies', 'version') after successful reads.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/e2e-scheduled.yaml:
- Around line 11-12: The workflow is missing the issues: write permission
required by the notify-on-failure job which calls github.rest.issues.create();
update the workflow permissions block to include issues: write so the API call
can succeed (e.g., add "issues: write" alongside "contents: read") and confirm
the notify-on-failure job still runs with the updated permissions.

---

Nitpick comments:
In @.github/workflows/e2e-scheduled.yaml:
- Around line 53-70: The notify-on-failure job currently creates issues with a
date-only title causing duplicate issues and may fail if labels 'bug' and 'ci'
don't exist; update the actions/github-script block to first search for an open
issue matching the same day's title using github.rest.issues.list or the search
API (refer to the existing title variable), and only call
github.rest.issues.create if no matching open issue is found, and additionally
either append a unique suffix (e.g., ${context.runId} or timestamp) to the title
variable to guarantee uniqueness; also validate or create the 'bug' and 'ci'
labels via github.rest.issues.getLabel / createLabel (or handle label-not-found
errors) before creating the issue so creation cannot fail due to missing labels.
- Around line 40-43: Add a pre-check step before the "Run full E2E" job to fail
fast when the NVIDIA_API_KEY secret is missing or empty: create a new step
(e.g., "Check NVIDIA_API_KEY") that runs a shell check against the
NVIDIA_API_KEY environment variable (the same env name used in the "Run full
E2E" step) and prints a clear error and exits non‑zero if it's unset/empty;
ensure the existing run of test/e2e/test-full-e2e.sh only proceeds when that
check passes so failures are explicit and informative.

In @.github/workflows/pr.yaml:
- Around line 77-97: Replace the bare open(...) calls with context managers and
add clearer error handling: use "with open(...)" when loading files for bp, each
preset file, and policy (references: bp = yaml.safe_load(...), cfg, the for
loops iterating presets, and policy = yaml.safe_load(...)); wrap each load in
try/except to catch FileNotFoundError/IOError and yaml errors and print a
concise, actionable CI message (and exit nonzero) rather than a raw traceback;
ensure you still assert the required keys ('components'/'inference'/'profiles',
'provider_type'/'model', 'network_policies', 'version') after successful reads.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: fa012b89-0a7f-4ab9-8184-34289b1cee1c

📥 Commits

Reviewing files that changed from the base of the PR and between 3ba517d and 3cf3497.

📒 Files selected for processing (2)
  • .github/workflows/e2e-scheduled.yaml
  • .github/workflows/pr.yaml

Comment thread .github/workflows/e2e-scheduled.yaml
Add validate-profiles job to pr.yaml that checks:
- All 4 inference profiles exist in blueprint.yaml
- All policy preset YAMLs have valid structure
- Base sandbox policy has required fields

Add e2e-scheduled.yaml for daily live inference E2E:
- Runs test/e2e/test-full-e2e.sh on weekday mornings
- Auto-creates GitHub issue on failure
- Requires NVIDIA_API_KEY secret (not yet configured)

Made-with: Cursor
@hulynn
hulynn force-pushed the qa/add-ci-validation branch from 3cf3497 to 2a609d5 Compare March 19, 2026 08:29
@jayavenkatesh19

jayavenkatesh19 commented Mar 19, 2026

Copy link
Copy Markdown
Contributor

Thanks for looking into this! Here's a few things I noticed since I've been working on the same thing (PR here: #386 )

On the E2E workflow:

  • The GITHUB_TOKEN env var isn't passed to the workflow steps. The scripts/install-openshell.sh tries gh release download first when gh cli is available (which it is on the ubuntu-latest runner), and without the token it'll fail. I ran into the same thing, took me a bit to figure out.

  • The test script runs nemoclaw onboard via the piped stdin approach (printf "name\n\nY\n" | nemoclaw onboard), which has given me issues where openshell's background port-forward inherits the pipe file descriptors and hangs, giving me real-time output to the CI job. feat: add non-interactive mode for CI/CD onboarding #318 added --non-interactive mode specifically to solve this, so it might be worth switching to install.sh --non-interactive which handles the full install + onboard path with env vars.

  • Without if: github.repository == 'NVIDIA/NemoClaw' on the job, the scheduled run will fire on every fork and fail nightly since they won't have the API key secret.

If you could look at my PR (#386) and leave a comment on there with your thoughts about it, that would be great.

On the blueprint/policy validation job on PR workflows:

  • This is a really nice idea and catching broken profiles or malformed policy YAML on every PR before it merges is valuable. I didn't include this in my PR and I think it's worth having.

Would it make sense to split the validate-profiles job into its own PR so that it can land independently? That way it doesn't have to wait as we figure out the best approach to E2E nightly testing.

@jacobtomlinson

Copy link
Copy Markdown
Member

Closing as a duplicate of #386

@ericksoa

Copy link
Copy Markdown
Contributor

Thanks for this PR, Lynn — really solid work jumping in with both the blueprint/policy validation and the scheduled E2E workflow. A few small things we noticed:

  1. Cron schedule timezone0 8 * * 1-5 is 8 AM UTC, which lands at midnight PT. If the intent is weekday mornings PT, 0 16 * * 1-5 (9 AM PT) might be a better fit. Does that match what you had in mind, or was UTC intentional?

  2. ci label — the notify-on-failure job applies ['bug', 'ci'] but we don't have a ci label on the repo yet. We could either create one or just use ['bug'] for now. What do you think?

  3. NVIDIA_API_KEY secret — as you noted, this isn't configured yet. We'll get that added on our end so the E2E can actually run once this merges. Just wanted to confirm — is there anything else the workflow needs from repo settings, or is the secret the only dependency?

Neither of these is a blocker — the core work here is great. Also, if you could enable "Allow edits from maintainers" on the PR, it makes it easier for us to help with small fixups like these.

@hulynn

hulynn commented Mar 20, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for the detailed reviews @jayavenkatesh19 @ericksoa! Great catches on the GITHUB_TOKEN, fork guard, and timezone — I missed those.

Since #386 covers the E2E workflow, I'll:

  1. Open a separate PR for the validate-profiles job (as @jayavenkatesh19 suggested)
  2. Leave a comment on ci: add nightly E2E with inference test #386 about the auto-issue-creation on failure

Appreciate the feedback — learned a lot from this first PR!

@wscurran wscurran added area: ci CI workflows, checks, release automation, or GitHub Actions area: e2e End-to-end tests, nightly failures, or validation infrastructure chore Build, CI, dependency, or tooling maintenance feature PR adds or expands user-visible functionality and removed CI/CD feature PR adds or expands user-visible functionality labels Jun 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: ci CI workflows, checks, release automation, or GitHub Actions area: e2e End-to-end tests, nightly failures, or validation infrastructure chore Build, CI, dependency, or tooling maintenance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants