Skip to content

fix(onboard): diagnose incomplete custom plugin images#6490

Merged
apurvvkumaria merged 4 commits into
mainfrom
fix/discussion-6108-plugin-image-verified
Jul 8, 2026
Merged

fix(onboard): diagnose incomplete custom plugin images#6490
apurvvkumaria merged 4 commits into
mainfrom
fix/discussion-6108-plugin-image-verified

Conversation

@cjagwani

@cjagwani cjagwani commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator

Summary

Fresh verified-history replacement for #6250. This PR preserves the reviewed net diff on current main while replacing the non-compliant historical commit chain with three newly signed, GitHub-Verified commits.

Aaron Erickson remains the original contributor and author of superseded PR #6250; cjagwani authored this replacement PR. Apurv Kumaria contributed the review-driven follow-up fixes. Both Aaron and Apurv are credited as co-authors on the replacement commit.

Related

Changes

  • Diagnose custom OpenClaw images that contain only the intermediate sandbox-base instead of the complete managed runtime.
  • Record authoritative image-plugin provenance and reconcile removed, renamed, and same-ID upgraded plugins during recreation and rebuild.
  • Preserve user-owned plugin, channel, and tool state while removing stale image-owned configuration; fail closed on incomplete provenance.
  • Add deterministic release lifecycle coverage for onboarding, restart, recreation, rebuild, workspace preservation, and EXDEV-safe runtime dependency replacement.
  • Authenticate only for the exact digest-pinned builder pre-pull, then remove Docker credentials before release-pinned fixture code runs.
  • Document the full-image plugin recipe, troubleshooting guidance, dependency risk controls, and the explicit REMOVE-WHEN condition.

Verification

  • 126 focused rebuild, restore, diagnosis, and custom-Dockerfile tests passed.
  • npm run build:cli passed.
  • Node 22 CLI typecheck passed.
  • Test-file size budget passed across 1,372 files.
  • Biome passed all 64 changed supported files.
  • git diff --cached --check passed before commit.
  • Replacement history contains three commits, all GitHub Verified with good ED25519 Git signatures.
  • Full standard CI and applicable live E2E are intentionally running again on this new exact head.

Provenance

The implementation and tests are the reviewed work from #6250, replayed onto current main because six historical commits in that PR could not satisfy the repository's GitHub-Verified requirement. This replacement does not claim those historical objects are verified; it provides a new, attributable, signed history containing their reviewed net result.

Signed-off-by: cjagwani cjagwani@nvidia.com
Co-authored-by: Aaron Erickson aerickson@nvidia.com
Co-authored-by: Apurv Kumaria akumaria@nvidia.com

Summary by CodeRabbit

  • New Features

    • Added safer OpenClaw plugin onboarding and recovery handling, including clearer guidance when an image is missing required runtime pieces.
    • Improved sandbox rebuild and restore flows to preserve plugin-related state more reliably.
  • Bug Fixes

    • Prevented unsafe recreates and restores when plugin provenance cannot be verified.
    • Improved recovery behavior for custom images and managed sandboxes.
  • Documentation

    • Expanded setup, troubleshooting, and command reference docs for OpenClaw plugin installation and recovery.

Fresh verified-history replacement for #6250; preserves its reviewed net diff on current main.

Signed-off-by: cjagwani <cjagwani@nvidia.com>
Co-authored-by: Aaron Erickson <aerickson@nvidia.com>
Co-authored-by: Apurv Kumaria <akumaria@nvidia.com>
@cjagwani cjagwani added integration: openclaw OpenClaw integration behavior area: onboarding Onboarding FSM, provider setup, sandbox launch, or first-run flow bug-fix PR fixes a bug or regression v0.0.78 Release target labels Jul 8, 2026
@cjagwani
cjagwani requested a review from cv July 8, 2026 19:40
@coderabbitai

coderabbitai Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 49f0e624-67c6-4352-977f-4995c46b97c9

📥 Commits

Reviewing files that changed from the base of the PR and between a54fa41 and 14a0edf.

📒 Files selected for processing (3)
  • .github/workflows/e2e.yaml
  • docs/get-started/quickstart.mdx
  • src/lib/onboard.ts
✅ Files skipped from review due to trivial changes (1)
  • docs/get-started/quickstart.mdx
🚧 Files skipped from review as they are similar to previous changes (2)
  • .github/workflows/e2e.yaml
  • src/lib/onboard.ts

📝 Walkthrough

Walkthrough

This PR introduces OpenClaw image-plugin provenance tracking across backup, restore, rebuild, and recreate flows, adding a new discovery/parsing/restore-planning module, provenance-aware config merge logic, managed-extension restore rework, safety guards blocking unsafe recreation, runtime diagnosis for custom images, documentation updates, and a new EXDEV weather-plugin E2E lifecycle test with supporting CI workflow and fixtures.

Changes

OpenClaw Plugin Provenance and Lifecycle Safety

