Skip to content

docs(security): clarify mutable-default config posture - #3407

Merged
ericksoa merged 1 commit into
mainfrom
docs/mutable-default-help-copy-signed
May 12, 2026
Merged

docs(security): clarify mutable-default config posture#3407
ericksoa merged 1 commit into
mainfrom
docs/mutable-default-help-copy-signed

Conversation

@ericksoa

@ericksoa ericksoa commented May 12, 2026

Copy link
Copy Markdown
Contributor

Summary

  • correct root help reconfiguration copy so fresh sandboxes are described as mutable by default, with durable config changes routed through host-side commands or re-onboard
  • document that Landlock's filesystem layout is fixed at sandbox creation while shields up adds host-side DAC/chattr lockdown for sensitive workloads
  • update inference/troubleshooting docs and generated skill references so openclaw.json is not described as immutable in the default sandbox
  • remove stale /sandbox is Landlock read-only comments from startup/test/Hermes scaffolding

Validation

  • npx vitest run test/root-help.test.ts
  • npm run build:cli
  • npm run typecheck:cli
  • python3 scripts/docs-to-skills.py docs/ .agents/skills/ --prefix nemoclaw-user --dry-run
  • bash test/e2e/e2e-cloud-experimental/check-docs.sh --only-links --local-only docs/security/best-practices.md docs/deployment/sandbox-hardening.md docs/inference/switch-inference-providers.md docs/reference/troubleshooting.md
  • uv run --group docs sphinx-build -W -b html docs docs/_build/html
  • node bin/nemoclaw.js help | rg -n 'Reconfiguration|Agent config|host-side|shields up|read-only|Landlock enforced'

Issue Notes

Summary by CodeRabbit

  • Documentation

    • Clarified that sandbox /sandbox directories remain writable by design and do not indicate Landlock failures.
    • Updated configuration guidance: in-sandbox edits are not durable; use host-side commands or nemoclaw onboard for proper reconfiguration.
    • Added security controls documentation: shields up/down/status commands for host-side config lockdown without recreating the sandbox.
  • Tests

    • Added test coverage for help feature output and reconfiguration guidance.

Review Change Stack

Signed-off-by: Aaron Erickson <aerickson@nvidia.com>
@coderabbitai

coderabbitai Bot commented May 12, 2026

Copy link
Copy Markdown
Contributor
📝 Walkthrough

Walkthrough

This PR updates documentation and code comments across NemoClaw to clarify sandbox filesystem policies, introduce shields commands for host-side config lockdown, and explain how openclaw.json is generated from host-side inputs. The changes remove misleading Landlock read-only messaging and add new test validation.

Changes

NemoClaw filesystem policy and shields command documentation

Layer / File(s) Summary
Filesystem mutability and Landlock compatibility
.agents/skills/nemoclaw-user-deploy-remote/references/sandbox-hardening.md, docs/deployment/sandbox-hardening.md, agents/hermes/Dockerfile.base, scripts/nemoclaw-start.sh
Documentation clarifies that /sandbox and /sandbox/.openclaw writable defaults are intentional and compatible with Landlock enforcement. Removes misleading "read-only home" messaging from Docker init files and shell script comments; explains tool redirects without Landlock read-only framing.
Shields command documentation and tables
.agents/skills/nemoclaw-user-configure-security/references/best-practices.md, docs/security/best-practices.md
New documentation and table updates describe nemoclaw shields status/up/down workflow and clarify that shields commands run on the host with privileged paths to layer config lockdown via ownership/immutable controls without altering the fixed Landlock policy. Distinguishes Landlock layout (immutable) from config lockdown posture (changeable via shields).
openclaw.json generation and mutability
.agents/skills/nemoclaw-user-configure-inference/references/switch-inference-providers.md, docs/inference/switch-inference-providers.md, .agents/skills/nemoclaw-user-reference/references/troubleshooting.md, docs/reference/troubleshooting.md
Clarifies that NemoClaw generates openclaw.json from host-side onboarding/rebuild/inference inputs, that fresh sandboxes keep the file writable for runtime state, and that direct in-sandbox edits are unsupported/non-durable. Emphasizes nemoclaw onboard rebuild as the supported path for applying config changes to NEMOCLAW_AGENT_TIMEOUT and NEMOCLAW_AGENT_HEARTBEAT_EVERY.
Help output and entrypoint updates
src/lib/actions/root-help.ts
Updates to root-help() guidance: agent config described as writable in the default sandbox, with host-side commands or re-running onboard for durable settings, and shields up option for config lockdown. Removes Landlock read-only framing.
Test validation and e2e comments
test/e2e-gateway-isolation.sh, test/e2e/test-sandbox-survival.sh, test/root-help.test.ts
Existing e2e test comments clarify sandbox ownership and writable defaults under mutable-default policy. New test/root-help.test.ts validates updated help output for expected strings ("writable in default sandbox", "shields up") and absence of conflicting Landlock read-only messaging.

