@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.
@@ -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.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": ["stdio", "http", "sse"],
23
+ "enum": [
24
+ "stdio",
25
+ "http",
26
+ "sse"
27
+ ],
24
28
  "default": "stdio"
25
29
  },
26
- "command": { "type": "string" },
27
- "args": { "type": "array", "items": { "type": "string" } },
28
- "env": { "type": "object", "additionalProperties": { "type": "string" } },
29
- "url": { "type": "string" }
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": ["deny-all", "allow-all"],
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": { "label": "GUI Port", "placeholder": "19820" },
53
- "policyDir": { "label": "Policy Directory" },
54
- "defaultPolicy": { "label": "Default Policy" },
55
- "verify": { "label": "Enable Formal Verification" }
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@clawdreyhepburn/carapace",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Cedar policy enforcement for agent tool access via OpenClaw's before_tool_call hook.",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -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
- // Simple: check if resource appears in the policy
632
- const resourceId = request.resource.replace(/.*::"/g, "").replace(/"$/, "");
633
- if (!policy.raw.includes(`"${resourceId}"`)) continue;
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 {