Layer / File(s) Summary
Plugin install discovery and provenance parsing
src/lib/state/openclaw-plugin-restore.ts, src/lib/state/openclaw-plugin-restore.test.ts, src/lib/state/sandbox-openclaw-plugin-restore.test.ts
New module discovers, parses, and validates plugin install records (sqlite/legacy), builds restore plans, and validates provenance completeness.
Config merge and restore-input provenance reconciliation
src/lib/state/openclaw-config-merge.ts, src/lib/state/openclaw-config-merge.test.ts, src/lib/state/openclaw-config-restore-input.ts, src/lib/state/openclaw-config-restore-input.test.ts
openclaw.json merge and restore-input building now reconcile image-owned vs user-owned plugin/channel state via ownership sets, failing closed on incomplete provenance.
Managed extensions restore and cleanup
src/lib/state/openclaw-managed-extensions.ts, src/lib/state/openclaw-managed-extensions.test.ts
Restore tar-args/cleanup builders switch from boolean flags to explicit managed extension directory and required-directory sets, with tighter symlink validation.
Sandbox state backup/restore orchestration
src/lib/state/sandbox.ts, src/lib/state/registry.ts, test/snapshot*.test.ts, test/registry.test.ts
Registry and rebuild manifest gain plugin provenance fields; backup/restore flows validate authoritative provenance and plan plugin restore accordingly.
Rebuild backup/preflight/restore guards
src/lib/actions/sandbox/rebuild-*.ts, test/helpers/rebuild-flow-*.ts
Rebuild bails on unsafe provenance, computes an expected post-version-check registry entry, and switches restore to restoreRecreatedSandboxState.
Onboard recreate protection and finalization
src/lib/onboard.ts, src/lib/onboard/*.ts, test/onboard*.test.ts
Adds UnsafeCustomImagePluginBackupError, createSandboxRecreateProtection, plugin-install discovery during finalization, and registry registration wiring.
Custom OpenClaw runtime diagnosis
src/lib/onboard/custom-openclaw-runtime-diagnosis.ts, src/lib/verify-deployment.ts
Classifies base-only custom images during deployment verification and surfaces tailored gateway/dashboard hints.
Documentation
docs/deployment/install-openclaw-plugins.mdx, docs/reference/*.mdx, docs/manage-sandboxes/lifecycle.mdx, docs/get-started/quickstart.mdx
Describes provenance-aware plugin installation workaround and legacy recovery constraints.
E2E workflow, fixture, and CI boundary tests
.github/workflows/e2e.yaml, .github/workflows/regression-e2e.yaml, test/e2e/live/openclaw-plugin-runtime-exdev.test.ts, test/e2e/fixtures/plugins/weather/*, docs/security/e2e-weather-plugin-fixture-dependency-review.md
Adds an OpenClaw plugin runtime EXDEV job and live lifecycle test, a weather plugin fixture, dependency review documentation, and updates CI boundary tests/budgets.

Estimated code review effort: 5 (Critical) | ~120 minutes

Possibly related PRs

  • NVIDIA/NemoClaw#5177: Modifies the same OpenClaw config merge/restore-input logic that this PR extends with image-plugin provenance-driven selective merge.

Suggested labels: integration: openclaw, area: sandbox, area: e2e, bug-fix

Suggested reviewers: ericksoa, jacobtomlinson

🚥 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 matches the main change: onboarding now diagnoses incomplete custom plugin images.
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.
✨ 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 fix/discussion-6108-plugin-image-verified

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

@github-code-quality

github-code-quality Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

Code Coverage Overview

Languages: TypeScript

TypeScript / code-coverage/plugin

The overall coverage remains at 96%, unchanged from the branch.

TypeScript / code-coverage/cli

The overall coverage in the branch remains at 76%, unchanged from the branch.

Show a code coverage summary of the most impacted files.
File 0b11898 14a0edf +/-
src/lib/actions...light-guards.ts 81% 71% -10%
src/lib/inference/config.ts 99% 96% -3%
src/lib/state/o...config-merge.ts 93% 91% -2%
src/lib/state/sandbox.ts 75% 76% +1%
src/lib/onboard...ure-contract.ts 89% 91% +2%
src/lib/actions...red-recovery.ts 78% 88% +10%
src/lib/sandbox...vileged-exec.ts 45% 56% +11%
src/lib/state/o...ugin-restore.ts 0% 94% +94%
src/lib/onboard...me-diagnosis.ts 0% 100% +100%
src/lib/onboard...e-protection.ts 0% 100% +100%

Updated July 08, 2026 21:05 UTC
Code Coverage is in Public Preview. Learn more and provide us with your feedback.

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: onboard-resume, onboard-repair, cloud-onboard, openclaw-plugin-runtime-exdev, rebuild-openclaw, sandbox-rebuild, state-backup-restore, security-posture
Optional E2E: diagnostics, sandbox-operations, rebuild-hermes

Dispatch hint: onboard-resume,onboard-repair,cloud-onboard,openclaw-plugin-runtime-exdev,rebuild-openclaw,sandbox-rebuild,state-backup-restore,security-posture

Workflow run

Full advisor summary

E2E Recommendation Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • onboard-resume (medium): Required by the onboarding resume rule: onboarding finalization, recreation, registry publication, and state-transition code changed. This live job exercises interrupted onboarding and resume behavior that unit tests cannot fully cover.
  • onboard-repair (high): Required by the onboarding resume rule and by changes to repair/recreate safety gates. This verifies real repair behavior after failed or partial onboarding states.
  • cloud-onboard (high): The changed onboarding, registry, deployment verification, and custom-runtime diagnosis paths can affect full hosted OpenClaw onboarding. Run the canonical hosted onboarding E2E to verify the end-to-end user flow still reaches a healthy dashboard/gateway.
  • openclaw-plugin-runtime-exdev (very high): The PR changes the custom OpenClaw plugin fixture, its dependency/provenance contract, the live test itself, and dispatch workflow wiring. This job is the closest existing live coverage for custom-plugin onboarding, restart/rebuild persistence, and runtime-deps EXDEV replacement.
  • rebuild-openclaw (very high): OpenClaw rebuild, state restore, managed extension/plugin restore, and policy reconciliation behavior changed. This validates a real OpenClaw sandbox rebuild with preserved state.
  • sandbox-rebuild (high): Shared sandbox rebuild preflight, backup, prepared recovery, and restore phases changed. This job provides broader lifecycle coverage beyond the OpenClaw-specific rebuild lane.
  • state-backup-restore (medium): State backup/restore, snapshot validation, managed extension preservation, and plugin restore inputs changed. This live job verifies the host/sandbox archive and restore contract with real OpenShell operations.
  • security-posture (high): Sandbox-controlled plugin paths, restore filtering, and tar traversal/security-boundary-adjacent code changed. Run the existing security posture lane to catch regressions in live sandbox hardening assumptions.

Optional E2E

  • diagnostics (medium): Useful adjacent confidence because verify-deployment/custom runtime diagnostics and user-facing failure guidance changed, but cloud-onboard already covers the main post-deployment health path.
  • sandbox-operations (medium): Optional broader lifecycle confidence for status/exec/recovery behavior after registry and sandbox lifecycle changes.
  • rebuild-hermes (high): Optional cross-agent check because some modified rebuild phases are shared, although the primary behavior in this PR is OpenClaw/custom-plugin focused.

New E2E recommendations

  • custom OpenClaw plugin provenance fail-closed recreation (high): The PR adds fail-closed logic for custom OpenClaw image plugin provenance during pre-recreate backup, not-ready installer recovery, and final registry publication. Existing unit tests and the EXDEV lifecycle E2E prove happy-path custom plugin persistence, but they do not appear to exercise a live unsafe-provenance backup/recreate block before deleting the original sandbox.
    • Suggested test: Add a live E2E that creates a custom OpenClaw image with an image-owned plugin, removes or corrupts the recorded authoritative plugin provenance in the selected backup/registry, attempts same-name recreate or not-ready installer recovery, and asserts the old sandbox and backup remain untouched with actionable recovery guidance.
  • custom OpenClaw image missing managed runtime diagnosis (medium): verify-deployment now diagnoses custom images that lack /tmp/gateway.log, /usr/local/bin/nemoclaw-start, and /sandbox/.openclaw/openclaw.json. Unit tests cover classification, but a live E2E would prove the diagnostic is emitted during real onboard --from failure instead of generic dashboard/gateway retry guidance.
    • Suggested test: Add a live negative-path E2E using a minimal custom OpenClaw Dockerfile based on sandbox-base alone, run nemoclaw onboard --from, and assert deployment verification reports the missing managed runtime contract without claiming the agent is live.

Dispatch hint

  • Workflow: .github/workflows/e2e.yaml
  • jobs input: onboard-resume,onboard-repair,cloud-onboard,openclaw-plugin-runtime-exdev,rebuild-openclaw,sandbox-rebuild,state-backup-restore,security-posture

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

E2E Target Recommendation

Required E2E targets: openclaw-plugin-runtime-exdev
Optional E2E targets: None

Dispatch required E2E targets:

  • gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=openclaw-plugin-runtime-exdev

Workflow run

Full E2E target advisor summary

E2E Target Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E targets

  • openclaw-plugin-runtime-exdev: Focused free-standing E2E job wired for changed live test test/e2e/live/openclaw-plugin-runtime-exdev.test.ts.
    • Dispatch: gh workflow run e2e.yaml --ref <pr-head-ref> --field jobs=openclaw-plugin-runtime-exdev

Optional E2E targets

  • None.

Relevant changed files

  • .github/workflows/e2e.yaml
  • src/lib/actions/sandbox/rebuild-backup-phase.ts
  • src/lib/actions/sandbox/rebuild-preflight-guards.ts
  • src/lib/actions/sandbox/rebuild-preflight-phase.ts
  • src/lib/actions/sandbox/rebuild-prepared-recovery.ts
  • src/lib/actions/sandbox/rebuild-restore-phase.ts
  • src/lib/onboard.ts
  • src/lib/onboard/created-sandbox-finalization.ts
  • src/lib/onboard/custom-openclaw-runtime-diagnosis.ts
  • src/lib/onboard/not-ready-recreate.ts
  • src/lib/onboard/sandbox-backup-on-recreate.ts
  • src/lib/onboard/sandbox-recreate-protection.ts
  • src/lib/onboard/sandbox-registration.ts
  • src/lib/state/openclaw-config-merge.ts
  • src/lib/state/openclaw-config-restore-input.ts
  • src/lib/state/openclaw-managed-extensions.ts
  • src/lib/state/openclaw-plugin-restore.ts
  • src/lib/state/registry.ts
  • src/lib/state/sandbox.ts
  • src/lib/verify-deployment.ts
  • test/e2e/fixtures/plugins/weather/.gitignore
  • test/e2e/fixtures/plugins/weather/openclaw.plugin.json
  • test/e2e/fixtures/plugins/weather/package-lock.json
  • test/e2e/fixtures/plugins/weather/package.json
  • test/e2e/fixtures/plugins/weather/src/index.ts
  • test/e2e/fixtures/plugins/weather/src/version.ts
  • test/e2e/fixtures/plugins/weather/tsconfig.json
  • test/e2e/live/openclaw-plugin-runtime-exdev.test.ts
  • test/e2e/support/e2e-workflow.test.ts
  • test/e2e/support/openclaw-plugin-runtime-exdev-workflow-boundary.test.ts
  • test/e2e/support/platform-parity-cloud-experimental.test.ts
  • test/e2e/support/upload-e2e-artifacts-workflow-boundary.test.ts

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor (Nemotron Ultra) — Blocked

Merge posture: Do not merge until addressed
Primary next action: Fix PRA-3: Empty-array provenance bypass in hasCompleteOpenClawImagePluginProvenance; then add or justify PRA-T1.
Open items: 5 required · 13 warnings · 3 suggestions · 8 test follow-ups
Since last review: 0 prior items resolved · 14 still apply · 3 new items found

Action checklist

  • PRA-3 Fix: Empty-array provenance bypass in hasCompleteOpenClawImagePluginProvenance in src/lib/state/openclaw-plugin-restore.ts:380
  • PRA-4 Fix: New monolith: openclaw-plugin-restore.ts at 476 lines (extraction needed) in src/lib/state/openclaw-plugin-restore.ts:1
  • PRA-5 Fix: Monolith growth: openclaw-config-merge.ts +164 lines, test +262 lines in src/lib/state/openclaw-config-merge.ts:1
  • PRA-6 Fix: Monolith growth: sandbox.ts +185 lines with provenance validation mixed in in src/lib/state/sandbox.ts:234
  • PRA-7 Fix: Monolith growth: created-sandbox-finalization.ts +49 lines, test +244 lines in src/lib/onboard/created-sandbox-finalization.ts:1
  • PRA-1 Resolve or justify: Source-of-truth review needed: src/lib/onboard/not-ready-recreate.ts:85 (registry/gateway sync workaround)
  • PRA-2 Resolve or justify: Source-of-truth review needed: src/lib/onboard/not-ready-recreate.ts:125 (installer restore flag workaround)
  • PRA-8 Resolve or justify: Weather fixture lockfile has 9 vulnerable packages in dev dependency graph in test/e2e/fixtures/plugins/weather/package-lock.json:1
  • PRA-9 Resolve or justify: OpenShell tmpfs wrapper delegates all non-create commands without allowlist in test/e2e/live/openclaw-plugin-runtime-exdev.test.ts:180
  • PRA-10 Resolve or justify: Duplicate customOpenClaw determination logic across 6 files in src/lib/onboard/not-ready-recreate.ts:95
  • PRA-11 Resolve or justify: Source-of-truth workaround for registry/gateway sync lacks tracking issue in src/lib/onboard/not-ready-recreate.ts:85
  • PRA-12 Resolve or justify: Second registry/gateway sync workaround lacks tracking issue in src/lib/onboard/not-ready-recreate.ts:125
  • PRA-13 Resolve or justify: Legacy pre-v0.0.76 custom-image migration path lacks test coverage in docs/deployment/install-openclaw-plugins.mdx:380
  • PRA-14 Resolve or justify: New 130-minute E2E job increases CI attack surface in .github/workflows/e2e.yaml:3870
  • PRA-15 Resolve or justify: 5153-line committed fixture lockfile expands supply chain surface in test/e2e/fixtures/plugins/weather/package-lock.json:1
  • PRA-T1 Add or justify test follow-up: Runtime validation
  • PRA-T2 Add or justify test follow-up: Runtime validation
  • PRA-T3 Add or justify test follow-up: Runtime validation
  • PRA-T4 Add or justify test follow-up: Runtime validation
  • PRA-T5 Add or justify test follow-up: Runtime validation
  • PRA-T6 Add or justify test follow-up: Missing negative test for reconcile=true with empty installs array
  • PRA-T7 Add or justify test follow-up: Missing test for selectPreUpgradeBackupForCreate source-of-truth workaround
  • PRA-T8 Add or justify test follow-up: Missing test for legacy pre-v0.0.76 custom-image migration path
  • PRA-16 In-scope improvement: Complex curl wrapper for gateway tool call could be simplified in docs/deployment/install-openclaw-plugins.mdx:186
  • PRA-17 In-scope improvement: Fixture review doc uses test-scaffold framing unnecessarily in docs/security/e2e-weather-plugin-fixture-dependency-review.md:1
  • PRA-18 In-scope improvement: registry.ts at 722 lines - extraction candidate for provenance types in src/lib/state/registry.ts:1

Findings index

ID Severity Category Location Required action
PRA-1 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-2 Resolve/justify architecture Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
PRA-3 Required security src/lib/state/openclaw-plugin-restore.ts:380 Add a separate field 'openclawImagePluginProvenanceCaptured: boolean' to RebuildManifest to distinguish 'captured and empty' from 'not captured'. Update hasComplete to check this flag, or require non-empty array when reconcile=true.
PRA-4 Required architecture src/lib/state/openclaw-plugin-restore.ts:1 Extract into focused modules: openclaw-plugin-index-reader.ts (SQLite/legacy parsing), openclaw-plugin-validator.ts (ID/path/loadPath validation), openclaw-plugin-discovery.ts (SSH discovery), openclaw-plugin-restore-planner.ts (planOpenClawPluginRestore). Keep public API surface minimal.
PRA-5 Required architecture src/lib/state/openclaw-config-merge.ts:1 Extract plugin provenance ownership computation and plugin-specific merge functions into openclaw-plugin-config-merge.ts. Keep core config merge (gateway, models, channels, tools) in openclaw-config-merge.ts.
PRA-6 Required architecture src/lib/state/sandbox.ts:234 Move provenance validation functions to openclaw-plugin-restore.ts or new openclaw-provenance-guard.ts. Keep sandbox.ts focused on backup/restore mechanics.
PRA-7 Required architecture src/lib/onboard/created-sandbox-finalization.ts:1 Extract plugin discovery into discoverFreshOpenClawImagePluginInstalls caller, restore validation into validateCustomOpenClawRestore, DCode validation into validateManagedDcodeRoute. Keep finalizeCreatedSandbox as orchestrator.
PRA-8 Resolve/justify security test/e2e/fixtures/plugins/weather/package-lock.json:1 Explicitly accept as documented residual risk per the review doc with compensating controls (exact versions, lockfile integrity, npm ci --ignore-scripts, dev/peer prune, secret-free workflow). Re-audit on any fixture manifest/lockfile change.
PRA-9 Resolve/justify security test/e2e/live/openclaw-plugin-runtime-exdev.test.ts:180 Add explicit allowlist of delegated subcommands or deny unknown subcommands for defense-in-depth. The wrapper should only pass through known-safe commands.
PRA-10 Resolve/justify correctness src/lib/onboard/not-ready-recreate.ts:95 Centralize in a single utility function isCustomOpenClawImage(sandboxEntry) used by all six files.
PRA-11 Resolve/justify architecture src/lib/onboard/not-ready-recreate.ts:85 Link a tracking issue for atomic registry/gateway sync in the source-of-truth comment (e.g., 'REMOVE-WHEN: #XXXX supplies atomic registry/gateway sync').
PRA-12 Resolve/justify correctness src/lib/onboard/not-ready-recreate.ts:125 Link to tracking issue for atomic registry/gateway sync (e.g., 'REMOVE-WHEN: #XXXX supplies atomic registry/gateway sync').
PRA-13 Resolve/justify correctness docs/deployment/install-openclaw-plugins.mdx:380 Add test: pre-v0.0.76 custom-image sandbox (no provenance in backup) is blocked from state-preserving rebuild but can be recreated with NEMOCLAW_RECREATE_WITHOUT_BACKUP=1.
PRA-14 Resolve/justify security .github/workflows/e2e.yaml:3870 Consider splitting into smaller jobs or reducing timeout. Document why 130 minutes is necessary and cannot be reduced.
PRA-15 Resolve/justify architecture test/e2e/fixtures/plugins/weather/package-lock.json:1 Document the lockfile size rationale clearly. Consider if a smaller fixture or generated lockfile with pinned dependencies could achieve the same test coverage with less maintenance burden.
PRA-16 Improvement docs docs/deployment/install-openclaw-plugins.mdx:186 Simplify to show direct openclaw plugins inspect + curl without heredoc/config piping. Keep only the proxy env sourcing as NemoClaw-specific.
PRA-17 Improvement docs docs/security/e2e-weather-plugin-fixture-dependency-review.md:1 Convert to simple SECURITY_REVIEW.md format without test-scaffold framing. Keep all technical content but simplify structure.
PRA-18 Improvement architecture src/lib/state/registry.ts:1 Extract provenance-related types and validation to openclaw-provenance-guard.ts alongside sandbox.ts extraction.
PRA-19 Resolve/justify tests src/lib/state/openclaw-plugin-restore.test.ts:350 Add test in sandbox-openclaw-plugin-restore.test.ts: manifest with reconcile=true and empty installs should be rejected or require explicit 'no-plugins' marker.
PRA-20 Resolve/justify tests src/lib/onboard/not-ready-recreate.ts:85 Add explicit test in not-ready-recreate.test.ts verifying the regression test conditions mentioned in the source-of-truth comment.

🚨 Required before merge

Address these before merging unless a maintainer explicitly overrides the advisor with rationale.

PRA-3 Required — Empty-array provenance bypass in hasCompleteOpenClawImagePluginProvenance

  • Location: src/lib/state/openclaw-plugin-restore.ts:380
  • Category: security
  • Problem: hasCompleteOpenClawImagePluginProvenance([], '/sandbox/.openclaw') returns true, treating an explicit empty array as 'complete provenance'. An attacker who can write a backup manifest can set reconcileOpenClawImagePluginProvenance===true with openclawImagePluginInstalls: [] to bypass provenance checks for a custom-image sandbox that actually had plugins, allowing stale image-owned plugins to be restored as user state during rebuild/restore.
  • Impact: Sandbox escape / trust boundary bypass: malicious or corrupted manifest can cause rebuild/restore to treat image-owned plugins as user state, potentially restoring malicious plugin code with user data permissions.
  • Required action: Add a separate field 'openclawImagePluginProvenanceCaptured: boolean' to RebuildManifest to distinguish 'captured and empty' from 'not captured'. Update hasComplete to check this flag, or require non-empty array when reconcile=true.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Check hasCompleteOpenClawImagePluginProvenance([], '/sandbox/.openclaw') === true in openclaw-plugin-restore.test.ts line ~350; verify parseOpenClawImagePluginInstalls([], dir) returns ok=true
  • Missing regression test: Add test in sandbox-openclaw-plugin-restore.test.ts: manifest with reconcile=true and empty installs should be rejected or require explicit 'no-plugins' marker
  • Done when: The required change is committed and verification passes: Check hasCompleteOpenClawImagePluginProvenance([], '/sandbox/.openclaw') === true in openclaw-plugin-restore.test.ts line ~350; verify parseOpenClawImagePluginInstalls([], dir) returns ok=true.
  • Evidence: openclaw-plugin-restore.ts:380 comment 'an explicit empty array is complete'; hasAuthoritativeOpenClawImagePluginProvenance only checks reconcile===true AND hasComplete

PRA-4 Required — New monolith: openclaw-plugin-restore.ts at 476 lines (extraction needed)

  • Location: src/lib/state/openclaw-plugin-restore.ts:1
  • Category: architecture
  • Problem: New file at 476 lines handles OpenClaw plugin provenance discovery, validation, restore planning, SQLite/legacy index parsing, SSH command construction, Python inline scripts, path validation, ID sanitization, and restore planning all in one file.
  • Impact: Exceeds 20-line growth threshold for new files. Mixes SSH discovery, Python script generation, validation, and restore planning in one file, increasing review burden and bug surface for security-critical provenance logic.
  • Required action: Extract into focused modules: openclaw-plugin-index-reader.ts (SQLite/legacy parsing), openclaw-plugin-validator.ts (ID/path/loadPath validation), openclaw-plugin-discovery.ts (SSH discovery), openclaw-plugin-restore-planner.ts (planOpenClawPluginRestore). Keep public API surface minimal.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: File is 476 lines; grep for 'export function' shows 8+ exported functions spanning discovery, validation, parsing, planning
  • Missing regression test: N/A - architectural extraction; existing tests should pass after refactor
  • Done when: The required change is committed and verification passes: File is 476 lines; grep for 'export function' shows 8+ exported functions spanning discovery, validation, parsing, planning.
  • Evidence: Single file exports discoverFreshOpenClawPluginExtensionDirs, discoverFreshOpenClawImagePluginInstalls, parseOpenClawImagePluginInstalls, hasCompleteOpenClawImagePluginProvenance, parseFreshOpenClawPluginExtensionDirs, planOpenClawPluginRestore, plus SSH/Python command builders

PRA-5 Required — Monolith growth: openclaw-config-merge.ts +164 lines, test +262 lines

  • Location: src/lib/state/openclaw-config-merge.ts:1
  • Category: architecture
  • Problem: openclaw-config-merge.ts grew +164 lines (now 468), test grew +262 lines (now 650). Plugin provenance ownership computation and plugin-specific merge functions (mergeOpenClawPlugins, mergeOpenClawEntryMap, mergeOpenClawPluginLoad, mergeOpenClawPluginIdList, mergeOpenClawPluginSlots) are mixed with core config merge logic.
  • Impact: Plugin-specific merge logic mixed with gateway/models/channels/tools merge increases cognitive load and coupling. Harder to verify ownership semantics are correct for plugin provenance.
  • Required action: Extract plugin provenance ownership computation and plugin-specific merge functions into openclaw-plugin-config-merge.ts. Keep core config merge (gateway, models, channels, tools) in openclaw-config-merge.ts.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: File grew from 304 to 468 lines; grep 'mergeOpenClawPlugin' shows 5 plugin-specific merge functions
  • Missing regression test: N/A - architectural extraction; existing merge tests should pass after refactor
  • Done when: The required change is committed and verification passes: File grew from 304 to 468 lines; grep 'mergeOpenClawPlugin' shows 5 plugin-specific merge functions.
  • Evidence: mergeOpenClawPlugins, mergeOpenClawEntryMap, mergeOpenClawPluginLoad, mergeOpenClawPluginIdList, mergeOpenClawPluginSlots all in one file with core mergeOpenClawRestoredConfig

PRA-6 Required — Monolith growth: sandbox.ts +185 lines with provenance validation mixed in

  • Location: src/lib/state/sandbox.ts:234
  • Category: architecture
  • Problem: sandbox.ts grew +185 lines (now 1990) with provenance validation functions (hasAuthoritativeOpenClawImagePluginProvenance, OPENCLAW_IMAGE_PLUGIN_PROVENANCE_RESTORE_ERROR) mixed into backup/restore mechanics.
  • Impact: Provenance validation logic mixed with tar extraction, backup/restore, symlink auditing increases file complexity and couples security-critical provenance checks with mechanical backup operations.
  • Required action: Move provenance validation functions to openclaw-plugin-restore.ts or new openclaw-provenance-guard.ts. Keep sandbox.ts focused on backup/restore mechanics.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: grep 'hasAuthoritativeOpenClawImagePluginProvenance\|OPENCLAW_IMAGE_PLUGIN_PROVENANCE_RESTORE_ERROR' in sandbox.ts shows provenance logic mixed with tar/backup logic
  • Missing regression test: N/A - architectural extraction; existing sandbox tests should pass after refactor
  • Done when: The required change is committed and verification passes: grep 'hasAuthoritativeOpenClawImagePluginProvenance\|OPENCLAW_IMAGE_PLUGIN_PROVENANCE_RESTORE_ERROR' in sandbox.ts shows provenance logic mixed with tar/backup logic.
  • Evidence: hasAuthoritativeOpenClawImagePluginProvenance and OPENCLAW_IMAGE_PLUGIN_PROVENANCE_RESTORE_ERROR defined in sandbox.ts alongside backupSandboxState, restoreRecreatedSandboxState, validateTarEntries

PRA-7 Required — Monolith growth: created-sandbox-finalization.ts +49 lines, test +244 lines

  • Location: src/lib/onboard/created-sandbox-finalization.ts:1
  • Category: architecture
  • Problem: created-sandbox-finalization.ts grew +49 lines (now 143), test grew +244 lines (now 630). Handles plugin discovery, restore validation, DCode validation, and registration all in one orchestrator.
  • Impact: Four distinct responsibilities in one function: discovery, restore, DCode validation, registration. Test file at 630 lines with 15+ test cases covering all paths.
  • Required action: Extract plugin discovery into discoverFreshOpenClawImagePluginInstalls caller, restore validation into validateCustomOpenClawRestore, DCode validation into validateManagedDcodeRoute. Keep finalizeCreatedSandbox as orchestrator.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: File has 4 distinct responsibilities: discovery, restore, DCode validation, registration; test file has 15+ test cases covering all paths
  • Missing regression test: N/A - architectural extraction; existing tests should pass after refactor
  • Done when: The required change is committed and verification passes: File has 4 distinct responsibilities: discovery, restore, DCode validation, registration; test file has 15+ test cases covering all paths.
  • Evidence: finalizeCreatedSandbox does discovery, then restore, then DCode validation, then register - each with distinct error handling and bail paths
Review findings by urgency: 5 required fixes, 13 items to resolve/justify, 3 in-scope improvements

⚠️ Resolve or justify before merge

Investigate these in the current review; either fix them, explain why they are not applicable, or document the accepted risk.

PRA-1 Resolve/justify — Source-of-truth review needed: src/lib/onboard/not-ready-recreate.ts:85 (registry/gateway sync workaround)

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Documented: returns null when liveExists=true and when hasExistingRegistryEntry=false; but no explicit test found
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: Source-of-truth comment at lines 85-92 without issue link

PRA-2 Resolve/justify — Source-of-truth review needed: src/lib/onboard/not-ready-recreate.ts:125 (installer restore flag workaround)

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Documented but no explicit test found
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: Comment at line 125 without REMOVE-WHEN reference

PRA-8 Resolve/justify — Weather fixture lockfile has 9 vulnerable packages in dev dependency graph

  • Location: test/e2e/fixtures/plugins/weather/package-lock.json:1
  • Category: security
  • Problem: Weather fixture lockfile has 9 vulnerable packages in OpenClaw 2026.5.27 dev dependency graph (3 moderate, 6 high). Advisory IDs include GHSA-22p9-wv53-3rq4, GHSA-2gcr-mfcq-wcc3, GHSA-35p6-xmwp-9g52, etc. Documented as accepted residual risk in e2e-weather-plugin-fixture-dependency-review.md.
  • Impact: Vulnerabilities in dev dependencies could affect fixture build; registry packages can later be found vulnerable or compromised. Accepted residual risk limited to secret-free E2E lane with read-only contents permission.
  • Recommended action: Explicitly accept as documented residual risk per the review doc with compensating controls (exact versions, lockfile integrity, npm ci --ignore-scripts, dev/peer prune, secret-free workflow). Re-audit on any fixture manifest/lockfile change.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Run 'npm audit --package-lock-only --ignore-scripts --json' from test/e2e/fixtures/plugins/weather; exits 1 with 9 vulnerable packages
  • Missing regression test: test/e2e-fixture-dependency-review.test.ts should fail if fixture lockfile changes without review doc update
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Run 'npm audit --package-lock-only --ignore-scripts --json' from test/e2e/fixtures/plugins/weather; exits 1 with 9 vulnerable packages.
  • Evidence: e2e-weather-plugin-fixture-dependency-review.md documents advisories and compensating controls; test/e2e-fixture-dependency-review.test.ts enforces review binding

PRA-9 Resolve/justify — OpenShell tmpfs wrapper delegates all non-create commands without allowlist

  • Location: test/e2e/live/openclaw-plugin-runtime-exdev.test.ts:180
  • Category: security
  • Problem: OpenShell tmpfs wrapper delegates all non-create commands without allowlist. Only intercepts 'sandbox create' to inject tmpfs config; all other subcommands (sandbox delete, gateway, exec, etc.) pass through unchecked.
  • Impact: Defense-in-depth gap: wrapper could delegate unsafe subcommands if real OpenShell adds dangerous commands in future. No explicit allowlist of known-safe delegated commands.
  • Recommended action: Add explicit allowlist of delegated subcommands or deny unknown subcommands for defense-in-depth. The wrapper should only pass through known-safe commands.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: createOpenShellTmpfsWrapper only checks for 'sandbox create'; everything else falls through to 'exec realOpenshell "$@"'
  • Missing regression test: Add test: unknown subcommand should be rejected or at least logged; verify wrapper doesn't delegate 'gateway' or 'exec' commands
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: createOpenShellTmpfsWrapper only checks for 'sandbox create'; everything else falls through to 'exec realOpenshell "$@"'.
  • Evidence: Wrapper script at line 180: only 'sandbox create' intercepted; default case 'exec realOpenshell "$@"'

PRA-10 Resolve/justify — Duplicate customOpenClaw determination logic across 6 files

  • Location: src/lib/onboard/not-ready-recreate.ts:95
  • Category: correctness
  • Problem: Duplicate customOpenClaw determination logic across 6 files: onboard.ts:2396, not-ready-recreate.ts:81, sandbox-backup-on-recreate.ts:40, rebuild-backup-phase.ts:151, sandbox-recreate-protection.ts (via parameter), custom-openclaw-runtime-diagnosis.ts:49.
  • Impact: Inconsistent updates risk: if logic changes (e.g., agent name comparison), 6 locations must be updated. DRY violation in security-critical path.
  • Recommended action: Centralize in a single utility function isCustomOpenClawImage(sandboxEntry) used by all six files.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: grep 'customOpenClaw\|fromDockerfile.*openclaw' shows 6+ occurrences with identical logic
  • Missing regression test: Add unit test for isCustomOpenClawImage utility covering all entry shapes (fromDockerfile + openclaw agent, fromDockerfile + no agent, managed image, etc.)
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: grep 'customOpenClaw\|fromDockerfile.*openclaw' shows 6+ occurrences with identical logic.
  • Evidence: All 6 locations use: Boolean(entry?.fromDockerfile) && (!entry?.agent || entry.agent === 'openclaw')

PRA-11 Resolve/justify — Source-of-truth workaround for registry/gateway sync lacks tracking issue

  • Location: src/lib/onboard/not-ready-recreate.ts:85
  • Category: architecture
  • Problem: Source-of-truth workaround for registry/gateway sync inconsistency lacks tracking issue. Comment says 'a real fix needs atomic registry/gateway sync, which is out of scope for this PR' but no issue number linked.
  • Impact: Workaround may become permanent without tracking. No visibility on when atomic sync will be implemented.
  • Recommended action: Link a tracking issue for atomic registry/gateway sync in the source-of-truth comment (e.g., 'REMOVE-WHEN: #XXXX supplies atomic registry/gateway sync').
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Lines 85-92 in not-ready-recreate.ts have source-of-truth comment without issue reference
  • Missing regression test: N/A - documentation/linking fix
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Lines 85-92 in not-ready-recreate.ts have source-of-truth comment without issue reference.
  • Evidence: Comment block at line 85: 'Source-of-truth review for the two drift returns below... source-fix constraint = a real fix needs atomic registry/gateway sync, which is out of scope for this PR'

PRA-12 Resolve/justify — Second registry/gateway sync workaround lacks tracking issue

  • Location: src/lib/onboard/not-ready-recreate.ts:125
  • Category: correctness
  • Problem: Second registry/gateway sync workaround at line 125 also lacks tracking issue link.
  • Impact: Same as PRA-9: workaround may become permanent without tracking issue reference.
  • Recommended action: Link to tracking issue for atomic registry/gateway sync (e.g., 'REMOVE-WHEN: #XXXX supplies atomic registry/gateway sync').
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Line 125 comment 'Installer contract: the installer MUST set NEMOCLAW_RESTORE_LATEST_BACKUP_ON_RECREATE=1...' has no REMOVE-WHEN reference
  • Missing regression test: N/A - documentation/linking fix
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Line 125 comment 'Installer contract: the installer MUST set NEMOCLAW_RESTORE_LATEST_BACKUP_ON_RECREATE=1...' has no REMOVE-WHEN reference.
  • Evidence: Comment at line 125 discusses installer contract but no REMOVE-WHEN or issue link

PRA-13 Resolve/justify — Legacy pre-v0.0.76 custom-image migration path lacks test coverage

  • Location: docs/deployment/install-openclaw-plugins.mdx:380
  • Category: correctness
  • Problem: Legacy pre-v0.0.76 custom-image migration path documented but lacks test coverage. Docs say 'Custom-image sandboxes created before v0.0.76 cannot enter the state-preserving path automatically when they lack recorded provenance. Keep the older sandbox intact, onboard the current release under a different name, and migrate its state manually.'
  • Impact: Undocumented behavior change risk: if legacy migration path breaks, no test will catch it. Users following docs may encounter unexpected failures.
  • Recommended action: Add test: pre-v0.0.76 custom-image sandbox (no provenance in backup) is blocked from state-preserving rebuild but can be recreated with NEMOCLAW_RECREATE_WITHOUT_BACKUP=1.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: No test in sandbox-openclaw-plugin-restore.test.ts or rebuild-backup-phase.test.ts covers pre-v0.0.76 backup without provenance
  • Missing regression test: Add test proving legacy custom-image sandbox without provenance is blocked from state-preserving rebuild but allowed to recreate with NEMOCLAW_RECREATE_WITHOUT_BACKUP=1
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: No test in sandbox-openclaw-plugin-restore.test.ts or rebuild-backup-phase.test.ts covers pre-v0.0.76 backup without provenance.
  • Evidence: Docs at line 380 describe legacy behavior but no corresponding test in sandbox-openclaw-plugin-restore.test.ts or rebuild-backup-phase.test.ts

PRA-14 Resolve/justify — New 130-minute E2E job increases CI attack surface

  • Location: .github/workflows/e2e.yaml:3870
  • Category: security
  • Problem: New openclaw-plugin-runtime-exdev job has 130-minute timeout (three 25-minute onboards + 20-minute rebuild + 15-minute buffer + 20-minute setup/teardown). Increases CI attack surface and resource consumption.
  • Impact: Long-running CI job expands attack surface for supply chain compromise; consumes runner resources for extended period.
  • Recommended action: Consider splitting into smaller jobs or reducing timeout. Document why 130 minutes is necessary and cannot be reduced.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Job definition shows timeout-minutes: 130 with comment explaining three bounded 25-minute onboards
  • Missing regression test: N/A - CI architecture decision
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Job definition shows timeout-minutes: 130 with comment explaining three bounded 25-minute onboards.
  • Evidence: e2e.yaml job 'openclaw-plugin-runtime-exdev' has timeout-minutes: 130

PRA-15 Resolve/justify — 5153-line committed fixture lockfile expands supply chain surface

  • Location: test/e2e/fixtures/plugins/weather/package-lock.json:1
  • Category: architecture
  • Problem: 5153-line committed fixture lockfile expands supply chain surface. While documented as intentional for determinism, the size is a maintenance burden.
  • Impact: Large lockfile increases review burden for dependency changes; harder to audit transitive dependencies; maintenance burden on fixture updates.
  • Recommended action: Document the lockfile size rationale clearly. Consider if a smaller fixture or generated lockfile with pinned dependencies could achieve the same test coverage with less maintenance burden.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: wc -l test/e2e/fixtures/plugins/weather/package-lock.json shows 5153 lines
  • Missing regression test: N/A - architectural decision documentation
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: wc -l test/e2e/fixtures/plugins/weather/package-lock.json shows 5153 lines.
  • Evidence: Lockfile is 5153 lines with full OpenClaw 2026.5.27 dev dependency graph; e2e-weather-plugin-fixture-dependency-review.md documents rationale

PRA-19 Resolve/justify — Missing negative test for reconcile=true with empty installs array

  • Location: src/lib/state/openclaw-plugin-restore.test.ts:350
  • Category: tests
  • Problem: Missing runtime validation test follow-up: the empty-array provenance bypass (PRA-1) has no negative test proving the vulnerability or the fix.
  • Impact: No test guards against regression of the empty-array bypass vulnerability.
  • Recommended action: Add test in sandbox-openclaw-plugin-restore.test.ts: manifest with reconcile=true and empty installs should be rejected or require explicit 'no-plugins' marker.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: openclaw-plugin-restore.test.ts line 350 shows 'distinguishes complete empty provenance from missing legacy provenance' test but no negative case for reconcile=true with empty array
  • Missing regression test: Add negative test: hasCompleteOpenClawImagePluginProvenance([], dir) should be false when reconcile=true context is implied
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: openclaw-plugin-restore.test.ts line 350 shows 'distinguishes complete empty provenance from missing legacy provenance' test but no negative case for reconcile=true with empty array.
  • Evidence: Test 'distinguishes complete empty provenance from missing legacy provenance' checks hasCompleteOpenClawImagePluginProvenance([], OPENCLAW_DIR) === true but no test for hasAuthoritativeOpenClawImagePluginProvenance with empty installs and reconcile=true

PRA-20 Resolve/justify — Missing test for selectPreUpgradeBackupForCreate source-of-truth workaround

  • Location: src/lib/onboard/not-ready-recreate.ts:85
  • Category: tests
  • Problem: Missing test for selectPreUpgradeBackupForCreate source-of-truth workaround. The comment describes invalid state (registry/gateway inconsistency), source boundary (pruneStaleSandboxEntry is best-effort), source-fix constraint (atomic sync out of scope), regression test (returns null when liveExists=true or hasExistingRegistryEntry=false), and removal condition (drop guards once atomic sync exists).
  • Impact: Workaround behavior not verified by tests; regression could silently change the drift handling.
  • Recommended action: Add explicit test in not-ready-recreate.test.ts verifying the regression test conditions mentioned in the source-of-truth comment.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: not-ready-recreate.test.ts should have tests for liveExists=true and hasExistingRegistryEntry=false returning null
  • Missing regression test: Add tests: selectPreUpgradeBackupForCreate returns null when liveExists=true; returns null when hasExistingRegistryEntry=false
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: not-ready-recreate.test.ts should have tests for liveExists=true and hasExistingRegistryEntry=false returning null.
  • Evidence: Source-of-truth comment at line 85 lists regression test conditions but no corresponding tests found in not-ready-recreate.test.ts

PRA-21 Resolve/justify — Missing test for legacy pre-v0.0.76 custom-image migration path

  • Location: docs/deployment/install-openclaw-plugins.mdx:380
  • Category: tests
  • Problem: Missing test for legacy pre-v0.0.76 custom-image migration path (PRA-11).
  • Impact: Same as PRA-11: legacy migration path untested.
  • Recommended action: Add test: pre-v0.0.76 custom-image sandbox (no provenance in backup) is blocked from state-preserving rebuild but can be recreated with NEMOCLAW_RECREATE_WITHOUT_BACKUP=1.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: No existing test covers this migration scenario
  • Missing regression test: Add integration test in sandbox-openclaw-plugin-restore.test.ts or rebuild-backup-phase.test.ts
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: No existing test covers this migration scenario.
  • Evidence: Docs describe legacy behavior but no test covers it

💡 In-scope improvements

These are lower-risk, not throwaway. Prefer fixing them in this PR when they are local to changed code; defer only with rationale or a linked follow-up.

PRA-16 Improvement — Complex curl wrapper for gateway tool call could be simplified

  • Location: docs/deployment/install-openclaw-plugins.mdx:186
  • Category: docs
  • Problem: Complex curl wrapper for gateway tool call uses heredoc/config piping. Could be simplified to show direct openclaw plugins inspect + curl without heredoc/config piping. Keep only the proxy env sourcing as NemoClaw-specific.
  • Impact: Documentation complexity obscures the actual verification steps; users may copy-paste without understanding.
  • Suggested action: Simplify to show direct openclaw plugins inspect + curl without heredoc/config piping. Keep only the proxy env sourcing as NemoClaw-specific.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Lines 186-195 show multi-line curl with --config - and heredoc for Authorization header
  • Missing regression test: N/A - documentation simplification
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Verification section uses: . /tmp/nemoclaw-proxy-env.sh && printf 'header = "Authorization: Bearer %s"\n' "$OPENCLAW_GATEWAY_TOKEN" | curl --noproxy '*' --max-time 30 --silent --show-error --fail-with-body --config - -H 'Content-Type: application/json' ...

PRA-17 Improvement — Fixture review doc uses test-scaffold framing unnecessarily

  • Location: docs/security/e2e-weather-plugin-fixture-dependency-review.md:1
  • Category: docs
  • Problem: Fixture review doc uses test-scaffold framing (test fixtures, test-only, etc.) unnecessarily. Technical content is solid but structure is verbose.
  • Impact: Documentation structure adds cognitive overhead; reviewers must filter through test-scaffold language to find security content.
  • Suggested action: Convert to simple SECURITY_REVIEW.md format without test-scaffold framing. Keep all technical content but simplify structure.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Doc has 'Checked-in Fixture Waiver', 'Accepted Residual Risk', 'Compensating Controls', 'Advisory Audit', 'Enforcement and Removal' sections with test-scaffold language
  • Missing regression test: N/A - documentation simplification
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Sections use test-scaffold framing: 'The following fixture lockfile is intentionally committed and covered by this review', 'This waiver is limited to test fixture code'

PRA-18 Improvement — registry.ts at 722 lines - extraction candidate for provenance types

  • Location: src/lib/state/registry.ts:1
  • Category: architecture
  • Problem: registry.ts at 722 lines (+9) is an extraction candidate for provenance types. Consider extracting provenance-related types and validation to openclaw-provenance-guard.ts alongside sandbox.ts extraction (PRA-4).
  • Impact: Provenance types mixed with registry CRUD operations increases file size and couples distinct concerns.
  • Suggested action: Extract provenance-related types and validation to openclaw-provenance-guard.ts alongside sandbox.ts extraction.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: File has grown to 722 lines; provenance types mixed with registry CRUD operations
  • Missing regression test: N/A - architectural extraction
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: registry.ts contains SandboxEntry, RebuildManifest types with provenance fields alongside registry CRUD functions
Simplification opportunities: 8 possible cuts, net -205 lines possible

These are safe simplification checks only. Do not remove validation, security controls, data-loss prevention, or required tests.

  • PRA-4 delete (src/lib/state/openclaw-plugin-restore.ts:1): Split openclaw-plugin-restore.ts into 4 focused modules
    • Replacement: openclaw-plugin-index-reader.ts, openclaw-plugin-validator.ts, openclaw-plugin-discovery.ts, openclaw-plugin-restore-planner.ts
    • Net: 0 lines
    • Safety boundary: Public API surface (discoverFreshOpenClawImagePluginInstalls, parseOpenClawImagePluginInstalls, hasCompleteOpenClawImagePluginProvenance, planOpenClawPluginRestore) must remain stable
  • PRA-5 delete (src/lib/state/openclaw-config-merge.ts:1): Extract plugin merge functions to openclaw-plugin-config-merge.ts
    • Replacement: New module for plugin provenance ownership and plugin-specific merge logic
    • Net: 0 lines
    • Safety boundary: mergeOpenClawRestoredConfig public API and ownership contract (OPENCLAW_CONFIG_RESTORE_OWNERSHIP) must remain stable
  • PRA-6 delete (src/lib/state/sandbox.ts:234): Move provenance validation to openclaw-provenance-guard.ts
    • Replacement: New module openclaw-provenance-guard.ts with hasAuthoritativeOpenClawImagePluginProvenance, OPENCLAW_IMAGE_PLUGIN_PROVENANCE_RESTORE_ERROR
    • Net: -50 lines
    • Safety boundary: RebuildManifest type and hasAuthoritativeOpenClawImagePluginProvenance function signature must remain stable for callers in rebuild-backup-phase.ts, sandbox-backup-on-recreate.ts, created-sandbox-finalization.ts
  • PRA-7 delete (src/lib/onboard/created-sandbox-finalization.ts:1): Extract validateCustomOpenClawRestore and validateManagedDcodeRoute helpers
    • Replacement: Two new pure functions for restore validation and DCode validation, called from finalizeCreatedSandbox
    • Net: 0 lines
    • Safety boundary: CreatedSandboxFinalizationOptions and CreatedSandboxFinalizationDeps interfaces must remain stable
  • PRA-10 stdlib (src/lib/onboard/not-ready-recreate.ts:95): Inline duplicate customOpenClaw logic in 6 files
    • Replacement: Single isCustomOpenClawImage(sandboxEntry) utility in shared module (e.g., onboard/sandbox-classification.ts)
    • Net: -30 lines
    • Safety boundary: Function must be pure and deterministic; no I/O or side effects
  • PRA-16 shrink (docs/deployment/install-openclaw-plugins.mdx:186): Replace heredoc curl config with direct stdin header
    • Replacement: . /tmp/nemoclaw-proxy-env.sh && curl -H "Authorization: Bearer $OPENCLAW_GATEWAY_TOKEN" -H "Content-Type: application/json" -d '{"agentId":"main","tool":"get_weather","args":{"location":"Santa Clara"}}' "http://127.0.0.1:${OPENCLAW\_GATEWAY\_PORT:-18789}/tools/invoke"
    • Net: -5 lines
    • Safety boundary: Must preserve stdin auth pattern (token not in process args) and proxy env sourcing
  • PRA-17 delete (docs/security/e2e-weather-plugin-fixture-dependency-review.md:1): Remove test-scaffold framing language
    • Replacement: Direct security review format: Scope, Risk Assessment, Compensating Controls, Advisory Audit, Revalidation Contract
    • Net: -20 lines
    • Safety boundary: All technical content (advisory IDs, SHA-256, compensating controls, revalidation steps) must be preserved
  • PRA-18 shrink (src/lib/state/registry.ts:1): Move provenance-related types to openclaw-provenance-guard.ts
    • Replacement: Shared provenance types module imported by registry.ts, sandbox.ts, rebuild-backup-phase.ts
    • Net: -100 lines
    • Safety boundary: RebuildManifest, SandboxEntry public types must remain compatible
Test follow-ups to resolve or justify

If these cover changed behavior, prefer adding them in this PR; otherwise state why existing coverage is enough or link the follow-up.

  • PRA-T1 Runtime validation — sandbox-openclaw-plugin-restore.test.ts: negative test for reconcile=true with empty installs array rejection. Runtime/sandbox/infrastructure paths need behavioral runtime validation: .github/workflows/e2e.yaml, .github/workflows/regression-e2e.yaml, ci/test-file-size-budget.json, docs/deployment/install-openclaw-plugins.mdx, docs/get-started/quickstart.mdx, docs/manage-sandboxes/lifecycle.mdx, docs/reference/commands.mdx, docs/reference/troubleshooting.mdx. Strong unit test coverage added but 4 specific gaps remain.
  • PRA-T2 Runtime validation — not-ready-recreate.test.ts: selectPreUpgradeBackupForCreate returns null when liveExists=true. Runtime/sandbox/infrastructure paths need behavioral runtime validation: .github/workflows/e2e.yaml, .github/workflows/regression-e2e.yaml, ci/test-file-size-budget.json, docs/deployment/install-openclaw-plugins.mdx, docs/get-started/quickstart.mdx, docs/manage-sandboxes/lifecycle.mdx, docs/reference/commands.mdx, docs/reference/troubleshooting.mdx. Strong unit test coverage added but 4 specific gaps remain.
  • PRA-T3 Runtime validation — not-ready-recreate.test.ts: selectPreUpgradeBackupForCreate returns null when hasExistingRegistryEntry=false. Runtime/sandbox/infrastructure paths need behavioral runtime validation: .github/workflows/e2e.yaml, .github/workflows/regression-e2e.yaml, ci/test-file-size-budget.json, docs/deployment/install-openclaw-plugins.mdx, docs/get-started/quickstart.mdx, docs/manage-sandboxes/lifecycle.mdx, docs/reference/commands.mdx, docs/reference/troubleshooting.mdx. Strong unit test coverage added but 4 specific gaps remain.
  • PRA-T4 Runtime validation — rebuild-backup-phase.test.ts: legacy pre-v0.0.76 backup (no provenance) blocked from state-preserving rebuild but allowed with NEMOCLAW_RECREATE_WITHOUT_BACKUP=1. Runtime/sandbox/infrastructure paths need behavioral runtime validation: .github/workflows/e2e.yaml, .github/workflows/regression-e2e.yaml, ci/test-file-size-budget.json, docs/deployment/install-openclaw-plugins.mdx, docs/get-started/quickstart.mdx, docs/manage-sandboxes/lifecycle.mdx, docs/reference/commands.mdx, docs/reference/troubleshooting.mdx. Strong unit test coverage added but 4 specific gaps remain.
  • PRA-T5 Runtime validation — openclaw-plugin-runtime-exdev.test.ts: unknown subcommand rejected by OpenShell tmpfs wrapper. Runtime/sandbox/infrastructure paths need behavioral runtime validation: .github/workflows/e2e.yaml, .github/workflows/regression-e2e.yaml, ci/test-file-size-budget.json, docs/deployment/install-openclaw-plugins.mdx, docs/get-started/quickstart.mdx, docs/manage-sandboxes/lifecycle.mdx, docs/reference/commands.mdx, docs/reference/troubleshooting.mdx. Strong unit test coverage added but 4 specific gaps remain.
  • PRA-T6 Missing negative test for reconcile=true with empty installs array — Add test in sandbox-openclaw-plugin-restore.test.ts: manifest with reconcile=true and empty installs should be rejected or require explicit 'no-plugins' marker.
  • PRA-T7 Missing test for selectPreUpgradeBackupForCreate source-of-truth workaround — Add explicit test in not-ready-recreate.test.ts verifying the regression test conditions mentioned in the source-of-truth comment.
  • PRA-T8 Missing test for legacy pre-v0.0.76 custom-image migration path — Add test: pre-v0.0.76 custom-image sandbox (no provenance in backup) is blocked from state-preserving rebuild but can be recreated with NEMOCLAW_RECREATE_WITHOUT_BACKUP=1.
Since last review details

Current findings, using the urgency labels above:

PRA-1 Resolve/justify — Source-of-truth review needed: src/lib/onboard/not-ready-recreate.ts:85 (registry/gateway sync workaround)

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Documented: returns null when liveExists=true and when hasExistingRegistryEntry=false; but no explicit test found
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: Source-of-truth comment at lines 85-92 without issue link

PRA-2 Resolve/justify — Source-of-truth review needed: src/lib/onboard/not-ready-recreate.ts:125 (installer restore flag workaround)

  • Location: not file-specific
  • Category: architecture
  • Problem: The advisor marked localized patch analysis as needs_followup.
  • Impact: A localized workaround can preserve or hide an invalid state when the source boundary is unclear.
  • Recommended action: Identify the invalid state, source boundary, source-fix constraint, regression test, and removal condition before merging the localized behavior.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Missing regression test: Documented but no explicit test found
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Inspect the localized patch and source-of-truth review fields for a concrete invalid state, source boundary, source-fix constraint, regression test, and removal condition.
  • Evidence: Comment at line 125 without REMOVE-WHEN reference

PRA-3 Required — Empty-array provenance bypass in hasCompleteOpenClawImagePluginProvenance

  • Location: src/lib/state/openclaw-plugin-restore.ts:380
  • Category: security
  • Problem: hasCompleteOpenClawImagePluginProvenance([], '/sandbox/.openclaw') returns true, treating an explicit empty array as 'complete provenance'. An attacker who can write a backup manifest can set reconcileOpenClawImagePluginProvenance===true with openclawImagePluginInstalls: [] to bypass provenance checks for a custom-image sandbox that actually had plugins, allowing stale image-owned plugins to be restored as user state during rebuild/restore.
  • Impact: Sandbox escape / trust boundary bypass: malicious or corrupted manifest can cause rebuild/restore to treat image-owned plugins as user state, potentially restoring malicious plugin code with user data permissions.
  • Required action: Add a separate field 'openclawImagePluginProvenanceCaptured: boolean' to RebuildManifest to distinguish 'captured and empty' from 'not captured'. Update hasComplete to check this flag, or require non-empty array when reconcile=true.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: Check hasCompleteOpenClawImagePluginProvenance([], '/sandbox/.openclaw') === true in openclaw-plugin-restore.test.ts line ~350; verify parseOpenClawImagePluginInstalls([], dir) returns ok=true
  • Missing regression test: Add test in sandbox-openclaw-plugin-restore.test.ts: manifest with reconcile=true and empty installs should be rejected or require explicit 'no-plugins' marker
  • Done when: The required change is committed and verification passes: Check hasCompleteOpenClawImagePluginProvenance([], '/sandbox/.openclaw') === true in openclaw-plugin-restore.test.ts line ~350; verify parseOpenClawImagePluginInstalls([], dir) returns ok=true.
  • Evidence: openclaw-plugin-restore.ts:380 comment 'an explicit empty array is complete'; hasAuthoritativeOpenClawImagePluginProvenance only checks reconcile===true AND hasComplete

PRA-4 Required — New monolith: openclaw-plugin-restore.ts at 476 lines (extraction needed)

  • Location: src/lib/state/openclaw-plugin-restore.ts:1
  • Category: architecture
  • Problem: New file at 476 lines handles OpenClaw plugin provenance discovery, validation, restore planning, SQLite/legacy index parsing, SSH command construction, Python inline scripts, path validation, ID sanitization, and restore planning all in one file.
  • Impact: Exceeds 20-line growth threshold for new files. Mixes SSH discovery, Python script generation, validation, and restore planning in one file, increasing review burden and bug surface for security-critical provenance logic.
  • Required action: Extract into focused modules: openclaw-plugin-index-reader.ts (SQLite/legacy parsing), openclaw-plugin-validator.ts (ID/path/loadPath validation), openclaw-plugin-discovery.ts (SSH discovery), openclaw-plugin-restore-planner.ts (planOpenClawPluginRestore). Keep public API surface minimal.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: File is 476 lines; grep for 'export function' shows 8+ exported functions spanning discovery, validation, parsing, planning
  • Missing regression test: N/A - architectural extraction; existing tests should pass after refactor
  • Done when: The required change is committed and verification passes: File is 476 lines; grep for 'export function' shows 8+ exported functions spanning discovery, validation, parsing, planning.
  • Evidence: Single file exports discoverFreshOpenClawPluginExtensionDirs, discoverFreshOpenClawImagePluginInstalls, parseOpenClawImagePluginInstalls, hasCompleteOpenClawImagePluginProvenance, parseFreshOpenClawPluginExtensionDirs, planOpenClawPluginRestore, plus SSH/Python command builders

PRA-5 Required — Monolith growth: openclaw-config-merge.ts +164 lines, test +262 lines

  • Location: src/lib/state/openclaw-config-merge.ts:1
  • Category: architecture
  • Problem: openclaw-config-merge.ts grew +164 lines (now 468), test grew +262 lines (now 650). Plugin provenance ownership computation and plugin-specific merge functions (mergeOpenClawPlugins, mergeOpenClawEntryMap, mergeOpenClawPluginLoad, mergeOpenClawPluginIdList, mergeOpenClawPluginSlots) are mixed with core config merge logic.
  • Impact: Plugin-specific merge logic mixed with gateway/models/channels/tools merge increases cognitive load and coupling. Harder to verify ownership semantics are correct for plugin provenance.
  • Required action: Extract plugin provenance ownership computation and plugin-specific merge functions into openclaw-plugin-config-merge.ts. Keep core config merge (gateway, models, channels, tools) in openclaw-config-merge.ts.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: File grew from 304 to 468 lines; grep 'mergeOpenClawPlugin' shows 5 plugin-specific merge functions
  • Missing regression test: N/A - architectural extraction; existing merge tests should pass after refactor
  • Done when: The required change is committed and verification passes: File grew from 304 to 468 lines; grep 'mergeOpenClawPlugin' shows 5 plugin-specific merge functions.
  • Evidence: mergeOpenClawPlugins, mergeOpenClawEntryMap, mergeOpenClawPluginLoad, mergeOpenClawPluginIdList, mergeOpenClawPluginSlots all in one file with core mergeOpenClawRestoredConfig

PRA-6 Required — Monolith growth: sandbox.ts +185 lines with provenance validation mixed in

  • Location: src/lib/state/sandbox.ts:234
  • Category: architecture
  • Problem: sandbox.ts grew +185 lines (now 1990) with provenance validation functions (hasAuthoritativeOpenClawImagePluginProvenance, OPENCLAW_IMAGE_PLUGIN_PROVENANCE_RESTORE_ERROR) mixed into backup/restore mechanics.
  • Impact: Provenance validation logic mixed with tar extraction, backup/restore, symlink auditing increases file complexity and couples security-critical provenance checks with mechanical backup operations.
  • Required action: Move provenance validation functions to openclaw-plugin-restore.ts or new openclaw-provenance-guard.ts. Keep sandbox.ts focused on backup/restore mechanics.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: grep 'hasAuthoritativeOpenClawImagePluginProvenance\|OPENCLAW_IMAGE_PLUGIN_PROVENANCE_RESTORE_ERROR' in sandbox.ts shows provenance logic mixed with tar/backup logic
  • Missing regression test: N/A - architectural extraction; existing sandbox tests should pass after refactor
  • Done when: The required change is committed and verification passes: grep 'hasAuthoritativeOpenClawImagePluginProvenance\|OPENCLAW_IMAGE_PLUGIN_PROVENANCE_RESTORE_ERROR' in sandbox.ts shows provenance logic mixed with tar/backup logic.
  • Evidence: hasAuthoritativeOpenClawImagePluginProvenance and OPENCLAW_IMAGE_PLUGIN_PROVENANCE_RESTORE_ERROR defined in sandbox.ts alongside backupSandboxState, restoreRecreatedSandboxState, validateTarEntries

PRA-7 Required — Monolith growth: created-sandbox-finalization.ts +49 lines, test +244 lines

  • Location: src/lib/onboard/created-sandbox-finalization.ts:1
  • Category: architecture
  • Problem: created-sandbox-finalization.ts grew +49 lines (now 143), test grew +244 lines (now 630). Handles plugin discovery, restore validation, DCode validation, and registration all in one orchestrator.
  • Impact: Four distinct responsibilities in one function: discovery, restore, DCode validation, registration. Test file at 630 lines with 15+ test cases covering all paths.
  • Required action: Extract plugin discovery into discoverFreshOpenClawImagePluginInstalls caller, restore validation into validateCustomOpenClawRestore, DCode validation into validateManagedDcodeRoute. Keep finalizeCreatedSandbox as orchestrator.
  • Expected follow-up: Fix before merge or get explicit maintainer override.
  • Verification: File has 4 distinct responsibilities: discovery, restore, DCode validation, registration; test file has 15+ test cases covering all paths
  • Missing regression test: N/A - architectural extraction; existing tests should pass after refactor
  • Done when: The required change is committed and verification passes: File has 4 distinct responsibilities: discovery, restore, DCode validation, registration; test file has 15+ test cases covering all paths.
  • Evidence: finalizeCreatedSandbox does discovery, then restore, then DCode validation, then register - each with distinct error handling and bail paths

PRA-8 Resolve/justify — Weather fixture lockfile has 9 vulnerable packages in dev dependency graph

  • Location: test/e2e/fixtures/plugins/weather/package-lock.json:1
  • Category: security
  • Problem: Weather fixture lockfile has 9 vulnerable packages in OpenClaw 2026.5.27 dev dependency graph (3 moderate, 6 high). Advisory IDs include GHSA-22p9-wv53-3rq4, GHSA-2gcr-mfcq-wcc3, GHSA-35p6-xmwp-9g52, etc. Documented as accepted residual risk in e2e-weather-plugin-fixture-dependency-review.md.
  • Impact: Vulnerabilities in dev dependencies could affect fixture build; registry packages can later be found vulnerable or compromised. Accepted residual risk limited to secret-free E2E lane with read-only contents permission.
  • Recommended action: Explicitly accept as documented residual risk per the review doc with compensating controls (exact versions, lockfile integrity, npm ci --ignore-scripts, dev/peer prune, secret-free workflow). Re-audit on any fixture manifest/lockfile change.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Run 'npm audit --package-lock-only --ignore-scripts --json' from test/e2e/fixtures/plugins/weather; exits 1 with 9 vulnerable packages
  • Missing regression test: test/e2e-fixture-dependency-review.test.ts should fail if fixture lockfile changes without review doc update
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Run 'npm audit --package-lock-only --ignore-scripts --json' from test/e2e/fixtures/plugins/weather; exits 1 with 9 vulnerable packages.
  • Evidence: e2e-weather-plugin-fixture-dependency-review.md documents advisories and compensating controls; test/e2e-fixture-dependency-review.test.ts enforces review binding

PRA-9 Resolve/justify — OpenShell tmpfs wrapper delegates all non-create commands without allowlist

  • Location: test/e2e/live/openclaw-plugin-runtime-exdev.test.ts:180
  • Category: security
  • Problem: OpenShell tmpfs wrapper delegates all non-create commands without allowlist. Only intercepts 'sandbox create' to inject tmpfs config; all other subcommands (sandbox delete, gateway, exec, etc.) pass through unchecked.
  • Impact: Defense-in-depth gap: wrapper could delegate unsafe subcommands if real OpenShell adds dangerous commands in future. No explicit allowlist of known-safe delegated commands.
  • Recommended action: Add explicit allowlist of delegated subcommands or deny unknown subcommands for defense-in-depth. The wrapper should only pass through known-safe commands.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: createOpenShellTmpfsWrapper only checks for 'sandbox create'; everything else falls through to 'exec realOpenshell "$@"'
  • Missing regression test: Add test: unknown subcommand should be rejected or at least logged; verify wrapper doesn't delegate 'gateway' or 'exec' commands
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: createOpenShellTmpfsWrapper only checks for 'sandbox create'; everything else falls through to 'exec realOpenshell "$@"'.
  • Evidence: Wrapper script at line 180: only 'sandbox create' intercepted; default case 'exec realOpenshell "$@"'

PRA-10 Resolve/justify — Duplicate customOpenClaw determination logic across 6 files

  • Location: src/lib/onboard/not-ready-recreate.ts:95
  • Category: correctness
  • Problem: Duplicate customOpenClaw determination logic across 6 files: onboard.ts:2396, not-ready-recreate.ts:81, sandbox-backup-on-recreate.ts:40, rebuild-backup-phase.ts:151, sandbox-recreate-protection.ts (via parameter), custom-openclaw-runtime-diagnosis.ts:49.
  • Impact: Inconsistent updates risk: if logic changes (e.g., agent name comparison), 6 locations must be updated. DRY violation in security-critical path.
  • Recommended action: Centralize in a single utility function isCustomOpenClawImage(sandboxEntry) used by all six files.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: grep 'customOpenClaw\|fromDockerfile.*openclaw' shows 6+ occurrences with identical logic
  • Missing regression test: Add unit test for isCustomOpenClawImage utility covering all entry shapes (fromDockerfile + openclaw agent, fromDockerfile + no agent, managed image, etc.)
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: grep 'customOpenClaw\|fromDockerfile.*openclaw' shows 6+ occurrences with identical logic.
  • Evidence: All 6 locations use: Boolean(entry?.fromDockerfile) && (!entry?.agent || entry.agent === 'openclaw')

PRA-11 Resolve/justify — Source-of-truth workaround for registry/gateway sync lacks tracking issue

  • Location: src/lib/onboard/not-ready-recreate.ts:85
  • Category: architecture
  • Problem: Source-of-truth workaround for registry/gateway sync inconsistency lacks tracking issue. Comment says 'a real fix needs atomic registry/gateway sync, which is out of scope for this PR' but no issue number linked.
  • Impact: Workaround may become permanent without tracking. No visibility on when atomic sync will be implemented.
  • Recommended action: Link a tracking issue for atomic registry/gateway sync in the source-of-truth comment (e.g., 'REMOVE-WHEN: #XXXX supplies atomic registry/gateway sync').
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Lines 85-92 in not-ready-recreate.ts have source-of-truth comment without issue reference
  • Missing regression test: N/A - documentation/linking fix
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Lines 85-92 in not-ready-recreate.ts have source-of-truth comment without issue reference.
  • Evidence: Comment block at line 85: 'Source-of-truth review for the two drift returns below... source-fix constraint = a real fix needs atomic registry/gateway sync, which is out of scope for this PR'

PRA-12 Resolve/justify — Second registry/gateway sync workaround lacks tracking issue

  • Location: src/lib/onboard/not-ready-recreate.ts:125
  • Category: correctness
  • Problem: Second registry/gateway sync workaround at line 125 also lacks tracking issue link.
  • Impact: Same as PRA-9: workaround may become permanent without tracking issue reference.
  • Recommended action: Link to tracking issue for atomic registry/gateway sync (e.g., 'REMOVE-WHEN: #XXXX supplies atomic registry/gateway sync').
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Line 125 comment 'Installer contract: the installer MUST set NEMOCLAW_RESTORE_LATEST_BACKUP_ON_RECREATE=1...' has no REMOVE-WHEN reference
  • Missing regression test: N/A - documentation/linking fix
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Line 125 comment 'Installer contract: the installer MUST set NEMOCLAW_RESTORE_LATEST_BACKUP_ON_RECREATE=1...' has no REMOVE-WHEN reference.
  • Evidence: Comment at line 125 discusses installer contract but no REMOVE-WHEN or issue link

PRA-13 Resolve/justify — Legacy pre-v0.0.76 custom-image migration path lacks test coverage

  • Location: docs/deployment/install-openclaw-plugins.mdx:380
  • Category: correctness
  • Problem: Legacy pre-v0.0.76 custom-image migration path documented but lacks test coverage. Docs say 'Custom-image sandboxes created before v0.0.76 cannot enter the state-preserving path automatically when they lack recorded provenance. Keep the older sandbox intact, onboard the current release under a different name, and migrate its state manually.'
  • Impact: Undocumented behavior change risk: if legacy migration path breaks, no test will catch it. Users following docs may encounter unexpected failures.
  • Recommended action: Add test: pre-v0.0.76 custom-image sandbox (no provenance in backup) is blocked from state-preserving rebuild but can be recreated with NEMOCLAW_RECREATE_WITHOUT_BACKUP=1.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: No test in sandbox-openclaw-plugin-restore.test.ts or rebuild-backup-phase.test.ts covers pre-v0.0.76 backup without provenance
  • Missing regression test: Add test proving legacy custom-image sandbox without provenance is blocked from state-preserving rebuild but allowed to recreate with NEMOCLAW_RECREATE_WITHOUT_BACKUP=1
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: No test in sandbox-openclaw-plugin-restore.test.ts or rebuild-backup-phase.test.ts covers pre-v0.0.76 backup without provenance.
  • Evidence: Docs at line 380 describe legacy behavior but no corresponding test in sandbox-openclaw-plugin-restore.test.ts or rebuild-backup-phase.test.ts

PRA-14 Resolve/justify — New 130-minute E2E job increases CI attack surface

  • Location: .github/workflows/e2e.yaml:3870
  • Category: security
  • Problem: New openclaw-plugin-runtime-exdev job has 130-minute timeout (three 25-minute onboards + 20-minute rebuild + 15-minute buffer + 20-minute setup/teardown). Increases CI attack surface and resource consumption.
  • Impact: Long-running CI job expands attack surface for supply chain compromise; consumes runner resources for extended period.
  • Recommended action: Consider splitting into smaller jobs or reducing timeout. Document why 130 minutes is necessary and cannot be reduced.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Job definition shows timeout-minutes: 130 with comment explaining three bounded 25-minute onboards
  • Missing regression test: N/A - CI architecture decision
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Job definition shows timeout-minutes: 130 with comment explaining three bounded 25-minute onboards.
  • Evidence: e2e.yaml job 'openclaw-plugin-runtime-exdev' has timeout-minutes: 130

PRA-15 Resolve/justify — 5153-line committed fixture lockfile expands supply chain surface

  • Location: test/e2e/fixtures/plugins/weather/package-lock.json:1
  • Category: architecture
  • Problem: 5153-line committed fixture lockfile expands supply chain surface. While documented as intentional for determinism, the size is a maintenance burden.
  • Impact: Large lockfile increases review burden for dependency changes; harder to audit transitive dependencies; maintenance burden on fixture updates.
  • Recommended action: Document the lockfile size rationale clearly. Consider if a smaller fixture or generated lockfile with pinned dependencies could achieve the same test coverage with less maintenance burden.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: wc -l test/e2e/fixtures/plugins/weather/package-lock.json shows 5153 lines
  • Missing regression test: N/A - architectural decision documentation
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: wc -l test/e2e/fixtures/plugins/weather/package-lock.json shows 5153 lines.
  • Evidence: Lockfile is 5153 lines with full OpenClaw 2026.5.27 dev dependency graph; e2e-weather-plugin-fixture-dependency-review.md documents rationale

PRA-16 Improvement — Complex curl wrapper for gateway tool call could be simplified

  • Location: docs/deployment/install-openclaw-plugins.mdx:186
  • Category: docs
  • Problem: Complex curl wrapper for gateway tool call uses heredoc/config piping. Could be simplified to show direct openclaw plugins inspect + curl without heredoc/config piping. Keep only the proxy env sourcing as NemoClaw-specific.
  • Impact: Documentation complexity obscures the actual verification steps; users may copy-paste without understanding.
  • Suggested action: Simplify to show direct openclaw plugins inspect + curl without heredoc/config piping. Keep only the proxy env sourcing as NemoClaw-specific.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Lines 186-195 show multi-line curl with --config - and heredoc for Authorization header
  • Missing regression test: N/A - documentation simplification
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Verification section uses: . /tmp/nemoclaw-proxy-env.sh && printf 'header = "Authorization: Bearer %s"\n' "$OPENCLAW_GATEWAY_TOKEN" | curl --noproxy '*' --max-time 30 --silent --show-error --fail-with-body --config - -H 'Content-Type: application/json' ...

PRA-17 Improvement — Fixture review doc uses test-scaffold framing unnecessarily

  • Location: docs/security/e2e-weather-plugin-fixture-dependency-review.md:1
  • Category: docs
  • Problem: Fixture review doc uses test-scaffold framing (test fixtures, test-only, etc.) unnecessarily. Technical content is solid but structure is verbose.
  • Impact: Documentation structure adds cognitive overhead; reviewers must filter through test-scaffold language to find security content.
  • Suggested action: Convert to simple SECURITY_REVIEW.md format without test-scaffold framing. Keep all technical content but simplify structure.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: Doc has 'Checked-in Fixture Waiver', 'Accepted Residual Risk', 'Compensating Controls', 'Advisory Audit', 'Enforcement and Removal' sections with test-scaffold language
  • Missing regression test: N/A - documentation simplification
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: Sections use test-scaffold framing: 'The following fixture lockfile is intentionally committed and covered by this review', 'This waiver is limited to test fixture code'

PRA-18 Improvement — registry.ts at 722 lines - extraction candidate for provenance types

  • Location: src/lib/state/registry.ts:1
  • Category: architecture
  • Problem: registry.ts at 722 lines (+9) is an extraction candidate for provenance types. Consider extracting provenance-related types and validation to openclaw-provenance-guard.ts alongside sandbox.ts extraction (PRA-4).
  • Impact: Provenance types mixed with registry CRUD operations increases file size and couples distinct concerns.
  • Suggested action: Extract provenance-related types and validation to openclaw-provenance-guard.ts alongside sandbox.ts extraction.
  • Expected follow-up: Prefer a current-PR fix when local to changed code; defer only with rationale or linked follow-up.
  • Verification: File has grown to 722 lines; provenance types mixed with registry CRUD operations
  • Missing regression test: N/A - architectural extraction
  • Done when: The local improvement is applied, or the PR notes why it should be deferred.
  • Evidence: registry.ts contains SandboxEntry, RebuildManifest types with provenance fields alongside registry CRUD functions

PRA-19 Resolve/justify — Missing negative test for reconcile=true with empty installs array

  • Location: src/lib/state/openclaw-plugin-restore.test.ts:350
  • Category: tests
  • Problem: Missing runtime validation test follow-up: the empty-array provenance bypass (PRA-1) has no negative test proving the vulnerability or the fix.
  • Impact: No test guards against regression of the empty-array bypass vulnerability.
  • Recommended action: Add test in sandbox-openclaw-plugin-restore.test.ts: manifest with reconcile=true and empty installs should be rejected or require explicit 'no-plugins' marker.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: openclaw-plugin-restore.test.ts line 350 shows 'distinguishes complete empty provenance from missing legacy provenance' test but no negative case for reconcile=true with empty array
  • Missing regression test: Add negative test: hasCompleteOpenClawImagePluginProvenance([], dir) should be false when reconcile=true context is implied
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: openclaw-plugin-restore.test.ts line 350 shows 'distinguishes complete empty provenance from missing legacy provenance' test but no negative case for reconcile=true with empty array.
  • Evidence: Test 'distinguishes complete empty provenance from missing legacy provenance' checks hasCompleteOpenClawImagePluginProvenance([], OPENCLAW_DIR) === true but no test for hasAuthoritativeOpenClawImagePluginProvenance with empty installs and reconcile=true

PRA-20 Resolve/justify — Missing test for selectPreUpgradeBackupForCreate source-of-truth workaround

  • Location: src/lib/onboard/not-ready-recreate.ts:85
  • Category: tests
  • Problem: Missing test for selectPreUpgradeBackupForCreate source-of-truth workaround. The comment describes invalid state (registry/gateway inconsistency), source boundary (pruneStaleSandboxEntry is best-effort), source-fix constraint (atomic sync out of scope), regression test (returns null when liveExists=true or hasExistingRegistryEntry=false), and removal condition (drop guards once atomic sync exists).
  • Impact: Workaround behavior not verified by tests; regression could silently change the drift handling.
  • Recommended action: Add explicit test in not-ready-recreate.test.ts verifying the regression test conditions mentioned in the source-of-truth comment.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: not-ready-recreate.test.ts should have tests for liveExists=true and hasExistingRegistryEntry=false returning null
  • Missing regression test: Add tests: selectPreUpgradeBackupForCreate returns null when liveExists=true; returns null when hasExistingRegistryEntry=false
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: not-ready-recreate.test.ts should have tests for liveExists=true and hasExistingRegistryEntry=false returning null.
  • Evidence: Source-of-truth comment at line 85 lists regression test conditions but no corresponding tests found in not-ready-recreate.test.ts

Workflow run details

This is an automated, non-binding review; it still expects maintainers and agents to respond to each required or warning item. Treat suggestions as current-PR improvements when they touch changed code; defer only with maintainer rationale or a linked follow-up. A human maintainer must make the final merge decision.

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

PR Review Advisor — Changes requested

Merge posture: Do not merge yet
Primary next action: Resolve or justify PRA-1: New custom-image help links still point at the wrong docs route.
Open items: 0 required · 2 warnings · 0 suggestions · 5 test follow-ups
Since last review: 0 prior items resolved · 2 still apply · 0 new items found

Action checklist

  • PRA-1 Resolve or justify: New custom-image help links still point at the wrong docs route in docs/reference/commands.mdx:604
  • PRA-2 Resolve or justify: Known vulnerable fixture dependency graph remains in the trusted E2E lane in docs/security/e2e-weather-plugin-fixture-dependency-review.md:43
  • PRA-T1 Add or justify test follow-up: Runtime validation
  • PRA-T2 Add or justify test follow-up: Runtime validation
  • PRA-T3 Add or justify test follow-up: Runtime validation
  • PRA-T4 Add or justify test follow-up: Acceptance clause
  • PRA-T5 Add or justify test follow-up: Acceptance clause

Findings index

ID Severity Category Location Required action
PRA-1 Resolve/justify docs docs/reference/commands.mdx:604 Update the new links in `docs/reference/commands.mdx` and `docs/reference/troubleshooting.mdx` to the actual deployment route, for example `../deployment/install-openclaw-plugins` from the reference pages, or add the intended route if the docs generator expects a different location.
PRA-2 Resolve/justify security docs/security/e2e-weather-plugin-fixture-dependency-review.md:43 Resolve or explicitly justify this residual risk before merge: shrink the fixture to avoid the vulnerable release-pinned graph while preserving the custom-plugin lifecycle proof, or keep the waiver with maintainer-visible acceptance that the lane remains secret-free/read-only and that the lockfile must be revalidated whenever it changes.
Review findings by urgency: 0 required fixes, 2 items to resolve/justify, 0 in-scope improvements

⚠️ Resolve or justify before merge

Investigate these in the current review; either fix them, explain why they are not applicable, or document the accepted risk.

PRA-1 Resolve/justify — New custom-image help links still point at the wrong docs route

  • Location: docs/reference/commands.mdx:604
  • Category: docs
  • Problem: The new custom OpenClaw image recovery guidance links to `../manage-sandboxes/install-openclaw-plugins` from both the commands reference and troubleshooting page, but the guide added by this PR lives at `docs/deployment/install-openclaw-plugins.mdx`. This repeats the prior Advisor finding and still applies at the current head.
  • Impact: Users who hit the base-only custom image diagnostic can be sent to a missing page instead of the version-matched full-runtime plugin recipe, increasing the chance they retry unsafe custom images or migrate state manually without the new provenance guidance.
  • Recommended action: Update the new links in `docs/reference/commands.mdx` and `docs/reference/troubleshooting.mdx` to the actual deployment route, for example `../deployment/install-openclaw-plugins` from the reference pages, or add the intended route if the docs generator expects a different location.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read `docs/reference/commands.mdx` around the custom OpenClaw image paragraph and `docs/reference/troubleshooting.mdx` around `Custom OpenClaw image creates without a gateway or dashboard`, then compare with `find docs -path '*install-openclaw-plugins.mdx'`; the only matching file is `docs/deployment/install-openclaw-plugins.mdx`.
  • Missing regression test: Add or extend docs link validation so the `Install OpenClaw Plugins` links from `docs/reference/commands.mdx` and `docs/reference/troubleshooting.mdx` resolve to `docs/deployment/install-openclaw-plugins.mdx`.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read `docs/reference/commands.mdx` around the custom OpenClaw image paragraph and `docs/reference/troubleshooting.mdx` around `Custom OpenClaw image creates without a gateway or dashboard`, then compare with `find docs -path '*install-openclaw-plugins.mdx'`; the only matching file is `docs/deployment/install-openclaw-plugins.mdx`.
  • Evidence: `docs/reference/commands.mdx` says `refer to [Install OpenClaw Plugins](../manage-sandboxes/install-openclaw-plugins)`, and `docs/reference/troubleshooting.mdx` uses the same target, while the repository contains `docs/deployment/install-openclaw-plugins.mdx` and no `docs/manage-sandboxes/install-openclaw-plugins.mdx`.

PRA-2 Resolve/justify — Known vulnerable fixture dependency graph remains in the trusted E2E lane

  • Location: docs/security/e2e-weather-plugin-fixture-dependency-review.md:43
  • Category: security
  • Problem: The weather plugin fixture lockfile is intentionally committed, and the review document records an `npm audit` result with 9 vulnerable packages, including high-severity advisories, in the release-pinned OpenClaw development graph. The workflow boundary mitigates this with read-only permissions, no repository secrets during fixture execution, SHA/digest pinning, `npm ci --ignore-scripts`, and pruning dev/peer dependencies before staging, but vulnerable package code still participates in fixture compilation and the test runtime.
  • Impact: If one of the pinned vulnerable packages is exploitable in the fixture build or runtime path, a scheduled trusted E2E run could execute vulnerable package code. The current controls reduce credential and repository-write exposure but do not remove the vulnerable code from the trusted test boundary.
  • Recommended action: Resolve or explicitly justify this residual risk before merge: shrink the fixture to avoid the vulnerable release-pinned graph while preserving the custom-plugin lifecycle proof, or keep the waiver with maintainer-visible acceptance that the lane remains secret-free/read-only and that the lockfile must be revalidated whenever it changes.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read `docs/security/e2e-weather-plugin-fixture-dependency-review.md` under `Advisory Audit`, then compare it with `test/e2e/fixtures/plugins/weather/package-lock.json`, `test/e2e-fixture-dependency-review.test.ts`, and the `openclaw-plugin-runtime-exdev` job in `.github/workflows/e2e.yaml` to confirm the advisory list and compensating controls.
  • Missing regression test: Existing `test/e2e-fixture-dependency-review.test.ts` binds the lockfile digest and required controls. If the waiver remains, add or keep a dependency-review freshness assertion that fails when `test/e2e/fixtures/plugins/weather/package-lock.json` changes without a refreshed advisory date/count and confirmation that the workflow remains no-secrets/read-only.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read `docs/security/e2e-weather-plugin-fixture-dependency-review.md` under `Advisory Audit`, then compare it with `test/e2e/fixtures/plugins/weather/package-lock.json`, `test/e2e-fixture-dependency-review.test.ts`, and the `openclaw-plugin-runtime-exdev` job in `.github/workflows/e2e.yaml` to confirm the advisory list and compensating controls.
  • Evidence: The review document states `npm audit exited 1 and reported 9 vulnerable packages (3 moderate and 6 high...)` and lists affected packages including `openclaw`, `tar`, `undici`, and others; the new scheduled workflow job runs the fixture in the `openclaw-plugin-runtime-exdev` lane.

💡 In-scope improvements

These are lower-risk, not throwaway. Prefer fixing them in this PR when they are local to changed code; defer only with rationale or a linked follow-up.

  • None.
Test follow-ups to resolve or justify

If these cover changed behavior, prefer adding them in this PR; otherwise state why existing coverage is enough or link the follow-up.

  • PRA-T1 Runtime validation — Docs link validation resolves `Install OpenClaw Plugins` links from `docs/reference/commands.mdx` and `docs/reference/troubleshooting.mdx` to `docs/deployment/install-openclaw-plugins.mdx`.. Unit and flow coverage is strong for provenance validation, restore merge ownership, negative paths, workflow structure, and fixture dependency controls. Because this PR changes Docker/OpenShell/onboard/rebuild behavior and adds a live workflow lane, behavior-specific runtime validation remains appropriate; external E2E pass/fail status is outside this review.
  • PRA-T2 Runtime validation — Fixture dependency waiver freshness fails when `test/e2e/fixtures/plugins/weather/package-lock.json` changes without updating the advisory date/count and confirming the workflow remains no-secrets/read-only.. Unit and flow coverage is strong for provenance validation, restore merge ownership, negative paths, workflow structure, and fixture dependency controls. Because this PR changes Docker/OpenShell/onboard/rebuild behavior and adds a live workflow lane, behavior-specific runtime validation remains appropriate; external E2E pass/fail status is outside this review.
  • PRA-T3 Runtime validation — Runtime validation for the custom OpenClaw plugin lifecycle exercises onboarding, gateway restart, same-name recreation, rebuild, workspace preservation, and EXDEV-safe runtime dependency replacement using the `openclaw-plugin-runtime-exdev` lane.. Unit and flow coverage is strong for provenance validation, restore merge ownership, negative paths, workflow structure, and fixture dependency controls. Because this PR changes Docker/OpenShell/onboard/rebuild behavior and adds a live workflow lane, behavior-specific runtime validation remains appropriate; external E2E pass/fail status is outside this review.
  • PRA-T4 Acceptance clause — Deterministic linked issue clauses — add test evidence or identify existing coverage. The trusted validation context reported `linkedIssues: []`, so there were no deterministic linked issue clauses or issue comments available to extract literally. PR-body references to Unable to install custom plugin with NemoClaw (OpenClaw) #6108/[Ubuntu 22.04][Agent] openclaw CLI fails to start in sandbox — plugin runtime install errors #3513/EXDEV: cross-device link not permitted — plugin installer fails when /tmp is overlay and /sandbox is ext4 #3127/VoiceClaw integration via existing messaging and provider contracts #5998 were treated as untrusted scope context only.
  • PRA-T5 Acceptance clause — PR body (untrusted): Document the full-image plugin recipe, troubleshooting guidance, dependency risk controls, and the explicit `REMOVE-WHEN` condition. — add test evidence or identify existing coverage. `docs/deployment/install-openclaw-plugins.mdx`, `docs/reference/troubleshooting.mdx`, `docs/security/e2e-weather-plugin-fixture-dependency-review.md`, and `src/lib/onboard/custom-openclaw-runtime-diagnosis.ts` add the requested guidance, risk controls, and `REMOVE-WHEN`; however, the new reference/troubleshooting links point to `../manage-sandboxes/install-openclaw-plugins` instead of the actual `docs/deployment/install-openclaw-plugins.mdx` route.
Since last review details

Current findings, using the urgency labels above:

PRA-1 Resolve/justify — New custom-image help links still point at the wrong docs route

  • Location: docs/reference/commands.mdx:604
  • Category: docs
  • Problem: The new custom OpenClaw image recovery guidance links to `../manage-sandboxes/install-openclaw-plugins` from both the commands reference and troubleshooting page, but the guide added by this PR lives at `docs/deployment/install-openclaw-plugins.mdx`. This repeats the prior Advisor finding and still applies at the current head.
  • Impact: Users who hit the base-only custom image diagnostic can be sent to a missing page instead of the version-matched full-runtime plugin recipe, increasing the chance they retry unsafe custom images or migrate state manually without the new provenance guidance.
  • Recommended action: Update the new links in `docs/reference/commands.mdx` and `docs/reference/troubleshooting.mdx` to the actual deployment route, for example `../deployment/install-openclaw-plugins` from the reference pages, or add the intended route if the docs generator expects a different location.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read `docs/reference/commands.mdx` around the custom OpenClaw image paragraph and `docs/reference/troubleshooting.mdx` around `Custom OpenClaw image creates without a gateway or dashboard`, then compare with `find docs -path '*install-openclaw-plugins.mdx'`; the only matching file is `docs/deployment/install-openclaw-plugins.mdx`.
  • Missing regression test: Add or extend docs link validation so the `Install OpenClaw Plugins` links from `docs/reference/commands.mdx` and `docs/reference/troubleshooting.mdx` resolve to `docs/deployment/install-openclaw-plugins.mdx`.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read `docs/reference/commands.mdx` around the custom OpenClaw image paragraph and `docs/reference/troubleshooting.mdx` around `Custom OpenClaw image creates without a gateway or dashboard`, then compare with `find docs -path '*install-openclaw-plugins.mdx'`; the only matching file is `docs/deployment/install-openclaw-plugins.mdx`.
  • Evidence: `docs/reference/commands.mdx` says `refer to [Install OpenClaw Plugins](../manage-sandboxes/install-openclaw-plugins)`, and `docs/reference/troubleshooting.mdx` uses the same target, while the repository contains `docs/deployment/install-openclaw-plugins.mdx` and no `docs/manage-sandboxes/install-openclaw-plugins.mdx`.

PRA-2 Resolve/justify — Known vulnerable fixture dependency graph remains in the trusted E2E lane

  • Location: docs/security/e2e-weather-plugin-fixture-dependency-review.md:43
  • Category: security
  • Problem: The weather plugin fixture lockfile is intentionally committed, and the review document records an `npm audit` result with 9 vulnerable packages, including high-severity advisories, in the release-pinned OpenClaw development graph. The workflow boundary mitigates this with read-only permissions, no repository secrets during fixture execution, SHA/digest pinning, `npm ci --ignore-scripts`, and pruning dev/peer dependencies before staging, but vulnerable package code still participates in fixture compilation and the test runtime.
  • Impact: If one of the pinned vulnerable packages is exploitable in the fixture build or runtime path, a scheduled trusted E2E run could execute vulnerable package code. The current controls reduce credential and repository-write exposure but do not remove the vulnerable code from the trusted test boundary.
  • Recommended action: Resolve or explicitly justify this residual risk before merge: shrink the fixture to avoid the vulnerable release-pinned graph while preserving the custom-plugin lifecycle proof, or keep the waiver with maintainer-visible acceptance that the lane remains secret-free/read-only and that the lockfile must be revalidated whenever it changes.
  • Expected follow-up: Resolve in this PR or explain why the risk is acceptable.
  • Verification: Read `docs/security/e2e-weather-plugin-fixture-dependency-review.md` under `Advisory Audit`, then compare it with `test/e2e/fixtures/plugins/weather/package-lock.json`, `test/e2e-fixture-dependency-review.test.ts`, and the `openclaw-plugin-runtime-exdev` job in `.github/workflows/e2e.yaml` to confirm the advisory list and compensating controls.
  • Missing regression test: Existing `test/e2e-fixture-dependency-review.test.ts` binds the lockfile digest and required controls. If the waiver remains, add or keep a dependency-review freshness assertion that fails when `test/e2e/fixtures/plugins/weather/package-lock.json` changes without a refreshed advisory date/count and confirmation that the workflow remains no-secrets/read-only.
  • Done when: The risk is fixed or explicitly justified in the PR. Verification: Read `docs/security/e2e-weather-plugin-fixture-dependency-review.md` under `Advisory Audit`, then compare it with `test/e2e/fixtures/plugins/weather/package-lock.json`, `test/e2e-fixture-dependency-review.test.ts`, and the `openclaw-plugin-runtime-exdev` job in `.github/workflows/e2e.yaml` to confirm the advisory list and compensating controls.
  • Evidence: The review document states `npm audit exited 1 and reported 9 vulnerable packages (3 moderate and 6 high...)` and lists affected packages including `openclaw`, `tar`, `undici`, and others; the new scheduled workflow job runs the fixture in the `openclaw-plugin-runtime-exdev` lane.

Workflow run details

This is an automated, non-binding review; it still expects maintainers and agents to respond to each required or warning item. Treat suggestions as current-PR improvements when they touch changed code; defer only with maintainer rationale or a linked follow-up. A human maintainer must make the final merge decision.

@cjagwani

cjagwani commented Jul 8, 2026

Copy link
Copy Markdown
Collaborator Author

Current-head maintainer disposition for advisor items at 2ce21b63e02202c2bf7b810f3adaaa817885a94d:

  • Empty-array provenance is intentional, not a bypass. reconcileOpenClawImagePluginProvenance: true is already the separate “captured and authoritative” marker the advisor proposes. With that marker, openclawImagePluginInstalls: [] means the image baseline was captured with zero plugins, so stale image-owned target plugins must be removed. Missing/legacy provenance is undefined, which fails hasCompleteOpenClawImagePluginProvenance; backup also refuses a custom image whose registry provenance is missing or invalid before creating the manifest. Tests explicitly cover empty-authoritative versus missing. A second equivalent boolean would not strengthen the boundary.
  • The docs links are correct for the published route. The source file is under docs/deployment, but docs/index.yml publishes it under the manage-sandboxes section. scripts/check-docs-published-routes.ts documents this exact source-path/published-route trap and npm run docs:check-routes passes. Changing the links to ../deployment/... would create the live 404.
  • Fixture advisory risk is explicitly accepted for this release-matched E2E. The reviewed document records the current 9-package advisory set and lockfile digest. Compensating controls are exact versions and registry integrity, npm ci --ignore-scripts, dev/peer pruning before staging, read-only workflow permissions, removed Docker auth, no repository secrets, and path-scoped artifacts. Any fixture manifest/lock change requires re-audit.
  • The OpenShell wrapper is test-only and intentionally delegates. It verifies an absolute executable with X_OK, intercepts only sandbox create to inject the EXDEV tmpfs driver, rejects duplicate driver config, and must delegate the remaining controlled lifecycle commands to exercise the real CLI. It is not a production or user-input command boundary.
  • Architecture findings are accepted, not merge blockers. The new plugin module is already a focused extraction; further splitting the validated discovery/planning pipeline now would increase lifecycle risk without changing behavior. Exact-head codebase growth guardrails pass, and the focused modules have broad behavioral tests.
  • Registry/gateway atomicity now has a removal-condition tracker: refactor(state): make registry and gateway lifecycle updates atomic #6492. The current guards remain fail-closed until that lifecycle protocol exists.
  • Legacy and negative paths have unit/integration coverage; live confidence is being refreshed. The advisor-required eight-lane run is 28971548139: onboard-resume, onboard-repair, cloud-onboard, openclaw-plugin-runtime-exdev, rebuild-openclaw, sandbox-rebuild, state-backup-restore, and upgrade-stale-sandbox.

No source change is warranted for the two top advisor findings. Independent review and the live run remain merge gates.

@cjagwani
cjagwani requested a review from miyoungc July 8, 2026 19:58

@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: 6

🧹 Nitpick comments (4)
src/lib/state/registry.ts (1)

511-516: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Duplicate clone logic for openclawImagePluginInstalls.

This inline clone (spread + loadPaths copy) duplicates cloneOpenClawImagePluginInstalls in src/lib/state/sandbox.ts (which is not exported). Since hasAuthoritativeOpenClawImagePluginProvenance in sandbox.ts depends on this shape being cloned consistently for provenance validation, having two independent implementations risks silent drift if one is updated without the other.

Consider exporting a single clone helper (e.g. from openclaw-plugin-restore.ts, which registry.ts already imports from) and reusing it in both registry.ts and sandbox.ts.

As per path instructions for src/lib/{actions,domain,adapters,state}/**: "Flag cross-layer cycles, duplicate sources of truth, and forwarding wrappers that add a new layer without retiring the old owner and its callers."

♻️ Proposed direction
-import type { OpenClawImagePluginInstall } from "./openclaw-plugin-restore";
+import {
+  cloneOpenClawImagePluginInstalls,
+  type OpenClawImagePluginInstall,
+} from "./openclaw-plugin-restore";
-      openclawImagePluginInstalls: Array.isArray(entry.openclawImagePluginInstalls)
-        ? entry.openclawImagePluginInstalls.map((install) => ({
-            ...install,
-            ...(install.loadPaths !== undefined ? { loadPaths: [...install.loadPaths] } : {}),
-          }))
-        : undefined,
+      openclawImagePluginInstalls: Array.isArray(entry.openclawImagePluginInstalls)
+        ? cloneOpenClawImagePluginInstalls(entry.openclawImagePluginInstalls)
+        : undefined,

(requires exporting cloneOpenClawImagePluginInstalls from openclaw-plugin-restore.ts and having sandbox.ts import it too, rather than keeping its own copy)

🤖 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 `@src/lib/state/registry.ts` around lines 511 - 516, The
`openclawImagePluginInstalls` clone logic is duplicated between `registry.ts`
and `sandbox.ts`, creating two sources of truth for the same
provenance-sensitive shape. Export a single helper such as
`cloneOpenClawImagePluginInstalls` from `openclaw-plugin-restore.ts` and update
both `registry.ts` and `hasAuthoritativeOpenClawImagePluginProvenance` in
`sandbox.ts` to reuse it, removing the inline spread/`loadPaths` copy so the
cloning behavior stays consistent.

Source: Path instructions

test/snapshot-openclaw-managed-extensions.test.ts (1)

216-225: 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Cleanup step mocks the removal decision instead of exercising the real command.

The tar branch (Line 226) actually executes real tar via spawnSync against the fixture, but this cleanup branch reimplements the "keep managed, delete the rest" decision in JS using a Set, rather than running the real generated find ... -exec rm -rf command against extensionsDir. The only real-command check is the substring assertion at Line 278 (! -name '${extensionName}'), which doesn't prove the full command is syntactically correct (quoting, -mindepth/-maxdepth, -exec ... + vs \;) when actually executed by a shell — a bug in the generated command (e.g. quoting an extension name incorrectly) could delete the wrong things in production while this test still passes.

Consider running the actual cmd through spawnSync("sh", ["-c", ...]) (substituting the sandbox-internal path for the real fixture path, as is effectively done for the tar destination) so the test proves the generated shell command itself behaves correctly.

As per path instructions for **/*.test.{ts,js,mts,mjs,cts,cjs}: "Flag copied production algorithms, broad mocks that bypass the behavior under test, and conditionals that make a test pass without exercising its claim."