Sequence Diagram(s)

sequenceDiagram
  participant Host
  participant Onboarding as nemoclaw onboard
  participant Sandbox
  participant Config as openclaw.json
  
  Host->>Onboarding: timeout/heartbeat/inference settings
  Onboarding->>Config: generate at sandbox creation
  Sandbox->>Config: writable for runtime state
  Note over Sandbox,Config: in-sandbox edits not supported
  Host->>Onboarding: nemoclaw onboard --resume
  Onboarding->>Config: regenerate with new values
Loading

🎯 2 (Simple) | ⏱️ ~8 minutes

🐰 A sandbox both locked and free,
With shields up high for all to see,
Config writable by day,
Yet onboard keeps it on the way,
Landlock silent, doing right,
Host-side lockdown, pixel-bright! 🛡️

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: updating documentation to clarify the mutable-default sandbox configuration posture across security and reference materials.
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.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch docs/mutable-default-help-copy-signed

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

@github-actions

github-actions Bot commented May 12, 2026

Copy link
Copy Markdown
Contributor

E2E Advisor Recommendation

Required E2E: test-e2e-gateway-isolation, sandbox-survival-e2e
Optional E2E: shields-config-e2e, cloud-onboard-e2e, sandbox-operations-e2e

Dispatch hint: sandbox-survival-e2e,shields-config-e2e,cloud-onboard-e2e,sandbox-operations-e2e

Workflow run

Full advisor summary

Pi Semantic E2E Advisor

Base: origin/main
Head: HEAD
Confidence: high

Required E2E

  • test-e2e-gateway-isolation: test/e2e-gateway-isolation.sh is directly modified in this PR (Tests 2/3/6 and the .openclaw new-file check are flipped to assert writable defaults). The same script is the command run by the test-e2e-gateway-isolation jobs in .github/workflows/sandbox-images-and-e2e.yaml and .github/workflows/pr-self-hosted.yaml, so it must run to prove the new assertions hold against a freshly built production image.
  • sandbox-survival-e2e: test/e2e/test-sandbox-survival.sh is directly modified: workspace-survival markers were moved from /sandbox to /sandbox/.openclaw with comments claiming the mutable-default writes through to durable agent state. The nightly sandbox-survival-e2e job runs exactly this script end-to-end, so it should be exercised to confirm the survival flow still writes, restarts, and observes the marker under the new path.

Optional E2E

  • shields-config-e2e: Both docs/security/best-practices.md and .agents/skills/nemoclaw-user-configure-security/references/best-practices.md add a new 'Locking Config with Shields' section describing nemoclaw <name> shields status|up|down --timeout --reason semantics. shields-config-e2e is the nightly job that validates shields up/down config mutability, rotate-token, audit trail, and auto-restore timer, so it is the natural confidence check that the documented behavior still matches implementation.
  • cloud-onboard-e2e: Troubleshooting and switch-inference docs now claim that NemoClaw writes openclaw.json during onboarding and that fresh sandboxes keep it writable — in direct contrast to the prior 'immutable at runtime' statements. cloud-onboard-e2e performs the public-installer onboard plus Landlock / sandbox-config verification and is a good confidence check that onboarding still lands the config with the documented ownership/mode.
  • sandbox-operations-e2e: Help text in src/lib/actions/root-help.ts now steers users to host-side commands and <name> shields up for durable reconfiguration. sandbox-operations-e2e covers sandbox list/connect/status/destroy plus gateway auto-recovery and multi-sandbox isolation, which is the closest E2E that exercises the host-side sandbox CLI flows the help text describes.

New E2E recommendations

  • docs-to-cli-parity (low): The new 'Locking Config with Shields' table in docs/security/best-practices.md documents specific CLI shapes (shields status, shields up, shields down --timeout 5m --reason "<reason>"). There is no single E2E that asserts the exact nemoclaw <name> shields ... usage strings surfaced by the CLI match what the security docs promise, so drift is possible as shields flags evolve.
    • Suggested test: Add a lightweight E2E (or extend test/e2e/test-shields-config.sh) that parses docs/security/best-practices.md + docs/deployment/sandbox-hardening.md for nemoclaw <name> shields ... examples and asserts each documented invocation passes CLI parsing (dry-run) against the installed binary, guarding against doc/CLI drift.
  • help-text-regression (low): test/root-help.test.ts covers the new help strings at unit level, but there is no E2E that asserts the rendered nemoclaw --help output seen by an end user after install.sh contains the updated 'shields up' reconfiguration hint. A small end-to-end help-rendering assertion would prevent installer/bundling regressions from silently reverting the user-facing text.
    • Suggested test: Add a small E2E step (e.g., in test/e2e/test-docs-validation.sh or a new test/e2e/test-root-help-e2e.sh) that runs nemoclaw --help after install.sh and greps for the shields up and mutable-default phrases introduced in this PR.

Dispatch hint

  • Workflow: .github/workflows/nightly-e2e.yaml
  • jobs input: sandbox-survival-e2e,shields-config-e2e,cloud-onboard-e2e,sandbox-operations-e2e

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

🧹 Nitpick comments (4)
docs/security/best-practices.md (1)

265-266: ⚡ Quick win

Split independent clauses into separate sentences.

Line 265 uses a semicolon to join two independent clauses.
The docs style guide requires periods to separate sentences.

As per coding guidelines, "Colons should only introduce a list. Flag colons used as general punctuation between clauses."
The same principle applies to semicolons.

Suggested revision
-Landlock itself stays fixed at sandbox creation; `shields up` does not rewrite the Landlock policy.
+Landlock itself stays fixed at sandbox creation.
+`shields up` does not rewrite the Landlock policy.
🤖 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 `@docs/security/best-practices.md` around lines 265 - 266, The sentence
"Landlock itself stays fixed at sandbox creation; `shields up` does not rewrite
the Landlock policy." joins two independent clauses with a semicolon — split
them into two sentences by replacing the semicolon with a period and
capitalizing "`shields up`" so it reads "Landlock itself stays fixed at sandbox
creation. `Shields up` does not rewrite the Landlock policy." Ensure the revised
wording follows the docs style guide about using periods instead of semicolons
and avoiding colons/semicolons as general punctuation.
docs/deployment/sandbox-hardening.md (1)

115-115: ⚡ Quick win

Split independent clauses into separate sentences.

Line 115 uses a semicolon to join two independent clauses.
The docs style guide requires periods to separate sentences.

Suggested revision
-That host-side command layers root ownership, read-only modes, and the immutable flag where available; it does not change the Landlock policy after sandbox creation.
+That host-side command layers root ownership, read-only modes, and the immutable flag where available.
+It does not change the Landlock policy after sandbox creation.

As per coding guidelines, semicolons should not be used as general punctuation between clauses in NemoClaw documentation.

🤖 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 `@docs/deployment/sandbox-hardening.md` at line 115, The sentence "That
host-side command layers root ownership, read-only modes, and the immutable flag
where available; it does not change the Landlock policy after sandbox creation."
uses a semicolon between two independent clauses—replace the semicolon with a
period and capitalize the start of the second clause so it becomes two sentences
(e.g., end the first clause after "available." and start "It does not change the
Landlock policy after sandbox creation.").
.agents/skills/nemoclaw-user-configure-inference/references/switch-inference-providers.md (1)

152-153: ⚡ Quick win

Use active voice and separate sentences.

Line 152 uses passive voice ("are overwritten by").
The docs style guide requires active voice.
Additionally, line 153 contains two sentences on the same line.

Suggested revision
-NemoClaw-managed build-time defaults, and direct file edits are overwritten by a
-rebuild. Rebuild the sandbox via `nemoclaw onboard --resume` to apply a new value.
+NemoClaw-managed build-time defaults, and rebuilding overwrites direct file edits.
+Rebuild the sandbox via `nemoclaw onboard --resume` to apply a new value.

As per coding guidelines, active voice is required in NemoClaw documentation, and each sentence must appear on its own line.

🤖 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
@.agents/skills/nemoclaw-user-configure-inference/references/switch-inference-providers.md
around lines 152 - 153, Rewrite the two-sentence fragment that currently reads
"NemoClaw-managed build-time defaults, and direct file edits are overwritten by
a rebuild. Rebuild the sandbox via `nemoclaw onboard --resume` to apply a new
value." into active voice and put each sentence on its own line; e.g., change
the passive clause "are overwritten by a rebuild" to an active form such as "A
rebuild overwrites NemoClaw-managed build-time defaults and direct file edits."
and then place "Rebuild the sandbox via `nemoclaw onboard --resume` to apply a
new value." on the following line so each sentence is separate.
docs/inference/switch-inference-providers.md (1)

176-177: ⚡ Quick win

Use active voice and separate sentences.

Line 176 uses passive voice ("are overwritten by").
The docs style guide requires active voice.
Additionally, line 177 contains two sentences on the same line.

Suggested revision
-NemoClaw-managed build-time defaults, and direct file edits are overwritten by a
-rebuild. Rebuild the sandbox via `nemoclaw onboard --resume` to apply a new value.
+NemoClaw-managed build-time defaults, and rebuilding overwrites direct file edits.
+Rebuild the sandbox via `nemoclaw onboard --resume` to apply a new value.

As per coding guidelines, active voice is required in NemoClaw documentation, and each sentence must appear on its own line.

🤖 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 `@docs/inference/switch-inference-providers.md` around lines 176 - 177, The
current sentence "NemoClaw-managed build-time defaults, and direct file edits
are overwritten by a rebuild. Rebuild the sandbox via `nemoclaw onboard
--resume` to apply a new value." uses passive voice and combines multiple
sentences on one line; rewrite it in active voice and put each sentence on its
own line. For example, replace it with an active sentence such as "A rebuild
overwrites NemoClaw-managed build-time defaults and direct file edits." on one
line, and keep the second instruction "Rebuild the sandbox via `nemoclaw onboard
--resume` to apply a new value." on the next line so each sentence stands alone.
🤖 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.

Nitpick comments:
In
@.agents/skills/nemoclaw-user-configure-inference/references/switch-inference-providers.md:
- Around line 152-153: Rewrite the two-sentence fragment that currently reads
"NemoClaw-managed build-time defaults, and direct file edits are overwritten by
a rebuild. Rebuild the sandbox via `nemoclaw onboard --resume` to apply a new
value." into active voice and put each sentence on its own line; e.g., change
the passive clause "are overwritten by a rebuild" to an active form such as "A
rebuild overwrites NemoClaw-managed build-time defaults and direct file edits."
and then place "Rebuild the sandbox via `nemoclaw onboard --resume` to apply a
new value." on the following line so each sentence is separate.

In `@docs/deployment/sandbox-hardening.md`:
- Line 115: The sentence "That host-side command layers root ownership,
read-only modes, and the immutable flag where available; it does not change the
Landlock policy after sandbox creation." uses a semicolon between two
independent clauses—replace the semicolon with a period and capitalize the start
of the second clause so it becomes two sentences (e.g., end the first clause
after "available." and start "It does not change the Landlock policy after
sandbox creation.").

In `@docs/inference/switch-inference-providers.md`:
- Around line 176-177: The current sentence "NemoClaw-managed build-time
defaults, and direct file edits are overwritten by a rebuild. Rebuild the
sandbox via `nemoclaw onboard --resume` to apply a new value." uses passive
voice and combines multiple sentences on one line; rewrite it in active voice
and put each sentence on its own line. For example, replace it with an active
sentence such as "A rebuild overwrites NemoClaw-managed build-time defaults and
direct file edits." on one line, and keep the second instruction "Rebuild the
sandbox via `nemoclaw onboard --resume` to apply a new value." on the next line
so each sentence stands alone.

In `@docs/security/best-practices.md`:
- Around line 265-266: The sentence "Landlock itself stays fixed at sandbox
creation; `shields up` does not rewrite the Landlock policy." joins two
independent clauses with a semicolon — split them into two sentences by
replacing the semicolon with a period and capitalizing "`shields up`" so it
reads "Landlock itself stays fixed at sandbox creation. `Shields up` does not
rewrite the Landlock policy." Ensure the revised wording follows the docs style
guide about using periods instead of semicolons and avoiding colons/semicolons
as general punctuation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: e797cd43-89cd-4116-929e-64b396d4bb6a

📥 Commits

Reviewing files that changed from the base of the PR and between edb7478 and f629d31.

📒 Files selected for processing (14)
  • .agents/skills/nemoclaw-user-configure-inference/references/switch-inference-providers.md
  • .agents/skills/nemoclaw-user-configure-security/references/best-practices.md
  • .agents/skills/nemoclaw-user-deploy-remote/references/sandbox-hardening.md
  • .agents/skills/nemoclaw-user-reference/references/troubleshooting.md
  • agents/hermes/Dockerfile.base
  • docs/deployment/sandbox-hardening.md
  • docs/inference/switch-inference-providers.md
  • docs/reference/troubleshooting.md
  • docs/security/best-practices.md
  • scripts/nemoclaw-start.sh
  • src/lib/actions/root-help.ts
  • test/e2e-gateway-isolation.sh
  • test/e2e/test-sandbox-survival.sh
  • test/root-help.test.ts

@ericksoa
ericksoa merged commit f634856 into main May 12, 2026
34 of 37 checks passed
miyoungc pushed a commit that referenced this pull request May 28, 2026
…4296)

## Summary
The sandbox-hardening filesystem-access table listed
`/sandbox/.nemoclaw` as read-write, matching the Landlock policy. In a
default sandbox the parent directory is `root:root` mode `1755`, so the
sandbox user cannot create files directly under it — reporters observed
`touch /sandbox/.nemoclaw/foo` returning "Permission denied" and read
the table as wrong. This PR clarifies the row and adds a note that the
Access column reflects Landlock only.

## Related Issue
Fixes #3690

## Changes
- `docs/deployment/sandbox-hardening.mdx`: rewrite the
`/sandbox/.nemoclaw` row to call out the DAC restriction and list the
actually writable children (`state/`, `migration/`, `snapshots/`,
`staging/`, `config.json`).
- Add a paragraph below the table explaining that Landlock declaration
is one of two gates; POSIX ownership/permissions additionally control
actual write success.

## Type of Change
- [x] Doc only (prose changes, no code sample modifications)

## Verification
- [x] `npx prek run --files docs/deployment/sandbox-hardening.mdx`
passes (full `--all-files` blocked by unrelated
`src/ext/wechat/login.test.ts` tsc miss on dist; pre-push pushed with
`--no-verify`)
- [ ] `npm test` — not run; docs-only
- [x] No secrets, API keys, or credentials committed
- [x] Docs updated for user-facing behavior changes
- [ ] `make docs` builds without warnings — not run locally; relying on
docs-to-skills prek hook (passed) and CI
- [x] Doc pages follow the style guide

The three already-stale rows in the table (`/sandbox`,
`/sandbox/.openclaw`, `/sandbox/.openclaw-data`) called out in #3690
were corrected in prior PRs (#3407 mutable-default posture, #3548 fern
migration); this PR addresses the remaining row. The reporter's "doc
never mentions shields up/down" concern is intentionally not addressed
here: shields are experimental and excluded from user-facing docs per
`docs/.docs-skip`.

---

Signed-off-by: Tony Luo <xialuo@nvidia.com>

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

* **Documentation**
* Clarified sandbox filesystem layout and permission semantics:
explicitly lists which sandbox subpaths are writable, notes
parent/blueprint directories remain root-owned, explains that the access
column reflects policy declarations (Landlock) while actual writes still
require POSIX/DAC permissions, and adds an example showing direct file
creation may still fail.

<!-- review_stack_entry_start -->

[![Review Change
Stack](https://storage.googleapis.com/coderabbit_public_assets/review-stack-in-coderabbit-ui.svg)](https://app.coderabbit.ai/change-stack/NVIDIA/NemoClaw/pull/4296?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack)

<!-- review_stack_entry_end -->
<!-- end of auto-generated comment: release notes by coderabbit.ai -->

Signed-off-by: Tony Luo <xialuo@nvidia.com>
@wscurran wscurran added area: docs Documentation, examples, guides, or docs build chore Build, CI, dependency, or tooling maintenance and removed documentation labels Jun 3, 2026
@cv
cv deleted the docs/mutable-default-help-copy-signed branch June 28, 2026 00:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: docs Documentation, examples, guides, or docs build chore Build, CI, dependency, or tooling maintenance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants