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 +0 -2
- package/assets/index.html +0 -4
- package/assets/styles.css +0 -12
- package/package.json +1 -1
- package/src/http.ts +3 -3
- package/src/policy-store.ts +27 -8
- package/src/policy.ts +40 -13
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
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
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: []
|
|
294
|
+
sendJson(res, 200, { readOnly: true, policies: [] });
|
|
295
295
|
return true;
|
|
296
296
|
}
|
|
297
|
-
const { policies
|
|
298
|
-
sendJson(res, 200, { readOnly: false, policies
|
|
297
|
+
const { policies } = await listPolicies({ stateDir: params.stateDir });
|
|
298
|
+
sendJson(res, 200, { readOnly: false, policies });
|
|
299
299
|
return true;
|
|
300
300
|
}
|
|
301
301
|
|
package/src/policy-store.ts
CHANGED
|
@@ -20,11 +20,17 @@ type PolicyRecord = {
|
|
|
20
20
|
type PolicyStoreBody = {
|
|
21
21
|
name?: string;
|
|
22
22
|
description?: string;
|
|
23
|
-
schema?:
|
|
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
|
-
|
|
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[]
|
|
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
|
-
|
|
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
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
}
|
|
1
|
+
const DEFAULT_SCHEMA = `entity id_token = {
|
|
2
|
+
aud: Set<String>,
|
|
3
|
+
iss: String,
|
|
4
|
+
sub: String
|
|
5
|
+
};
|
|
6
6
|
|
|
7
|
-
entity
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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:
|
|
93
|
+
schema: buildSchemaContent(),
|
|
67
94
|
trusted_issuers: {},
|
|
68
95
|
},
|
|
69
96
|
},
|