🤖 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/snapshot-openclaw-managed-extensions.test.ts` around lines 216 - 225,
The cleanup test is bypassing the real generated shell command by reimplementing
the delete/keep logic in JS, so it doesn’t validate the actual `find ... -exec
rm -rf` behavior. Update the `cmd.includes("/sandbox/.openclaw/extensions") &&
cmd.includes("-exec rm -rf")` branch in
`snapshot-openclaw-managed-extensions.test.ts` to execute the generated `cmd`
with `spawnSync("sh", ["-c", ...])` against the fixture path, similar to the
existing `tar` branch, so the test exercises the real command syntax and quoting
instead of a mocked `Set`-based cleanup.

Source: Path instructions

test/regression-e2e-workflow.test.ts (1)

75-75: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Add a local issue-reference suffix to this renamed test title.

The reworded title doesn't carry a (#nnnn) suffix, per the repo's test-naming convention for **/*.test.ts files.

As per coding guidelines, **/*.test.ts: "Write behavior-oriented test titles, and put local issue references in a final (#1234) suffix."

🤖 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/regression-e2e-workflow.test.ts` at line 75, The renamed test title in
the regression E2E workflow test is missing the required local issue-reference
suffix. Update the title in the it(...) call to keep the behavior-oriented
wording and append the appropriate final "(`#1234`)"-style suffix to match the
repo convention for test-regression-e2e-workflow.test.ts and other **/*.test.ts
files.

Source: Coding guidelines

src/lib/onboard/sandbox-registration.ts (1)

118-125: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicate clone logic with registry.ts.

This clone transform for OpenClawImagePluginInstall[] (spread + defensively copy loadPaths) duplicates the identical logic in src/lib/state/registry.ts (lines ~511-516). Extracting a shared helper (e.g., colocated with the OpenClawImagePluginInstall type in openclaw-plugin-restore.ts) would prevent the two clone paths from silently diverging if the install shape changes later.

♻️ Proposed shared helper
+export function cloneOpenClawImagePluginInstalls(
+  installs: readonly OpenClawImagePluginInstall[],
+): OpenClawImagePluginInstall[] {
+  return installs.map((install) => ({
+    ...install,
+    ...(install.loadPaths !== undefined ? { loadPaths: [...install.loadPaths] } : {}),
+  }));
+}

Then in sandbox-registration.ts:

     ...(input.openclawImagePluginInstalls !== undefined
       ? {
-          openclawImagePluginInstalls: input.openclawImagePluginInstalls.map((install) => ({
-            ...install,
-            ...(install.loadPaths !== undefined ? { loadPaths: [...install.loadPaths] } : {}),
-          })),
+          openclawImagePluginInstalls: cloneOpenClawImagePluginInstalls(
+            input.openclawImagePluginInstalls,
+          ),
         }
       : {}),
🤖 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 `@src/lib/onboard/sandbox-registration.ts` around lines 118 - 125, The
OpenClawImagePluginInstall clone logic in sandbox registration duplicates the
same spread-and-copy behavior already used in registry.ts, so move it into a
shared helper near the OpenClawImagePluginInstall type in
openclaw-plugin-restore.ts and use that helper from both sandbox-registration.ts
and registry.ts. Keep the helper responsible for cloning each install and
defensively copying loadPaths so both call sites stay in sync if the shape
changes later.
🤖 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 `@docs/security/e2e-weather-plugin-fixture-dependency-review.md`:
- Around line 1-5: The new markdown review document is missing the required SPDX
license header; add the standard HTML-comment SPDX header used by other
docs/markdown files at the top of the file, keeping the rest of the content
unchanged. Use the existing documentation pattern in this repo as the reference
so the header matches the format expected for Markdown sources.
- Line 32: The Markdown list item in the security fixture dependency review note
contains two sentences on one line; split it into separate lines so each
sentence stands alone. Update the affected bullet text in the documentation and
keep the rest of the wording unchanged, preserving the one-sentence-per-line
convention for docs content.

In `@src/lib/actions/sandbox/rebuild-backup-phase.test.ts`:
- Around line 230-297: Update the four affected `it()` titles in
`rebuild-backup-phase.test.ts` to append the local issue reference suffix
`(`#6108`)` so they match the suite’s test-title convention. Keep the existing
behavior-oriented wording in each case, and only modify the titles for the tests
covering `runRebuildBackupPhase` and its backup manifest/provenance cases.

In `@src/lib/state/openclaw-config-restore-input.ts`:
- Around line 145-150: The restore path in openclaw-config-restore-input should
distinguish the previous-provenance failure from the fresh-branch message.
Update the error returned in the previousImagePluginInstalls check inside the
restore logic that calls hasCompleteOpenClawImagePluginProvenance so it clearly
says the previous OpenClaw image plugin provenance is incomplete, matching the
existing fresh-branch qualifier and removing ambiguity about which side failed.

In `@src/lib/state/sandbox.ts`:
- Around line 1451-1458: The OpenClaw plugin install parsing in
restoreSandboxStateInternal is hardcoding the provenance root instead of using
the configured directory, which can mismatch the sandbox state root. Update the
parseOpenClawImagePluginInstalls call in the openclaw branch to use the same
configured path derived from agent.configPaths.dir (and the same
manifest.dir/writableDir root used elsewhere) rather than the literal
/sandbox/.openclaw, so plugin provenance is validated consistently.

In `@test/helpers/rebuild-flow-recovery-cases.ts`:
- Around line 40-67: Add an assertion on restoreSandboxStateSpy in the recovery
test so the restore path is verified, not just the delete flow. In
rebuildSandbox/createRebuildFlowHarness, confirm the restore call preserves the
manifest provenance fields by checking targetAgentType and
freshOpenClawImagePluginInstalls are passed through from the recoveryManifest.
Keep the existing expectations around backupSandboxStateSpy and runOpenshellSpy,
and anchor the new check on restoreSandboxStateSpy to catch regressions in the
recovery path.

---

Nitpick comments:
In `@src/lib/onboard/sandbox-registration.ts`:
- Around line 118-125: The OpenClawImagePluginInstall clone logic in sandbox
registration duplicates the same spread-and-copy behavior already used in
registry.ts, so move it into a shared helper near the OpenClawImagePluginInstall
type in openclaw-plugin-restore.ts and use that helper from both
sandbox-registration.ts and registry.ts. Keep the helper responsible for cloning
each install and defensively copying loadPaths so both call sites stay in sync
if the shape changes later.

In `@src/lib/state/registry.ts`:
- Around line 511-516: The `openclawImagePluginInstalls` clone logic is
duplicated between `registry.ts` and `sandbox.ts`, creating two sources of truth
for the same provenance-sensitive shape. Export a single helper such as
`cloneOpenClawImagePluginInstalls` from `openclaw-plugin-restore.ts` and update
both `registry.ts` and `hasAuthoritativeOpenClawImagePluginProvenance` in
`sandbox.ts` to reuse it, removing the inline spread/`loadPaths` copy so the
cloning behavior stays consistent.

In `@test/regression-e2e-workflow.test.ts`:
- Line 75: The renamed test title in the regression E2E workflow test is missing
the required local issue-reference suffix. Update the title in the it(...) call
to keep the behavior-oriented wording and append the appropriate final
"(`#1234`)"-style suffix to match the repo convention for
test-regression-e2e-workflow.test.ts and other **/*.test.ts files.

