@vellumai/credential-executor 0.6.5 → 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.
Files changed (46) hide show
  1. package/Dockerfile +5 -5
  2. package/bun.lock +15 -7
  3. package/node_modules/@vellumai/credential-storage/src/__tests__/package-boundary.test.ts +32 -6
  4. package/node_modules/@vellumai/egress-proxy/src/__tests__/package-boundary.test.ts +32 -1
  5. package/node_modules/@vellumai/egress-proxy/src/types.ts +19 -0
  6. package/node_modules/@vellumai/{ces-contracts → service-contracts}/bun.lock +1 -1
  7. package/node_modules/@vellumai/{ces-contracts → service-contracts}/package.json +4 -2
  8. package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/contracts.test.ts +5 -1
  9. package/node_modules/@vellumai/service-contracts/src/__tests__/package-boundary.test.ts +155 -0
  10. package/node_modules/@vellumai/service-contracts/src/credential-rpc.ts +23 -0
  11. package/node_modules/@vellumai/service-contracts/src/index.ts +25 -0
  12. package/node_modules/@vellumai/{ces-contracts/src/index.ts → service-contracts/src/transport.ts} +6 -28
  13. package/node_modules/@vellumai/service-contracts/src/trust-rules.ts +116 -0
  14. package/package.json +3 -3
  15. package/src/__tests__/bulk-set-credentials.test.ts +1 -1
  16. package/src/__tests__/command-executor.test.ts +2 -2
  17. package/src/__tests__/http-executor.test.ts +1 -1
  18. package/src/__tests__/local-materializers.test.ts +1 -1
  19. package/src/__tests__/managed-integration.test.ts +1 -1
  20. package/src/__tests__/managed-lazy-getters.test.ts +1 -1
  21. package/src/__tests__/managed-materializers.test.ts +1 -1
  22. package/src/__tests__/managed-rejection.test.ts +1 -1
  23. package/src/__tests__/transport.test.ts +1 -1
  24. package/src/audit/store.ts +2 -2
  25. package/src/commands/executor.ts +2 -2
  26. package/src/grants/rpc-handlers.ts +1 -1
  27. package/src/http/audit.ts +1 -1
  28. package/src/http/executor.ts +2 -2
  29. package/src/http/policy.ts +1 -1
  30. package/src/main.ts +1 -1
  31. package/src/managed-errors.ts +2 -2
  32. package/src/managed-lazy-getters.ts +4 -4
  33. package/src/managed-main.ts +3 -3
  34. package/src/materializers/local.ts +1 -1
  35. package/src/server.ts +2 -2
  36. package/src/subjects/local.ts +2 -2
  37. package/src/subjects/managed.ts +1 -1
  38. package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +0 -471
  39. package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +0 -436
  40. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/grants.test.ts +0 -0
  41. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/error.ts +0 -0
  42. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/grants.ts +0 -0
  43. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/handles.ts +0 -0
  44. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rendering.ts +0 -0
  45. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rpc.ts +0 -0
  46. /package/node_modules/@vellumai/{ces-contracts → service-contracts}/tsconfig.json +0 -0
