Skip to content

Commit cbf72e5

Browse files
giodl73-repoGio Della-Libera
andauthored
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 4e09b06: 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>
1 parent 9c5e8eb commit cbf72e5

27 files changed

Lines changed: 2231 additions & 2 deletions

.github/labeler.yml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,11 @@
286286
- changed-files:
287287
- any-glob-to-any-file:
288288
- "extensions/oc-path/**"
289+
"extensions: policy":
290+
- changed-files:
291+
- any-glob-to-any-file:
292+
- "extensions/policy/**"
293+
- "docs/cli/policy.md"
289294
"extensions: open-prose":
290295
- changed-files:
291296
- any-glob-to-any-file:

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ Docs: https://docs.openclaw.ai
77
### Changes
88

99
- Dependencies: bump the bundled Codex harness to `@openai/codex` `0.132.0` and refresh the app-server model-list docs for the new catalog.
10+
- CLI/policy: add the bundled Policy plugin for policy-backed channel conformance checks, doctor lint findings, and opt-in workspace repair. (#80407) Thanks @giodl73-repo.
1011
- Agents/config: allow `agents.list[].experimental.localModelLean` so lean local-model mode can be enabled for one configured agent instead of globally.
1112
- Providers/xAI: add device-code OAuth login so remote and headless setups can authorize xAI without a localhost browser callback. (#84005) Thanks @fuller-stack-dev.
1213

docs/cli/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ Use the setup commands by intent:
3535
| Pairing and channels | [`pairing`](/cli/pairing) · [`qr`](/cli/qr) · [`channels`](/cli/channels) |
3636
| Security and plugins | [`security`](/cli/security) · [`secrets`](/cli/secrets) · [`skills`](/cli/skills) · [`plugins`](/cli/plugins) · [`proxy`](/cli/proxy) |
3737
| Legacy aliases | [`daemon`](/cli/daemon) (gateway service) · [`clawbot`](/cli/clawbot) (namespace) |
38-
| Plugins (optional) | [`path`](/cli/path) · [`voicecall`](/cli/voicecall) (if installed) |
38+
| Plugins (optional) | [`path`](/cli/path) · [`policy`](/cli/policy) · [`voicecall`](/cli/voicecall) (if installed) |
3939

4040
## Global flags
4141

docs/cli/policy.md

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
---
2+
summary: "CLI reference for `openclaw policy` channel conformance checks"
3+
read_when:
4+
- You want to check OpenClaw settings against an authored policy.jsonc
5+
- You want policy findings in doctor lint
6+
- You need a policy attestation hash for audit evidence
7+
title: "Policy"
8+
---
9+
10+
# `openclaw policy`
11+
12+
`openclaw policy` is provided by the bundled Policy plugin. Policy is an
13+
enterprise conformance layer over existing OpenClaw settings: `policy.jsonc`
14+
defines authored requirements, OpenClaw observes the active workspace as
15+
evidence, and policy health checks report drift through `doctor --lint`.
16+
17+
This first policy slice manages configured channels. For example, IT can record
18+
that Telegram is not approved, then `doctor --lint` reports any enabled Telegram
19+
channel and `doctor --fix` can turn it off when workspace repairs are explicitly
20+
enabled.
21+
22+
## Quick start
23+
24+
Enable the bundled Policy plugin before first use:
25+
26+
```bash
27+
openclaw plugins enable policy
28+
```
29+
30+
When policy is enabled, doctor can load policy health checks without activating
31+
arbitrary plugins. The plugin remains enabled if `policy.jsonc` is missing, so
32+
doctor can report the missing artifact.
33+
34+
Policy is authored, not generated from the user's current settings. A minimal
35+
channel policy looks like this:
36+
37+
```jsonc
38+
{
39+
"channels": {
40+
"denyRules": [
41+
{
42+
"id": "no-telegram",
43+
"when": { "provider": "telegram" },
44+
"reason": "Telegram is not approved for this workspace.",
45+
},
46+
],
47+
},
48+
}
49+
```
50+
51+
The rules are the authority. A category block is only a namespace; checks run
52+
when a concrete rule is present. OpenClaw reads current `channels.*` settings
53+
and reports settings that do not conform.
54+
55+
Run policy-only checks during authoring:
56+
57+
```bash
58+
openclaw policy check
59+
openclaw policy check --json
60+
openclaw policy check --severity-min error
61+
```
62+
63+
`policy check` runs only the policy check set and emits evidence, findings, and
64+
attestation hashes. The same findings also appear in `openclaw doctor --lint`
65+
when the Policy plugin is enabled.
66+
67+
Example clean JSON output includes stable hashes that can be recorded by an
68+
operator or supervisor:
69+
70+
```json
71+
{
72+
"ok": true,
73+
"attestation": {
74+
"policy": {
75+
"path": "policy.jsonc",
76+
"hash": "sha256:..."
77+
},
78+
"workspace": {
79+
"scope": "policy",
80+
"hash": "sha256:..."
81+
},
82+
"findingsHash": "sha256:...",
83+
"attestationHash": "sha256:..."
84+
},
85+
"checksRun": 5,
86+
"checksSkipped": 0,
87+
"findings": []
88+
}
89+
```
90+
91+
## Configure policy
92+
93+
Policy config lives under `plugins.entries.policy.config`.
94+
95+
```jsonc
96+
{
97+
"plugins": {
98+
"entries": {
99+
"policy": {
100+
"enabled": true,
101+
"config": {
102+
"enabled": true,
103+
"path": "policy.jsonc",
104+
"workspaceRepairs": false,
105+
"expectedHash": "sha256:...",
106+
"expectedAttestationHash": "sha256:...",
107+
},
108+
},
109+
},
110+
},
111+
}
112+
```
113+
114+
| Setting | Purpose |
115+
| ------------------------- | --------------------------------------------------------------- |
116+
| `enabled` | Enable policy checks even before `policy.jsonc` exists. |
117+
| `workspaceRepairs` | Allow `doctor --fix` to edit policy-managed workspace settings. |
118+
| `expectedHash` | Optional hash-lock for the approved policy artifact. |
119+
| `expectedAttestationHash` | Optional hash-lock for the last accepted clean policy check. |
120+
| `path` | Workspace-relative location of the policy artifact. |
121+
122+
Set `plugins.entries.policy.config.enabled` to `false` to disable policy checks
123+
for a workspace while leaving the plugin installed.
124+
125+
## Accept policy state
126+
127+
The attestation hash identifies the stable claim: policy hash, evidence hash,
128+
findings hash, and whether the result was clean. It intentionally does not
129+
include `checkedAt`, so the same policy state produces the same attestation
130+
across repeated checks.
131+
132+
If a later gateway or supervisor uses policy to block, approve, or annotate a
133+
runtime action, it should record the attestation hash from the last clean policy
134+
check. `checkedAt` stays in JSON output for audit logs, but is not part of the
135+
stable attestation hash.
136+
137+
Use this lifecycle when accepting policy state:
138+
139+
1. Author or review `policy.jsonc`.
140+
2. Run `openclaw policy check --json`.
141+
3. If the result is clean, record `attestation.policy.hash` as `expectedHash`.
142+
4. Record `attestation.attestationHash` as `expectedAttestationHash`.
143+
5. Re-run `openclaw doctor --lint` in CI or release gates.
144+
145+
If policy rules change intentionally, update both accepted hashes from a clean
146+
check. If workspace settings change intentionally but policy stays the same,
147+
only `expectedAttestationHash` usually changes.
148+
149+
## Findings
150+
151+
Policy currently verifies:
152+
153+
| Check id | Finding |
154+
| ---------------------------------- | ------------------------------------------------------------------- |
155+
| `policy/policy-jsonc-missing` | Policy is enabled but `policy.jsonc` is missing. |
156+
| `policy/policy-jsonc-invalid` | Policy cannot be parsed or has malformed rules. |
157+
| `policy/policy-hash-mismatch` | Policy does not match configured `expectedHash`. |
158+
| `policy/attestation-hash-mismatch` | Current policy evidence no longer matches the accepted attestation. |
159+
| `policy/channels-denied-provider` | An enabled channel matches a channel deny rule. |
160+
161+
Policy findings can include `target` and `requirement`: the observed workspace
162+
thing that does not conform, and the authored rule that made it a finding.
163+
164+
## Repair
165+
166+
`doctor --lint` and `policy check` are read-only.
167+
168+
`doctor --fix` only edits policy-managed workspace settings when
169+
`workspaceRepairs` is explicitly enabled. Without that opt-in, policy checks
170+
report what they would repair and leave settings unchanged.
171+
172+
In this version, repair can disable channels that are enabled in OpenClaw config
173+
but denied by `channels.denyRules`. Enable `workspaceRepairs` only after the
174+
policy file has been reviewed, because a valid deny rule can turn off a
175+
configured channel:
176+
177+
```jsonc
178+
{
179+
"plugins": {
180+
"entries": {
181+
"policy": {
182+
"config": {
183+
"workspaceRepairs": true,
184+
},
185+
},
186+
},
187+
},
188+
}
189+
```
190+
191+
## Exit codes
192+
193+
`policy check` exits `0` when there are no findings at the threshold, `1` when
194+
findings are present, and `2` for argument or runtime failures.

docs/docs.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1669,7 +1669,7 @@
16691669
},
16701670
{
16711671
"group": "Plugins and skills",
1672-
"pages": ["cli/plugins", "cli/path", "cli/skills"]
1672+
"pages": ["cli/plugins", "cli/path", "cli/policy", "cli/skills"]
16731673
},
16741674
{
16751675
"group": "Interfaces",

docs/plugins/plugin-inventory.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ commands.
109109
| [opencode-go](/plugins/reference/opencode-go) | Adds OpenCode Go model provider support to OpenClaw. | `@openclaw/opencode-go-provider`<br />included in OpenClaw | providers: opencode-go; contracts: mediaUnderstandingProviders |
110110
| [openrouter](/plugins/reference/openrouter) | Adds OpenRouter model provider support to OpenClaw. | `@openclaw/openrouter-provider`<br />included in OpenClaw | providers: openrouter; contracts: imageGenerationProviders, mediaUnderstandingProviders, musicGenerationProviders, speechProviders, videoGenerationProviders |
111111
| [perplexity](/plugins/reference/perplexity) | Adds web search provider support. | `@openclaw/perplexity-plugin`<br />included in OpenClaw | contracts: webSearchProviders |
112+
| [policy](/plugins/reference/policy) | Adds policy-backed doctor checks for workspace conformance. | `@openclaw/policy`<br />included in OpenClaw | plugin |
112113
| [qianfan](/plugins/reference/qianfan) | Adds Qianfan model provider support to OpenClaw. | `@openclaw/qianfan-provider`<br />included in OpenClaw | providers: qianfan |
113114
| [qwen](/plugins/reference/qwen) | Adds Qwen, Qwen Cloud, Model Studio, DashScope model provider support to OpenClaw. | `@openclaw/qwen-provider`<br />included in OpenClaw | providers: qwen, qwencloud, modelstudio, dashscope; contracts: mediaUnderstandingProviders, videoGenerationProviders |
114115
| [runway](/plugins/reference/runway) | Adds video generation provider support. | `@openclaw/runway-provider`<br />included in OpenClaw | contracts: videoGenerationProviders |

docs/plugins/reference.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ pnpm plugins:inventory:gen
9696
| [openrouter](/plugins/reference/openrouter) | Adds OpenRouter model provider support to OpenClaw. | `@openclaw/openrouter-provider`<br />included in OpenClaw | providers: openrouter; contracts: imageGenerationProviders, mediaUnderstandingProviders, musicGenerationProviders, speechProviders, videoGenerationProviders |
9797
| [openshell](/plugins/reference/openshell) | Sandbox backend powered by OpenShell with mirrored local workspaces and SSH-based command execution. | `@openclaw/openshell-sandbox`<br />npm; ClawHub | plugin |
9898
| [perplexity](/plugins/reference/perplexity) | Adds web search provider support. | `@openclaw/perplexity-plugin`<br />included in OpenClaw | contracts: webSearchProviders |
99+
| [policy](/plugins/reference/policy) | Adds policy-backed doctor checks for workspace conformance. | `@openclaw/policy`<br />included in OpenClaw | plugin |
99100
| [qa-channel](/plugins/reference/qa-channel) | Adds the QA Channel surface for sending and receiving OpenClaw messages. | `@openclaw/qa-channel`<br />source checkout only | channels: qa-channel |
100101
| [qa-lab](/plugins/reference/qa-lab) | OpenClaw QA lab plugin with private debugger UI and scenario runner. | `@openclaw/qa-lab`<br />source checkout only | plugin |
101102
| [qa-matrix](/plugins/reference/qa-matrix) | Matrix QA transport runner and substrate. | `@openclaw/qa-matrix`<br />source checkout only | plugin |

docs/plugins/reference/policy.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
---
2+
summary: "Adds policy-backed doctor checks for workspace conformance."
3+
read_when:
4+
- You are installing, configuring, or auditing the policy plugin
5+
title: "Policy plugin"
6+
---
7+
8+
# Policy plugin
9+
10+
Adds policy-backed doctor checks for workspace conformance.
11+
12+
## Distribution
13+
14+
- Package: `@openclaw/policy`
15+
- Install route: included in OpenClaw
16+
17+
## Surface
18+
19+
plugin
20+
21+
## Related docs
22+
23+
- [policy](/cli/policy)

docs/plugins/sdk-subpaths.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ For the plugin authoring guide, see [Plugin SDK overview](/plugins/sdk-overview)
2929
| `plugin-sdk/provider-entry` | `defineSingleProviderPluginEntry` |
3030
| `plugin-sdk/migration` | Migration provider item helpers such as `createMigrationItem`, reason constants, item status markers, redaction helpers, and `summarizeMigrationItems` |
3131
| `plugin-sdk/migration-runtime` | Runtime migration helpers such as `copyMigrationFileItem`, `withCachedMigrationConfigRuntime`, and `writeMigrationReport` |
32+
| `plugin-sdk/health` | Doctor health-check registration, detection, repair, selection, severity, and finding types for bundled health consumers |
3233

3334
### Deprecated compatibility and test helpers
3435

extensions/policy/api.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export { registerPolicyDoctorChecks } from "./src/doctor/register.js";

0 commit comments

Comments
 (0)