In `@test/snapshot-openclaw-managed-extensions.test.ts`:
- Around line 216-225: The cleanup test is bypassing the real generated shell
command by reimplementing the delete/keep logic in JS, so it doesn’t validate
the actual `find ... -exec rm -rf` behavior. Update the
`cmd.includes("/sandbox/.openclaw/extensions") && cmd.includes("-exec rm -rf")`
branch in `snapshot-openclaw-managed-extensions.test.ts` to execute the
generated `cmd` with `spawnSync("sh", ["-c", ...])` against the fixture path,
similar to the existing `tar` branch, so the test exercises the real command
syntax and quoting instead of a mocked `Set`-based cleanup.
🪄 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: f0fdb58f-f01b-46a4-b212-ea4e5b46435d

📥 Commits

Reviewing files that changed from the base of the PR and between 5ddf9a1 and 2ce21b6.

⛔ Files ignored due to path filters (1)
  • test/e2e/fixtures/plugins/weather/package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (78)
  • .github/workflows/e2e.yaml
  • .github/workflows/regression-e2e.yaml
  • ci/test-file-size-budget.json
  • docs/deployment/install-openclaw-plugins.mdx
  • docs/get-started/quickstart.mdx
  • docs/manage-sandboxes/lifecycle.mdx
  • docs/reference/commands.mdx
  • docs/reference/troubleshooting.mdx
  • docs/security/e2e-weather-plugin-fixture-dependency-review.md
  • src/lib/actions/sandbox/rebuild-backup-phase.test.ts
  • src/lib/actions/sandbox/rebuild-backup-phase.ts
  • src/lib/actions/sandbox/rebuild-dcode-pre-delete-drift.test.ts
  • src/lib/actions/sandbox/rebuild-dcode-recovery.test.ts
  • src/lib/actions/sandbox/rebuild-local-provider-recreate.test.ts
  • src/lib/actions/sandbox/rebuild-preflight-guards.ts
  • src/lib/actions/sandbox/rebuild-preflight-phase.ts
  • src/lib/actions/sandbox/rebuild-prepared-recovery.test.ts
  • src/lib/actions/sandbox/rebuild-prepared-recovery.ts
  • src/lib/actions/sandbox/rebuild-restore-phase.test.ts
  • src/lib/actions/sandbox/rebuild-restore-phase.ts
  • src/lib/onboard.ts
  • src/lib/onboard/created-sandbox-finalization.test.ts
  • src/lib/onboard/created-sandbox-finalization.ts
  • src/lib/onboard/custom-openclaw-runtime-diagnosis.test.ts
  • src/lib/onboard/custom-openclaw-runtime-diagnosis.ts
  • src/lib/onboard/not-ready-recreate.test.ts
  • src/lib/onboard/not-ready-recreate.ts
  • src/lib/onboard/sandbox-backup-on-recreate.test.ts
  • src/lib/onboard/sandbox-backup-on-recreate.ts
  • src/lib/onboard/sandbox-recreate-protection.test.ts
  • src/lib/onboard/sandbox-recreate-protection.ts
  • src/lib/onboard/sandbox-registration.test.ts
  • src/lib/onboard/sandbox-registration.ts
  • src/lib/state/openclaw-config-merge.test.ts
  • src/lib/state/openclaw-config-merge.ts
  • src/lib/state/openclaw-config-restore-input.test.ts
  • src/lib/state/openclaw-config-restore-input.ts
  • src/lib/state/openclaw-managed-extensions.test.ts
  • src/lib/state/openclaw-managed-extensions.ts
  • src/lib/state/openclaw-plugin-restore.test.ts
  • src/lib/state/openclaw-plugin-restore.ts
  • src/lib/state/registry.ts
  • src/lib/state/sandbox-openclaw-plugin-restore.test.ts
  • src/lib/state/sandbox.ts
  • src/lib/verify-deployment.test.ts
  • src/lib/verify-deployment.ts
  • test/e2e-fixture-dependency-review.test.ts
  • test/e2e/fixtures/plugins/weather/.gitignore
  • test/e2e/fixtures/plugins/weather/openclaw.plugin.json
  • test/e2e/fixtures/plugins/weather/package.json
  • test/e2e/fixtures/plugins/weather/src/index.ts
  • test/e2e/fixtures/plugins/weather/src/version.ts
  • test/e2e/fixtures/plugins/weather/tsconfig.json
  • test/e2e/live/openclaw-plugin-runtime-exdev.test.ts
  • test/e2e/support/e2e-workflow.test.ts
  • test/e2e/support/openclaw-plugin-runtime-exdev-workflow-boundary.test.ts
  • test/e2e/support/platform-parity-cloud-experimental.test.ts
  • test/e2e/support/upload-e2e-artifacts-workflow-boundary.test.ts
  • test/helpers/onboard-openshell-fixture.ts
  • test/helpers/rebuild-flow-harness.ts
  • test/helpers/rebuild-flow-lifecycle-cases.ts
  • test/helpers/rebuild-flow-recovery-cases.ts
  • test/helpers/rebuild-flow-test-harness.ts
  • test/helpers/rebuild-flow-test-support.ts
  • test/langchain-deepagents-code-image.test.ts
  • test/onboard-custom-dockerfile.test.ts
  • test/onboard-installer-restore-intent.test.ts
  • test/onboard-messaging.test.ts
  • test/onboard.test.ts
  • test/registry.test.ts
  • test/regression-e2e-workflow.test.ts
  • test/security-sandbox-tar-traversal.test.ts
  • test/shellquote-sandbox.test.ts
  • test/snapshot-openclaw-managed-extensions.test.ts
  • test/snapshot-recovery-validation.test.ts
  • test/snapshot.test.ts
  • tools/e2e/upload-e2e-artifacts-workflow-boundary.mts
  • tsconfig.cli.json
