Skip to content

test(e2e): migrate test-credential-sanitization.sh to vitest#5336

Merged
jyaunches merged 11 commits into
mainfrom
e2e-migrate/test-credential-sanitization
Jun 12, 2026
Merged

test(e2e): migrate test-credential-sanitization.sh to vitest#5336
jyaunches merged 11 commits into
mainfrom
e2e-migrate/test-credential-sanitization

Conversation

@jyaunches

@jyaunches jyaunches commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Summary

Migrate test/e2e/test-credential-sanitization.sh with the simplest equivalent Vitest coverage.

Related Issues

Refs #5098
Refs #156
Refs #1438

Contract mapping

  • Legacy assertion: migration bundle config strips credential fields, removes auth-profiles.json, preserves non-secret workspace/config data, and keeps symlink traversal out of sensitive-file removal.
    • Replacement: test/e2e-scenario/live/credential-sanitization.test.ts local product-code assertions using sanitizeConfigFile, stripCredentials, isSensitiveFile, and isCredentialField.
    • Boundary preserved: real filesystem bundle mutation plus product sanitization code.
  • Legacy assertion: blueprint digest is not empty and tracks the pinned sandbox image digest.
    • Replacement: credential-sanitization.test.ts parses nemoclaw-blueprint/blueprint.yaml and asserts sha256:<64hex> plus image-digest equality.
    • Boundary preserved: shipped blueprint YAML.
  • Legacy assertion: after install/onboard, sandbox agent state does not expose auth-profiles.json or secret-shaped nvapi-/ghp_/npm_ values.
    • Replacement: credential-sanitization.test.ts runs bash install.sh --non-interactive --yes-i-accept-third-party-software, then probes the real OpenShell sandbox filesystem from Vitest.
    • Boundary preserved: install.sh, Docker/OpenShell, real sandbox exec, NVIDIA_API_KEY secret redaction.

Simplicity check

  • Test shape: simple live Vitest test with local helper functions.
  • Original runner/lane: nightly-e2e.yaml job credential-sanitization-e2e, runs-on: ubuntu-latest, Docker/OpenShell, NVIDIA_API_KEY, timeout 60 minutes.
  • Replacement runner: same ubuntu-latest class in .github/workflows/e2e-vitest-scenarios.yaml job credential-sanitization-vitest, with Docker/OpenShell and NVIDIA_API_KEY.
  • New shared helpers: none.
  • New framework/registry/ledger: none.
  • Workflow changes: add selective free-standing Vitest job credential-sanitization-vitest; legacy shell deletion and shell workflow retirement deferred to Epic: Migrate legacy bash E2E into the Vitest E2E system #5098 Phase 11.
  • Selective dispatch: gh workflow run e2e-vitest-scenarios.yaml --repo NVIDIA/NemoClaw --ref e2e-migrate/test-credential-sanitization -f jobs=credential-sanitization-vitest -f pr_number=<PR>.

Verification

  • npm ci --ignore-scripts
  • npm run build:cli
  • npx vitest run --project e2e-vitest-support test/e2e-scenario/support-tests/e2e-scenarios-workflow.test.ts --silent=false --reporter=default
  • NEMOCLAW_RUN_E2E_SCENARIOS=1 npx vitest run --project e2e-scenarios-live test/e2e-scenario/live/credential-sanitization.test.ts --silent=false --reporter=default (local no-secret run: product-code assertions pass, live sandbox section skips on missing NVIDIA_API_KEY)
  • npx vitest run test/validate-blueprint.test.ts src/lib/security/credential-filter.test.ts --silent=false --reporter=default
  • npm run typecheck:cli
  • git diff --check
  • PR: test(e2e): migrate test-credential-sanitization.sh to vitest #5336
  • Same-runner selective run: https://github.com/NVIDIA/NemoClaw/actions/runs/27432354309credential-sanitization-vitest passed on ubuntu-latest with Docker/OpenShell and NVIDIA_API_KEY after latest main merge/dependency fix (f2cd7cc46).

Summary by CodeRabbit

  • Tests

    • Added a live end-to-end test that validates credential sanitization during install/onboarding, checks sandbox filesystem boundaries, ensures sensitive fields are redacted, and emits a scenario artifact summarizing assertions.
  • Chores

    • CI updated to add a dedicated credential-sanitization job to validation, matrix generation and PR reporting; job runs the new live scenario, handles Docker auth with fallback/retry and ensures cleanup.

@coderabbitai

coderabbitai Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Adds a live credential-sanitization Vitest scenario, a free-standing GitHub Actions job to run it, and workflow-boundary validator and test updates to register and depend on that job.

Changes

Credential sanitization E2E workflow