@@ -1,436 +0,0 @@
1
- /**
2
- * Trust rule types shared between the assistant daemon and the gateway.
3
- *
4
- * These are extracted from `assistant/src/permissions/types.ts` and
5
- * `assistant/src/permissions/trust-store.ts` so that both packages can
6
- * reference a single canonical definition.
7
- *
8
- * Tools are grouped into "families" based on how their permission candidates
9
- * are constructed and matched:
10
- *
11
- * - **Scoped**: tools whose candidates include a filesystem path and obey
12
- * directory-boundary scope constraints (`file_read`, `file_write`,
13
- * `file_edit`, `host_file_read`, `host_file_write`, `host_file_edit`,
14
- * `bash`, `host_bash`).
15
- * - **URL**: tools whose candidates include a URL (`web_fetch`,
16
- * `network_request`).
17
- * - **Managed skill**: tools that manage first-party skill packages
18
- * (`scaffold_managed_skill`, `delete_managed_skill`).
19
- * - **Skill load**: the `skill_load` tool, which uses a distinct candidate
20
- * namespace (`skill_load:selector` or `skill_load_dynamic:selector`).
21
- * - **Generic**: everything else (computer-use tools, UI surface tools,
22
- * recall, skill_execute, etc.).
23
- */
24
-
25
- // ---------------------------------------------------------------------------
26
- // Trust decision
27
- // ---------------------------------------------------------------------------
28
-
29
- /** The possible decisions a trust rule can make. */
30
- export type TrustDecision = "allow" | "deny" | "ask";
31
-
32
- // ---------------------------------------------------------------------------
33
- // Tool family constants
34
- // ---------------------------------------------------------------------------
35
-
36
- /**
37
- * Tools whose permission candidates are scoped to a filesystem path and obey
38
- * directory-boundary scope constraints.
39
- */
40
- export const SCOPED_TOOLS = [
41
- "file_read",
42
- "file_write",
43
- "file_edit",
44
- "host_file_read",
45
- "host_file_write",
46
- "host_file_edit",
47
- "bash",
48
- "host_bash",
49
- ] as const;
50
-
51
- /**
52
- * Tools whose permission candidates include a URL.
53
- */
54
- export const URL_TOOLS = ["web_fetch", "network_request"] as const;
55
-
56
- /**
57
- * Tools that manage first-party skill packages (scaffold/delete).
58
- */
59
- export const MANAGED_SKILL_TOOLS = [
60
- "scaffold_managed_skill",
61
- "delete_managed_skill",
62
- ] as const;
63
-
64
- /**
65
- * The skill_load tool name. Separated from the array constants because
66
- * skill_load is a singleton, not a family with multiple members.
67
- */
68
- export const SKILL_LOAD_TOOL = "skill_load" as const;
69
-
70
- /** Set for O(1) lookups when classifying tool names. */
71
- const SCOPED_TOOLS_SET: ReadonlySet<string> = new Set(SCOPED_TOOLS);
72
- const URL_TOOLS_SET: ReadonlySet<string> = new Set(URL_TOOLS);
73
- const MANAGED_SKILL_TOOLS_SET: ReadonlySet<string> = new Set(
74
- MANAGED_SKILL_TOOLS,
75
- );
76
-
77
- // ---------------------------------------------------------------------------
78
- // Trust rule — base and family-specific variants
79
- // ---------------------------------------------------------------------------
80
-
81
- /** Fields shared by all trust rule variants. */
82
- export interface TrustRuleBase {
83
- id: string;
84
- tool: string;
85
- pattern: string;
86
- decision: TrustDecision;
87
- priority: number;
88
- createdAt: number;
89
- /**
90
- * Set when a user explicitly modifies a default trust rule.
91
- * When present, `backfillDefaults()` will not overwrite the rule
92
- * with updated template values on upgrade — preserving the user's
93
- * customization.
94
- */
95
- userModifiedAt?: number;
96
- }
97
-
98
- /**
99
- * A trust rule for a scoped tool (filesystem-path-based candidates).
100
- *
101
- * Scoped rules may carry `executionTarget` to constrain matching to a
102
- * specific execution environment.
103
- */
104
- export interface ScopedTrustRule extends TrustRuleBase {
105
- tool: (typeof SCOPED_TOOLS)[number];
106
- scope: string;
107
- executionTarget?: string;
108
- }
109
-
110
- /**
111
- * A trust rule for a URL-based tool.
112
- *
113
- * URL rules do not use `executionTarget`.
114
- */
115
- export interface UrlTrustRule extends TrustRuleBase {
116
- tool: (typeof URL_TOOLS)[number];
117
- }
118
-
119
- /**
120
- * A trust rule for a managed-skill tool (scaffold/delete).
121
- */
122
- export interface ManagedSkillTrustRule extends TrustRuleBase {
123
- tool: (typeof MANAGED_SKILL_TOOLS)[number];
124
- }
125
-
126
- /**
127
- * A trust rule for the `skill_load` tool.
128
- */
129
- export interface SkillLoadTrustRule extends TrustRuleBase {
130
- tool: typeof SKILL_LOAD_TOOL;
131
- }
132
-
133
- /**
134
- * A trust rule for any tool that doesn't belong to a known family.
135
- *
136
- * Generic rules preserve `executionTarget` for backward compatibility —
137
- * existing rules for unknown/new tools may carry this field.
138
- * Scope is intentionally absent: new tools that need scope must be explicitly
139
- * added to `SCOPED_TOOLS` and use `ScopedTrustRule`.
140
- */
141
- export interface GenericTrustRule extends TrustRuleBase {
142
- tool: string;
143
- executionTarget?: string;
144
- }
145
-
146
- /**
147
- * Discriminated union of all trust rule families.
148
- *
149
- * The union is discriminated on the `tool` field: known tool names narrow to
150
- * the corresponding family variant, while unknown tool names fall through to
151
- * `GenericTrustRule`.
152
- *
153
- * For backward compatibility, `TrustRule` remains the single type that all
154
- * existing code uses. The family-specific interfaces exist so that new code
155
- * can narrow the type when it knows the tool family.
156
- */
157
- export type TrustRule =
158
- | ScopedTrustRule
159
- | UrlTrustRule
160
- | ManagedSkillTrustRule
161
- | SkillLoadTrustRule
162
- | GenericTrustRule;
163
-
164
- // ---------------------------------------------------------------------------
165
- // Type guards
166
- // ---------------------------------------------------------------------------
167
-
168
- /** Narrow a TrustRule to a ScopedTrustRule. */
169
- export function isScopedRule(rule: TrustRule): rule is ScopedTrustRule {
170
- return SCOPED_TOOLS_SET.has(rule.tool);
171
- }
172
-
173
- /** Narrow a TrustRule to a UrlTrustRule. */
174
- export function isUrlRule(rule: TrustRule): rule is UrlTrustRule {
175
- return URL_TOOLS_SET.has(rule.tool);
176
- }
177
-
178
- /** Narrow a TrustRule to a ManagedSkillTrustRule. */
179
- export function isManagedSkillRule(
180
- rule: TrustRule,
181
- ): rule is ManagedSkillTrustRule {
182
- return MANAGED_SKILL_TOOLS_SET.has(rule.tool);
183
- }
184
-
185
- /** Narrow a TrustRule to a SkillLoadTrustRule. */
186
- export function isSkillLoadRule(rule: TrustRule): rule is SkillLoadTrustRule {
187
- return rule.tool === SKILL_LOAD_TOOL;
188
- }
189
-
190
- // ---------------------------------------------------------------------------
191
- // Scope helper
192
- // ---------------------------------------------------------------------------
193
-
194
- /**
195
- * Return the effective scope for any trust rule. Only scoped rules carry a
196
- * `scope` field; all other rule families return `"everywhere"`.
197
- */
198
- export function ruleScope(rule: TrustRule): string {
199
- if (isScopedRule(rule)) {
200
- return rule.scope;
201
- }
202
- return "everywhere";
203
- }
204
-
205
- // ---------------------------------------------------------------------------
206
- // Canonical parse / normalize
207
- // ---------------------------------------------------------------------------
208
-
209
- /**
210
- * Result of parsing a raw trust rule object. Includes the normalized rule
211
- * and a flag indicating whether any normalization occurred (so callers can
212
- * trigger a re-save of the trust file).
213
- */
214
- export interface ParsedTrustRule {
215
- rule: TrustRule;
216
- /** True if any fields were stripped or modified during normalization. */
217
- normalized: boolean;
218
- }
219
-
220
- /**
221
- * Parse and normalize a raw trust rule object into a canonical `TrustRule`.
222
- *
223
- * Normalization strips fields that are invalid for the rule's tool family:
224
- * - URL rules: `executionTarget` and `scope` are stripped.
225
- * - Managed skill rules: `executionTarget` and `scope` are stripped.
226
- * - Skill load rules: `executionTarget` and `scope` are stripped.
227
- * - Scoped rules: `scope` is preserved (defaulting to `"everywhere"`),
228
- * `executionTarget` is preserved when valid.
229
- * - Generic (unknown) rules: `scope` is stripped (new tools that need scope
230
- * must be added to `SCOPED_TOOLS`); `executionTarget` is preserved for
231
- * forward compatibility.
232
- * - All families: `allowHighRisk` is stripped (replaced by runtime
233
- * determination in checker.ts). Old trust.json files with `allowHighRisk`
234
- * are normalized on load.
235
- */
236
- export function parseTrustRule(raw: Record<string, unknown>): ParsedTrustRule {
237
- let normalized = false;
238
-
239
- // Extract base fields with coercion for safety — mark normalized whenever
240
- // a field is coerced to its default so callers know to re-save.
241
- const id = typeof raw.id === "string" ? raw.id : ((normalized = true), "");
242
- const tool =
243
- typeof raw.tool === "string" ? raw.tool : ((normalized = true), "");
244
- const pattern =
245
- typeof raw.pattern === "string" ? raw.pattern : ((normalized = true), "");
246
- const decision = isValidDecision(raw.decision)
247
- ? raw.decision
248
- : ((normalized = true), "ask" as const);
249
- const priority =
250
- typeof raw.priority === "number" ? raw.priority : ((normalized = true), 100);
251
- const createdAt =
252
- typeof raw.createdAt === "number"
253
- ? raw.createdAt
254
- : ((normalized = true), 0);
255
- const userModifiedAt =
256
- typeof raw.userModifiedAt === "number" ? raw.userModifiedAt : undefined;
257
-
258
- // Build the base rule — scope is NOT included here; it is added only by
259
- // the scoped and generic branches below.
260
- const base: TrustRuleBase = {
261
- id,
262
- tool,
263
- pattern,
264
- decision,
265
- priority,
266
- createdAt,
267
- ...(userModifiedAt != null ? { userModifiedAt } : {}),
268
- };
269
-
270
- // Determine the family and strip invalid fields
271
- if (URL_TOOLS_SET.has(tool)) {
272
- // URL rules must not carry executionTarget or scope.
273
- if (raw.executionTarget !== undefined) {
274
- normalized = true;
275
- }
276
- if (typeof raw.scope === "string" && raw.scope !== "everywhere") {
277
- normalized = true;
278
- }
279
- // allowHighRisk is stripped (replaced by runtime determination).
280
- if (raw.allowHighRisk !== undefined) {
281
- normalized = true;
282
- }
283
- const rule: UrlTrustRule = { ...base, tool: tool as UrlTrustRule["tool"] };
284
- return { rule, normalized };
285
- }
286
-
287
- if (MANAGED_SKILL_TOOLS_SET.has(tool)) {
288
- // Managed skill rules must not carry executionTarget or scope.
289
- if (raw.executionTarget !== undefined) {
290
- normalized = true;
291
- }
292
- if (typeof raw.scope === "string" && raw.scope !== "everywhere") {
293
- normalized = true;
294
- }
295
- // allowHighRisk is stripped (replaced by runtime determination).
296
- if (raw.allowHighRisk !== undefined) {
297
- normalized = true;
298
- }
299
- const rule: ManagedSkillTrustRule = {
300
- ...base,
301
- tool: tool as ManagedSkillTrustRule["tool"],
302
- };
303
- return { rule, normalized };
304
- }
305
-
306
- if (tool === SKILL_LOAD_TOOL) {
307
- // Skill-load rules must not carry executionTarget or scope.
308
- if (raw.executionTarget !== undefined) {
309
- normalized = true;
310
- }
311
- if (typeof raw.scope === "string" && raw.scope !== "everywhere") {
312
- normalized = true;
313
- }
314
- // allowHighRisk is stripped (replaced by runtime determination).
315
- if (raw.allowHighRisk !== undefined) {
316
- normalized = true;
317
- }
318
- const rule: SkillLoadTrustRule = { ...base, tool: SKILL_LOAD_TOOL };
319
- return { rule, normalized };
320
- }
321
-
322
- if (SCOPED_TOOLS_SET.has(tool)) {
323
- // Scoped rules include scope (defaulting to "everywhere") and preserve
324
- // executionTarget.
325
- const scope =
326
- typeof raw.scope === "string"
327
- ? raw.scope
328
- : ((normalized = true), "everywhere");
329
- const rule: ScopedTrustRule = {
330
- ...base,
331
- tool: tool as ScopedTrustRule["tool"],
332
- scope,
333
- };
334
- if (
335
- typeof raw.executionTarget === "string" &&
336
- raw.executionTarget.length > 0
337
- ) {
338
- rule.executionTarget = raw.executionTarget;
339
- } else if (raw.executionTarget !== undefined && raw.executionTarget !== "") {
340
- normalized = true;
341
- }
342
- // allowHighRisk is stripped (replaced by runtime determination).
343
- if (raw.allowHighRisk !== undefined) {
344
- normalized = true;
345
- }
346
- return { rule, normalized };
347
- }
348
-
349
- // Generic (unknown) tool — strip scope (new tools that need scope must be
350
- // added to SCOPED_TOOLS explicitly), preserve executionTarget for forward compat.
351
- const rule: GenericTrustRule = { ...base };
352
- if (
353
- typeof raw.scope === "string" &&
354
- raw.scope !== "" &&
355
- raw.scope !== "everywhere"
356
- ) {
357
- normalized = true;
358
- }
359
- if (
360
- typeof raw.executionTarget === "string" &&
361
- raw.executionTarget.length > 0
362
- ) {
363
- rule.executionTarget = raw.executionTarget;
364
- } else if (raw.executionTarget !== undefined && raw.executionTarget !== "") {
365
- normalized = true;
366
- }
367
- // allowHighRisk is stripped (replaced by runtime determination).
368
- if (raw.allowHighRisk !== undefined) {
369
- normalized = true;
370
- }
371
- return { rule, normalized };
372
- }
373
-
374
- function isValidDecision(value: unknown): value is TrustDecision {
375
- return value === "allow" || value === "deny" || value === "ask";
376
- }
377
-
378
- // ---------------------------------------------------------------------------
379
- // Trust file (on-disk shape)
380
- // ---------------------------------------------------------------------------
381
-
382
- /** Shape of the `trust.json` file persisted to disk. */
383
- export interface TrustFileData {
384
- version: number;
385
- rules: TrustRule[];
386
- /** Set to true when the user explicitly accepts the starter approval bundle. */
387
- starterBundleAccepted?: boolean;
388
- }
389
-
390
- /**
391
- * Result of parsing a raw trust file. Includes the parsed data and a flag
392
- * indicating whether any rules were normalized.
393
- */
394
- export interface ParsedTrustFileData {
395
- data: TrustFileData;
396
- /** True if any rules were normalized during parsing. */
397
- normalized: boolean;
398
- }
399
-
400
- /**
401
- * Parse and normalize a raw trust file object.
402
- *
403
- * Each rule in the `rules` array is run through `parseTrustRule` for
404
- * family-aware normalization. The `normalized` flag in the result is true
405
- * if *any* rule was modified, signaling the caller that a re-save is warranted.
406
- */
407
- export function parseTrustFileData(
408
- raw: Record<string, unknown>,
409
- ): ParsedTrustFileData {
410
- const version = typeof raw.version === "number" ? raw.version : 0;
411
- const starterBundleAccepted =
412
- raw.starterBundleAccepted === true ? true : undefined;
413
- const rawRules = Array.isArray(raw.rules) ? raw.rules : [];
414
-
415
- let anyNormalized = false;
416
- const rules: TrustRule[] = [];
417
-
418
- for (const rawRule of rawRules) {
419
- if (rawRule == null || typeof rawRule !== "object" || Array.isArray(rawRule)) {
420
- anyNormalized = true;
421
- continue;
422
- }
423
- const { rule, normalized } = parseTrustRule(
424
- rawRule as Record<string, unknown>,
425
- );
426
- if (normalized) anyNormalized = true;
427
- rules.push(rule);
428
- }
429
-
430
- const data: TrustFileData = { version, rules };
431
- if (starterBundleAccepted) {
432
- data.starterBundleAccepted = true;
433
- }
434
-
435
- return { data, normalized: anyNormalized };
436
- }