mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-18 00:23:25 -06:00
55263b3dfa
Add exec approvals artifact evidence to Policy.
- add the execApprovals policy namespace and check IDs for required artifact presence, default/per-agent security posture, autoAllowSkills, and allowlist drift
- read the active exec-approvals.json artifact only when execApprovals policy rules are configured, honoring OPENCLAW_STATE_DIR before the default ~/.openclaw path
- emit redacted posture evidence and stable oc:// references without socket tokens, command text, resolved paths, timestamps, or approval-session details
- document the public policy surface and add focused scanner, doctor, conformance, and CLI coverage
Validation:
- GitHub Actions for head b82eefe492 are green, including Real behavior proof.
- ClawSweeper re-review completed for the same head with proof: sufficient and status: ready for maintainer look.
- Maintainer artifact-boundary acceptance is recorded in the PR discussion and body.
Co-authored-by: Gio Della-Libera <235387111+giodl73-repo@users.noreply.github.com>
207 lines
5.6 KiB
TypeScript
207 lines
5.6 KiB
TypeScript
// Policy tests cover policy state plugin behavior.
|
|
import { describe, expect, it } from "vitest";
|
|
import { scanPolicyChannels, scanPolicyExecApprovals, scanPolicyTools } from "./policy-state.js";
|
|
|
|
describe("scanPolicyChannels", () => {
|
|
it("ignores reserved channel config namespaces", () => {
|
|
expect(
|
|
scanPolicyChannels({
|
|
channels: {
|
|
defaults: {
|
|
provider: "telegram",
|
|
},
|
|
modelByChannel: {
|
|
telegram: "openai/gpt-5.5",
|
|
},
|
|
telegram: {
|
|
enabled: true,
|
|
},
|
|
},
|
|
}),
|
|
).toEqual([
|
|
{
|
|
enabled: true,
|
|
id: "telegram",
|
|
provider: "telegram",
|
|
source: "oc://openclaw.config/channels/telegram",
|
|
},
|
|
]);
|
|
});
|
|
|
|
it("does not treat channel arrays as channel config maps", () => {
|
|
expect(
|
|
scanPolicyChannels({
|
|
channels: [{ enabled: true }],
|
|
}),
|
|
).toEqual([]);
|
|
});
|
|
});
|
|
|
|
describe("scanPolicyTools", () => {
|
|
it("scans documented bullet tool declarations", async () => {
|
|
await expect(
|
|
scanPolicyTools(
|
|
[
|
|
"## Tools",
|
|
"- deploy_tool: risk: critical sensitivity: restricted owner: ops IRREVERSIBLE_EXTERNAL",
|
|
"- inspect: risk: low",
|
|
" sensitivity: public",
|
|
" owner: support",
|
|
].join("\n"),
|
|
),
|
|
).resolves.toEqual([
|
|
{
|
|
id: "deploy-tool",
|
|
source: "oc://TOOLS.md/tools/deploy-tool",
|
|
line: 2,
|
|
risk: "critical",
|
|
sensitivity: "restricted",
|
|
owner: "ops",
|
|
capabilities: ["IRREVERSIBLE_EXTERNAL"],
|
|
},
|
|
{
|
|
id: "inspect",
|
|
source: "oc://TOOLS.md/tools/inspect",
|
|
line: 3,
|
|
risk: "low",
|
|
sensitivity: "public",
|
|
owner: "support",
|
|
},
|
|
]);
|
|
});
|
|
|
|
it("does not treat indented metadata bullets as tool declarations", async () => {
|
|
await expect(
|
|
scanPolicyTools(["## Tools", "- deploy: risk: critical", " - owner: ops"].join("\n")),
|
|
).resolves.toEqual([
|
|
{
|
|
id: "deploy",
|
|
source: "oc://TOOLS.md/tools/deploy",
|
|
line: 2,
|
|
risk: "critical",
|
|
owner: "ops",
|
|
},
|
|
]);
|
|
});
|
|
});
|
|
|
|
describe("scanPolicyExecApprovals", () => {
|
|
it("scans redacted exec approvals posture and allowlist metadata", () => {
|
|
const evidence = scanPolicyExecApprovals(
|
|
JSON.stringify({
|
|
version: 1,
|
|
socket: { path: "/tmp/openclaw.sock", token: "secret-token" },
|
|
defaults: { security: "full", ask: "off", askFallback: "full", autoAllowSkills: true },
|
|
agents: {
|
|
sebby: {
|
|
security: "allowlist",
|
|
ask: "on-miss",
|
|
allowlist: [
|
|
{
|
|
pattern: "deploy",
|
|
argPattern: "^--prod$",
|
|
source: "allow-always",
|
|
commandText: "deploy --prod",
|
|
lastUsedCommand: "deploy --prod",
|
|
},
|
|
{
|
|
pattern: "inspect",
|
|
source: "free-form text that must not leak",
|
|
},
|
|
],
|
|
},
|
|
},
|
|
}),
|
|
);
|
|
|
|
expect(evidence).toEqual([
|
|
expect.objectContaining({
|
|
id: "defaults",
|
|
kind: "defaults",
|
|
security: "full",
|
|
autoAllowSkills: true,
|
|
}),
|
|
expect.objectContaining({
|
|
id: "agent:sebby",
|
|
kind: "agent",
|
|
agentId: "sebby",
|
|
security: "allowlist",
|
|
ask: "on-miss",
|
|
}),
|
|
expect.objectContaining({
|
|
id: "agent:sebby:allowlist:0",
|
|
kind: "allowlist",
|
|
agentId: "sebby",
|
|
pattern: "deploy",
|
|
argPattern: "^--prod$",
|
|
entrySource: "allow-always",
|
|
}),
|
|
expect.not.objectContaining({
|
|
entrySource: "free-form text that must not leak",
|
|
}),
|
|
]);
|
|
expect(JSON.stringify(evidence)).not.toContain("secret-token");
|
|
expect(JSON.stringify(evidence)).not.toContain("deploy --prod");
|
|
expect(JSON.stringify(evidence)).not.toContain("free-form text that must not leak");
|
|
});
|
|
|
|
it("omits malformed exec approval mode fields", () => {
|
|
expect(
|
|
scanPolicyExecApprovals(
|
|
JSON.stringify({
|
|
version: 1,
|
|
defaults: { security: "bogus", ask: "bad", askFallback: "nope" },
|
|
agents: {
|
|
sebby: { security: "bogus", ask: "bad", askFallback: "nope" },
|
|
},
|
|
}),
|
|
),
|
|
).toEqual([
|
|
expect.not.objectContaining({ security: expect.any(String) }),
|
|
expect.not.objectContaining({ security: expect.any(String) }),
|
|
]);
|
|
});
|
|
|
|
it("normalizes legacy default agents and string allowlist entries", () => {
|
|
expect(
|
|
scanPolicyExecApprovals(
|
|
JSON.stringify({
|
|
version: 1,
|
|
agents: {
|
|
default: {
|
|
security: "allowlist",
|
|
allowlist: ["legacy", { pattern: "doctor" }],
|
|
},
|
|
},
|
|
}),
|
|
),
|
|
).toEqual([
|
|
expect.objectContaining({
|
|
id: "defaults",
|
|
kind: "defaults",
|
|
}),
|
|
expect.objectContaining({
|
|
id: "agent:main",
|
|
kind: "agent",
|
|
agentId: "main",
|
|
security: "allowlist",
|
|
source: "oc://exec-approvals.json/agents/default",
|
|
}),
|
|
expect.objectContaining({
|
|
id: "agent:main:allowlist:0",
|
|
kind: "allowlist",
|
|
agentId: "main",
|
|
pattern: "legacy",
|
|
source: "oc://exec-approvals.json/agents/default/allowlist/#0",
|
|
}),
|
|
expect.objectContaining({
|
|
id: "agent:main:allowlist:1",
|
|
kind: "allowlist",
|
|
agentId: "main",
|
|
pattern: "doctor",
|
|
source: "oc://exec-approvals.json/agents/default/allowlist/#1",
|
|
}),
|
|
]);
|
|
});
|
|
});
|