@clawdreyhepburn/carapace 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/openclaw.plugin.json +41 -11
- package/package.json +1 -1
- package/src/cedar-engine-cedarling.ts +14 -3
- package/src/index.ts +20 -0
package/openclaw.plugin.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"id": "carapace",
|
|
3
3
|
"name": "Carapace",
|
|
4
4
|
"description": "Cedar policy enforcement for agent tool access via before_tool_call hook. Your agent's exoskeleton.",
|
|
5
|
-
"version": "1.0.
|
|
5
|
+
"version": "1.0.4",
|
|
6
6
|
"configSchema": {
|
|
7
7
|
"type": "object",
|
|
8
8
|
"additionalProperties": true,
|
|
@@ -20,13 +20,31 @@
|
|
|
20
20
|
"properties": {
|
|
21
21
|
"transport": {
|
|
22
22
|
"type": "string",
|
|
23
|
-
"enum": [
|
|
23
|
+
"enum": [
|
|
24
|
+
"stdio",
|
|
25
|
+
"http",
|
|
26
|
+
"sse"
|
|
27
|
+
],
|
|
24
28
|
"default": "stdio"
|
|
25
29
|
},
|
|
26
|
-
"command": {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
"
|
|
30
|
+
"command": {
|
|
31
|
+
"type": "string"
|
|
32
|
+
},
|
|
33
|
+
"args": {
|
|
34
|
+
"type": "array",
|
|
35
|
+
"items": {
|
|
36
|
+
"type": "string"
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
"env": {
|
|
40
|
+
"type": "object",
|
|
41
|
+
"additionalProperties": {
|
|
42
|
+
"type": "string"
|
|
43
|
+
}
|
|
44
|
+
},
|
|
45
|
+
"url": {
|
|
46
|
+
"type": "string"
|
|
47
|
+
}
|
|
30
48
|
}
|
|
31
49
|
}
|
|
32
50
|
},
|
|
@@ -37,7 +55,10 @@
|
|
|
37
55
|
},
|
|
38
56
|
"defaultPolicy": {
|
|
39
57
|
"type": "string",
|
|
40
|
-
"enum": [
|
|
58
|
+
"enum": [
|
|
59
|
+
"deny-all",
|
|
60
|
+
"allow-all"
|
|
61
|
+
],
|
|
41
62
|
"default": "allow-all",
|
|
42
63
|
"description": "Default policy when no Cedar policies match. allow-all passes everything through; deny-all blocks everything not explicitly permitted."
|
|
43
64
|
},
|
|
@@ -49,9 +70,18 @@
|
|
|
49
70
|
}
|
|
50
71
|
},
|
|
51
72
|
"uiHints": {
|
|
52
|
-
"guiPort": {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
73
|
+
"guiPort": {
|
|
74
|
+
"label": "GUI Port",
|
|
75
|
+
"placeholder": "19820"
|
|
76
|
+
},
|
|
77
|
+
"policyDir": {
|
|
78
|
+
"label": "Policy Directory"
|
|
79
|
+
},
|
|
80
|
+
"defaultPolicy": {
|
|
81
|
+
"label": "Default Policy"
|
|
82
|
+
},
|
|
83
|
+
"verify": {
|
|
84
|
+
"label": "Enable Formal Verification"
|
|
85
|
+
}
|
|
56
86
|
}
|
|
57
87
|
}
|
package/package.json
CHANGED
|
@@ -627,10 +627,21 @@ export class CedarlingEngine {
|
|
|
627
627
|
let hasForbid = false;
|
|
628
628
|
const reasons: string[] = [];
|
|
629
629
|
|
|
630
|
+
const principalId = request.principal;
|
|
631
|
+
const actionId = request.action;
|
|
632
|
+
const resourceId = request.resource;
|
|
633
|
+
|
|
630
634
|
for (const [id, policy] of this.policies) {
|
|
631
|
-
//
|
|
632
|
-
const
|
|
633
|
-
|
|
635
|
+
// Parse constraints from raw policy text
|
|
636
|
+
const hasPrincipalConstraint = /principal\s*==/.test(policy.raw);
|
|
637
|
+
const hasActionConstraint = /action\s*==/.test(policy.raw);
|
|
638
|
+
const hasResourceConstraint = /resource\s*==/.test(policy.raw);
|
|
639
|
+
|
|
640
|
+
// Check if this policy matches the request
|
|
641
|
+
// Unconstrained fields match everything (Cedar semantics)
|
|
642
|
+
if (hasPrincipalConstraint && !policy.raw.includes(principalId)) continue;
|
|
643
|
+
if (hasActionConstraint && !policy.raw.includes(actionId)) continue;
|
|
644
|
+
if (hasResourceConstraint && !policy.raw.includes(resourceId)) continue;
|
|
634
645
|
|
|
635
646
|
if (policy.effect === "forbid") {
|
|
636
647
|
hasForbid = true;
|
package/src/index.ts
CHANGED
|
@@ -107,9 +107,12 @@ export default function register(api: OpenClawPluginApi) {
|
|
|
107
107
|
// --- Register before_tool_call hook ---
|
|
108
108
|
if (api.on) {
|
|
109
109
|
api.on("before_tool_call", async (event: any) => {
|
|
110
|
+
logger.info(`[Carapace] HOOK FIRED: keys=${JSON.stringify(Object.keys(event))}`);
|
|
111
|
+
logger.info(`[Carapace] before_tool_call fired: ${JSON.stringify(Object.keys(event))}`);
|
|
110
112
|
const toolName: string = event.toolName ?? event.tool ?? event.name ?? "";
|
|
111
113
|
const params: Record<string, unknown> = event.params ?? event.arguments ?? event.input ?? {};
|
|
112
114
|
|
|
115
|
+
logger.info(`[Carapace] tool=${toolName} defaultPolicy=${config.defaultPolicy ?? "allow-all"}`);
|
|
113
116
|
if (!toolName) return {};
|
|
114
117
|
|
|
115
118
|
stats.toolCallsEvaluated++;
|
|
@@ -147,6 +150,15 @@ export default function register(api: OpenClawPluginApi) {
|
|
|
147
150
|
context = params ? { arguments: params } : {};
|
|
148
151
|
}
|
|
149
152
|
|
|
153
|
+
// Short-circuit: if default policy is allow-all and no Cedar policies are loaded,
|
|
154
|
+
// skip Cedar evaluation entirely (Cedar is deny-by-default with no policies)
|
|
155
|
+
const effectiveDefault = config.defaultPolicy ?? "allow-all";
|
|
156
|
+
const policies = cedar.getPolicies?.() ?? [];
|
|
157
|
+
if (effectiveDefault === "allow-all" && policies.length === 0) {
|
|
158
|
+
logger.info(`✅ [Carapace] ALLOW (no policies, default allow-all): ${toolName}`);
|
|
159
|
+
return {};
|
|
160
|
+
}
|
|
161
|
+
|
|
150
162
|
const decision = await cedar.authorize({
|
|
151
163
|
principal: `Agent::"openclaw"`,
|
|
152
164
|
action: `Action::"${action}"`,
|
|
@@ -154,6 +166,11 @@ export default function register(api: OpenClawPluginApi) {
|
|
|
154
166
|
context,
|
|
155
167
|
});
|
|
156
168
|
|
|
169
|
+
// If Cedar returns no definitive decision and default is allow-all, allow
|
|
170
|
+
if (effectiveDefault === "allow-all" && decision.decision !== "deny") {
|
|
171
|
+
return {};
|
|
172
|
+
}
|
|
173
|
+
|
|
157
174
|
const auditEntry = {
|
|
158
175
|
timestamp: new Date().toISOString(),
|
|
159
176
|
tool: toolName,
|
|
@@ -171,6 +188,9 @@ export default function register(api: OpenClawPluginApi) {
|
|
|
171
188
|
}
|
|
172
189
|
|
|
173
190
|
return {};
|
|
191
|
+
}, {
|
|
192
|
+
name: "carapace.cedar-enforcement",
|
|
193
|
+
description: "Cedar policy enforcement for all tool calls",
|
|
174
194
|
});
|
|
175
195
|
logger.info("Registered before_tool_call hook for Cedar policy enforcement");
|
|
176
196
|
} else {
|