💤 Files with no reviewable changes (1)
  • test/langchain-deepagents-code-image.test.ts

Comment thread docs/security/e2e-weather-plugin-fixture-dependency-review.md
Comment thread docs/security/e2e-weather-plugin-fixture-dependency-review.md Outdated
Comment thread src/lib/actions/sandbox/rebuild-backup-phase.test.ts
Comment thread src/lib/state/openclaw-config-restore-input.ts
Comment thread src/lib/state/sandbox.ts Outdated
Comment thread test/helpers/rebuild-flow-recovery-cases.ts
cv added 2 commits July 8, 2026 13:08
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

E2E Target Results — ⚠️ Some jobs cancelled — partial pass

Run: 28971548139
Workflow ref: fix/discussion-6108-plugin-image-verified
Requested targets: (default — all supported)
Requested jobs: onboard-resume,onboard-repair,cloud-onboard,openclaw-plugin-runtime-exdev,rebuild-openclaw,sandbox-rebuild,state-backup-restore,upgrade-stale-sandbox
Summary: 7 passed, 0 failed, 1 cancelled, 0 skipped

Job Result
cloud-onboard ✅ success
onboard-repair ✅ success
onboard-resume ✅ success
openclaw-plugin-runtime-exdev ⚠️ cancelled
rebuild-openclaw ✅ success
sandbox-rebuild ✅ success
state-backup-restore ✅ success
upgrade-stale-sandbox ✅ success

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