Layer / File(s) Summary
Live E2E credential sanitization test
test/e2e-scenario/live/credential-sanitization.test.ts
Introduces contract assertions for credential filtering (sanitizing bundle configs, stripping credential fields, verifying digest), then provisions a Docker/OpenShell sandbox via install.sh with NVIDIA API key redaction, probes the sandbox filesystem to assert auth-profiles.json absence and absence of secret token patterns, and includes best-effort cleanup with optional skip if Docker is unavailable.
Workflow job wiring and environment setup
.github/workflows/e2e-vitest-scenarios.yaml
Adds credential-sanitization-vitest free-standing job with sandbox env, Docker Hub auth (anonymous fallback and retry), Vitest execution, artifact upload, and docker logout cleanup. Extends validate-jobs and generate-matrix allowlists to include the job/scenario, skips the scenario for registry-driven matrix rows, and wires report-to-pr to depend on the new job.
Workflow boundary validation and test coverage
tools/e2e-scenarios/workflow-boundary.mts, test/e2e-scenario/support-tests/e2e-scenarios-workflow.test.ts
Registers credential-sanitization-vitest as an allowed free-standing job, validates selector mapping and dependency wiring, updates generate-matrix/validate-jobs expectations, and extends dispatch-selector and jobs-only dispatch tests to cover the new scenario/job pairing.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

  • NVIDIA/NemoClaw#5219: Similar e2e Vitest workflow job/matrix plumbing changes for another free-standing Vitest job.
  • NVIDIA/NemoClaw#5333: Related workflow-boundary and job registration updates for a different scenario/job pair.
  • NVIDIA/NemoClaw#5243: Adds a free-standing Vitest job and updates validator/allowlist wiring in the same files.

Suggested reviewers

  • cv

Poem

🐰 I hop through sandboxes, soft and bright,
I sniff for tokens hidden from sight.
Bundles scrubbed and digests tight,
Artifacts safe, jobs ran right.
A rabbit cheers — tests passed tonight!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately and concisely describes the main change: migration of a shell E2E test to Vitest, with specific reference to the credential-sanitization test.
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.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ 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 e2e-migrate/test-credential-sanitization

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

@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: credential-sanitization-vitest
Optional E2E: credential-migration-vitest

Dispatch hint: credential-sanitization-vitest

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • credential-sanitization-vitest (high: live Docker/OpenShell sandbox with install.sh/onboarding and secret-backed NVIDIA_API_KEY lane): Required because this PR introduces the live credential sanitization E2E job and its workflow dispatch mapping. It exercises the changed credential boundary, install/onboard flow, sandbox lifecycle, Docker/OpenShell integration, NVIDIA_API_KEY redaction, and artifact upload path.

Optional E2E

  • credential-migration-vitest (medium-high: live credential migration scenario with Docker/OpenShell setup): Optional adjacent confidence check because the new credential sanitization scenario is migrated from legacy credential handling coverage and imports the same security/credential-filter behavior area as credential migration. Useful to catch regressions in nearby credential state handling, but not required because no production credential migration code changed.

New E2E recommendations

  • None.

Dispatch hint

  • Workflow: .github/workflows/e2e-vitest-scenarios.yaml
  • jobs input: credential-sanitization-vitest

@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

Vitest E2E Scenario Recommendation

Required Vitest E2E scenarios: credential-sanitization-vitest
Optional Vitest E2E scenarios: None

Dispatch required Vitest E2E scenarios:

  • gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=credential-sanitization-vitest

Workflow run

Full Vitest E2E advisor summary

Vitest E2E Scenario Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required Vitest E2E scenarios

  • credential-sanitization-vitest: Focused free-standing Vitest job wired for changed live test test/e2e-scenario/live/credential-sanitization.test.ts.
    • Dispatch: gh workflow run e2e-vitest-scenarios.yaml --ref <pr-head-ref> --field jobs=credential-sanitization-vitest

Optional Vitest E2E scenarios

  • None.

Relevant changed files

  • .github/workflows/e2e-vitest-scenarios.yaml
  • test/e2e-scenario/live/credential-sanitization.test.ts
  • test/e2e-scenario/support-tests/e2e-scenarios-workflow.test.ts
  • tools/e2e-scenarios/free-standing-jobs.env

@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 (1)
tools/e2e-scenarios/workflow-boundary.mts (1)

1691-1693: ⚡ Quick win

Give credential-sanitization-vitest a dedicated boundary validator.

Line 1692 only checks selector wiring. The new job also carries secret scope, Docker auth, artifact-path, and cleanup contracts, but none of those are locked down here the way the other secret-bearing live jobs are.

🤖 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 `@tools/e2e-scenarios/workflow-boundary.mts` around lines 1691 - 1693, Add a
dedicated boundary validator for the "credential-sanitization-vitest" job
instead of only calling validateFreeStandingJobSelector for selector wiring;
implement and invoke a new validator (e.g.,
validateCredentialSanitizationVitestBoundary) that enforces the same constraints
applied to other secret-bearing live jobs: validate secret scope, Docker auth,
artifact-path, and cleanup contract restrictions. Locate the existing
validateFreeStandingJobSelector calls and replace or augment the line for
"credential-sanitization-vitest" to call your new validator so those additional
contracts are locked down for that job.
🤖 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.

