clawclamp 0.1.11 → 0.1.12

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/assets/app.js CHANGED
@@ -21,7 +21,6 @@ const policyCreateBtn = qs("policy-create");
21
21
  const policyUpdateBtn = qs("policy-update");
22
22
  const policyDeleteBtn = qs("policy-delete");
23
23
  const policyStatusEl = qs("policy-status");
24
- const policySchemaEl = qs("policy-schema");
25
24
  let policyReadOnly = false;
26
25
  let policies = [];
27
26
  let deniedTools = new Set();
@@ -188,7 +187,6 @@ async function refreshPolicies() {
188
187
  const result = await fetchJson(`${API_BASE}/policies`);
189
188
  policyReadOnly = result.readOnly === true;
190
189
  renderPolicyList(result.policies || []);
191
- policySchemaEl.textContent = result.schema || "";
192
190
  policyCreateBtn.disabled = policyReadOnly;
193
191
  policyUpdateBtn.disabled = policyReadOnly;
194
192
  policyDeleteBtn.disabled = policyReadOnly;
package/assets/index.html CHANGED
@@ -91,10 +91,6 @@
91
91
  </div>
92
92
  <div id="policy-status" class="note"></div>
93
93
  </div>
94
- <div class="policy-schema">
95
- <div class="label">Schema</div>
96
- <pre id="policy-schema"></pre>
97
- </div>
98
94
  </div>
99
95
  </div>
100
96
  </section>
package/assets/styles.css CHANGED
@@ -313,18 +313,6 @@ input {
313
313
  flex-wrap: wrap;
314
314
  }
315
315
 
316
- .policy-schema pre {
317
- margin: 0;
318
- padding: 10px;
319
- border: 1px solid var(--border);
320
- border-radius: 8px;
321
- background: #f3f5f9;
322
- font-size: 0.75rem;
323
- line-height: 1.4;
324
- max-height: 260px;
325
- overflow: auto;
326
- }
327
-
328
316
  @media (max-width: 900px) {
329
317
  .policy-grid {
330
318
  grid-template-columns: 1fr;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawclamp",
3
- "version": "0.1.11",
3
+ "version": "0.1.12",
4
4
  "description": "OpenClaw Cedar authorization guard with audit UI",
5
5
  "type": "module",
6
6
  "dependencies": {
package/src/http.ts CHANGED
@@ -291,11 +291,11 @@ export function createClawClampHttpHandler(params: {
291
291
 
292
292
  if (apiPath === "policies" && req.method === "GET") {
293
293
  if (params.config.policyStoreUri) {
294
- sendJson(res, 200, { readOnly: true, policies: [], schema: "" });
294
+ sendJson(res, 200, { readOnly: true, policies: [] });
295
295
  return true;
296
296
  }
297
- const { policies, schema } = await listPolicies({ stateDir: params.stateDir });
298
- sendJson(res, 200, { readOnly: false, policies, schema });
297
+ const { policies } = await listPolicies({ stateDir: params.stateDir });
298
+ sendJson(res, 200, { readOnly: false, policies });
299
299
  return true;
300
300
  }
301
301
 
@@ -20,11 +20,17 @@ type PolicyRecord = {
20
20
  type PolicyStoreBody = {
21
21
  name?: string;
22
22
  description?: string;
23
- schema?: string;
23
+ schema?: EncodedContent;
24
24
  trusted_issuers?: Record<string, unknown>;
25
25
  policies?: Record<string, PolicyRecord>;
26
26
  };
27
27
 
28
+ type EncodedContent = {
29
+ encoding?: "none" | "base64";
30
+ content_type?: "cedar" | "cedar-json";
31
+ body?: string;
32
+ };
33
+
28
34
  export type PolicyStoreSnapshot = {
29
35
  cedar_version: string;
30
36
  policy_stores: Record<string, PolicyStoreBody>;
@@ -67,7 +73,16 @@ function normalizePolicyStore(raw: unknown): PolicyStoreSnapshot {
67
73
 
68
74
  const candidate = raw as Record<string, unknown>;
69
75
  if (candidate.policy_stores && typeof candidate.policy_stores === "object") {
70
- return candidate as PolicyStoreSnapshot;
76
+ const normalized = candidate as PolicyStoreSnapshot;
77
+ const writable = normalized.policy_stores?.[POLICY_STORE_ID];
78
+ if (writable?.schema && typeof writable.schema === "string") {
79
+ writable.schema = {
80
+ encoding: "base64",
81
+ content_type: "cedar",
82
+ body: writable.schema,
83
+ };
84
+ }
85
+ return normalized;
71
86
  }
72
87
 
73
88
  const legacyPolicies =
@@ -87,9 +102,14 @@ function normalizePolicyStore(raw: unknown): PolicyStoreSnapshot {
87
102
  name: "Clawclamp Policy Store",
88
103
  description: "Migrated legacy policy store.",
89
104
  schema:
90
- legacySchema ||
91
105
  fallback.policy_stores[POLICY_STORE_ID]?.schema ||
92
- "",
106
+ (legacySchema
107
+ ? {
108
+ encoding: "base64",
109
+ content_type: "cedar",
110
+ body: legacySchema,
111
+ }
112
+ : undefined),
93
113
  trusted_issuers: {},
94
114
  policies: legacyPolicies,
95
115
  },
@@ -105,7 +125,7 @@ function getWritableStore(store: PolicyStoreSnapshot): PolicyStoreBody {
105
125
  const fallback = buildDefaultPolicyStore() as PolicyStoreSnapshot;
106
126
  const created = fallback.policy_stores[POLICY_STORE_ID] ?? {
107
127
  policies: {},
108
- schema: "",
128
+ schema: undefined,
109
129
  trusted_issuers: {},
110
130
  };
111
131
  if (!store.policy_stores) {
@@ -149,7 +169,7 @@ export async function ensurePolicyStore(params: {
149
169
 
150
170
  export async function listPolicies(params: {
151
171
  stateDir: string;
152
- }): Promise<{ policies: PolicyEntry[]; schema: string }> {
172
+ }): Promise<{ policies: PolicyEntry[] }> {
153
173
  return withStateFileLock(params.stateDir, "policy-store", async () => {
154
174
  const store = await readPolicyStore(params.stateDir);
155
175
  const policyStore = getWritableStore(store);
@@ -157,8 +177,7 @@ export async function listPolicies(params: {
157
177
  id,
158
178
  content: decodeBase64(payload.policy_content ?? ""),
159
179
  }));
160
- const schemaEncoded = policyStore.schema ?? "";
161
- return { policies, schema: schemaEncoded ? decodeBase64(schemaEncoded) : "" };
180
+ return { policies };
162
181
  });
163
182
  }
164
183
 
package/src/policy.ts CHANGED
@@ -1,18 +1,31 @@
1
- const DEFAULT_SCHEMA = `entity User {
2
- attrs {
3
- role: String,
4
- }
5
- }
1
+ const DEFAULT_SCHEMA = `entity id_token = {
2
+ aud: Set<String>,
3
+ iss: String,
4
+ sub: String
5
+ };
6
6
 
7
- entity Tool {
8
- attrs {
9
- name: String,
10
- risk: String,
11
- }
12
- }
7
+ entity Role;
8
+
9
+ entity User in [Role] = {
10
+ role: String
11
+ };
12
+
13
+ entity Access_token = {
14
+ aud: String,
15
+ iss: String,
16
+ jti: String,
17
+ client_id: String
18
+ };
19
+
20
+ entity Workload = {};
21
+
22
+ entity Tool = {
23
+ name: String,
24
+ risk: String
25
+ };
13
26
 
14
27
  action "Invoke" appliesTo {
15
- principal: [User],
28
+ principal: [User, Role, Workload],
16
29
  resource: [Tool],
17
30
  context: {
18
31
  now: Long,
@@ -33,10 +46,24 @@ when {
33
46
 
34
47
  const POLICY_STORE_ID = "clawclamp";
35
48
 
49
+ type EncodedContent = {
50
+ encoding: "none" | "base64";
51
+ content_type: "cedar" | "cedar-json";
52
+ body: string;
53
+ };
54
+
36
55
  function toBase64(raw: string): string {
37
56
  return Buffer.from(raw, "utf8").toString("base64");
38
57
  }
39
58
 
59
+ function buildSchemaContent(): EncodedContent {
60
+ return {
61
+ encoding: "none",
62
+ content_type: "cedar",
63
+ body: DEFAULT_SCHEMA,
64
+ };
65
+ }
66
+
40
67
  export function buildDefaultPolicyStore(): Record<string, unknown> {
41
68
  const policies: Record<
42
69
  string,
@@ -63,7 +90,7 @@ export function buildDefaultPolicyStore(): Record<string, unknown> {
63
90
  name: "Clawclamp Policy Store",
64
91
  description: "Local Cedar policies for Clawclamp.",
65
92
  policies,
66
- schema: toBase64(DEFAULT_SCHEMA),
93
+ schema: buildSchemaContent(),
67
94
  trusted_issuers: {},
68
95
  },
69
96
  },