E2E Target Results — ✅ All requested jobs passed

Run: 28972828216
Workflow ref: fix/discussion-6108-plugin-image-verified
Requested targets: (default — all supported)
Requested jobs: onboard-resume,onboard-repair,cloud-onboard,rebuild-openclaw,sandbox-rebuild,state-backup-restore,upgrade-stale-sandbox
Summary: 7 passed, 0 failed, 0 cancelled, 0 skipped

Job Result
cloud-onboard ✅ success
onboard-repair ✅ success
onboard-resume ✅ success
rebuild-openclaw ✅ success
sandbox-rebuild ✅ success
state-backup-restore ✅ success
upgrade-stale-sandbox ✅ success

@github-actions

github-actions Bot commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

E2E Target Results — ✅ All requested jobs passed

Run: 28972654149
Workflow ref: fix/discussion-6108-plugin-image-verified
Requested targets: (default — all supported)
Requested jobs: openclaw-plugin-runtime-exdev
Summary: 1 passed, 0 failed, 0 cancelled, 0 skipped

Job Result
openclaw-plugin-runtime-exdev ✅ success

@cv cv self-assigned this Jul 8, 2026
@apurvvkumaria
apurvvkumaria enabled auto-merge (squash) July 8, 2026 20:52
…lugin-image-verified

