ci: add validate-profiles job to PR workflow#482
Conversation
| No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (3)
✅ Files skipped from review due to trivial changes (2)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughAdds a GitHub Actions job that runs a new Python validator for blueprint and sandbox policy YAMLs, and updates an e2e test to expect an additional inference profile. Changes
Sequence Diagram(s)sequenceDiagram participant GH as "GitHub Actions" participant Runner as "Runner (ubuntu-latest)" participant FS as "Repository Files" participant Py as "Python 3.11 (validator)" GH->>Runner: trigger PR workflow (validate-profiles job) Runner->>FS: checkout repository Runner->>Py: setup Python 3.11 & pip install pyyaml Runner->>Py: run `test/validate-blueprint.py` Py->>FS: read `nemoclaw-blueprint/blueprint.yaml` and `.../openclaw-sandbox.yaml` Py-->>Py: validate declared vs defined profiles and required fields Py-->>Runner: exit 0 (pass) or 1 (fail) Runner-->>GH: report job result Estimated code review effort🎯 2 (Simple) | ⏱️ ~10 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (3)
.github/workflows/pr.yaml (3)
88-95: Consider validating that preset files actually exist.If the
presetsdirectory is empty or contains no.yamlfiles, the script will print"Policy presets: 0 files OK"and pass silently. This could mask accidental deletion of all preset files. Adding a minimum count check would catch this regression.🛡️ Proposed fix to add minimum file check
preset_dir = 'nemoclaw-blueprint/policies/presets' count = 0 for f in sorted(os.listdir(preset_dir)): if f.endswith('.yaml'): data = yaml.safe_load(open(os.path.join(preset_dir, f))) assert data and 'network_policies' in data, f'{f}: missing network_policies key' count += 1 + assert count > 0, f'No policy preset YAML files found in {preset_dir}' print(f'Policy presets: {count} files 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 88 - 95, The script currently counts YAML preset files in preset_dir ('nemoclaw-blueprint/policies/presets') but silently allows count == 0; update the logic after the loop (the block using preset_dir, count, and the final print) to validate that at least one .yaml file was found and fail loudly if none are present (e.g., raise an AssertionError or exit non‑zero with a clear message like "no preset files found in preset_dir"); keep the existing assertions for each file but add this minimum-count check so accidental deletion of all presets is detected.
78-78: Unusedsysimport.The
sysmodule is imported but never used in the script.🧹 Proposed fix
- import yaml, os, sys + import yaml, os🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/pr.yaml at line 78, The import line "import yaml, os, sys" contains an unused symbol sys; remove sys from the import so only used modules (yaml and os) are imported or split into separate imports as needed, ensuring no other references to sys exist in the script (search for "sys" and delete or replace any usages before removing the import).
80-80: Consider using context managers for file handles.The
open()calls rely on garbage collection to close file handles. While this works in short scripts, using context managers (with open(...) as f) is more explicit and aligns with Python best practices.♻️ Proposed refactor using context managers
- bp = yaml.safe_load(open('nemoclaw-blueprint/blueprint.yaml')) + with open('nemoclaw-blueprint/blueprint.yaml') as f: + bp = yaml.safe_load(f)- data = yaml.safe_load(open(os.path.join(preset_dir, f))) + with open(os.path.join(preset_dir, fp)) as fh: + data = yaml.safe_load(fh)- 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)Also applies to: 92-92, 97-97
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In @.github/workflows/pr.yaml at line 80, Replace bare open() calls passed directly into yaml.safe_load and any other places using open('nemoclaw-blueprint/blueprint.yaml') with context-manager usage: open the file with "with open(... ) as f:" and then call yaml.safe_load(f) inside the block, doing the same for the other occurrences noted (the expressions like yaml.safe_load(open(...)) at the other lines). This ensures the file handle is closed immediately after use while preserving existing variable names (e.g., bp) and behavior.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed. Nitpick comments: In @.github/workflows/pr.yaml: - Around line 88-95: The script currently counts YAML preset files in preset_dir ('nemoclaw-blueprint/policies/presets') but silently allows count == 0; update the logic after the loop (the block using preset_dir, count, and the final print) to validate that at least one .yaml file was found and fail loudly if none are present (e.g., raise an AssertionError or exit non‑zero with a clear message like "no preset files found in preset_dir"); keep the existing assertions for each file but add this minimum-count check so accidental deletion of all presets is detected. - Line 78: The import line "import yaml, os, sys" contains an unused symbol sys; remove sys from the import so only used modules (yaml and os) are imported or split into separate imports as needed, ensuring no other references to sys exist in the script (search for "sys" and delete or replace any usages before removing the import). - Line 80: Replace bare open() calls passed directly into yaml.safe_load and any other places using open('nemoclaw-blueprint/blueprint.yaml') with context-manager usage: open the file with "with open(... ) as f:" and then call yaml.safe_load(f) inside the block, doing the same for the other occurrences noted (the expressions like yaml.safe_load(open(...)) at the other lines). This ensures the file handle is closed immediately after use while preserving existing variable names (e.g., bp) and behavior. ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 816e9212-6bd4-49e9-9839-83d738d9e9eb
📒 Files selected for processing (1)
.github/workflows/pr.yaml
| Thanks for splitting this out! A few thoughts for future proofing this: The policy preset validation ( Hardcoding the profile list will be a maintenance issue. The check reads from We should check It would also be good to move this out of inline Python for maintainability. A Also, I'm thinking about the check structure like this:
I might be missing something else here, so would love to hear your thoughts about this! |
| @jayavenkatesh19 Thanks for the thorough review! All great points — I agree with each one:
I'll push an updated commit shortly. |
Address review feedback from jayavenkatesh19 on PR NVIDIA#482: - Move inline Python to standalone test/validate-blueprint.py - Read declared profiles dynamically from blueprint.yaml top-level instead of hardcoding the list - Validate provider_type + endpoint instead of model (ncp uses dynamic_endpoint so model is not always required) - Drop policy preset validation (already covered by test/policies.test.js) - Add ncp to e2e-test.sh Phase 3 profile assertions (3 → 4 profiles) Made-with: Cursor
Address review feedback from jayavenkatesh19 on PR NVIDIA#482: - Move inline Python to standalone test/validate-blueprint.py - Read declared profiles dynamically from blueprint.yaml top-level instead of hardcoding the list - Validate provider_type + endpoint instead of model (ncp uses dynamic_endpoint so model is not always required) - Drop policy preset validation (already covered by test/policies.test.js) - Add ncp to e2e-test.sh Phase 3 profile assertions (3 → 4 profiles) Made-with: Cursor
5955416 to 81795c2 Compare There was a problem hiding this comment.
Actionable comments posted: 2
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed. Inline comments: In `@test/validate-blueprint.py`: - Around line 31-33: The YAML root (bp) may be None or not a mapping, so before using bp.get(...) in the declarations for declared and defined, coerce bp to a dict when safe_load returns a non-mapping: after bp = yaml.safe_load(open(BLUEPRINT_PATH)) check if isinstance(bp, dict) (or use "if not isinstance(bp, dict): bp = {}") so declared = bp.get("profiles", []) and defined = bp.get("components", {}).get("inference", {}).get("profiles", {}) won't raise; apply the same defensive check where bp is used later (around the code that computes declared/defined at lines showing those variables). - Around line 41-43: The current loop in validate-blueprint.py only checks presence of keys (cfg and REQUIRED_PROFILE_FIELDS) but allows empty/null values; update the validation in the loop that iterates REQUIRED_PROFILE_FIELDS (and the check(...) calls) to assert each required field in cfg is non-empty/non-null (e.g., not None and not empty string/whitespace) — specifically ensure fields like 'provider_type' and 'endpoint' are validated for truthiness and meaningful content; use the existing check function to report a clear failure message including the profile name and field when a required value is missing or blank. ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 443447d1-15d9-41f4-9c1c-4550fec84a15
📒 Files selected for processing (3)
.github/workflows/pr.yamltest/e2e-test.shtest/validate-blueprint.py
🚧 Files skipped from review as they are similar to previous changes (1)
- .github/workflows/pr.yaml
Add validate-profiles job that runs on every pull request to catch blueprint and policy configuration regressions before merge: - Validates all 4 inference profiles exist in blueprint.yaml (default, ncp, nim-local, vllm) with required fields - Validates provider_type + endpoint for each profile - Validates base sandbox policy has required fields - Standalone script (test/validate-blueprint.py) for maintainability - Add ncp to e2e-test.sh Phase 3 profile assertions (3 → 4 profiles) This complements the existing test-unit and test-e2e-sandbox jobs by catching configuration breakage early in the PR cycle. Made-with: Cursor
81795c2 to c0103ea Compare
Add validate-profiles job that runs on every pull request to catch blueprint and policy configuration regressions before merge:
This complements the existing test-unit and test-e2e-sandbox jobs by catching configuration breakage early in the PR cycle.
Summary
Add validate-profiles job to the PR workflow that validates blueprint inference profiles, policy preset YAML files, and base sandbox policy on every pull request. This catches configuration regressions before merge, complementing the existing test-unit and test-e2e-sandbox jobs.
Related Issue
None
Changes
Type of Change
Testing
make checkpasses.npm testpasses.make docsbuilds without warnings. (for doc-only changes)Checklist
General
Code Changes
make formatapplied (TypeScript and Python).Doc Changes
update-docsagent skill to draft changes while complying with the style guide. For example, prompt your agent with "/update-docscatch up the docs for the new changes I made in this PR."Summary by CodeRabbit
Chores
Tests