feat(policy): add channel conformance checks (#80407)

Summary:
- Add the bundled Policy plugin with policy-backed doctor checks for channel conformance.
- Add `openclaw policy check` attestations, accepted-attestation drift checks, and opt-in doctor repair.
- Add policy CLI docs, generated plugin inventory/reference docs, and changelog credit.

Verification:
- node --import tsx scripts/sync-plugin-versions.ts --check
- pnpm plugins:inventory:check
- pnpm docs:list
- git diff --check origin/main..HEAD
- node scripts/run-vitest.mjs extensions/policy/src/policy-state.test.ts extensions/policy/src/cli.test.ts extensions/policy/src/doctor/register.test.ts src/flows/bundled-health-checks.test.ts src/cli/program/register.maintenance.test.ts
- codex review --uncommitted; accepted finding fixed, reran clean
- codex review --commit HEAD
- GitHub CI for 4e09b067f4: CI, Workflow Sanity, CodeQL, CodeQL Critical Quality, OpenGrep PR Diff, Real behavior proof, Dependency Change Awareness all green; reran failed Windows Node setup job successfully

Co-authored-by: Gio Della-Libera <giodl73@gmail.com>
Co-authored-by: Gio Della-Libera <giodl@microsoft.com>
This commit is contained in:
Gio Della-Libera
2026-05-20 03:50:21 -07:00
committed by GitHub
parent 9c5e8eb495
commit cbf72e5e26
27 changed files with 2231 additions and 2 deletions

View File

@@ -35,7 +35,7 @@ Use the setup commands by intent:
| Pairing and channels | [`pairing`](/cli/pairing) · [`qr`](/cli/qr) · [`channels`](/cli/channels) |
| Security and plugins | [`security`](/cli/security) · [`secrets`](/cli/secrets) · [`skills`](/cli/skills) · [`plugins`](/cli/plugins) · [`proxy`](/cli/proxy) |
| Legacy aliases | [`daemon`](/cli/daemon) (gateway service) · [`clawbot`](/cli/clawbot) (namespace) |
| Plugins (optional) | [`path`](/cli/path) · [`voicecall`](/cli/voicecall) (if installed) |
| Plugins (optional) | [`path`](/cli/path) · [`policy`](/cli/policy) · [`voicecall`](/cli/voicecall) (if installed) |
## Global flags

194
docs/cli/policy.md Normal file
View File

@@ -0,0 +1,194 @@
---
summary: "CLI reference for `openclaw policy` channel conformance checks"
read_when:
- You want to check OpenClaw settings against an authored policy.jsonc
- You want policy findings in doctor lint
- You need a policy attestation hash for audit evidence
title: "Policy"
---
# `openclaw policy`
`openclaw policy` is provided by the bundled Policy plugin. Policy is an
enterprise conformance layer over existing OpenClaw settings: `policy.jsonc`
defines authored requirements, OpenClaw observes the active workspace as
evidence, and policy health checks report drift through `doctor --lint`.
This first policy slice manages configured channels. For example, IT can record
that Telegram is not approved, then `doctor --lint` reports any enabled Telegram
channel and `doctor --fix` can turn it off when workspace repairs are explicitly
enabled.
## Quick start
Enable the bundled Policy plugin before first use:
```bash
openclaw plugins enable policy
```
When policy is enabled, doctor can load policy health checks without activating
arbitrary plugins. The plugin remains enabled if `policy.jsonc` is missing, so
doctor can report the missing artifact.
Policy is authored, not generated from the user's current settings. A minimal
channel policy looks like this:
```jsonc
{
"channels": {
"denyRules": [
{
"id": "no-telegram",
"when": { "provider": "telegram" },
"reason": "Telegram is not approved for this workspace.",
},
],
},
}
```
The rules are the authority. A category block is only a namespace; checks run
when a concrete rule is present. OpenClaw reads current `channels.*` settings
and reports settings that do not conform.
Run policy-only checks during authoring:
```bash
openclaw policy check
openclaw policy check --json
openclaw policy check --severity-min error
```
`policy check` runs only the policy check set and emits evidence, findings, and
attestation hashes. The same findings also appear in `openclaw doctor --lint`
when the Policy plugin is enabled.
Example clean JSON output includes stable hashes that can be recorded by an
operator or supervisor:
```json
{
"ok": true,
"attestation": {
"policy": {
"path": "policy.jsonc",
"hash": "sha256:..."
},
"workspace": {
"scope": "policy",
"hash": "sha256:..."
},
"findingsHash": "sha256:...",
"attestationHash": "sha256:..."
},
"checksRun": 5,
"checksSkipped": 0,
"findings": []
}
```
## Configure policy
Policy config lives under `plugins.entries.policy.config`.
```jsonc
{
"plugins": {
"entries": {
"policy": {
"enabled": true,
"config": {
"enabled": true,
"path": "policy.jsonc",
"workspaceRepairs": false,
"expectedHash": "sha256:...",
"expectedAttestationHash": "sha256:...",
},
},
},
},
}
```
| Setting | Purpose |
| ------------------------- | --------------------------------------------------------------- |
| `enabled` | Enable policy checks even before `policy.jsonc` exists. |
| `workspaceRepairs` | Allow `doctor --fix` to edit policy-managed workspace settings. |
| `expectedHash` | Optional hash-lock for the approved policy artifact. |
| `expectedAttestationHash` | Optional hash-lock for the last accepted clean policy check. |
| `path` | Workspace-relative location of the policy artifact. |
Set `plugins.entries.policy.config.enabled` to `false` to disable policy checks
for a workspace while leaving the plugin installed.
## Accept policy state
The attestation hash identifies the stable claim: policy hash, evidence hash,
findings hash, and whether the result was clean. It intentionally does not
include `checkedAt`, so the same policy state produces the same attestation
across repeated checks.
If a later gateway or supervisor uses policy to block, approve, or annotate a
runtime action, it should record the attestation hash from the last clean policy
check. `checkedAt` stays in JSON output for audit logs, but is not part of the
stable attestation hash.
Use this lifecycle when accepting policy state:
1. Author or review `policy.jsonc`.
2. Run `openclaw policy check --json`.
3. If the result is clean, record `attestation.policy.hash` as `expectedHash`.
4. Record `attestation.attestationHash` as `expectedAttestationHash`.
5. Re-run `openclaw doctor --lint` in CI or release gates.
If policy rules change intentionally, update both accepted hashes from a clean
check. If workspace settings change intentionally but policy stays the same,
only `expectedAttestationHash` usually changes.
## Findings
Policy currently verifies:
| Check id | Finding |
| ---------------------------------- | ------------------------------------------------------------------- |
| `policy/policy-jsonc-missing` | Policy is enabled but `policy.jsonc` is missing. |
| `policy/policy-jsonc-invalid` | Policy cannot be parsed or has malformed rules. |
| `policy/policy-hash-mismatch` | Policy does not match configured `expectedHash`. |
| `policy/attestation-hash-mismatch` | Current policy evidence no longer matches the accepted attestation. |
| `policy/channels-denied-provider` | An enabled channel matches a channel deny rule. |
Policy findings can include `target` and `requirement`: the observed workspace
thing that does not conform, and the authored rule that made it a finding.
## Repair
`doctor --lint` and `policy check` are read-only.
`doctor --fix` only edits policy-managed workspace settings when
`workspaceRepairs` is explicitly enabled. Without that opt-in, policy checks
report what they would repair and leave settings unchanged.
In this version, repair can disable channels that are enabled in OpenClaw config
but denied by `channels.denyRules`. Enable `workspaceRepairs` only after the
policy file has been reviewed, because a valid deny rule can turn off a
configured channel:
```jsonc
{
"plugins": {
"entries": {
"policy": {
"config": {
"workspaceRepairs": true,
},
},
},
},
}
```
## Exit codes
`policy check` exits `0` when there are no findings at the threshold, `1` when
findings are present, and `2` for argument or runtime failures.