Inline comments:
In `@test/e2e-scenario/live/credential-sanitization.test.ts`:
- Around line 321-336: The call to secrets.required("NVIDIA_API_KEY") runs
unconditionally and should be moved so it only executes when Docker is
available; change the logic in the test so you first run host.command("docker",
["info"], ...) and check docker.exitCode, then inside the success path (before
running the live sandbox checks) call secrets.required("NVIDIA_API_KEY") and
assert its prefix, and only throw the Docker-required Error/skip when docker
fails (using process.env.GITHUB_ACTIONS and skip as currently done); update any
references to resultText(docker) accordingly so the secret is not required for
the local skip path.

---

Nitpick comments:
In `@tools/e2e-scenarios/workflow-boundary.mts`:
- Around line 1691-1693: Add a dedicated boundary validator for the
"credential-sanitization-vitest" job instead of only calling
validateFreeStandingJobSelector for selector wiring; implement and invoke a new
validator (e.g., validateCredentialSanitizationVitestBoundary) that enforces the
same constraints applied to other secret-bearing live jobs: validate secret
scope, Docker auth, artifact-path, and cleanup contract restrictions. Locate the
existing validateFreeStandingJobSelector calls and replace or augment the line
for "credential-sanitization-vitest" to call your new validator so those
additional contracts are locked down for that job.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 49733c8c-e012-4313-838d-984eb23ecbaf

📥 Commits

Reviewing files that changed from the base of the PR and between 561bd2f and 7129297.

📒 Files selected for processing (4)
  • .github/workflows/e2e-vitest-scenarios.yaml
  • test/e2e-scenario/live/credential-sanitization.test.ts
  • test/e2e-scenario/support-tests/e2e-scenarios-workflow.test.ts
  • tools/e2e-scenarios/workflow-boundary.mts

Comment on lines +321 to +336
const apiKey = secrets.required("NVIDIA_API_KEY");
expect(apiKey.startsWith("nvapi-"), "NVIDIA_API_KEY must start with nvapi-").toBe(true);

const docker = await host.command("docker", ["info"], {
artifactName: "prereq-docker-info-credential-sanitization",
env: buildAvailabilityProbeEnv(),
timeoutMs: 30_000,
});
if (docker.exitCode !== 0) {
if (process.env.GITHUB_ACTIONS === "true") {
throw new Error(
`Docker is required for credential sanitization live E2E: ${resultText(docker)}`,
);
}
skip("Docker is required for credential sanitization live E2E");
}

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Move the NVIDIA_API_KEY requirement behind the local skip path.

secrets.required("NVIDIA_API_KEY") runs before the Docker/local skip branch, so a local run without that secret throws immediately instead of executing the contract checks and skipping only the live sandbox portion.