Signed-off-by: cjagwani <cjagwani@nvidia.com>

# Conflicts:
#	test/langchain-deepagents-code-image.test.ts
@apurvvkumaria
apurvvkumaria merged commit f2fa8ad into main Jul 8, 2026
200 checks passed
@apurvvkumaria
apurvvkumaria deleted the fix/discussion-6108-plugin-image-verified branch July 8, 2026 21:05
@cjagwani cjagwani mentioned this pull request Jul 9, 2026
21 tasks
cv pushed a commit that referenced this pull request Jul 9, 2026
<!-- markdownlint-disable MD041 -->
## Summary

Prepares the user documentation for NemoClaw v0.0.78 by replacing the
unreleased section with release highlights and synchronizing the
affected inference, lifecycle, messaging, and CLI reference pages with
merged behavior.

## Changes

- Publish the v0.0.78 release-notes section with links to the most
specific user guides for each shipped behavior.
- Document authoritative Deep Agents route health, Nemotron Ultra
profile behavior, and Hermes compatible-endpoint context metadata.
- Document forced rebuild recovery after total backup failure and the
ownership-safe tunnel/full-stop behavior.
- Keep command examples and shared agent variants aligned with the
current OpenClaw, Hermes, and Deep Agents interfaces.

Source mapping:

