diff --git a/rfcs/0003-policy-conformance.md b/rfcs/0003-policy-conformance.md new file mode 100644 index 00000000..0c5ef7d0 --- /dev/null +++ b/rfcs/0003-policy-conformance.md @@ -0,0 +1,189 @@ +--- +title: Policy Conformance +authors: + - Gio Della-Libera +created: 2026-05-27 +last_updated: 2026-07-15 +status: accepted +issue: +rfc_pr: https://github.com/openclaw/rfcs/pull/40 +--- + +# Proposal: Policy Conformance + +## Summary + +Define OpenClaw Policy as an authored configuration-conformance and audit-evidence layer over existing OpenClaw settings. Operators write `policy.jsonc`; OpenClaw observes attributable workspace, configuration, and named product-artifact evidence; `openclaw policy check`, `compare`, and `watch` report drift; and Policy findings also participate in Doctor's structured health surface. Policy does not become a second runtime configuration system or a request-time authorization engine. + +The normative Policy 1.0 contract is in [Policy Conformance 1.0 specification](0003/policy-conformance-v1-spec.md). + +## Motivation + +Operators need to answer four related questions without duplicating OpenClaw configuration: + +1. Does the active workspace conform to an approved policy? +2. Is a workspace policy equal to or stricter than an organization baseline? +3. Has accepted evidence drifted since the last clean review? +4. Can Doctor explain and, where safe, narrow a nonconforming setting? + +The original Policy RFC established configuration conformance, scoped overlays, stable findings, and attestations. The implementation has since expanded to cover named `exec-approvals.json` evidence, Gateway node-command deny posture, continuous attestation watching, schema-owned strictness metadata, and classified repair guidance. + +Those additions need one coherent contract. In particular, repair must not turn Policy into an authority that silently chooses credentials, providers, sandbox backends, exposure models, or approval posture. Automatic repair is limited to deterministic narrowing changes. Ambiguous or high-blast-radius changes remain review-required or manual. + +## Goals + +- Keep `policy.jsonc` authoritative for required posture while OpenClaw config remains authoritative for runtime behavior. +- Reject unsupported policy fields instead of silently ignoring them. +- Emit stable findings with attributable evidence and `oc://` references. +- Produce deterministic policy, evidence, findings, and attestation hashes. +- State the integrity boundary of those hashes without presenting them as signatures. +- Compare a workspace policy against an authored baseline using shared strictness metadata. +- Support stricter agent- and channel-scoped overlays. +- Cover Gateway node-command deny posture without treating Policy as node authorization. +- Classify every Policy finding as automatic, review-required, manual, validate-only, or unsupported. +- Apply only deterministic narrowing repairs, and only after explicit workspace repair opt-in. +- Keep Policy findings available through both `openclaw policy check` and `openclaw doctor --lint`. + +## Non-Goals + +- Replacing `openclaw.json` or other owner-managed configuration. +- Generating an approved policy from current settings and calling it compliant. +- Inspecting raw secret values, credential stores, arbitrary files, logs, or transient runtime decisions. +- Authorizing or denying tool calls, node invocations, or network requests at request time. +- Automatically choosing credentials, model providers, sandbox backends, Gateway auth modes, or exec-approval posture. +- Mirroring every OpenClaw configuration field into Policy. +- Treating a clean config-level check as proof that no sensitive data exists. +- Providing signed, tamper-proof, or fleet-wide audit storage. +- Making `policy watch` a fail-closed runtime enforcement mechanism. + +## Proposal + +### Author and evaluate policy + +Policy is provided by the bundled Policy plugin. Operators enable the plugin and author `policy.jsonc`: + +```bash +openclaw plugins enable policy +openclaw policy check +openclaw policy check --json +``` + +Each rule states required posture. A check runs only when its concrete rule is present. Unsupported keys and invalid selector/section combinations fail as invalid policy rather than being ignored. + +Policy evaluation produces: + +- the authored policy hash; +- attributable, redacted evidence; +- stable structured findings; +- an evidence hash; +- a findings hash; +- a stable attestation hash that excludes the observation timestamp. + +`policy check` is read-only. Its JSON findings include `policy.fixRecommendation` metadata so automation can distinguish automatic, review-required, manual, validate-only, and unsupported remediation classes without inferring them from prose. + +The hashes identify exact policy, evidence, and finding content. They are not signatures and do not make local files tamper-proof. An operator that needs durable audit assurance must store accepted hashes and check output in a trusted external control plane or evidence system. + +### Compare baselines and watch accepted state + +`openclaw policy compare --baseline ` compares two authored policies. It does not inspect runtime state. The checked policy must contain every required baseline rule and be equal or stricter according to schema-owned metadata. + +`openclaw policy watch` repeatedly evaluates current evidence and reports when findings appear or the current attestation no longer matches `expectedAttestationHash`. `--once` provides the same drift check for CI and release gates. + +Watch is a per-workspace observer. It does not block runtime actions, replace supervisor monitoring, or provide fleet distribution by itself. + +The same strictness metadata owns: + +- baseline comparison; +- overlapping scoped-overlay validation; +- empty-list semantics; +- allowed enum values; +- normalization rules; +- the check ids associated with each policy field. + +### Use attributable evidence only + +Policy may evaluate existing OpenClaw configuration, workspace declarations, and named product artifacts when they provide stable, reviewable posture. + +`exec-approvals.json` is explicit opt-in evidence. Policy retains posture such as default and per-agent security modes, auto-allow-skills posture, and reviewed allowlist patterns. It omits socket credentials, command text, resolved paths, timestamps, and approval-session details. Missing or invalid required evidence is a finding, not an inferred pass. + +Policy does not read per-agent credential stores or raw secret values. Secret and auth-profile checks use config declarations and SecretRef metadata only. + +### Support scoped overlays + +Named scopes apply stricter rules to selected targets: + +- `agentIds` can scope tools, workspace access, sandbox, session-memory data handling, and exec-approval posture. +- `channelIds` can scope channel ingress posture. + +Global policy still applies. Repeated rules for the same target must be equal or stricter. A weaker duplicate claim is invalid before evidence evaluation. + +### Cover Gateway node-command posture + +`gateway.nodes.denyCommands` is a case-sensitive deny-superset rule. Policy reports `policy/gateway-node-command-denied` when a command required by policy, such as `system.run`, is not present in OpenClaw's configured node-command deny list. + +This remains conformance, not authorization. The Gateway node-command policy continues to own runtime command admission. A deployment that intentionally permits a privileged command must update the authored policy after review. + +### Classify and constrain repairs + +Every Policy finding has one fix class: + +| Fix class | Meaning | +| --- | --- | +| `automatic` | A deterministic narrowing change can be applied without choosing new authority or capability. | +| `reviewRequired` | A concrete change can be previewed or described, but an operator must approve the target or blast radius. | +| `manual` | Repair belongs to another owner flow, artifact, credential, or policy review process. | +| `validateOnly` | The finding can be checked but has no repair action. | +| `unsupported` | Evidence is insufficient to define a truthful repair. | + +Automatic repairs require: + +```jsonc +{ + "plugins": { + "entries": { + "policy": { + "config": { + "workspaceRepairs": true + } + } + } + } +} +``` + +Without that opt-in, `doctor --fix` reports a skipped repair and warning. Automatic repair may only narrow existing product-managed config. Current narrowers include disabling denied channels, adding required global and agent-workspace tool denies, disabling elevated tools, closing open group ingress, restoring mention gates, disabling insecure Control UI toggles, disabling denied Gateway HTTP endpoints, switching remote Gateway mode to local, restoring sensitive-log redaction, and disabling telemetry content capture. + +Scoped findings are skipped when a shared config mutation would affect targets outside the selected scope. Repair must not broaden policy, add capability, or guess an owner-specific value. + +Automatic repair returns a patched OpenClaw config through Doctor's normal repair path rather than writing config directly. Doctor remains responsible for the standard config-write, validation, backup, and post-repair detection flow. + +Review-required preview currently covers non-loopback Gateway bind and Gateway node-command deny additions. It returns structured effects and warnings but does not mutate config. + +### Preserve one shared health signal + +Policy-specific authoring workflows use `policy check`, `compare`, and `watch`. The final workspace health gate remains: + +```bash +openclaw doctor --lint +``` + +Policy checks register through the shared health contract. Their stable finding ids, evidence references, and repair metadata remain consistent across Policy CLI and Doctor output. + +## Rationale + +This design separates three kinds of authority: + +- `policy.jsonc` owns approved posture; +- OpenClaw configuration and named artifacts own observed behavior and evidence; +- the relevant runtime subsystem owns request-time enforcement. + +That separation keeps Policy useful to operators and auditors without adding a second control plane. Schema-owned strictness metadata avoids independent comparison implementations drifting apart. Explicit repair classes make remediation inspectable, while the narrow automatic-repair bar prevents a clean-looking result from hiding an unreviewed authority change. + +Policy may observe broadly and explain precisely, but it mutates only deterministic narrowing settings, remains removable as a plugin, and adds no request-path enforcement latency. + +## Unresolved questions + +- Which additional review-required findings should gain structured previews after their target-selection rules are proven? +- Should new selector types be added beyond `agentIds` and `channelIds`, and what evidence would make them attributable? +- Which named product artifacts meet the same stability and redaction bar as `exec-approvals.json`? +- Should a future runtime enforcement RFC consume a clean Policy attestation, and which runtime owner would define freshness and failure behavior? diff --git a/rfcs/0003/policy-conformance-v1-spec.md b/rfcs/0003/policy-conformance-v1-spec.md new file mode 100644 index 00000000..dde53982 --- /dev/null +++ b/rfcs/0003/policy-conformance-v1-spec.md @@ -0,0 +1,229 @@ +# Policy Conformance 1.0 specification + +## Status + +This document is the normative sidecar specification for RFC 0003. + +The keywords **MUST**, **MUST NOT**, **SHOULD**, and **MAY** are normative. + +## 1. Ownership model + +1. `policy.jsonc` MUST define required posture. +2. OpenClaw config and named product artifacts MUST remain the sources of observed evidence. +3. Policy MUST NOT become a second runtime configuration file. +4. Policy findings MUST NOT be treated as request-time authorization decisions. +5. Unsupported policy keys MUST produce an invalid-policy finding. + +## 2. Command contract + +### 2.1 `policy check` + +`openclaw policy check` MUST: + +- evaluate the selected `policy.jsonc`; +- collect attributable and redacted evidence; +- emit stable findings; +- calculate policy, evidence, findings, and attestation hashes; +- exit `0` when no finding meets the selected severity; +- exit `1` when a finding meets the selected severity; +- exit `2` on argument or runtime failure. + +`--json` MUST emit the attestation, evidence, check counts, and findings. + +Each registered Policy JSON finding MUST include `policy.fixRecommendation`. +Optional recommendation fields remain omitted when they do not apply. Example: + +```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.", + "ocPath": "oc://openclaw.config/gateway/nodes/denyCommands", + "requirement": "oc://policy.jsonc/gateway/nodes/denyCommands", + "policy": { + "fixRecommendation": { + "fixClass": "reviewRequired", + "policyPath": ["gateway", "nodes", "denyCommands"], + "configTargets": ["gateway.nodes.denyCommands"], + "summary": "Add the command to gateway node denyCommands or update policy after review." + } + } +} +``` + +### 2.2 `policy compare` + +`openclaw policy compare --baseline ` MUST compare authored policy files only. + +The checked policy MUST be equal or stricter than the baseline for every baseline rule. Comparison MUST use `POLICY_RULE_METADATA` or its successor as the single source for strictness, normalization, allowed values, and empty-list semantics. + +### 2.3 `policy watch` + +`openclaw policy watch` MUST report: + +- `clean` when the check is clean and accepted attestation matches; +- `findings` when non-attestation findings exist; +- `stale` when current evidence does not match `expectedAttestationHash`. + +`--once` MUST perform one evaluation. Continuous mode SHOULD suppress duplicate unchanged reports. + +Watch MUST remain a per-workspace observer. It MUST NOT be represented as request-time enforcement or a fleet distribution mechanism. + +## 3. Evidence and attestation + +Evidence MUST be: + +- attributable to a stable config, workspace, or named-artifact source; +- deterministic for the same observed posture; +- redacted to omit secret values and unrelated operational data; +- addressable with stable `oc://` references where possible. + +The attestation MUST identify: + +- policy hash; +- evidence hash; +- findings hash; +- clean or dirty state. + +The stable attestation hash MUST exclude observation time. `checkedAt` MAY be included for audit chronology. + +Policy hashes are content identifiers, not signatures. Policy MUST NOT describe the local hash tuple as tamper-proof or independently authentic. Durable audit assurance MUST come from storing accepted hashes and reports in a trusted external system. + +Policy MUST NOT read raw secret values, arbitrary workspace files, logs, or per-agent credential stores. + +## 4. Named artifact evidence + +An artifact MAY become Policy evidence only when it has: + +1. a stable product-owned schema; +2. explicit policy opt-in; +3. posture-oriented fields; +4. deterministic redaction; +5. stable evidence references; +6. missing, invalid, and drift tests. + +For `exec-approvals.json`: + +- any substantive `execApprovals` rule MUST require valid attributable evidence; +- missing required evidence MUST emit `policy/exec-approvals-missing`; +- invalid evidence MUST emit `policy/exec-approvals-invalid`; +- socket credentials, command text, resolved paths, timestamps, and approval-session details MUST be omitted. + +## 5. Scoped overlays + +Supported selectors are: + +| Selector | Supported sections | +| --- | --- | +| `agentIds` | `tools`, `agents.workspace`, `sandbox`, `dataHandling.memory`, `execApprovals` | +| `channelIds` | `ingress.channels` | + +A scope MUST contain at least one supported selector. Unsupported selector/section combinations MUST be rejected. + +When multiple scopes apply to the same target and field, the combined claim MUST be equal or stricter. A weaker duplicate claim MUST fail policy validation. + +## 6. Strictness semantics + +Policy fields MUST declare one strictness kind: + +- `allowlist-subset`; +- `denylist-superset`; +- `ordered-string`; +- `requires-true`; +- `requires-false`; +- `exact-list`. + +Empty arrays MUST NOT have a universal meaning. Each list field MUST declare whether an empty list is meaningful or disables the rule. + +The same metadata MUST drive baseline comparison and overlapping-scope validation. + +## 7. Gateway node commands + +`gateway.nodes.denyCommands` MUST: + +- compare exact command ids case-sensitively; +- use deny-superset strictness; +- observe `gateway.nodes.denyCommands`; +- emit `policy/gateway-node-command-denied` for every required command absent from config. + +Policy MUST NOT infer denial from the absence of `gateway.nodes.allowCommands`. Runtime admission remains owned by the Gateway node-command policy. + +## 8. Repair classification + +Every registered Policy check MUST have fix metadata with: + +- `checkId`; +- `fixClass`; +- summary; +- optional policy path; +- optional config targets. + +Allowed fix classes are: + +| Class | Required behavior | +| --- | --- | +| `automatic` | MAY mutate only deterministic narrowing config after explicit opt-in. | +| `reviewRequired` | MAY return a non-mutating structured preview. | +| `manual` | MUST direct the operator to the owning workflow or artifact. | +| `validateOnly` | MUST remain detection-only. | +| `unsupported` | MUST explain why a truthful repair is unavailable. | + +## 9. Automatic repair + +Automatic Policy repair MUST require: + +```text +plugins.entries.policy.config.workspaceRepairs = true +``` + +Without that value, repair MUST return `skipped` and MUST NOT mutate config. + +Automatic repair MUST: + +- narrow existing product-managed config; +- avoid choosing credentials, providers, sandbox backends, auth modes, or approval posture; +- skip a scoped repair when the available mutation target is shared more broadly than the scope; +- return patched config through the Doctor health contract instead of writing config directly; +- return structured change summaries; +- allow Doctor's post-repair detection to validate the result. + +The shipped automatic set includes: + +- `policy/channels-denied-provider`; +- `policy/agents-tool-not-denied`; +- `policy/tools-elevated-enabled`; +- `policy/tools-required-deny-missing`; +- `policy/gateway-control-ui-insecure`; +- `policy/gateway-http-endpoint-enabled`; +- `policy/gateway-remote-enabled`; +- `policy/ingress-open-groups-denied`; +- `policy/ingress-group-mention-required`; +- `policy/data-handling-redaction-disabled`; +- `policy/data-handling-telemetry-content-capture`. + +## 10. Review-required preview + +A review-required preview MUST NOT mutate config. + +It SHOULD return: + +- `status: "skipped"`; +- a reason explaining that review is required; +- a human-readable proposed change; +- a structured effect with `dryRunSafe: true`. + +The shipped preview set includes: + +- `policy/gateway-non-loopback-bind`; +- `policy/gateway-node-command-denied`. + +Classification as `reviewRequired` does not imply that a preview implementation exists yet. + +## 11. Compatibility + +- Existing supported policy fields and finding ids SHOULD remain stable. +- A renamed field SHOULD have a documented deprecation window. +- Changes to strictness or attestation inputs MUST be treated as contract changes. +- Changes to evidence canonicalization or hash inputs MUST be treated as attestation contract changes. +- Policy checks MUST remain available through `doctor --lint`. +- Disabling the Policy plugin MUST remove Policy evaluation without changing unrelated OpenClaw runtime behavior. diff --git a/rfcs/needs_refactoring/policy-conformance.md b/rfcs/needs_refactoring/policy-conformance.md deleted file mode 100644 index 4337a9a2..00000000 --- a/rfcs/needs_refactoring/policy-conformance.md +++ /dev/null @@ -1,219 +0,0 @@ ---- -title: Policy Conformance 1.0 -authors: - - giodl73-repo -created: 2026-05-27 -last_updated: 2026-06-15 -status: accepted -issue: -rfc_pr: https://github.com/openclaw/rfcs/pull/6 ---- - -# Proposal: Policy Conformance 1.0 - -## Summary - -Define OpenClaw policy as a configuration conformance and audit-evidence layer over existing OpenClaw settings. A workspace operator authors `policy.jsonc`, OpenClaw observes the active workspace configuration as evidence, and policy checks report drift through `openclaw policy check` and the shared `doctor --lint` health surface. - -## Motivation - -Policy 1.0 should help operators answer a narrow question: does this workspace configuration conform to the approved policy file? It should not become a second configuration language, a secrets-management system, or a broad runtime enforcement layer. - -The Policy plugin contributes conformance checks to OpenClaw. Policy rules live in `policy.jsonc`; plugin settings live under `plugins.entries.policy.config`. The current policy surface covers configured channels, MCP server ids, model provider ids and selected model refs, private-network SSRF posture, ingress and channel access posture, Gateway exposure posture, agent workspace posture, global and per-agent tool posture, governed tool metadata declarations, sandbox runtime posture, config secret provider and SecretRef provenance, config auth profile metadata, exec approval artifact posture, and policy-to-policy baseline comparison. - -The final health gate remains `doctor --lint`. Policy-specific authoring and audit workflows can run `openclaw policy check`, but policy findings should also flow into Doctor so operators have one shared lint signal. - -As policy grows, there is pressure to mirror every OpenClaw setting in `policy.jsonc`. That would make policy harder to review, harder to keep current, and ambiguous about which file actually controls runtime behavior. Policy 1.0 should stay focused on conformance questions that can be answered from observed OpenClaw configuration and workspace declarations. - -Evidence quality varies by surface. Some posture is directly observable from config, such as configured channels, provider ids, MCP server ids, and Gateway bind posture. Some posture is stored in named product artifacts. Those artifacts can be policy evidence only when they have a stable product schema, contain reviewable posture rather than secret material, are read by an explicit opt-in policy section, and can be redacted to stable evidence fields. `exec-approvals.json` is the first concrete example because it stores default and per-agent exec approval posture plus reviewed allowlist patterns. This RFC does not grant blanket coverage for every file under the OpenClaw state directory. Other posture depends on runtime-specific details, credential liveness, filesystem integrity, arbitrary file contents, logs, or secret material that policy should not inspect. A policy field without attributable evidence should fail as unobservable for that target instead of becoming a best-effort pass. - -Enterprise baselines and per-agent or per-channel overlays both need to answer whether one policy is equal or stricter than another. If each check implements that comparison separately, scoped overlays and baseline comparison will drift. Strictness metadata should be owned with the policy schema so baseline compare, scoped overlay validation, and future repair previews use the same rules. - -Policy findings can identify nonconforming config, but they are not runtime authorization decisions by themselves. Any future enforcement must name the runtime hook, evidence, and tests that prove the same contract at the point of use. - -## Goals - -- Keep policy anchored in existing OpenClaw configuration and workspace declarations. -- Report conformance findings with stable check ids, evidence references, and attestation hashes. -- Support organization baselines with `openclaw policy compare --baseline`. -- Allow named scoped overlays for selectors such as agent ids and channel ids. -- Require scoped overlays to be equal or more restrictive than broader policy when they touch the same field. -- Use shared strictness metadata for policy comparison and scoped overlay validation. -- Cover the first enterprise conformance areas without copying every OpenClaw config option into policy. -- Keep runtime enforcement explicitly out of scope unless an existing OpenClaw runtime hook can prove and enforce the same contract. - -## Non-Goals - -- Replacing OpenClaw configuration. -- Claiming there are no secrets in config or taking ownership of secret-value management. -- Inspecting per-agent credential stores, secret material, or runtime approval decisions. -- Enforcing every policy requirement at runtime. -- Mirroring every plugin, channel, provider, or agent setting. -- Treating unobservable runtime state as passing evidence. -- Adding an operator-facing governance product beyond policy conformance. - -## Proposal - -OpenClaw should not generate an authoritative policy from the current workspace and call that compliant. Operators author the required posture. OpenClaw then observes active settings and reports where they drift. Generated examples, repair previews, or upgrade helpers can assist authors, but the approved `policy.jsonc` remains the authority. - -Each check should identify the policy requirement being evaluated, the OpenClaw config or workspace declaration used as evidence, whether the evidence conforms, the stable finding id when it does not conform, and the policy, evidence, findings, and attestation hashes for audit records. When OpenClaw cannot observe a configured policy field for the selected target, the result should be a finding, not a silent pass. For example, a container posture field that cannot be observed for a selected sandbox backend should report that the claim is unobservable for that target. - -Policy field names should express the compliance concern rather than duplicate low-level config fields. For example, sandbox policy should say whether a container posture allows host networking or requires read-only mounts. It should not expose Docker-specific names unless Docker is the compliance concern. OpenClaw config remains the source of behavior. Policy only states the approved posture and reports whether the current config satisfies it. - -Policy 1.0 is config conformance. It can make findings about tool posture, sandbox posture, ingress posture, and Gateway exposure based on observed config, but those findings are not runtime authorization decisions by themselves. Future runtime enforcement can reuse policy rules only where OpenClaw has a stable runtime hook, clear evidence, and tests that prove the same contract at the point of use. - -Policy supports top-level rules for broad workspace posture and named `scopes.` blocks for stricter posture on selected targets. A scope name is descriptive. Matching comes from selectors inside the scope. The initial selectors are: - -| Selector | Supported sections | Purpose | -| --- | --- | --- | -| `agentIds` | `tools`, `agents.workspace`, `sandbox`, `execApprovals` | Apply stricter agent, tool, sandbox, or exec approval posture to one or more runtime agents. | -| `channelIds` | `ingress.channels` | Apply stricter channel ingress posture to one or more configured channels. | - -Unsupported selector and section combinations should be rejected instead of ignored. A scope without an enforceable selector should be invalid. The same target can appear in multiple scopes. That allows operators to compose policy by purpose, such as "release agents" and "restricted shell agents." If two applicable scopes touch the same field, the duplicate field must be equal or more restrictive according to shared policy metadata. Weaker duplicate claims should fail during policy compilation before check evaluation begins. - -Policy should keep comparison semantics in schema-owned metadata rather than custom per-check logic. The same metadata should be used for `policy compare --baseline`, scoped overlay validation, and future dry-run upgrade or repair previews. The initial rule types are allow-lists, deny-lists, required booleans, exact lists, and ordered strings. Empty values should not receive a universal meaning. Each policy field should define whether an empty array means "allow nothing," "require nothing," or "rule omitted." A check should run only when its concrete rule is present. - -`openclaw policy compare --baseline ` compares one policy file to another policy file. It does not inspect runtime state, credentials, or secret values. This supports the common enterprise lifecycle: - -1. A central security or compliance owner authors an official baseline policy. -2. A workspace operator proposes or edits a workspace `policy.jsonc`. -3. `policy compare --baseline official.policy.jsonc --policy policy.jsonc` verifies that the workspace policy is not missing or weaker than the baseline. -4. `openclaw policy check` verifies that the active workspace config conforms to the approved workspace policy. - -The checked policy can be stricter than the baseline. A broad top-level checked rule can satisfy a scoped baseline rule when it is equally or more restrictive for the selected target. - -The seed conformance areas are channels, MCP, models, private network posture, ingress, Gateway exposure, agents, tools, sandbox posture, exec approvals, secrets, and auth profiles. These checks are intentionally conformance-level. Policy can report that a denied provider, channel, MCP server, private-network posture, or exec approval posture is configured. It does not prove that no external system can ever reach the same service, and it does not make runtime approval decisions. - -Ingress policy covers direct-message session scope and channel group admission posture. Channel-scoped ingress should use `channelIds` because channel posture is attributable. Session DM scope remains global while the evidence is not channel-attributable. Gateway exposure policy covers bind posture, auth posture, Control UI posture, remote Gateway posture, and HTTP endpoint posture. These checks should stay close to operator-facing exposure questions rather than becoming a copy of every Gateway config field. - -Agent workspace policy and tool posture policy cover configured workspace access, tool profile, filesystem posture, exec posture, elevated mode, additive tool grants, and deny lists. These are config conformance checks, not runtime operator approval checks. Exec approval policy can separately cover the named `exec-approvals.json` artifact for required file presence, default and per-agent security posture, and reviewed allowlist patterns. Sandbox policy covers sandbox mode, backend, and observable container/browser posture. Container posture fields should be allowed only where OpenClaw can observe them for the selected target. Operators can use scopes to apply different sandbox requirements to different agent groups. - -The `execApprovals` policy section is an explicit opt-in to read the active named `exec-approvals.json` product artifact. A configured exec approvals posture rule requires valid attributable artifact evidence. Missing artifacts must report `policy/exec-approvals-missing`; unreadable or schema-invalid artifacts must report `policy/exec-approvals-invalid`; absent evidence must not be replaced with inferred runtime defaults. `requireFile: false` by itself is a no-op and does not require or read the artifact. Any other configured `execApprovals` rule, including scoped `defaults`, scoped `agents`, or `allowlist.expected` rules, requires the valid redacted artifact evidence needed to evaluate that rule. - -The exec approvals evidence model is posture-only. Policy may retain default security mode, per-agent effective security mode, and reviewed allowlist pattern identifiers. It must omit socket paths, socket tokens, command text, resolved paths, timestamps, approval-session details, and any other data that is not needed to evaluate the configured posture rule. Evidence references should use stable `oc://exec-approvals.json/...` paths so findings can link a policy requirement to the redacted artifact record without exposing the raw artifact. - -For example, a policy can require the approvals artifact, deny permissive approval defaults, and allow selected agents to use only reviewed exec approval allowlists: - -```jsonc -{ - "execApprovals": { - "requireFile": true, - "defaults": { - // Security modes: "deny", "allowlist", or "full". - // This default permits only the locked-down deny posture. - "allowSecurity": ["deny"] - } - }, - "scopes": { - "restricted-shell": { - "agentIds": ["family-agent", "groups-agent"], - "execApprovals": { - "agents": { - // Selected agents may use reviewed allowlist posture, but not "full". - "allowSecurity": ["allowlist"], - "allowlist": { - "expected": ["travel-hub", "calendar-cli", "/bin/date"] - } - } - } - } - } -} -``` - -The collected evidence is redacted posture, not the raw artifact. For example, this artifact includes socket credentials and command text: - -```json -{ - "socket": { "path": "/tmp/openclaw.sock", "token": "secret-token" }, - "defaults": { "security": "full" }, - "agents": { - "sebby": { - "security": "full", - "allowlist": [{ "pattern": "deploy", "commandText": "deploy --prod" }] - } - } -} -``` - -Policy evidence should retain only attributable posture records: - -```json -[ - { - "kind": "defaults", - "source": "oc://exec-approvals.json/defaults", - "security": "full" - }, - { - "kind": "agent", - "source": "oc://exec-approvals.json/agents/sebby", - "agentId": "sebby", - "security": "full" - }, - { - "kind": "allowlist", - "source": "oc://exec-approvals.json/agents/sebby/allowlist/#0", - "agentId": "sebby", - "pattern": "deploy" - } -] -``` - -A finding then links the policy requirement to the redacted evidence reference: - -```json -{ - "checkId": "policy/exec-approvals-agent-security-unapproved", - "ocPath": "oc://exec-approvals.json/agents/sebby", - "requirement": "oc://policy.jsonc/execApprovals/agents/allowSecurity", - "message": "exec approvals agent 'sebby' uses unapproved security mode 'full'." -} -``` - -Policy can require managed secret provider declarations, deny insecure provider sources, require auth profile metadata in OpenClaw config, and attest redacted posture from named non-secret product artifacts. It should not read raw secret values or claim to regulate all secret lifecycle concerns. Secrets management, credential storage, rotation, and runtime credential access remain owned by their existing OpenClaw systems and future dedicated work. - -The policy evidence roadmap should stay focused on posture that can be expressed as authored policy and supported by attributable, redacted evidence: - -- P1 covers the highest-value policy evidence gaps. `execApprovals` should read `exec-approvals.json` through the explicit policy section described above and report required file presence, invalid artifact shape, default security posture, per-agent effective security posture, and exact reviewed allowlist patterns. Sandbox policy should also gain a mode allowlist so a policy can assert that selected agents must remain `off` when the approved isolation model is exec allowlists plus tool denies rather than sandboxing. -- P2 covers additional config-backed policy rules where OpenClaw already has stable evidence: elevated default posture, agent-to-agent enablement and allowlists, trusted safe-bin directories, and plugin allow/deny policy. These should use existing allowlist, denylist, exact-list, or required-boolean strictness metadata rather than bespoke comparison logic. -- P3 remains explicit and low priority. Routing bindings may be policy evidence if the rule is framed as static routing posture. Cron recurring-job counts should not become policy evidence unless a future proposal defines a stable, low-noise cron posture artifact rather than treating dynamic job count as compliance state. - -Future evidence files should meet the same bar as `exec-approvals.json`: stable product schema, explicit policy opt-in, posture-oriented fields, deterministic redaction, stable `oc://` evidence references, and focused tests for invalid, missing, and drift states. Policy should not inspect credential stores, raw secret material, arbitrary wrapper file contents, filesystem layout integrity, transient runtime decisions, or logs. Those surfaces should remain with Doctor, command-specific self-tests, credential/status commands, or log monitoring. - -Each policy section should document the `policy.jsonc` syntax, the observed OpenClaw state, the reason an operator would set the field, whether the check is global or supports selectors, whether missing or unobservable evidence is a finding, and whether the rule participates in baseline comparison and scoped strictness. The CLI docs should continue to show: - -```bash -openclaw policy check -openclaw policy check --json -openclaw policy compare --baseline official.policy.jsonc -openclaw doctor --lint -``` - -The rollout plan is: - -1. Land policy sections as narrow conformance PRs, each with docs and focused tests. -2. Keep PR bodies explicit about syntax, evidence, check ids, and config-only semantics. -3. Run local review and ClawSweeper until each PR has no findings. -4. Update `docs/cli/policy.md` as the canonical user-facing policy reference. -5. Add strictness metadata for every policy field that participates in compare or scoped overlay validation. -6. Add maintainer-only drift checks that flag new config areas or changed config semantics that policy may need to consider. -7. Track future policy evidence work as separate implementation issues: P1 for exec approvals plus sandbox mode allowlists, P2 for config-backed coverage, and separate non-policy work for Doctor, command self-tests, credential/status commands, or log monitoring. - -## Rationale - -This design keeps policy as a compliance layer over OpenClaw configuration rather than a parallel configuration system. It lets operators compare approved policy files, check active workspace configuration against the approved workspace policy, and collect stable findings and attestation hashes without claiming to inspect secret material or enforce runtime authorization. - -The alternative of mirroring every config field into policy would make policy comprehensive on paper, but it would duplicate ownership and make drift harder to control. The alternative of treating policy as runtime enforcement would overclaim the evidence available in Policy 1.0 and would require separate runtime hooks that this RFC does not define. - -Policy rules are operator and audit contracts once shipped. Renaming a field, changing a finding id, or changing strictness semantics can break downstream baselines and attestation workflows. When a policy field must change, prefer accepting the old field during a deprecation window, reporting a clear Doctor or policy finding, documenting the migration in the CLI policy reference, and preserving attestation behavior where possible. - -## Follow-up questions - -The exec approvals artifact contract is resolved for this RFC: configured `execApprovals` posture rules require valid attributable artifact evidence, and missing or invalid artifacts produce explicit findings instead of inferred runtime defaults. The remaining questions are follow-up design choices for Policy after 1.0 rather than blockers for the exec approvals evidence contract: - -- Should `policy compare` remain the final command name, or should OpenClaw expose an alias such as `policy conform` for baseline workflows? -- Which additional selectors are worth adding after `agentIds` and `channelIds`? -- Should Gateway or provider policy ever support selectors, or are those intentionally workspace-global until OpenClaw has attributable evidence? -- What is the minimum maintainer drift check needed to keep policy current with config changes without making policy a public config-audit command? -- Which runtime enforcement hooks, if any, should explicitly consume policy rules after 1.0?