Proposed fix
-    const apiKey = secrets.required("NVIDIA_API_KEY");
-    expect(apiKey.startsWith("nvapi-"), "NVIDIA_API_KEY must start with nvapi-").toBe(true);
+    const apiKey = process.env.NVIDIA_API_KEY ?? "";
+    if (!apiKey) {
+      if (process.env.GITHUB_ACTIONS === "true") {
+        throw new Error("NVIDIA_API_KEY is required for credential sanitization live E2E");
+      }
+      skip("NVIDIA_API_KEY is required for credential sanitization live E2E");
+    }
+    expect(apiKey.startsWith("nvapi-"), "NVIDIA_API_KEY must start with nvapi-").toBe(true);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const apiKey = secrets.required("NVIDIA_API_KEY");
expect(apiKey.startsWith("nvapi-"), "NVIDIA_API_KEY must start with nvapi-").toBe(true);
const docker = await host.command("docker", ["info"], {
artifactName: "prereq-docker-info-credential-sanitization",
env: buildAvailabilityProbeEnv(),
timeoutMs: 30_000,
});
if (docker.exitCode !== 0) {
if (process.env.GITHUB_ACTIONS === "true") {
throw new Error(
`Docker is required for credential sanitization live E2E: ${resultText(docker)}`,
);
}
skip("Docker is required for credential sanitization live E2E");
}
const apiKey = process.env.NVIDIA_API_KEY ?? "";
if (!apiKey) {
if (process.env.GITHUB_ACTIONS === "true") {
throw new Error("NVIDIA_API_KEY is required for credential sanitization live E2E");
}
skip("NVIDIA_API_KEY is required for credential sanitization live E2E");
}
expect(apiKey.startsWith("nvapi-"), "NVIDIA_API_KEY must start with nvapi-").toBe(true);
const docker = await host.command("docker", ["info"], {
artifactName: "prereq-docker-info-credential-sanitization",
env: buildAvailabilityProbeEnv(),
timeoutMs: 30_000,
});
if (docker.exitCode !== 0) {
if (process.env.GITHUB_ACTIONS === "true") {
throw new Error(
`Docker is required for credential sanitization live E2E: ${resultText(docker)}`,
);
}
skip("Docker is required for credential sanitization live E2E");
}
🤖 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/live/credential-sanitization.test.ts` around lines 321 -
336, The call to secrets.required("NVIDIA_API_KEY") runs unconditionally and
should be moved so it only executes when Docker is available; change the logic
in the test so you first run host.command("docker", ["info"], ...) and check
docker.exitCode, then inside the success path (before running the live sandbox
checks) call secrets.required("NVIDIA_API_KEY") and assert its prefix, and only
throw the Docker-required Error/skip when docker fails (using
process.env.GITHUB_ACTIONS and skip as currently done); update any references to
resultText(docker) accordingly so the secret is not required for the local skip
path.

@github-actions

Copy link
Copy Markdown
Contributor

Vitest E2E Scenario Results — ❌ Some jobs failed

Run: 27421946896
Workflow ref: e2e-migrate/test-credential-sanitization
Requested scenarios: (default — all supported)
Requested jobs: credential-sanitization-vitest
Summary: 2 passed, 1 failed, 17 skipped

Job Result
credential-migration-vitest ⏭️ skipped
credential-sanitization-vitest ❌ failure
double-onboard-vitest ⏭️ skipped
gateway-guard-recovery ⏭️ skipped
generate-matrix ✅ success
hermes-e2e-vitest ⏭️ skipped
hermes-root-entrypoint-smoke-vitest ⏭️ skipped
inference-routing-vitest ⏭️ skipped
issue-4434-tui-unreachable-inference-vitest ⏭️ skipped
launchable-smoke-vitest ⏭️ skipped
live-scenarios ⏭️ skipped
model-router-provider-routed-inference-vitest ⏭️ skipped
network-policy-vitest ⏭️ skipped
onboard-negative-paths-vitest ⏭️ skipped
openclaw-tui-chat-correlation-vitest ⏭️ skipped
openshell-version-pin-vitest ⏭️ skipped
rebuild-openclaw-vitest ⏭️ skipped
runtime-overrides-vitest ⏭️ skipped
token-rotation-vitest ⏭️ skipped
validate-jobs ✅ success

Failed jobs: credential-sanitization-vitest. Check run artifacts for logs.

@github-actions

github-actions Bot commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor

Findings: 1 needs attention, 2 worth checking, 0 nice ideas
Since last review: 0 prior items resolved, 3 still apply, 0 new items found

Review findings

🛠️ Needs attention

  • Restore symlink traversal parity for sensitive-file removal (test/e2e-scenario/live/credential-sanitization.test.ts:102): The PR contract says the migrated test keeps symlink traversal out of sensitive-file removal, but the new Vitest coverage only creates and removes a regular auth-profiles.json. The legacy shell test explicitly created a symlinked auth-profiles.json pointing outside the bundle and asserted the outside target survived. This is also the unresolved source-of-truth issue for the localized deletion helper: the test reimplements the recursive file-removal walker instead of proving the production removal boundary preserves symlink safety.
    • Recommendation: Add a focused Vitest assertion such as `credential sanitization sensitive-file removal skips symlinked auth-profiles.json and preserves the outside target`, preferably through the same production removal path used by the migrated scenario or through an existing deterministic product-level test of the production walker. If the production walker cannot be exercised directly, document that boundary and cover the local helper's symlink case explicitly.
    • Evidence: PR clause: "Legacy assertion: migration bundle config strips credential fields, removes `auth-profiles.json`, preserves non-secret workspace/config data, and keeps symlink traversal out of sensitive-file removal." Legacy `test/e2e/test-credential-sanitization.sh` Phase 3/C8 creates a symlinked `auth-profiles.json` pointing outside the bundle and checks the outside file remains. New `assertLocalCredentialSanitizationContract()` writes only a regular `auth-profiles.json`, calls local `removeSensitiveFiles()`, and asserts the regular file is gone.

🔎 Worth checking

  • Source-of-truth review needed: test/e2e-scenario/live/credential-sanitization.test.ts sensitive-file removal parity: 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: Legacy C8 creates a symlinked `auth-profiles.json` pointing outside the bundle. New `removeSensitiveFiles()` skips symlinks in local code, but `assertLocalCredentialSanitizationContract()` only creates a regular file.
  • Lock down the credential-sanitization workflow boundary (.github/workflows/e2e-vitest-scenarios.yaml:696): The new `credential-sanitization-vitest` job runs installer/onboarding, Docker/OpenShell, and sandbox probes with `NVIDIA_API_KEY` plus Docker Hub credentials. The actual job uses several good constraints, but there is no credential-sanitization-specific boundary validator, so future regressions could move secrets to broader env, loosen checkout credentials, upload hidden artifacts, interpolate dispatch inputs, or remove cleanup without a dedicated support test catching it. The job also authenticates Docker Hub before branch-controlled build/test code using the default Docker auth location; unlike stricter sibling jobs, it does not require an isolated `DOCKER_CONFIG` under `RUNNER_TEMP` and removal of that directory.
    • Recommendation: Add a dedicated `validateCredentialSanitizationVitestJob()` and support-test mutations mirroring the stricter high-risk job validators: pinned checkout/setup/upload actions, `persist-credentials: false`, no dispatch-input interpolation, `NVIDIA_API_KEY` only on the Vitest step, Docker Hub credentials only on the login step, stable artifact path with `include-hidden-files: false`, Docker auth cleanup that always runs, and preferably an isolated `DOCKER_CONFIG` under `RUNNER_TEMP` that is removed in cleanup.
    • Evidence: The workflow adds `credential-sanitization-vitest` with Docker Hub secrets, `NVIDIA_API_KEY`, full artifact-directory upload, and `docker logout docker.io` cleanup. `tools/e2e-scenarios/workflow-boundary.mts` validates many high-risk sibling jobs, but no `validateCredentialSanitizationVitestJob()` exists; the support-test diff only adds selector expectations for `credential-sanitization` / `credential-sanitization-vitest`.

🌱 Nice ideas

  • None.
Consider writing more tests for
  • **Runtime validation** — credential sanitization sensitive-file removal skips symlinked auth-profiles.json and preserves the outside target. The PR touches live sandbox/installer credential paths and a secret-bearing GitHub Actions workflow. Runtime coverage is present, but the migrated symlink negative path and workflow-boundary regression protections are incomplete.
  • **Runtime validation** — credential sanitization bundle deletion path uses the production sanitizer or fails when the production walker follows auth-profiles.json symlinks. The PR touches live sandbox/installer credential paths and a secret-bearing GitHub Actions workflow. Runtime coverage is present, but the migrated symlink negative path and workflow-boundary regression protections are incomplete.
  • **Runtime validation** — workflow boundary rejects credential-sanitization-vitest when NVIDIA_API_KEY is moved to job env or a non-Vitest step. The PR touches live sandbox/installer credential paths and a secret-bearing GitHub Actions workflow. Runtime coverage is present, but the migrated symlink negative path and workflow-boundary regression protections are incomplete.
  • **Runtime validation** — workflow boundary rejects credential-sanitization-vitest when checkout is unpinned or persist-credentials is true. The PR touches live sandbox/installer credential paths and a secret-bearing GitHub Actions workflow. Runtime coverage is present, but the migrated symlink negative path and workflow-boundary regression protections are incomplete.
  • **Runtime validation** — workflow boundary rejects credential-sanitization-vitest when artifact upload includes hidden files or broadens the artifact path unexpectedly. The PR touches live sandbox/installer credential paths and a secret-bearing GitHub Actions workflow. Runtime coverage is present, but the migrated symlink negative path and workflow-boundary regression protections are incomplete.
  • **Acceptance clause:** Legacy assertion: migration bundle config strips credential fields, removes `auth-profiles.json`, preserves non-secret workspace/config data, and keeps symlink traversal out of sensitive-file removal. — add test evidence or identify existing coverage. `assertLocalCredentialSanitizationContract()` covers credential stripping, regular `auth-profiles.json` removal, model preservation, and workspace-file preservation. It does not recreate the legacy symlinked `auth-profiles.json` target-preservation case.
  • **Acceptance clause:** Boundary preserved: real filesystem bundle mutation plus product sanitization code. — add test evidence or identify existing coverage. The test mutates a real temporary bundle and calls product `sanitizeConfigFile()`. Sensitive-file deletion is exercised through local `removeSensitiveFiles()` using product `isSensitiveFile()`, not the private production directory walker.
  • **test/e2e-scenario/live/credential-sanitization.test.ts sensitive-file removal parity** — Regular sensitive-file removal is covered. The legacy symlink target-preservation case is not covered through either the local helper or the production walker.. Legacy C8 creates a symlinked `auth-profiles.json` pointing outside the bundle. New `removeSensitiveFiles()` skips symlinks in local code, but `assertLocalCredentialSanitizationContract()` only creates a regular file.
Since last review details

Current findings:

  • Source-of-truth review needed: test/e2e-scenario/live/credential-sanitization.test.ts sensitive-file removal parity: 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: Legacy C8 creates a symlinked `auth-profiles.json` pointing outside the bundle. New `removeSensitiveFiles()` skips symlinks in local code, but `assertLocalCredentialSanitizationContract()` only creates a regular file.
  • Restore symlink traversal parity for sensitive-file removal (test/e2e-scenario/live/credential-sanitization.test.ts:102): The PR contract says the migrated test keeps symlink traversal out of sensitive-file removal, but the new Vitest coverage only creates and removes a regular auth-profiles.json. The legacy shell test explicitly created a symlinked auth-profiles.json pointing outside the bundle and asserted the outside target survived. This is also the unresolved source-of-truth issue for the localized deletion helper: the test reimplements the recursive file-removal walker instead of proving the production removal boundary preserves symlink safety.
    • Recommendation: Add a focused Vitest assertion such as `credential sanitization sensitive-file removal skips symlinked auth-profiles.json and preserves the outside target`, preferably through the same production removal path used by the migrated scenario or through an existing deterministic product-level test of the production walker. If the production walker cannot be exercised directly, document that boundary and cover the local helper's symlink case explicitly.
    • Evidence: PR clause: "Legacy assertion: migration bundle config strips credential fields, removes `auth-profiles.json`, preserves non-secret workspace/config data, and keeps symlink traversal out of sensitive-file removal." Legacy `test/e2e/test-credential-sanitization.sh` Phase 3/C8 creates a symlinked `auth-profiles.json` pointing outside the bundle and checks the outside file remains. New `assertLocalCredentialSanitizationContract()` writes only a regular `auth-profiles.json`, calls local `removeSensitiveFiles()`, and asserts the regular file is gone.
  • Lock down the credential-sanitization workflow boundary (.github/workflows/e2e-vitest-scenarios.yaml:696): The new `credential-sanitization-vitest` job runs installer/onboarding, Docker/OpenShell, and sandbox probes with `NVIDIA_API_KEY` plus Docker Hub credentials. The actual job uses several good constraints, but there is no credential-sanitization-specific boundary validator, so future regressions could move secrets to broader env, loosen checkout credentials, upload hidden artifacts, interpolate dispatch inputs, or remove cleanup without a dedicated support test catching it. The job also authenticates Docker Hub before branch-controlled build/test code using the default Docker auth location; unlike stricter sibling jobs, it does not require an isolated `DOCKER_CONFIG` under `RUNNER_TEMP` and removal of that directory.
    • Recommendation: Add a dedicated `validateCredentialSanitizationVitestJob()` and support-test mutations mirroring the stricter high-risk job validators: pinned checkout/setup/upload actions, `persist-credentials: false`, no dispatch-input interpolation, `NVIDIA_API_KEY` only on the Vitest step, Docker Hub credentials only on the login step, stable artifact path with `include-hidden-files: false`, Docker auth cleanup that always runs, and preferably an isolated `DOCKER_CONFIG` under `RUNNER_TEMP` that is removed in cleanup.
    • Evidence: The workflow adds `credential-sanitization-vitest` with Docker Hub secrets, `NVIDIA_API_KEY`, full artifact-directory upload, and `docker logout docker.io` cleanup. `tools/e2e-scenarios/workflow-boundary.mts` validates many high-risk sibling jobs, but no `validateCredentialSanitizationVitestJob()` exists; the support-test diff only adds selector expectations for `credential-sanitization` / `credential-sanitization-vitest`.

Workflow run details

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

@github-actions

Copy link
Copy Markdown
Contributor

Vitest E2E Scenario Results — ✅ All jobs passed

Run: 27422540435
Workflow ref: e2e-migrate/test-credential-sanitization
Requested scenarios: (default — all supported)
Requested jobs: credential-sanitization-vitest
Summary: 3 passed, 0 failed, 17 skipped

Job Result
credential-migration-vitest ⏭️ skipped
credential-sanitization-vitest ✅ success
double-onboard-vitest ⏭️ skipped
gateway-guard-recovery ⏭️ skipped
generate-matrix ✅ success
hermes-e2e-vitest ⏭️ skipped
hermes-root-entrypoint-smoke-vitest ⏭️ skipped
inference-routing-vitest ⏭️ skipped
issue-4434-tui-unreachable-inference-vitest ⏭️ skipped
launchable-smoke-vitest ⏭️ skipped
live-scenarios ⏭️ skipped
model-router-provider-routed-inference-vitest ⏭️ skipped
network-policy-vitest ⏭️ skipped
onboard-negative-paths-vitest ⏭️ skipped
openclaw-tui-chat-correlation-vitest ⏭️ skipped
openshell-version-pin-vitest ⏭️ skipped
rebuild-openclaw-vitest ⏭️ skipped
runtime-overrides-vitest ⏭️ skipped
token-rotation-vitest ⏭️ skipped
validate-jobs ✅ success

@wscurran wscurran added area: e2e End-to-end tests, nightly failures, or validation infrastructure chore Build, CI, dependency, or tooling maintenance labels Jun 12, 2026
@github-actions

Copy link
Copy Markdown
Contributor

Vitest E2E Scenario Results — ✅ All jobs passed

Run: 27423613232
Workflow ref: e2e-migrate/test-credential-sanitization
Requested scenarios: (default — all supported)
Requested jobs: credential-sanitization-vitest
Summary: 3 passed, 0 failed, 18 skipped

Job Result
credential-migration-vitest ⏭️ skipped
credential-sanitization-vitest ✅ success
double-onboard-vitest ⏭️ skipped
gateway-guard-recovery ⏭️ skipped
generate-matrix ✅ success
hermes-e2e-vitest ⏭️ skipped
hermes-root-entrypoint-smoke-vitest ⏭️ skipped
inference-routing-vitest ⏭️ skipped
issue-4434-tui-unreachable-inference-vitest ⏭️ skipped
launchable-smoke-vitest ⏭️ skipped
live-scenarios ⏭️ skipped
model-router-provider-routed-inference-vitest ⏭️ skipped
network-policy-vitest ⏭️ skipped
onboard-negative-paths-vitest ⏭️ skipped
openclaw-tui-chat-correlation-vitest ⏭️ skipped
openshell-version-pin-vitest ⏭️ skipped
rebuild-openclaw-vitest ⏭️ skipped
runtime-overrides-vitest ⏭️ skipped
skill-agent-vitest ⏭️ skipped
token-rotation-vitest ⏭️ skipped
validate-jobs ✅ success

@github-actions

Copy link
Copy Markdown
Contributor

Vitest E2E Scenario Results — ✅ All jobs passed

Run: 27425214870
Workflow ref: e2e-migrate/test-credential-sanitization
Requested scenarios: (default — all supported)
Requested jobs: credential-sanitization-vitest
Summary: 3 passed, 0 failed, 19 skipped

Job Result
credential-migration-vitest ⏭️ skipped
credential-sanitization-vitest ✅ success
double-onboard-vitest ⏭️ skipped
gateway-guard-recovery ⏭️ skipped
generate-matrix ✅ success
hermes-e2e-vitest ⏭️ skipped
hermes-root-entrypoint-smoke-vitest ⏭️ skipped
inference-routing-vitest ⏭️ skipped
issue-4434-tui-unreachable-inference-vitest ⏭️ skipped
launchable-smoke-vitest ⏭️ skipped
live-scenarios ⏭️ skipped
model-router-provider-routed-inference-vitest ⏭️ skipped
network-policy-vitest ⏭️ skipped
onboard-negative-paths-vitest ⏭️ skipped
openclaw-tui-chat-correlation-vitest ⏭️ skipped
openshell-version-pin-vitest ⏭️ skipped
rebuild-openclaw-vitest ⏭️ skipped
runtime-overrides-vitest ⏭️ skipped
sandbox-survival-vitest ⏭️ skipped
skill-agent-vitest ⏭️ skipped
token-rotation-vitest ⏭️ skipped
validate-jobs ✅ success

@github-actions

Copy link
Copy Markdown
Contributor

Vitest E2E Scenario Results — ✅ All jobs passed

Run: 27426332138
Workflow ref: e2e-migrate/test-credential-sanitization
Requested scenarios: (default — all supported)
Requested jobs: credential-sanitization-vitest
Summary: 3 passed, 0 failed, 20 skipped

Job Result
credential-migration-vitest ⏭️ skipped
credential-sanitization-vitest ✅ success
double-onboard-vitest ⏭️ skipped
gateway-guard-recovery ⏭️ skipped
generate-matrix ✅ success
hermes-e2e-vitest ⏭️ skipped
hermes-root-entrypoint-smoke-vitest ⏭️ skipped
inference-routing-vitest ⏭️ skipped
issue-4434-tui-unreachable-inference-vitest ⏭️ skipped
launchable-smoke-vitest ⏭️ skipped
live-scenarios ⏭️ skipped
model-router-provider-routed-inference-vitest ⏭️ skipped
network-policy-vitest ⏭️ skipped
onboard-negative-paths-vitest ⏭️ skipped
openclaw-tui-chat-correlation-vitest ⏭️ skipped
openshell-version-pin-vitest ⏭️ skipped
rebuild-openclaw-vitest ⏭️ skipped
runtime-overrides-vitest ⏭️ skipped
sandbox-rebuild-vitest ⏭️ skipped
sandbox-survival-vitest ⏭️ skipped
skill-agent-vitest ⏭️ skipped
token-rotation-vitest ⏭️ skipped
validate-jobs ✅ success

@github-actions

Copy link
Copy Markdown
Contributor

Vitest E2E Scenario Results — ✅ All jobs passed

Run: 27427632562
Workflow ref: e2e-migrate/test-credential-sanitization
Requested scenarios: (default — all supported)
Requested jobs: credential-sanitization-vitest
Summary: 3 passed, 0 failed, 21 skipped

Job Result
credential-migration-vitest ⏭️ skipped
credential-sanitization-vitest ✅ success
double-onboard-vitest ⏭️ skipped
gateway-guard-recovery ⏭️ skipped
generate-matrix ✅ success
hermes-e2e-vitest ⏭️ skipped
hermes-root-entrypoint-smoke-vitest ⏭️ skipped
inference-routing-vitest ⏭️ skipped
issue-4434-tui-unreachable-inference-vitest ⏭️ skipped
launchable-smoke-vitest ⏭️ skipped
live-scenarios ⏭️ skipped
model-router-provider-routed-inference-vitest ⏭️ skipped
network-policy-vitest ⏭️ skipped
onboard-negative-paths-vitest ⏭️ skipped
openclaw-tui-chat-correlation-vitest ⏭️ skipped
openshell-version-pin-vitest ⏭️ skipped
rebuild-openclaw-vitest ⏭️ skipped
runtime-overrides-vitest ⏭️ skipped
sandbox-rebuild-vitest ⏭️ skipped
sandbox-survival-vitest ⏭️ skipped
shields-config-vitest ⏭️ skipped
skill-agent-vitest ⏭️ skipped
token-rotation-vitest ⏭️ skipped
validate-jobs ✅ success

@github-actions

Copy link
Copy Markdown
Contributor

Vitest E2E Scenario Results — ✅ All jobs passed

Run: 27428479727
Workflow ref: e2e-migrate/test-credential-sanitization
Requested scenarios: (default — all supported)
Requested jobs: credential-sanitization-vitest
Summary: 3 passed, 0 failed, 21 skipped

Job Result
credential-migration-vitest ⏭️ skipped
credential-sanitization-vitest ✅ success
double-onboard-vitest ⏭️ skipped
gateway-guard-recovery ⏭️ skipped
generate-matrix ✅ success
hermes-e2e-vitest ⏭️ skipped
hermes-root-entrypoint-smoke-vitest ⏭️ skipped
inference-routing-vitest ⏭️ skipped
issue-4434-tui-unreachable-inference-vitest ⏭️ skipped
launchable-smoke-vitest ⏭️ skipped
live-scenarios ⏭️ skipped
model-router-provider-routed-inference-vitest ⏭️ skipped
network-policy-vitest ⏭️ skipped
onboard-negative-paths-vitest ⏭️ skipped
openclaw-tui-chat-correlation-vitest ⏭️ skipped
openshell-version-pin-vitest ⏭️ skipped
rebuild-openclaw-vitest ⏭️ skipped
runtime-overrides-vitest ⏭️ skipped
sandbox-rebuild-vitest ⏭️ skipped
sandbox-survival-vitest ⏭️ skipped
shields-config-vitest ⏭️ skipped
skill-agent-vitest ⏭️ skipped
token-rotation-vitest ⏭️ skipped
validate-jobs ✅ success

@github-actions

Copy link
Copy Markdown
Contributor

Vitest E2E Scenario Results — ✅ All jobs passed

Run: 27431351010
Workflow ref: e2e-migrate/test-credential-sanitization
Requested scenarios: (default — all supported)
Requested jobs: credential-sanitization-vitest
Summary: 3 passed, 0 failed, 21 skipped

Job Result
credential-migration-vitest ⏭️ skipped
credential-sanitization-vitest ✅ success
double-onboard-vitest ⏭️ skipped
gateway-guard-recovery ⏭️ skipped
generate-matrix ✅ success
hermes-e2e-vitest ⏭️ skipped
hermes-root-entrypoint-smoke-vitest ⏭️ skipped
inference-routing-vitest ⏭️ skipped
issue-4434-tui-unreachable-inference-vitest ⏭️ skipped
launchable-smoke-vitest ⏭️ skipped
live-scenarios ⏭️ skipped
model-router-provider-routed-inference-vitest ⏭️ skipped
network-policy-vitest ⏭️ skipped
onboard-negative-paths-vitest ⏭️ skipped
openclaw-tui-chat-correlation-vitest ⏭️ skipped
openshell-version-pin-vitest ⏭️ skipped
rebuild-openclaw-vitest ⏭️ skipped
runtime-overrides-vitest ⏭️ skipped
sandbox-rebuild-vitest ⏭️ skipped
sandbox-survival-vitest ⏭️ skipped
shields-config-vitest ⏭️ skipped
skill-agent-vitest ⏭️ skipped
token-rotation-vitest ⏭️ skipped
validate-jobs ✅ success

@github-actions

Copy link
Copy Markdown
Contributor

Vitest E2E Scenario Results — ✅ All jobs passed

Run: 27432354309
Workflow ref: e2e-migrate/test-credential-sanitization
Requested scenarios: (default — all supported)
Requested jobs: credential-sanitization-vitest
Summary: 2 passed, 0 failed, 21 skipped

Job Result
credential-migration-vitest ⏭️ skipped
credential-sanitization-vitest ✅ success
double-onboard-vitest ⏭️ skipped
gateway-guard-recovery ⏭️ skipped
generate-matrix ✅ success
hermes-e2e-vitest ⏭️ skipped
hermes-root-entrypoint-smoke-vitest ⏭️ skipped
inference-routing-vitest ⏭️ skipped
issue-4434-tui-unreachable-inference-vitest ⏭️ skipped
launchable-smoke-vitest ⏭️ skipped
live-scenarios ⏭️ skipped
model-router-provider-routed-inference-vitest ⏭️ skipped
network-policy-vitest ⏭️ skipped
onboard-negative-paths-vitest ⏭️ skipped
openclaw-tui-chat-correlation-vitest ⏭️ skipped
openshell-version-pin-vitest ⏭️ skipped
rebuild-openclaw-vitest ⏭️ skipped
runtime-overrides-vitest ⏭️ skipped
sandbox-rebuild-vitest ⏭️ skipped
sandbox-survival-vitest ⏭️ skipped
shields-config-vitest ⏭️ skipped
skill-agent-vitest ⏭️ skipped
token-rotation-vitest ⏭️ skipped

@jyaunches jyaunches merged commit 62f7243 into main Jun 12, 2026
77 of 80 checks passed
@jyaunches jyaunches deleted the e2e-migrate/test-credential-sanitization branch June 12, 2026 18:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: e2e End-to-end tests, nightly failures, or validation infrastructure chore Build, CI, dependency, or tooling maintenance v0.0.65 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants