From fa8f10e6cd0e020c1de87fb5b9c0b5ec362d93fa Mon Sep 17 00:00:00 2001 From: Gio Della-Libera Date: Thu, 2 Jul 2026 20:51:13 -0700 Subject: [PATCH] docs(policy): document gateway node command policy --- docs/cli/policy.md | 53 ++++++++++++++++++++++++-------- docs/plugins/reference/policy.md | 7 ++++- 2 files changed, 46 insertions(+), 14 deletions(-) diff --git a/docs/cli/policy.md b/docs/cli/policy.md index 98dd9123453a..e4a0078c63e8 100644 --- a/docs/cli/policy.md +++ b/docs/cli/policy.md @@ -18,13 +18,13 @@ report drift through `doctor --lint`. The final conformance signal is a clean instead of creating a separate health gate. Policy currently manages configured channels, MCP servers, model providers, -network SSRF posture, ingress/channel access posture, Gateway exposure posture, agent workspace posture, +network SSRF posture, ingress/channel access posture, Gateway exposure and node command posture, agent workspace posture, data-handling posture, OpenClaw config secret provider/auth profile posture, and governed tool declarations. For example, IT or a workspace operator can record that Telegram is not an approved channel provider, restrict MCP servers and model refs to approved entries, require private-network fetch/browser access to remain disabled, require direct-message session isolation and channel ingress posture -to stay within reviewed bounds, require Gateway bind/auth/HTTP exposure to stay within reviewed +to stay within reviewed bounds, require Gateway bind/auth/HTTP exposure and privileged node commands to stay within reviewed bounds, require agent workspace access and tool denies to stay in a reviewed posture, require OpenClaw config SecretRefs to use managed providers, require config auth profiles to carry provider/mode metadata, require governed tools to @@ -114,6 +114,9 @@ file posture, and tool metadata looks like this: "denyEndpoints": ["chatCompletions", "responses"], "requireUrlAllowlists": true, }, + "nodes": { + "denyCommands": ["system.run"], + }, }, "agents": { "workspace": { @@ -181,7 +184,7 @@ when a concrete rule is present. OpenClaw reads current `channels.*` settings `mcp.servers.*`, `models.providers.*`, selected agent model refs, network SSRF settings, direct-message session scope, channel DM policy, channel group policy, channel/group mention gates, Gateway bind/auth/Control UI/Tailscale/remote/HTTP -posture, OpenClaw config agent sandbox workspace access and tool deny posture, +posture, Gateway node command posture, OpenClaw config agent sandbox workspace access and tool deny posture, data-handling config posture, config secret provider and SecretRef provenance, config auth profile metadata, configured global/per-agent tool posture, and `TOOLS.md` declarations as evidence, then @@ -361,16 +364,23 @@ Every scope present in `policy.jsonc` must be valid and enforceable. #### Gateway -| Policy field | Observed state | Use when | -| --------------------------------------- | ---------------------------------------------- | ------------------------------------------------------------ | -| `gateway.exposure.allowNonLoopbackBind` | `gateway.bind` | Set to `false` to require loopback Gateway binding. | -| `gateway.exposure.allowTailscaleFunnel` | Tailscale serve/funnel Gateway posture | Set to `false` to deny Tailscale Funnel exposure. | -| `gateway.auth.requireAuth` | `gateway.auth.mode` | Set to `true` to reject disabled Gateway auth. | -| `gateway.auth.requireExplicitRateLimit` | `gateway.auth.rateLimit` | Set to `true` to require explicit auth rate-limit config. | -| `gateway.controlUi.allowInsecure` | Control UI insecure auth/device/origin toggles | Set to `false` to deny insecure Control UI exposure toggles. | -| `gateway.remote.allow` | Remote Gateway mode/config | Set to `false` to deny remote Gateway mode. | -| `gateway.http.denyEndpoints` | Gateway HTTP API endpoints | Deny endpoint ids such as `chatCompletions` or `responses`. | -| `gateway.http.requireUrlAllowlists` | Gateway HTTP URL-fetch inputs | Set to `true` to require URL allowlists on URL-fetch inputs. | +| Policy field | Observed state | Use when | +| --------------------------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------ | +| `gateway.exposure.allowNonLoopbackBind` | `gateway.bind` | Set to `false` to require loopback Gateway binding. | +| `gateway.exposure.allowTailscaleFunnel` | Tailscale serve/funnel Gateway posture | Set to `false` to deny Tailscale Funnel exposure. | +| `gateway.auth.requireAuth` | `gateway.auth.mode` | Set to `true` to reject disabled Gateway auth. | +| `gateway.auth.requireExplicitRateLimit` | `gateway.auth.rateLimit` | Set to `true` to require explicit auth rate-limit config. | +| `gateway.controlUi.allowInsecure` | Control UI insecure auth/device/origin toggles | Set to `false` to deny insecure Control UI exposure toggles. | +| `gateway.remote.allow` | Remote Gateway mode/config | Set to `false` to deny remote Gateway mode. | +| `gateway.http.denyEndpoints` | Gateway HTTP API endpoints | Deny endpoint ids such as `chatCompletions` or `responses`. | +| `gateway.http.requireUrlAllowlists` | Gateway HTTP URL-fetch inputs | Set to `true` to require URL allowlists on URL-fetch inputs. | +| `gateway.nodes.denyCommands` | `gateway.nodes.denyCommands` | Require exact node command ids such as `system.run` to be denied in OpenClaw config. | + +`gateway.nodes.denyCommands` is an exact, case-sensitive deny-superset rule. +Use it when policy must prove that privileged node commands are explicitly +denied by OpenClaw config. A deployment that intentionally allows a privileged +node command should update `policy.jsonc` after review instead of relying on +`gateway.nodes.allowCommands` alone. #### Agent workspace @@ -815,6 +825,7 @@ Policy currently verifies: | `policy/gateway-remote-enabled` | Gateway remote mode is active when policy denies it. | | `policy/gateway-http-endpoint-enabled` | A Gateway HTTP API endpoint is enabled while denied by policy. | | `policy/gateway-http-url-fetch-unrestricted` | Gateway HTTP URL-fetch input lacks a required URL allowlist. | +| `policy/gateway-node-command-denied` | A node command denied by policy is not denied by OpenClaw config. | | `policy/agents-workspace-access-denied` | Agent sandbox mode or workspace access is outside the policy allowlist. | | `policy/agents-tool-not-denied` | An agent or default config does not deny a tool required by policy. | | `policy/tools-profile-unapproved` | A configured global or per-agent tool profile is outside the allowlist. | @@ -955,6 +966,22 @@ Example Gateway exposure finding: } ``` +Example Gateway node command finding: + +```json +{ + "checkId": "policy/gateway-node-command-denied", + "severity": "error", + "message": "Gateway node command 'system.run' is denied by policy but not denied by OpenClaw config.", + "source": "policy", + "path": "openclaw config", + "ocPath": "oc://openclaw.config/gateway/nodes/denyCommands", + "target": "oc://openclaw.config/gateway/nodes/denyCommands", + "requirement": "oc://policy.jsonc/gateway/nodes/denyCommands", + "fixHint": "Add 'system.run' to gateway.nodes.denyCommands or update policy after review." +} +``` + Example agent workspace finding: ```json diff --git a/docs/plugins/reference/policy.md b/docs/plugins/reference/policy.md index d02cc0324073..9b07c95137b1 100644 --- a/docs/plugins/reference/policy.md +++ b/docs/plugins/reference/policy.md @@ -26,7 +26,7 @@ The Policy plugin contributes doctor health checks for policy-managed OpenClaw settings and governed workspace declarations. Policy currently covers channel conformance, governed tool metadata, MCP server posture, model-provider posture, private-network access posture, Gateway exposure posture, agent workspace/tool -posture, configured global/per-agent tool posture, configured sandbox runtime +and node command posture, configured global/per-agent tool posture, configured sandbox runtime posture, ingress/channel access posture, data-handling posture, and OpenClaw config secret provider/auth profile posture. @@ -48,6 +48,11 @@ additive `alsoAllow` entries because they can widen effective tool posture. These checks observe config conformance only; they do not read runtime approval state or add runtime enforcement. +Gateway node command rules can require exact, case-sensitive command ids such +as `system.run` to be present in OpenClaw config +`gateway.nodes.denyCommands`. These checks observe config conformance only; +they do not add runtime enforcement or change the gateway command allowlist. + Sandbox posture rules can require approved sandbox modes/backends, deny host container networking, deny container namespace joins, require read-only container mounts, deny container runtime socket mounts and unconfined container profiles,