Repository navigation
fix: hand off private Cloud Hypervisor diagnostics to runner ownership - #9659
Conversation
Transfer diagnostic ownership to the invoking host identity and exclude private Cloud Hypervisor artifacts from legacy permission broadening during cleanup. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Documentation PreviewDocumentation has been built for this PR. To view locally:
Built from commit 4297582 |
|
@copilot address review feedback |
There was a problem hiding this comment.
🟡 Changes recommended
Privileged diagnostic and cleanup operations can follow symlinks and modify unrelated host paths.
3 open findings
What changed in this PR
Hands Cloud Hypervisor diagnostics from privileged AWF processes to the non-root runner while preserving private permissions.
Changes:
- Applies runner ownership and restrictive modes to diagnostic bundles.
- Excludes private diagnostics from public artifact permission repair.
- Adds regression coverage and documentation.
| File | Description |
|---|---|
src/cloud-hypervisor/diagnostics.ts |
Adds diagnostic ownership handoff. |
src/cloud-hypervisor/diagnostics-permissions.test.ts |
Tests ownership and modes. |
src/artifact-preservation.ts |
Preserves private diagnostic permissions. |
src/artifact-preservation-cloud-hypervisor.test.ts |
Tests cleanup handoff paths. |
docs/cloud-hypervisor-foundation.md |
Documents private runner-owned diagnostics. |
🧠 Review effort: Balanced
Give feedback about Copilot approvals in this survey to enter a drawing for a $150 gift card.
| await dependencies.mkdir(directory, { recursive: true, mode: 0o700 }); | ||
| await dependencies.chmod(directory, 0o700); | ||
| await dependencies.chown(directory, identity.uid, identity.gid); |
| await dependencies.writeFile(destination, contents, { mode: 0o600 }); | ||
| await dependencies.chmod(destination, 0o600); | ||
| await dependencies.chown(destination, identity.uid, identity.gid); |
|
| Metric | Base | PR | Delta |
|---|---|---|---|
| Lines | 93.01% | 92.97% | 📉 -0.04% |
| Statements | 91.50% | 91.47% | 📉 -0.03% |
| Functions | 90.21% | 90.27% | 📈 +0.06% |
| Branches | 85.29% | 85.22% | 📉 -0.07% |
📁 Per-file Coverage Changes (4 files)
| File | Lines (Before → After) | Statements (Before → After) |
|---|---|---|
src/cloud-hypervisor/diagnostics.ts |
87.8% → 85.8% (-2.07%) | 85.7% → 84.0% (-1.73%) |
src/nvx/one-shot-adapter.ts |
83.7% → 83.1% (-0.59%) | 80.5% → 80.0% (-0.55%) |
src/artifact-preservation.ts |
94.8% → 95.0% (+0.15%) | 95.0% → 94.7% (-0.26%) |
src/log-directory-setup.ts |
96.8% → 100.0% (+3.18%) | 96.9% → 100.0% (+3.13%) |
Coverage comparison generated by scripts/ci/compare-coverage.ts
Addressed the symlink-safety feedback in commit |
|
✅ Copilot review passed with no inline comments. @lpcox Add the |
|
@copilot fix this failing codeql check https://github.com/github/gh-aw-firewall/pull/9659/checks?check_run_id=113056170980 |
Fixed the CodeQL findings in commit |
|
| Metric | Base | PR | Delta |
|---|---|---|---|
| Lines | 93.01% | 92.97% | 📉 -0.04% |
| Statements | 91.50% | 91.47% | 📉 -0.03% |
| Functions | 90.21% | 90.27% | 📈 +0.06% |
| Branches | 85.29% | 85.22% | 📉 -0.07% |
📁 Per-file Coverage Changes (5 files)
| File | Lines (Before → After) | Statements (Before → After) |
|---|---|---|
src/cloud-hypervisor/diagnostics.ts |
87.8% → 85.8% (-2.07%) | 85.7% → 84.0% (-1.73%) |
src/nvx/one-shot-adapter.ts |
83.7% → 83.1% (-0.59%) | 80.5% → 80.0% (-0.55%) |
src/enclave/host-executor-server.ts |
90.3% → 90.3% (+0.00%) | 88.8% → 89.1% (+0.31%) |
src/artifact-preservation.ts |
94.8% → 95.0% (+0.15%) | 95.0% → 94.7% (-0.26%) |
src/log-directory-setup.ts |
96.8% → 100.0% (+3.18%) | 96.9% → 100.0% (+3.13%) |
Coverage comparison generated by scripts/ci/compare-coverage.ts
|
@copilot the codeql check is still failing https://github.com/github/gh-aw-firewall/pull/9659/checks?check_run_id=113060378289 |
Updated the test in commit |
|
| Metric | Base | PR | Delta |
|---|---|---|---|
| Lines | 93.01% | 92.97% | 📉 -0.04% |
| Statements | 91.50% | 91.47% | 📉 -0.03% |
| Functions | 90.21% | 90.27% | 📈 +0.06% |
| Branches | 85.29% | 85.22% | 📉 -0.07% |
📁 Per-file Coverage Changes (4 files)
| File | Lines (Before → After) | Statements (Before → After) |
|---|---|---|
src/cloud-hypervisor/diagnostics.ts |
87.8% → 85.8% (-2.07%) | 85.7% → 84.0% (-1.73%) |
src/nvx/one-shot-adapter.ts |
83.7% → 83.1% (-0.59%) | 80.5% → 80.0% (-0.55%) |
src/artifact-preservation.ts |
94.8% → 95.0% (+0.15%) | 95.0% → 94.7% (-0.26%) |
src/log-directory-setup.ts |
96.8% → 100.0% (+3.18%) | 96.9% → 100.0% (+3.13%) |
Coverage comparison generated by scripts/ci/compare-coverage.ts
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
| Metric | Base | PR | Delta |
|---|---|---|---|
| Lines | 93.01% | 92.97% | 📉 -0.04% |
| Statements | 91.50% | 91.47% | 📉 -0.03% |
| Functions | 90.21% | 90.27% | 📈 +0.06% |
| Branches | 85.29% | 85.22% | 📉 -0.07% |
📁 Per-file Coverage Changes (4 files)
| File | Lines (Before → After) | Statements (Before → After) |
|---|---|---|
src/cloud-hypervisor/diagnostics.ts |
87.8% → 85.8% (-2.07%) | 85.7% → 84.0% (-1.73%) |
src/nvx/one-shot-adapter.ts |
83.7% → 83.1% (-0.59%) | 80.5% → 80.0% (-0.55%) |
src/artifact-preservation.ts |
94.8% → 95.0% (+0.15%) | 95.0% → 94.7% (-0.26%) |
src/log-directory-setup.ts |
96.8% → 100.0% (+3.18%) | 96.9% → 100.0% (+3.13%) |
Coverage comparison generated by scripts/ci/compare-coverage.ts
|
🚀 Security Guard has started processing this pull request |
|
💎 Smoke Gemini is crystallizing results on this pull request... |
|
🔑 Smoke Copilot BYOK AOAI (api-key) is testing Azure OpenAI BYOK (api-key) mode on this pull request... |
|
✅ Smoke Copilot BYOK completed. Copilot BYOK mode operational. 🔓
|
|
📡 Smoke OTel Tracing completed. All tracing scenarios validated. ✅
|
|
✅ Build Test Suite completed successfully!
|
|
📰 VERDICT: Smoke Copilot has concluded. All systems operational. This is a developing story. 🎤
|
Smoke Test: Cloud Hypervisor + Copilot
All checks passed.
|
|
EGRESS_RESULT allow=pass deny=pass
Overall: PASS — cc @lpcox
|
Smoke Test: Claude Engine Validation
Overall result: PASS
|
|
Services smoke test
Overall: PASS
|
|
Smoke Copilot: PASS
|
Smoke Test: Copilot BYOK (Direct Mode) ✅Status: PASS Running in direct BYOK mode (
All tests passed at 2026-10-07T23:47:23Z
|
|
Smoke OTEL: ✅ S1 otel.js loads (startRequestSpan, setTokenAttributes, setBudgetAttributes, endSpan, endSpanError, shutdown, isEnabled...) · ✅ S2 68/68 OTEL tests pass (3 suites) · ✅ S3 env forwarding (GITHUB_AW_OTEL_TRACE_ID/PARENT_SPAN_ID in env-passthrough.ts; OTEL vars in api-proxy-env-config.ts) · ✅ S4
|
🏗️ Build Test Suite Results
Overall: 6/8 ecosystems passed — FAIL Failures
The
|
Chroot Version Comparison
Result: Not all tests passed. Node.js differs between host and chroot, so the
|

Symptom and evidence
The Smoke Cloud Hypervisor run 37688958250, validating #9559, failed in the shared gh-aw-actions secret-redaction step with
ERR_VALIDATION: Failed to remove artifact source after secret redaction failedafter replacing several non-writable audit files.Cloud Hypervisor is invoked through
sudo --preserve-env awf. Diagnostic producers created root-owned directories/files with modes0700/0600. AWF's artifact cleanup then appliedchmod -R a+rXto the audit tree, making these paths readable (0755/0644) without making them runner-writable; rootless ownership repair returns early when AWF is running as root. A readable root-owned diagnostic in a root-owned non-writable subdirectory can therefore be enumerated by the redactor but fail both replacement and deletion. The inaccessible-directory skip does not resolve that state.The logs hide the exact rejected path and original redaction exception. This fixes an evidenced producer/handoff permissions defect consistent with the failure, not a confirmed identification of the failing file.
Changes
0700and file0600modes, including existing files and boot-attempt/startup diagnostic roots.Validation
npm run build— passed.npm run type-check— passed.git diff --checkpassed.Live Linux/KVM smoke reproduction was not run on this macOS host. No workflows were manually dispatched.
Follow-up
A separate gh-aw-actions diagnostic improvement should report a safely sanitized path and failure stage/errno when redaction and cleanup both fail, without weakening fail-closed behavior. This PR does not change that external repository or generated gh-aw lock files.