@vellumai/credential-executor 0.6.6 → 0.7.0
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/Dockerfile +1 -1
- package/bun.lock +15 -7
- package/node_modules/@vellumai/credential-storage/src/__tests__/package-boundary.test.ts +32 -6
- package/node_modules/@vellumai/egress-proxy/src/__tests__/package-boundary.test.ts +32 -1
- package/node_modules/@vellumai/{ces-contracts → service-contracts}/bun.lock +1 -1
- package/node_modules/@vellumai/{ces-contracts → service-contracts}/package.json +4 -2
- package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/contracts.test.ts +5 -1
- package/node_modules/@vellumai/service-contracts/src/__tests__/package-boundary.test.ts +155 -0
- package/node_modules/@vellumai/service-contracts/src/credential-rpc.ts +23 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +25 -0
- package/node_modules/@vellumai/{ces-contracts/src/index.ts → service-contracts/src/transport.ts} +6 -28
- package/node_modules/@vellumai/service-contracts/src/trust-rules.ts +116 -0
- package/package.json +3 -3
- package/src/__tests__/bulk-set-credentials.test.ts +1 -1
- package/src/__tests__/command-executor.test.ts +2 -2
- package/src/__tests__/http-executor.test.ts +1 -1
- package/src/__tests__/local-materializers.test.ts +1 -1
- package/src/__tests__/managed-integration.test.ts +1 -1
- package/src/__tests__/managed-lazy-getters.test.ts +1 -1
- package/src/__tests__/managed-materializers.test.ts +1 -1
- package/src/__tests__/managed-rejection.test.ts +1 -1
- package/src/__tests__/transport.test.ts +1 -1
- package/src/audit/store.ts +2 -2
- package/src/commands/executor.ts +2 -2
- package/src/grants/rpc-handlers.ts +1 -1
- package/src/http/audit.ts +1 -1
- package/src/http/executor.ts +2 -2
- package/src/http/policy.ts +1 -1
- package/src/main.ts +1 -1
- package/src/managed-errors.ts +2 -2
- package/src/managed-lazy-getters.ts +4 -4
- package/src/managed-main.ts +3 -3
- package/src/materializers/local.ts +1 -1
- package/src/server.ts +2 -2
- package/src/subjects/local.ts +2 -2
- package/src/subjects/managed.ts +1 -1
- package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +0 -471
- package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +0 -436
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/grants.test.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/error.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/grants.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/handles.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rendering.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rpc.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/tsconfig.json +0 -0
|
@@ -1,471 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for trust-rule family types and canonical parsing/normalization.
|
|
3
|
-
*
|
|
4
|
-
* Verifies:
|
|
5
|
-
* 1. Scoped-rule parsing preserves executionTarget, strips allowHighRisk.
|
|
6
|
-
* 2. Non-scoped known-tool rules strip executionTarget and allowHighRisk.
|
|
7
|
-
* 3. Unknown-tool rules preserve executionTarget, strip allowHighRisk.
|
|
8
|
-
* 4. Normalization flag behavior signals when a re-save is warranted.
|
|
9
|
-
* 5. parseTrustFileData handles full trust file objects.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
import { describe, expect, test } from "bun:test";
|
|
13
|
-
import {
|
|
14
|
-
isManagedSkillRule,
|
|
15
|
-
isScopedRule,
|
|
16
|
-
isSkillLoadRule,
|
|
17
|
-
isUrlRule,
|
|
18
|
-
parseTrustFileData,
|
|
19
|
-
parseTrustRule,
|
|
20
|
-
ruleScope,
|
|
21
|
-
SCOPED_TOOLS,
|
|
22
|
-
URL_TOOLS,
|
|
23
|
-
MANAGED_SKILL_TOOLS,
|
|
24
|
-
SKILL_LOAD_TOOL,
|
|
25
|
-
} from "../trust-rules.js";
|
|
26
|
-
import type {
|
|
27
|
-
GenericTrustRule,
|
|
28
|
-
ManagedSkillTrustRule,
|
|
29
|
-
ScopedTrustRule,
|
|
30
|
-
SkillLoadTrustRule,
|
|
31
|
-
TrustRule,
|
|
32
|
-
UrlTrustRule,
|
|
33
|
-
} from "../trust-rules.js";
|
|
34
|
-
|
|
35
|
-
// ---------------------------------------------------------------------------
|
|
36
|
-
// Helpers
|
|
37
|
-
// ---------------------------------------------------------------------------
|
|
38
|
-
|
|
39
|
-
function makeRaw(overrides: Record<string, unknown> = {}): Record<string, unknown> {
|
|
40
|
-
return {
|
|
41
|
-
id: "test-rule-1",
|
|
42
|
-
tool: "bash",
|
|
43
|
-
pattern: "**",
|
|
44
|
-
scope: "everywhere",
|
|
45
|
-
decision: "allow",
|
|
46
|
-
priority: 100,
|
|
47
|
-
createdAt: 1700000000000,
|
|
48
|
-
...overrides,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// ---------------------------------------------------------------------------
|
|
53
|
-
// Scoped-rule parsing
|
|
54
|
-
// ---------------------------------------------------------------------------
|
|
55
|
-
|
|
56
|
-
describe("parseTrustRule — scoped tools", () => {
|
|
57
|
-
test.each([...SCOPED_TOOLS])("preserves executionTarget and strips allowHighRisk for %s", (tool) => {
|
|
58
|
-
const raw = makeRaw({
|
|
59
|
-
tool,
|
|
60
|
-
executionTarget: "container-a",
|
|
61
|
-
allowHighRisk: true,
|
|
62
|
-
});
|
|
63
|
-
const { rule, normalized } = parseTrustRule(raw);
|
|
64
|
-
// allowHighRisk triggers normalization
|
|
65
|
-
expect(normalized).toBe(true);
|
|
66
|
-
expect(rule.tool).toBe(tool);
|
|
67
|
-
expect((rule as ScopedTrustRule).executionTarget).toBe("container-a");
|
|
68
|
-
// allowHighRisk is stripped
|
|
69
|
-
expect("allowHighRisk" in rule).toBe(false);
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
test("scoped rule without optional fields is not normalized", () => {
|
|
73
|
-
const raw = makeRaw({ tool: "host_bash" });
|
|
74
|
-
const { rule, normalized } = parseTrustRule(raw);
|
|
75
|
-
expect(normalized).toBe(false);
|
|
76
|
-
expect(rule.tool).toBe("host_bash");
|
|
77
|
-
expect("executionTarget" in rule).toBe(false);
|
|
78
|
-
expect("allowHighRisk" in rule).toBe(false);
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
test("type guard isScopedRule narrows correctly", () => {
|
|
82
|
-
const { rule } = parseTrustRule(makeRaw({ tool: "file_write" }));
|
|
83
|
-
expect(isScopedRule(rule)).toBe(true);
|
|
84
|
-
expect(isUrlRule(rule)).toBe(false);
|
|
85
|
-
expect(isManagedSkillRule(rule)).toBe(false);
|
|
86
|
-
expect(isSkillLoadRule(rule)).toBe(false);
|
|
87
|
-
});
|
|
88
|
-
});
|
|
89
|
-
|
|
90
|
-
// ---------------------------------------------------------------------------
|
|
91
|
-
// Non-scoped known-tool scope stripping
|
|
92
|
-
// ---------------------------------------------------------------------------
|
|
93
|
-
|
|
94
|
-
describe("parseTrustRule — URL tools strip invalid fields", () => {
|
|
95
|
-
test.each([...URL_TOOLS])(
|
|
96
|
-
"strips executionTarget and allowHighRisk on %s",
|
|
97
|
-
(tool) => {
|
|
98
|
-
const raw = makeRaw({
|
|
99
|
-
tool,
|
|
100
|
-
executionTarget: "should-be-stripped",
|
|
101
|
-
allowHighRisk: true,
|
|
102
|
-
});
|
|
103
|
-
const { rule, normalized } = parseTrustRule(raw);
|
|
104
|
-
expect(normalized).toBe(true);
|
|
105
|
-
expect(rule.tool).toBe(tool);
|
|
106
|
-
expect("executionTarget" in rule).toBe(false);
|
|
107
|
-
expect("allowHighRisk" in rule).toBe(false);
|
|
108
|
-
},
|
|
109
|
-
);
|
|
110
|
-
|
|
111
|
-
test("URL tool without invalid fields is not normalized", () => {
|
|
112
|
-
const raw = makeRaw({ tool: "web_fetch" });
|
|
113
|
-
const { rule, normalized } = parseTrustRule(raw);
|
|
114
|
-
expect(normalized).toBe(false);
|
|
115
|
-
expect(rule.tool).toBe("web_fetch");
|
|
116
|
-
// scope is stripped even though it was present in raw input
|
|
117
|
-
expect("scope" in rule).toBe(false);
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
test("URL tool with scope 'everywhere' strips scope without normalization flag", () => {
|
|
121
|
-
const raw = makeRaw({ tool: "web_fetch", scope: "everywhere" });
|
|
122
|
-
const { rule, normalized } = parseTrustRule(raw);
|
|
123
|
-
expect(normalized).toBe(false);
|
|
124
|
-
expect("scope" in rule).toBe(false);
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
test("URL tool with non-'everywhere' scope strips scope and sets normalized", () => {
|
|
128
|
-
const raw = makeRaw({ tool: "web_fetch", scope: "/some/dir" });
|
|
129
|
-
const { rule, normalized } = parseTrustRule(raw);
|
|
130
|
-
expect(normalized).toBe(true);
|
|
131
|
-
expect("scope" in rule).toBe(false);
|
|
132
|
-
});
|
|
133
|
-
|
|
134
|
-
test("type guard isUrlRule narrows correctly", () => {
|
|
135
|
-
const { rule } = parseTrustRule(makeRaw({ tool: "network_request" }));
|
|
136
|
-
expect(isUrlRule(rule)).toBe(true);
|
|
137
|
-
expect(isScopedRule(rule)).toBe(false);
|
|
138
|
-
});
|
|
139
|
-
});
|
|
140
|
-
|
|
141
|
-
describe("parseTrustRule — managed skill tools strip invalid fields", () => {
|
|
142
|
-
test.each([...MANAGED_SKILL_TOOLS])(
|
|
143
|
-
"strips executionTarget and allowHighRisk on %s",
|
|
144
|
-
(tool) => {
|
|
145
|
-
const raw = makeRaw({
|
|
146
|
-
tool,
|
|
147
|
-
executionTarget: "x",
|
|
148
|
-
allowHighRisk: false,
|
|
149
|
-
});
|
|
150
|
-
const { rule, normalized } = parseTrustRule(raw);
|
|
151
|
-
expect(normalized).toBe(true);
|
|
152
|
-
expect("executionTarget" in rule).toBe(false);
|
|
153
|
-
expect("allowHighRisk" in rule).toBe(false);
|
|
154
|
-
},
|
|
155
|
-
);
|
|
156
|
-
|
|
157
|
-
test("managed skill tool with scope 'everywhere' strips scope without normalization flag", () => {
|
|
158
|
-
const raw = makeRaw({ tool: "scaffold_managed_skill", scope: "everywhere" });
|
|
159
|
-
const { rule, normalized } = parseTrustRule(raw);
|
|
160
|
-
expect(normalized).toBe(false);
|
|
161
|
-
expect("scope" in rule).toBe(false);
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
test("managed skill tool with non-'everywhere' scope strips scope and sets normalized", () => {
|
|
165
|
-
const raw = makeRaw({ tool: "delete_managed_skill", scope: "/some/dir" });
|
|
166
|
-
const { rule, normalized } = parseTrustRule(raw);
|
|
167
|
-
expect(normalized).toBe(true);
|
|
168
|
-
expect("scope" in rule).toBe(false);
|
|
169
|
-
});
|
|
170
|
-
|
|
171
|
-
test("type guard isManagedSkillRule narrows correctly", () => {
|
|
172
|
-
const { rule } = parseTrustRule(makeRaw({ tool: "scaffold_managed_skill" }));
|
|
173
|
-
expect(isManagedSkillRule(rule)).toBe(true);
|
|
174
|
-
expect(isScopedRule(rule)).toBe(false);
|
|
175
|
-
});
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
describe("parseTrustRule — skill_load strips invalid fields", () => {
|
|
179
|
-
test("strips executionTarget and allowHighRisk on skill_load", () => {
|
|
180
|
-
const raw = makeRaw({
|
|
181
|
-
tool: SKILL_LOAD_TOOL,
|
|
182
|
-
executionTarget: "container-b",
|
|
183
|
-
allowHighRisk: true,
|
|
184
|
-
});
|
|
185
|
-
const { rule, normalized } = parseTrustRule(raw);
|
|
186
|
-
expect(normalized).toBe(true);
|
|
187
|
-
expect(rule.tool).toBe(SKILL_LOAD_TOOL);
|
|
188
|
-
expect("executionTarget" in rule).toBe(false);
|
|
189
|
-
expect("allowHighRisk" in rule).toBe(false);
|
|
190
|
-
});
|
|
191
|
-
|
|
192
|
-
test("skill_load without invalid fields is not normalized", () => {
|
|
193
|
-
const raw = makeRaw({ tool: SKILL_LOAD_TOOL, pattern: "skill_load:*" });
|
|
194
|
-
const { rule, normalized } = parseTrustRule(raw);
|
|
195
|
-
expect(normalized).toBe(false);
|
|
196
|
-
expect(rule.tool).toBe(SKILL_LOAD_TOOL);
|
|
197
|
-
expect("scope" in rule).toBe(false);
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
test("skill_load with scope 'everywhere' strips scope without normalization flag", () => {
|
|
201
|
-
const raw = makeRaw({ tool: SKILL_LOAD_TOOL, scope: "everywhere" });
|
|
202
|
-
const { rule, normalized } = parseTrustRule(raw);
|
|
203
|
-
expect(normalized).toBe(false);
|
|
204
|
-
expect("scope" in rule).toBe(false);
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
test("skill_load with non-'everywhere' scope strips scope and sets normalized", () => {
|
|
208
|
-
const raw = makeRaw({ tool: SKILL_LOAD_TOOL, scope: "/some/dir" });
|
|
209
|
-
const { rule, normalized } = parseTrustRule(raw);
|
|
210
|
-
expect(normalized).toBe(true);
|
|
211
|
-
expect("scope" in rule).toBe(false);
|
|
212
|
-
});
|
|
213
|
-
|
|
214
|
-
test("type guard isSkillLoadRule narrows correctly", () => {
|
|
215
|
-
const { rule } = parseTrustRule(makeRaw({ tool: SKILL_LOAD_TOOL }));
|
|
216
|
-
expect(isSkillLoadRule(rule)).toBe(true);
|
|
217
|
-
expect(isScopedRule(rule)).toBe(false);
|
|
218
|
-
});
|
|
219
|
-
});
|
|
220
|
-
|
|
221
|
-
// ---------------------------------------------------------------------------
|
|
222
|
-
// Unknown-tool preservation
|
|
223
|
-
// ---------------------------------------------------------------------------
|
|
224
|
-
|
|
225
|
-
describe("parseTrustRule — unknown tools", () => {
|
|
226
|
-
test("preserves executionTarget but strips allowHighRisk for unknown tools", () => {
|
|
227
|
-
const raw = makeRaw({
|
|
228
|
-
tool: "future_tool_v99",
|
|
229
|
-
executionTarget: "edge-worker",
|
|
230
|
-
allowHighRisk: true,
|
|
231
|
-
});
|
|
232
|
-
const { rule, normalized } = parseTrustRule(raw);
|
|
233
|
-
// allowHighRisk triggers normalization
|
|
234
|
-
expect(normalized).toBe(true);
|
|
235
|
-
expect(rule.tool).toBe("future_tool_v99");
|
|
236
|
-
expect((rule as GenericTrustRule).executionTarget).toBe("edge-worker");
|
|
237
|
-
expect("allowHighRisk" in rule).toBe(false);
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
test("unknown tool without optional fields is not normalized", () => {
|
|
241
|
-
const raw = makeRaw({ tool: "computer_use_click" });
|
|
242
|
-
const { rule, normalized } = parseTrustRule(raw);
|
|
243
|
-
expect(normalized).toBe(false);
|
|
244
|
-
expect(rule.tool).toBe("computer_use_click");
|
|
245
|
-
expect("scope" in rule).toBe(false);
|
|
246
|
-
expect("executionTarget" in rule).toBe(false);
|
|
247
|
-
expect("allowHighRisk" in rule).toBe(false);
|
|
248
|
-
});
|
|
249
|
-
|
|
250
|
-
test("unknown tool with non-everywhere scope strips scope and sets normalized", () => {
|
|
251
|
-
const raw = makeRaw({ tool: "future_tool_v99", scope: "/some/dir" });
|
|
252
|
-
const { rule, normalized } = parseTrustRule(raw);
|
|
253
|
-
expect(normalized).toBe(true);
|
|
254
|
-
expect("scope" in rule).toBe(false);
|
|
255
|
-
});
|
|
256
|
-
|
|
257
|
-
test("all type guards return false for generic rules", () => {
|
|
258
|
-
const { rule } = parseTrustRule(makeRaw({ tool: "some_new_tool" }));
|
|
259
|
-
expect(isScopedRule(rule)).toBe(false);
|
|
260
|
-
expect(isUrlRule(rule)).toBe(false);
|
|
261
|
-
expect(isManagedSkillRule(rule)).toBe(false);
|
|
262
|
-
expect(isSkillLoadRule(rule)).toBe(false);
|
|
263
|
-
});
|
|
264
|
-
});
|
|
265
|
-
|
|
266
|
-
// ---------------------------------------------------------------------------
|
|
267
|
-
// Normalization flag behavior
|
|
268
|
-
// ---------------------------------------------------------------------------
|
|
269
|
-
|
|
270
|
-
describe("parseTrustRule — normalization flag", () => {
|
|
271
|
-
test("normalized is false when no changes needed (no allowHighRisk)", () => {
|
|
272
|
-
const raw = makeRaw({ tool: "host_bash" });
|
|
273
|
-
const { normalized } = parseTrustRule(raw);
|
|
274
|
-
expect(normalized).toBe(false);
|
|
275
|
-
});
|
|
276
|
-
|
|
277
|
-
test("normalized is true when allowHighRisk is present (stripped)", () => {
|
|
278
|
-
const raw = makeRaw({ tool: "host_bash", allowHighRisk: true });
|
|
279
|
-
const { normalized } = parseTrustRule(raw);
|
|
280
|
-
expect(normalized).toBe(true);
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
test("normalized is true when URL tool has allowHighRisk (stripped)", () => {
|
|
284
|
-
const raw = makeRaw({ tool: "web_fetch", allowHighRisk: true });
|
|
285
|
-
const { normalized } = parseTrustRule(raw);
|
|
286
|
-
expect(normalized).toBe(true);
|
|
287
|
-
});
|
|
288
|
-
|
|
289
|
-
test("normalized is true when decision is coerced", () => {
|
|
290
|
-
const raw = makeRaw({ tool: "bash", decision: "invalid_decision" });
|
|
291
|
-
const { rule, normalized } = parseTrustRule(raw);
|
|
292
|
-
expect(normalized).toBe(true);
|
|
293
|
-
expect(rule.decision).toBe("ask");
|
|
294
|
-
});
|
|
295
|
-
|
|
296
|
-
test("empty executionTarget string is not preserved on scoped rules", () => {
|
|
297
|
-
const raw = makeRaw({ tool: "bash", executionTarget: "" });
|
|
298
|
-
const { rule, normalized } = parseTrustRule(raw);
|
|
299
|
-
expect(normalized).toBe(false);
|
|
300
|
-
expect("executionTarget" in rule).toBe(false);
|
|
301
|
-
});
|
|
302
|
-
});
|
|
303
|
-
|
|
304
|
-
// ---------------------------------------------------------------------------
|
|
305
|
-
// ruleScope helper
|
|
306
|
-
// ---------------------------------------------------------------------------
|
|
307
|
-
|
|
308
|
-
describe("ruleScope", () => {
|
|
309
|
-
test("returns scope for scoped rules", () => {
|
|
310
|
-
const { rule } = parseTrustRule(makeRaw({ tool: "bash", scope: "/projects" }));
|
|
311
|
-
expect(ruleScope(rule)).toBe("/projects");
|
|
312
|
-
});
|
|
313
|
-
|
|
314
|
-
test("returns 'everywhere' for non-scoped rules without scope", () => {
|
|
315
|
-
const { rule } = parseTrustRule(makeRaw({ tool: "web_fetch" }));
|
|
316
|
-
expect("scope" in rule).toBe(false);
|
|
317
|
-
expect(ruleScope(rule)).toBe("everywhere");
|
|
318
|
-
});
|
|
319
|
-
|
|
320
|
-
test("returns 'everywhere' for generic rules (scope is stripped)", () => {
|
|
321
|
-
const { rule } = parseTrustRule(makeRaw({ tool: "future_tool", scope: "/custom" }));
|
|
322
|
-
expect("scope" in rule).toBe(false);
|
|
323
|
-
expect(ruleScope(rule)).toBe("everywhere");
|
|
324
|
-
});
|
|
325
|
-
|
|
326
|
-
test("returns 'everywhere' for scoped rules with default scope", () => {
|
|
327
|
-
const { rule } = parseTrustRule(makeRaw({ tool: "file_read", scope: "everywhere" }));
|
|
328
|
-
expect(ruleScope(rule)).toBe("everywhere");
|
|
329
|
-
});
|
|
330
|
-
});
|
|
331
|
-
|
|
332
|
-
// ---------------------------------------------------------------------------
|
|
333
|
-
// parseTrustFileData
|
|
334
|
-
// ---------------------------------------------------------------------------
|
|
335
|
-
|
|
336
|
-
describe("parseTrustFileData", () => {
|
|
337
|
-
test("parses a valid trust file with mixed rule families", () => {
|
|
338
|
-
const raw = {
|
|
339
|
-
version: 3,
|
|
340
|
-
starterBundleAccepted: true,
|
|
341
|
-
rules: [
|
|
342
|
-
makeRaw({ id: "r1", tool: "bash" }),
|
|
343
|
-
makeRaw({ id: "r2", tool: "web_fetch", pattern: "web_fetch:https://example.com/*" }),
|
|
344
|
-
makeRaw({ id: "r3", tool: "skill_load", pattern: "skill_load:*" }),
|
|
345
|
-
],
|
|
346
|
-
};
|
|
347
|
-
const { data, normalized } = parseTrustFileData(raw);
|
|
348
|
-
expect(normalized).toBe(false);
|
|
349
|
-
expect(data.version).toBe(3);
|
|
350
|
-
expect(data.starterBundleAccepted).toBe(true);
|
|
351
|
-
expect(data.rules).toHaveLength(3);
|
|
352
|
-
expect(data.rules[0].tool).toBe("bash");
|
|
353
|
-
expect(data.rules[1].tool).toBe("web_fetch");
|
|
354
|
-
expect(data.rules[2].tool).toBe("skill_load");
|
|
355
|
-
});
|
|
356
|
-
|
|
357
|
-
test("reports normalized when any rule is modified", () => {
|
|
358
|
-
const raw = {
|
|
359
|
-
version: 3,
|
|
360
|
-
rules: [
|
|
361
|
-
makeRaw({ id: "r1", tool: "bash" }),
|
|
362
|
-
// This rule has an invalid field for its family
|
|
363
|
-
makeRaw({ id: "r2", tool: "web_fetch", executionTarget: "stale" }),
|
|
364
|
-
],
|
|
365
|
-
};
|
|
366
|
-
const { data, normalized } = parseTrustFileData(raw);
|
|
367
|
-
expect(normalized).toBe(true);
|
|
368
|
-
expect(data.rules).toHaveLength(2);
|
|
369
|
-
expect("executionTarget" in data.rules[1]).toBe(false);
|
|
370
|
-
});
|
|
371
|
-
|
|
372
|
-
test("reports normalized when allowHighRisk is present (stripped)", () => {
|
|
373
|
-
const raw = {
|
|
374
|
-
version: 3,
|
|
375
|
-
rules: [
|
|
376
|
-
makeRaw({ id: "r1", tool: "bash", allowHighRisk: true }),
|
|
377
|
-
],
|
|
378
|
-
};
|
|
379
|
-
const { data, normalized } = parseTrustFileData(raw);
|
|
380
|
-
expect(normalized).toBe(true);
|
|
381
|
-
expect(data.rules).toHaveLength(1);
|
|
382
|
-
expect("allowHighRisk" in data.rules[0]).toBe(false);
|
|
383
|
-
});
|
|
384
|
-
|
|
385
|
-
test("skips null/non-object entries and flags as normalized", () => {
|
|
386
|
-
const raw = {
|
|
387
|
-
version: 3,
|
|
388
|
-
rules: [null, 42, makeRaw({ id: "r1", tool: "bash" })],
|
|
389
|
-
};
|
|
390
|
-
const { data, normalized } = parseTrustFileData(raw);
|
|
391
|
-
expect(normalized).toBe(true);
|
|
392
|
-
expect(data.rules).toHaveLength(1);
|
|
393
|
-
expect(data.rules[0].id).toBe("r1");
|
|
394
|
-
});
|
|
395
|
-
|
|
396
|
-
test("handles missing rules array", () => {
|
|
397
|
-
const raw = { version: 3 };
|
|
398
|
-
const { data, normalized } = parseTrustFileData(raw);
|
|
399
|
-
expect(normalized).toBe(false);
|
|
400
|
-
expect(data.rules).toEqual([]);
|
|
401
|
-
});
|
|
402
|
-
|
|
403
|
-
test("handles missing version", () => {
|
|
404
|
-
const raw = { rules: [] };
|
|
405
|
-
const { data } = parseTrustFileData(raw);
|
|
406
|
-
expect(data.version).toBe(0);
|
|
407
|
-
});
|
|
408
|
-
|
|
409
|
-
test("starterBundleAccepted defaults to undefined when not true", () => {
|
|
410
|
-
const raw = { version: 3, rules: [], starterBundleAccepted: false };
|
|
411
|
-
const { data } = parseTrustFileData(raw);
|
|
412
|
-
expect(data.starterBundleAccepted).toBeUndefined();
|
|
413
|
-
});
|
|
414
|
-
});
|
|
415
|
-
|
|
416
|
-
// ---------------------------------------------------------------------------
|
|
417
|
-
// Type-level smoke tests (compile-time only — no runtime assertions)
|
|
418
|
-
// ---------------------------------------------------------------------------
|
|
419
|
-
|
|
420
|
-
describe("type-level compatibility", () => {
|
|
421
|
-
test("TrustRule union is assignable from all family interfaces", () => {
|
|
422
|
-
// These assignments verify that each family interface satisfies TrustRule.
|
|
423
|
-
// If any interface breaks the union, TypeScript will fail at compile time.
|
|
424
|
-
const scoped: ScopedTrustRule = {
|
|
425
|
-
id: "s1",
|
|
426
|
-
tool: "bash",
|
|
427
|
-
pattern: "**",
|
|
428
|
-
scope: "everywhere",
|
|
429
|
-
decision: "allow",
|
|
430
|
-
priority: 50,
|
|
431
|
-
createdAt: 0,
|
|
432
|
-
executionTarget: "host",
|
|
433
|
-
};
|
|
434
|
-
const url: UrlTrustRule = {
|
|
435
|
-
id: "u1",
|
|
436
|
-
tool: "web_fetch",
|
|
437
|
-
pattern: "web_fetch:*",
|
|
438
|
-
decision: "allow",
|
|
439
|
-
priority: 90,
|
|
440
|
-
createdAt: 0,
|
|
441
|
-
};
|
|
442
|
-
const managed: ManagedSkillTrustRule = {
|
|
443
|
-
id: "m1",
|
|
444
|
-
tool: "scaffold_managed_skill",
|
|
445
|
-
pattern: "scaffold_managed_skill:*",
|
|
446
|
-
decision: "ask",
|
|
447
|
-
priority: 1000,
|
|
448
|
-
createdAt: 0,
|
|
449
|
-
};
|
|
450
|
-
const skillLoad: SkillLoadTrustRule = {
|
|
451
|
-
id: "sl1",
|
|
452
|
-
tool: "skill_load",
|
|
453
|
-
pattern: "skill_load:*",
|
|
454
|
-
decision: "allow",
|
|
455
|
-
priority: 100,
|
|
456
|
-
createdAt: 0,
|
|
457
|
-
};
|
|
458
|
-
const generic: GenericTrustRule = {
|
|
459
|
-
id: "g1",
|
|
460
|
-
tool: "computer_use_click",
|
|
461
|
-
pattern: "**",
|
|
462
|
-
decision: "ask",
|
|
463
|
-
priority: 1000,
|
|
464
|
-
createdAt: 0,
|
|
465
|
-
};
|
|
466
|
-
|
|
467
|
-
// All should be assignable to TrustRule
|
|
468
|
-
const rules: TrustRule[] = [scoped, url, managed, skillLoad, generic];
|
|
469
|
-
expect(rules).toHaveLength(5);
|
|
470
|
-
});
|
|
471
|
-
});
|