- [#3787](#3787) ->
`docs/about/release-notes.mdx`: Record reliable workspace template
seeding during sandbox startup.
- [#4960](#4960) ->
`docs/about/release-notes.mdx`: Record safer detection of rewritten
OpenClaw gateway processes.
- [#5676](#5676) ->
`docs/about/release-notes.mdx`: Record warning-tolerant agent-list JSON
handling.
- [#5857](#5857) ->
`docs/about/release-notes.mdx`: Record synchronization of explicit
OpenClaw main-agent model state.
- [#5929](#5929) ->
`docs/about/release-notes.mdx`: Record copyable SSH port-forward
guidance for remote dashboards.
- [#6068](#6068) ->
`docs/about/release-notes.mdx`: Record custom-image plugin provenance
reconciliation.
- [#6116](#6116) ->
`docs/about/release-notes.mdx`: Record live-loopback dashboard-forward
recovery.
- [#6122](#6122) ->
`docs/about/release-notes.mdx`: Announce validated, round-trippable
policy YAML output.
- [#6211](#6211) ->
`docs/manage-sandboxes/lifecycle.mdx`, `docs/reference/commands.mdx`,
`docs/about/release-notes.mdx`: Explain the explicit no-backup `rebuild
--force` recovery boundary.
- [#6283](#6283) ->
`docs/about/release-notes.mdx`: Record Hermes WebUI port alignment.
- [#6293](#6293) ->
`docs/inference/switch-inference-providers.mdx`,
`docs/about/release-notes.mdx`: Document compatible-endpoint
context-length probing for Hermes.
- [#6320](#6320) ->
`docs/about/release-notes.mdx`: Record bounded gateway-recovery waits.
- [#6377](#6377) ->
`docs/reference/commands.mdx`, `docs/about/release-notes.mdx`: Explain
rebuild diagnostics and prepared MCP-destroy recovery.
- [#6412](#6412) ->
`docs/get-started/quickstart-langchain-deepagents-code.mdx`,
`docs/about/release-notes.mdx`: Document authoritative agent-visible
inference route health.
- [#6421](#6421) ->
`docs/about/release-notes.mdx`: Record the longer quiet-pull window for
managed vLLM images.
- [#6431](#6431) ->
`docs/inference/model-capability-audit.mdx`,
`docs/about/release-notes.mdx`: Document the version-pinned Nemotron
Ultra profile plugin.
- [#6439](#6439) ->
`docs/about/release-notes.mdx`: Summarize the authenticated, pinned
credential-capture helper boundary.
- [#6450](#6450) ->
`docs/manage-sandboxes/messaging-channels.mdx`,
`docs/reference/commands.mdx`, `docs/about/release-notes.mdx`: Document
host-forward cleanup and ownership-safe gateway-port release.
- [#6474](#6474) ->
`docs/manage-sandboxes/messaging-channels.mdx`,
`docs/about/release-notes.mdx`: Record composable OpenClaw messaging
runtime loaders.
- [#6475](#6475) ->
`docs/about/release-notes.mdx`: Record removal of the unavailable Kimi
K2.6 production endpoint option.
- [#6480](#6480) ->
`docs/about/release-notes.mdx`: Record stderr routing for the plugin
registration banner.
- [#6481](#6481) ->
`docs/about/release-notes.mdx`: Record post-pull Ollama model discovery
checks.
- [#6482](#6482) ->
`docs/about/release-notes.mdx`: Record Ollama model warm-up after daemon
restart.
- [#6486](#6486) ->
`docs/about/release-notes.mdx`: Publish the opt-in, thread-scoped Deep
Agents auto-approval boundary.
- [#6490](#6490) ->
`docs/about/release-notes.mdx`: Record diagnostics for custom images
missing the managed runtime.
- [#6494](#6494) ->
`docs/inference/model-capability-audit.mdx`,
`docs/about/release-notes.mdx`: Document nonempty tool-call content
preservation and placeholder rejection.
- [#6497](#6497) ->
`docs/get-started/quickstart-langchain-deepagents-code.mdx`,
`docs/about/release-notes.mdx`: Document isolated Deep Agents
route-probe output.
- [#6506](#6506) ->
`docs/get-started/quickstart-langchain-deepagents-code.mdx`,
`docs/about/release-notes.mdx`: Document observability-preserving
managed route probes.
- [#6508](#6508) ->
`docs/about/release-notes.mdx`: Link the new extension taxonomy and
SDK-readiness reference from the release summary.

Release-source verification: GitHub reports all 29 cited source PRs as
merged with base `main`, and every merge commit is an ancestor of
`origin/main` at `17bf9a6a9688b3b1d69cf4b37d3f23110acb055e`. No
source-mapping mismatches were found.

## Type of Change

- [ ] Code change (feature, bug fix, or refactor)
- [ ] Code change with doc updates
- [ ] Doc only (prose changes, no code sample modifications)
- [x] Doc only (includes code sample changes)

## Quality Gates

<!-- Check exactly one tests line and one docs line. Check other lines
when applicable. Add every requested justification or approval
reference. -->
- [ ] Tests added or updated for changed behavior
- [ ] Existing tests cover changed behavior — justification:
- [x] Tests not applicable — justification: Documentation-only
release-prep changes; `npm run docs` validates variants, routes, and
Fern content.
- [x] Docs updated for user-facing behavior changes
- [ ] Docs not applicable — justification:
- [ ] Sensitive paths changed (security, policy, credentials, preflight,
onboarding, inference, runner, sandbox, or messaging)
- [ ] Sensitive-path review completed or maintainer-approved waiver
recorded — reviewer/approval link/justification:
- [ ] Non-success, skipped, or missing CI check accepted by maintainer —
check name, approval link, and follow-up issue:

## Verification

<!-- Check each applicable item only when supported by the requested
evidence. Run targeted tests once per relevant change set and rerun
after later edits or hook autofixes that can affect the tested behavior.
Do not rerun hook-covered checks. -->
- [x] PR description includes the DCO sign-off declaration and every
commit appears as `Verified` in GitHub
- [x] Normal `pre-commit`, `commit-msg`, and `pre-push` hooks passed, or
`npm run check:diff` passed when hooks were skipped or unavailable
- [x] Targeted behavior tests pass for the current change set, or tests
are marked not applicable above — command/result or justification: Tests
are not applicable to this documentation-only change set.
- [ ] Applicable broad gate passed — `npm test` for broad
runtime/test-harness changes; `npm run check` for repo-wide
validation/coverage changes — command/result:
- [x] Quality Gates section completed with required justifications or
waivers
- [x] No secrets, API keys, or credentials committed
- [ ] `npm run docs` builds without warnings (doc changes only) — exited
0 with zero errors; Fern reported the existing unauthenticated
redirect-check and light-mode contrast warnings.
- [x] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only)
- [ ] New doc pages include SPDX header and frontmatter (new pages only)

---
<!-- DCO sign-off is required in this PR description, and every commit
must appear as Verified in GitHub. Run: git config user.name && git
config user.email -->
Signed-off-by: Charan Jagwani <cjagwani@nvidia.com>

---------

Signed-off-by: cjagwani <cjagwani@nvidia.com>
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
<!-- markdownlint-disable MD041 -->
## Summary

Fresh verified-history replacement for NVIDIA#6250. This PR preserves the
reviewed net diff on current `main` while replacing the non-compliant
historical commit chain with three newly signed, GitHub-Verified
commits.

Aaron Erickson remains the original contributor and author of superseded
PR NVIDIA#6250; cjagwani authored this replacement PR. Apurv Kumaria
contributed the review-driven follow-up fixes. Both Aaron and Apurv are
credited as co-authors on the replacement commit.

## Related

- Supersedes NVIDIA#6250
- [Discussion
NVIDIA#6108](NVIDIA#6108)
- Regression coverage for NVIDIA#3513 and NVIDIA#3127
- The no-source-checkout managed plugin lifecycle remains tracked by
NVIDIA#5998

## Changes

- Diagnose custom OpenClaw images that contain only the intermediate
`sandbox-base` instead of the complete managed runtime.
- Record authoritative image-plugin provenance and reconcile removed,
renamed, and same-ID upgraded plugins during recreation and rebuild.
- Preserve user-owned plugin, channel, and tool state while removing
stale image-owned configuration; fail closed on incomplete provenance.
- Add deterministic release lifecycle coverage for onboarding, restart,
recreation, rebuild, workspace preservation, and EXDEV-safe runtime
dependency replacement.
- Authenticate only for the exact digest-pinned builder pre-pull, then
remove Docker credentials before release-pinned fixture code runs.
- Document the full-image plugin recipe, troubleshooting guidance,
dependency risk controls, and the explicit `REMOVE-WHEN` condition.

## Verification

- 126 focused rebuild, restore, diagnosis, and custom-Dockerfile tests
passed.
- `npm run build:cli` passed.
- Node 22 CLI typecheck passed.
- Test-file size budget passed across 1,372 files.
- Biome passed all 64 changed supported files.
- `git diff --cached --check` passed before commit.
- Replacement history contains three commits, all GitHub Verified with
good ED25519 Git signatures.
- Full standard CI and applicable live E2E are intentionally running
again on this new exact head.

## Provenance

The implementation and tests are the reviewed work from NVIDIA#6250, replayed
onto current `main` because six historical commits in that PR could not
satisfy the repository's GitHub-Verified requirement. This replacement
does not claim those historical objects are verified; it provides a new,
attributable, signed history containing their reviewed net result.

Signed-off-by: cjagwani <cjagwani@nvidia.com>
Co-authored-by: Aaron Erickson <aerickson@nvidia.com>
Co-authored-by: Apurv Kumaria <akumaria@nvidia.com>


<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **New Features**
* Added OpenClaw weather plugin E2E fixtures and expanded end-to-end
plugin lifecycle coverage, including a new runtime-deps EXDEV lane.
* **Bug Fixes**
* Strengthened onboarding/recovery to fail closed when OpenClaw
image-plugin provenance is incomplete, and tightened rebuild/restore
gating and hints.
* Improved handling of OpenClaw managed extensions and restore planning
with stricter symlink and identity checks.
* **Documentation**
* Updated installation, lifecycle, quickstart, commands, and
troubleshooting docs with safer recovery and pinned sandbox workflows.
* **Tests/CI**
* Updated E2E/regression workflows and added provenance-related
rebuild/restore test coverage.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

---------

Signed-off-by: cjagwani <cjagwani@nvidia.com>
Signed-off-by: Carlos Villela <cvillela@nvidia.com>
Co-authored-by: Aaron Erickson <aerickson@nvidia.com>
Co-authored-by: Apurv Kumaria <akumaria@nvidia.com>
Co-authored-by: Carlos Villela <cvillela@nvidia.com>
Hadar301 pushed a commit to Hadar301/NemoClaw-OpenShift that referenced this pull request Jul 12, 2026
<!-- markdownlint-disable MD041 -->
## Summary

Prepares the user documentation for NemoClaw v0.0.78 by replacing the
unreleased section with release highlights and synchronizing the
affected inference, lifecycle, messaging, and CLI reference pages with
merged behavior.

## Changes

- Publish the v0.0.78 release-notes section with links to the most
specific user guides for each shipped behavior.
- Document authoritative Deep Agents route health, Nemotron Ultra
profile behavior, and Hermes compatible-endpoint context metadata.
- Document forced rebuild recovery after total backup failure and the
ownership-safe tunnel/full-stop behavior.
- Keep command examples and shared agent variants aligned with the
current OpenClaw, Hermes, and Deep Agents interfaces.

Source mapping:

- [NVIDIA#3787](NVIDIA#3787) ->
`docs/about/release-notes.mdx`: Record reliable workspace template
seeding during sandbox startup.
- [NVIDIA#4960](NVIDIA#4960) ->
`docs/about/release-notes.mdx`: Record safer detection of rewritten
OpenClaw gateway processes.
- [NVIDIA#5676](NVIDIA#5676) ->
`docs/about/release-notes.mdx`: Record warning-tolerant agent-list JSON
handling.
- [NVIDIA#5857](NVIDIA#5857) ->
`docs/about/release-notes.mdx`: Record synchronization of explicit
OpenClaw main-agent model state.
- [NVIDIA#5929](NVIDIA#5929) ->
`docs/about/release-notes.mdx`: Record copyable SSH port-forward
guidance for remote dashboards.
- [NVIDIA#6068](NVIDIA#6068) ->
`docs/about/release-notes.mdx`: Record custom-image plugin provenance
reconciliation.
- [NVIDIA#6116](NVIDIA#6116) ->
`docs/about/release-notes.mdx`: Record live-loopback dashboard-forward
recovery.
- [NVIDIA#6122](NVIDIA#6122) ->
`docs/about/release-notes.mdx`: Announce validated, round-trippable
policy YAML output.
- [NVIDIA#6211](NVIDIA#6211) ->
`docs/manage-sandboxes/lifecycle.mdx`, `docs/reference/commands.mdx`,
`docs/about/release-notes.mdx`: Explain the explicit no-backup `rebuild
--force` recovery boundary.
- [NVIDIA#6283](NVIDIA#6283) ->
`docs/about/release-notes.mdx`: Record Hermes WebUI port alignment.
- [NVIDIA#6293](NVIDIA#6293) ->
`docs/inference/switch-inference-providers.mdx`,
`docs/about/release-notes.mdx`: Document compatible-endpoint
context-length probing for Hermes.
- [NVIDIA#6320](NVIDIA#6320) ->
`docs/about/release-notes.mdx`: Record bounded gateway-recovery waits.
- [NVIDIA#6377](NVIDIA#6377) ->
`docs/reference/commands.mdx`, `docs/about/release-notes.mdx`: Explain
rebuild diagnostics and prepared MCP-destroy recovery.
- [NVIDIA#6412](NVIDIA#6412) ->
`docs/get-started/quickstart-langchain-deepagents-code.mdx`,
`docs/about/release-notes.mdx`: Document authoritative agent-visible
inference route health.
- [NVIDIA#6421](NVIDIA#6421) ->
`docs/about/release-notes.mdx`: Record the longer quiet-pull window for
managed vLLM images.
- [NVIDIA#6431](NVIDIA#6431) ->
`docs/inference/model-capability-audit.mdx`,
`docs/about/release-notes.mdx`: Document the version-pinned Nemotron
Ultra profile plugin.
- [NVIDIA#6439](NVIDIA#6439) ->
`docs/about/release-notes.mdx`: Summarize the authenticated, pinned
credential-capture helper boundary.
- [NVIDIA#6450](NVIDIA#6450) ->
`docs/manage-sandboxes/messaging-channels.mdx`,
`docs/reference/commands.mdx`, `docs/about/release-notes.mdx`: Document
host-forward cleanup and ownership-safe gateway-port release.
- [NVIDIA#6474](NVIDIA#6474) ->
`docs/manage-sandboxes/messaging-channels.mdx`,
`docs/about/release-notes.mdx`: Record composable OpenClaw messaging
runtime loaders.
- [NVIDIA#6475](NVIDIA#6475) ->
`docs/about/release-notes.mdx`: Record removal of the unavailable Kimi
K2.6 production endpoint option.
- [NVIDIA#6480](NVIDIA#6480) ->
`docs/about/release-notes.mdx`: Record stderr routing for the plugin
registration banner.
- [NVIDIA#6481](NVIDIA#6481) ->
`docs/about/release-notes.mdx`: Record post-pull Ollama model discovery
checks.
- [NVIDIA#6482](NVIDIA#6482) ->
`docs/about/release-notes.mdx`: Record Ollama model warm-up after daemon
restart.
- [NVIDIA#6486](NVIDIA#6486) ->
`docs/about/release-notes.mdx`: Publish the opt-in, thread-scoped Deep
Agents auto-approval boundary.
- [NVIDIA#6490](NVIDIA#6490) ->
`docs/about/release-notes.mdx`: Record diagnostics for custom images
missing the managed runtime.
- [NVIDIA#6494](NVIDIA#6494) ->
`docs/inference/model-capability-audit.mdx`,
`docs/about/release-notes.mdx`: Document nonempty tool-call content
preservation and placeholder rejection.
- [NVIDIA#6497](NVIDIA#6497) ->
`docs/get-started/quickstart-langchain-deepagents-code.mdx`,
`docs/about/release-notes.mdx`: Document isolated Deep Agents
route-probe output.
- [NVIDIA#6506](NVIDIA#6506) ->
`docs/get-started/quickstart-langchain-deepagents-code.mdx`,
`docs/about/release-notes.mdx`: Document observability-preserving
managed route probes.
- [NVIDIA#6508](NVIDIA#6508) ->
`docs/about/release-notes.mdx`: Link the new extension taxonomy and
SDK-readiness reference from the release summary.

Release-source verification: GitHub reports all 29 cited source PRs as
merged with base `main`, and every merge commit is an ancestor of
`origin/main` at `17bf9a6a9688b3b1d69cf4b37d3f23110acb055e`. No
source-mapping mismatches were found.

## Type of Change

- [ ] Code change (feature, bug fix, or refactor)
- [ ] Code change with doc updates
- [ ] Doc only (prose changes, no code sample modifications)
- [x] Doc only (includes code sample changes)

## Quality Gates

<!-- Check exactly one tests line and one docs line. Check other lines
when applicable. Add every requested justification or approval
reference. -->
- [ ] Tests added or updated for changed behavior
- [ ] Existing tests cover changed behavior — justification:
- [x] Tests not applicable — justification: Documentation-only
release-prep changes; `npm run docs` validates variants, routes, and
Fern content.
- [x] Docs updated for user-facing behavior changes
- [ ] Docs not applicable — justification:
- [ ] Sensitive paths changed (security, policy, credentials, preflight,
onboarding, inference, runner, sandbox, or messaging)
- [ ] Sensitive-path review completed or maintainer-approved waiver
recorded — reviewer/approval link/justification:
- [ ] Non-success, skipped, or missing CI check accepted by maintainer —
check name, approval link, and follow-up issue:

## Verification

<!-- Check each applicable item only when supported by the requested
evidence. Run targeted tests once per relevant change set and rerun
after later edits or hook autofixes that can affect the tested behavior.
Do not rerun hook-covered checks. -->
- [x] PR description includes the DCO sign-off declaration and every
commit appears as `Verified` in GitHub
- [x] Normal `pre-commit`, `commit-msg`, and `pre-push` hooks passed, or
`npm run check:diff` passed when hooks were skipped or unavailable
- [x] Targeted behavior tests pass for the current change set, or tests
are marked not applicable above — command/result or justification: Tests
are not applicable to this documentation-only change set.
- [ ] Applicable broad gate passed — `npm test` for broad
runtime/test-harness changes; `npm run check` for repo-wide
validation/coverage changes — command/result:
- [x] Quality Gates section completed with required justifications or
waivers
- [x] No secrets, API keys, or credentials committed
- [ ] `npm run docs` builds without warnings (doc changes only) — exited
0 with zero errors; Fern reported the existing unauthenticated
redirect-check and light-mode contrast warnings.
- [x] Doc pages follow the [style
guide](https://github.com/NVIDIA/NemoClaw/blob/main/docs/CONTRIBUTING.md)
(doc changes only)
- [ ] New doc pages include SPDX header and frontmatter (new pages only)

---
<!-- DCO sign-off is required in this PR description, and every commit
must appear as Verified in GitHub. Run: git config user.name && git
config user.email -->
Signed-off-by: Charan Jagwani <cjagwani@nvidia.com>

---------

Signed-off-by: cjagwani <cjagwani@nvidia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: onboarding Onboarding FSM, provider setup, sandbox launch, or first-run flow bug-fix PR fixes a bug or regression integration: openclaw OpenClaw integration behavior v0.0.78 Release target

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants