@vellumai/assistant 0.5.4 → 0.5.6
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 +17 -27
- package/node_modules/@vellumai/ces-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +42 -0
- package/package.json +1 -1
- package/src/__tests__/actor-token-service.test.ts +113 -0
- package/src/__tests__/config-schema.test.ts +2 -2
- package/src/__tests__/context-window-manager.test.ts +78 -0
- package/src/__tests__/conversation-title-service.test.ts +30 -1
- package/src/__tests__/credential-security-invariants.test.ts +2 -0
- package/src/__tests__/docker-signing-key-bootstrap.test.ts +207 -0
- package/src/__tests__/memory-regressions.test.ts +8 -30
- package/src/__tests__/openai-whisper.test.ts +93 -0
- package/src/__tests__/require-fresh-approval.test.ts +4 -0
- package/src/__tests__/slack-messaging-token-resolution.test.ts +319 -0
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -0
- package/src/__tests__/tool-executor.test.ts +4 -0
- package/src/__tests__/volume-security-guard.test.ts +155 -0
- package/src/cli/commands/conversations.ts +0 -18
- package/src/config/bundled-skills/messaging/tools/shared.ts +1 -0
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +16 -37
- package/src/config/env-registry.ts +9 -0
- package/src/config/env.ts +8 -2
- package/src/config/feature-flag-registry.json +8 -8
- package/src/config/schema.ts +0 -12
- package/src/config/schemas/memory.ts +0 -4
- package/src/config/schemas/platform.ts +1 -1
- package/src/config/schemas/security.ts +4 -0
- package/src/context/window-manager.ts +53 -2
- package/src/credential-execution/managed-catalog.ts +5 -15
- package/src/daemon/conversation-agent-loop.ts +0 -60
- package/src/daemon/conversation-memory.ts +0 -117
- package/src/daemon/conversation-runtime-assembly.ts +0 -2
- package/src/daemon/daemon-control.ts +7 -0
- package/src/daemon/handlers/conversations.ts +0 -11
- package/src/daemon/lifecycle.ts +10 -47
- package/src/daemon/providers-setup.ts +2 -1
- package/src/followups/followup-store.ts +5 -2
- package/src/hooks/manager.ts +7 -0
- package/src/instrument.ts +33 -1
- package/src/memory/conversation-crud.ts +0 -236
- package/src/memory/conversation-title-service.ts +26 -10
- package/src/memory/db-init.ts +5 -13
- package/src/memory/embedding-local.ts +11 -5
- package/src/memory/indexer.ts +15 -106
- package/src/memory/job-handlers/conversation-starters.ts +24 -36
- package/src/memory/job-handlers/embedding.ts +0 -79
- package/src/memory/job-utils.ts +1 -1
- package/src/memory/jobs-store.ts +0 -8
- package/src/memory/jobs-worker.ts +0 -20
- package/src/memory/migrations/189-drop-simplified-memory.ts +42 -0
- package/src/memory/migrations/index.ts +1 -3
- package/src/memory/qdrant-client.ts +4 -6
- package/src/memory/schema/conversations.ts +0 -3
- package/src/memory/schema/index.ts +0 -2
- package/src/messaging/draft-store.ts +2 -2
- package/src/messaging/provider.ts +9 -0
- package/src/messaging/providers/slack/adapter.ts +29 -2
- package/src/oauth/connection-resolver.test.ts +22 -18
- package/src/oauth/connection-resolver.ts +92 -7
- package/src/oauth/platform-connection.test.ts +78 -69
- package/src/oauth/platform-connection.ts +12 -19
- package/src/permissions/defaults.ts +3 -3
- package/src/permissions/trust-client.ts +332 -0
- package/src/permissions/trust-store-interface.ts +105 -0
- package/src/permissions/trust-store.ts +531 -39
- package/src/platform/client.test.ts +148 -0
- package/src/platform/client.ts +71 -0
- package/src/providers/speech-to-text/openai-whisper.test.ts +190 -0
- package/src/providers/speech-to-text/openai-whisper.ts +68 -0
- package/src/providers/speech-to-text/resolve.ts +9 -0
- package/src/providers/speech-to-text/types.ts +17 -0
- package/src/runtime/auth/route-policy.ts +14 -0
- package/src/runtime/auth/token-service.ts +133 -0
- package/src/runtime/http-server.ts +4 -2
- package/src/runtime/routes/conversation-management-routes.ts +0 -36
- package/src/runtime/routes/conversation-query-routes.ts +44 -2
- package/src/runtime/routes/conversation-routes.ts +2 -1
- package/src/runtime/routes/inbound-message-handler.ts +27 -3
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +16 -1
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +287 -0
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +122 -0
- package/src/runtime/routes/log-export-routes.ts +1 -0
- package/src/runtime/routes/memory-item-routes.test.ts +221 -3
- package/src/runtime/routes/memory-item-routes.ts +124 -2
- package/src/runtime/routes/secret-routes.ts +4 -1
- package/src/runtime/routes/upgrade-broadcast-routes.ts +151 -0
- package/src/schedule/schedule-store.ts +0 -21
- package/src/security/ces-credential-client.ts +173 -0
- package/src/security/secure-keys.ts +65 -22
- package/src/signals/bash.ts +3 -0
- package/src/signals/cancel.ts +3 -0
- package/src/signals/confirm.ts +3 -0
- package/src/signals/conversation-undo.ts +3 -0
- package/src/signals/event-stream.ts +7 -0
- package/src/signals/shotgun.ts +3 -0
- package/src/signals/trust-rule.ts +3 -0
- package/src/skills/inline-command-render.ts +5 -1
- package/src/skills/inline-command-runner.ts +30 -2
- package/src/telemetry/usage-telemetry-reporter.test.ts +23 -36
- package/src/telemetry/usage-telemetry-reporter.ts +21 -19
- package/src/tools/memory/handlers.ts +1 -129
- package/src/tools/permission-checker.ts +18 -0
- package/src/tools/skills/load.ts +9 -2
- package/src/util/device-id.ts +70 -7
- package/src/util/logger.ts +35 -9
- package/src/util/platform.ts +29 -5
- package/src/util/xml.ts +8 -0
- package/src/workspace/heartbeat-service.ts +5 -24
- package/src/workspace/migrations/migrate-to-workspace-volume.ts +113 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/__tests__/archive-recall.test.ts +0 -560
- package/src/__tests__/conversation-memory-dirty-tail.test.ts +0 -150
- package/src/__tests__/conversation-switch-memory-reduction.test.ts +0 -474
- package/src/__tests__/db-memory-archive-migration.test.ts +0 -372
- package/src/__tests__/db-memory-brief-state-migration.test.ts +0 -213
- package/src/__tests__/db-memory-reducer-checkpoints.test.ts +0 -273
- package/src/__tests__/memory-brief-open-loops.test.ts +0 -530
- package/src/__tests__/memory-brief-time.test.ts +0 -285
- package/src/__tests__/memory-brief-wrapper.test.ts +0 -311
- package/src/__tests__/memory-chunk-archive.test.ts +0 -400
- package/src/__tests__/memory-chunk-dual-write.test.ts +0 -453
- package/src/__tests__/memory-episode-archive.test.ts +0 -370
- package/src/__tests__/memory-episode-dual-write.test.ts +0 -626
- package/src/__tests__/memory-observation-archive.test.ts +0 -375
- package/src/__tests__/memory-observation-dual-write.test.ts +0 -318
- package/src/__tests__/memory-reducer-job.test.ts +0 -538
- package/src/__tests__/memory-reducer-scheduling.test.ts +0 -473
- package/src/__tests__/memory-reducer-store.test.ts +0 -728
- package/src/__tests__/memory-reducer-types.test.ts +0 -707
- package/src/__tests__/memory-reducer.test.ts +0 -704
- package/src/__tests__/memory-simplified-config.test.ts +0 -281
- package/src/__tests__/simplified-memory-e2e.test.ts +0 -666
- package/src/__tests__/simplified-memory-runtime.test.ts +0 -616
- package/src/config/schemas/memory-simplified.ts +0 -101
- package/src/memory/archive-recall.ts +0 -516
- package/src/memory/archive-store.ts +0 -400
- package/src/memory/brief-formatting.ts +0 -33
- package/src/memory/brief-open-loops.ts +0 -266
- package/src/memory/brief-time.ts +0 -162
- package/src/memory/brief.ts +0 -75
- package/src/memory/job-handlers/backfill-simplified-memory.ts +0 -462
- package/src/memory/job-handlers/reduce-conversation-memory.ts +0 -229
- package/src/memory/migrations/185-memory-brief-state.ts +0 -52
- package/src/memory/migrations/186-memory-archive.ts +0 -109
- package/src/memory/migrations/187-memory-reducer-checkpoints.ts +0 -19
- package/src/memory/reducer-scheduler.ts +0 -242
- package/src/memory/reducer-store.ts +0 -271
- package/src/memory/reducer-types.ts +0 -106
- package/src/memory/reducer.ts +0 -467
- package/src/memory/schema/memory-archive.ts +0 -121
- package/src/memory/schema/memory-brief.ts +0 -55
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP client for the gateway's trust rule endpoints.
|
|
3
|
+
*
|
|
4
|
+
* Provides CRUD operations over trust rules stored in the gateway,
|
|
5
|
+
* replacing direct filesystem access to trust.json when the assistant
|
|
6
|
+
* runs in a containerized environment.
|
|
7
|
+
*
|
|
8
|
+
* Both async and synchronous variants are exported. The sync variants
|
|
9
|
+
* use `Bun.spawnSync` + `curl` to make blocking HTTP calls — acceptable
|
|
10
|
+
* for user-initiated write operations that are infrequent.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import type { TrustRule } from "@vellumai/ces-contracts";
|
|
14
|
+
|
|
15
|
+
import { getGatewayInternalBaseUrl } from "../config/env.js";
|
|
16
|
+
import { mintDaemonDeliveryToken } from "../runtime/auth/token-service.js";
|
|
17
|
+
import { getLogger } from "../util/logger.js";
|
|
18
|
+
|
|
19
|
+
const log = getLogger("trust-client");
|
|
20
|
+
|
|
21
|
+
const REQUEST_TIMEOUT_MS = 10_000;
|
|
22
|
+
|
|
23
|
+
// ---------------------------------------------------------------------------
|
|
24
|
+
// Result types (not in ces-contracts — local to the client)
|
|
25
|
+
// ---------------------------------------------------------------------------
|
|
26
|
+
|
|
27
|
+
export interface AcceptStarterBundleResult {
|
|
28
|
+
accepted: boolean;
|
|
29
|
+
rulesAdded: number;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
// ---------------------------------------------------------------------------
|
|
33
|
+
// Helpers
|
|
34
|
+
// ---------------------------------------------------------------------------
|
|
35
|
+
|
|
36
|
+
function authHeaders(): Record<string, string> {
|
|
37
|
+
return {
|
|
38
|
+
Authorization: `Bearer ${mintDaemonDeliveryToken()}`,
|
|
39
|
+
"Content-Type": "application/json",
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Execute a fetch request with standard timeout and error handling.
|
|
45
|
+
* Throws a descriptive error on non-OK responses or network failures.
|
|
46
|
+
*/
|
|
47
|
+
async function request<T>(
|
|
48
|
+
method: string,
|
|
49
|
+
path: string,
|
|
50
|
+
body?: unknown,
|
|
51
|
+
): Promise<T> {
|
|
52
|
+
const url = `${getGatewayInternalBaseUrl()}${path}`;
|
|
53
|
+
const options: RequestInit = {
|
|
54
|
+
method,
|
|
55
|
+
headers: authHeaders(),
|
|
56
|
+
signal: AbortSignal.timeout(REQUEST_TIMEOUT_MS),
|
|
57
|
+
};
|
|
58
|
+
if (body !== undefined) {
|
|
59
|
+
options.body = JSON.stringify(body);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
let response: Response;
|
|
63
|
+
try {
|
|
64
|
+
response = await fetch(url, options);
|
|
65
|
+
} catch (err) {
|
|
66
|
+
log.error({ err, method, path }, "Trust rule request failed (network)");
|
|
67
|
+
throw new Error(
|
|
68
|
+
`Trust rule request failed: ${method} ${path}: ${err instanceof Error ? err.message : String(err)}`,
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (!response.ok) {
|
|
73
|
+
const text = await response.text().catch(() => "<unreadable>");
|
|
74
|
+
log.error(
|
|
75
|
+
{ status: response.status, body: text, method, path },
|
|
76
|
+
"Trust rule request failed",
|
|
77
|
+
);
|
|
78
|
+
throw new Error(
|
|
79
|
+
`Trust rule request failed (${response.status}): ${method} ${path}: ${text}`,
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return (await response.json()) as T;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Synchronous HTTP request via `Bun.spawnSync` + `curl`.
|
|
88
|
+
*
|
|
89
|
+
* Used by the gateway trust store adapter for write operations that must
|
|
90
|
+
* return synchronously to satisfy the `TrustStoreBackend` interface.
|
|
91
|
+
* Write operations are user-initiated and infrequent, so blocking is acceptable.
|
|
92
|
+
*/
|
|
93
|
+
function requestSync<T>(method: string, path: string, body?: unknown): T {
|
|
94
|
+
const url = `${getGatewayInternalBaseUrl()}${path}`;
|
|
95
|
+
const headers = authHeaders();
|
|
96
|
+
const args: string[] = [
|
|
97
|
+
"curl",
|
|
98
|
+
"-s",
|
|
99
|
+
"-S",
|
|
100
|
+
"-X",
|
|
101
|
+
method,
|
|
102
|
+
"--max-time",
|
|
103
|
+
String(Math.ceil(REQUEST_TIMEOUT_MS / 1000)),
|
|
104
|
+
"-H",
|
|
105
|
+
`Authorization: ${headers.Authorization}`,
|
|
106
|
+
"-H",
|
|
107
|
+
"Content-Type: application/json",
|
|
108
|
+
"-w",
|
|
109
|
+
"\n%{http_code}",
|
|
110
|
+
];
|
|
111
|
+
if (body !== undefined) {
|
|
112
|
+
args.push("-d", JSON.stringify(body));
|
|
113
|
+
}
|
|
114
|
+
args.push(url);
|
|
115
|
+
|
|
116
|
+
const proc = Bun.spawnSync(args, {
|
|
117
|
+
stdout: "pipe",
|
|
118
|
+
stderr: "pipe",
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
if (proc.exitCode !== 0) {
|
|
122
|
+
const stderr = proc.stderr.toString().trim();
|
|
123
|
+
log.error(
|
|
124
|
+
{ exitCode: proc.exitCode, stderr, method, path },
|
|
125
|
+
"Trust rule sync request failed (curl)",
|
|
126
|
+
);
|
|
127
|
+
throw new Error(
|
|
128
|
+
`Trust rule sync request failed: ${method} ${path}: curl exit ${proc.exitCode}: ${stderr}`,
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
const output = proc.stdout.toString().trim();
|
|
133
|
+
// curl -w "\n%{http_code}" appends the HTTP status code on the last line
|
|
134
|
+
const lastNewline = output.lastIndexOf("\n");
|
|
135
|
+
const responseBody = lastNewline >= 0 ? output.slice(0, lastNewline) : "";
|
|
136
|
+
const statusCode = parseInt(
|
|
137
|
+
lastNewline >= 0 ? output.slice(lastNewline + 1) : output,
|
|
138
|
+
10,
|
|
139
|
+
);
|
|
140
|
+
|
|
141
|
+
if (statusCode < 200 || statusCode >= 300) {
|
|
142
|
+
log.error(
|
|
143
|
+
{ status: statusCode, body: responseBody, method, path },
|
|
144
|
+
"Trust rule sync request failed",
|
|
145
|
+
);
|
|
146
|
+
throw new Error(
|
|
147
|
+
`Trust rule sync request failed (${statusCode}): ${method} ${path}: ${responseBody}`,
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
if (!responseBody) {
|
|
152
|
+
return {} as T;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
try {
|
|
156
|
+
return JSON.parse(responseBody) as T;
|
|
157
|
+
} catch (err) {
|
|
158
|
+
log.error(
|
|
159
|
+
{ err, responseBody, method, path },
|
|
160
|
+
"Failed to parse sync response JSON",
|
|
161
|
+
);
|
|
162
|
+
throw new Error(
|
|
163
|
+
`Trust rule sync request: failed to parse response: ${method} ${path}`,
|
|
164
|
+
);
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
// ---------------------------------------------------------------------------
|
|
169
|
+
// Public API
|
|
170
|
+
// ---------------------------------------------------------------------------
|
|
171
|
+
|
|
172
|
+
/** Fetch all trust rules from the gateway. */
|
|
173
|
+
export async function getAllRules(): Promise<TrustRule[]> {
|
|
174
|
+
const data = await request<{ rules: TrustRule[] }>("GET", "/v1/trust-rules");
|
|
175
|
+
return data.rules;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/** Create a new trust rule. */
|
|
179
|
+
export async function addRule(params: {
|
|
180
|
+
tool: string;
|
|
181
|
+
pattern: string;
|
|
182
|
+
scope: string;
|
|
183
|
+
decision?: TrustRule["decision"];
|
|
184
|
+
priority?: number;
|
|
185
|
+
allowHighRisk?: boolean;
|
|
186
|
+
executionTarget?: string;
|
|
187
|
+
}): Promise<TrustRule> {
|
|
188
|
+
const data = await request<{ rule: TrustRule }>(
|
|
189
|
+
"POST",
|
|
190
|
+
"/v1/trust-rules",
|
|
191
|
+
params,
|
|
192
|
+
);
|
|
193
|
+
return data.rule;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/** Update an existing trust rule by ID. */
|
|
197
|
+
export async function updateRule(
|
|
198
|
+
id: string,
|
|
199
|
+
updates: {
|
|
200
|
+
tool?: string;
|
|
201
|
+
pattern?: string;
|
|
202
|
+
scope?: string;
|
|
203
|
+
decision?: TrustRule["decision"];
|
|
204
|
+
priority?: number;
|
|
205
|
+
allowHighRisk?: boolean;
|
|
206
|
+
executionTarget?: string;
|
|
207
|
+
},
|
|
208
|
+
): Promise<TrustRule> {
|
|
209
|
+
const data = await request<{ rule: TrustRule }>(
|
|
210
|
+
"PATCH",
|
|
211
|
+
`/v1/trust-rules/${encodeURIComponent(id)}`,
|
|
212
|
+
updates,
|
|
213
|
+
);
|
|
214
|
+
return data.rule;
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** Remove a trust rule by ID. Returns true if the rule was found and deleted. */
|
|
218
|
+
export async function removeRule(id: string): Promise<boolean> {
|
|
219
|
+
const data = await request<{ success: boolean }>(
|
|
220
|
+
"DELETE",
|
|
221
|
+
`/v1/trust-rules/${encodeURIComponent(id)}`,
|
|
222
|
+
);
|
|
223
|
+
return data.success;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/** Clear all user trust rules (default rules are preserved by the gateway). */
|
|
227
|
+
export async function clearRules(): Promise<void> {
|
|
228
|
+
await request<{ success: boolean }>("POST", "/v1/trust-rules/clear");
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Find the highest-priority matching rule for a tool invocation.
|
|
233
|
+
*
|
|
234
|
+
* @param tool Tool name (e.g. "host_bash")
|
|
235
|
+
* @param candidates Command candidates to match against rule patterns
|
|
236
|
+
* @param scope Working directory scope
|
|
237
|
+
*/
|
|
238
|
+
export async function findMatchingRule(
|
|
239
|
+
tool: string,
|
|
240
|
+
candidates: string[],
|
|
241
|
+
scope: string,
|
|
242
|
+
): Promise<TrustRule | null> {
|
|
243
|
+
const params = new URLSearchParams({
|
|
244
|
+
tool,
|
|
245
|
+
commands: candidates.join(","),
|
|
246
|
+
scope,
|
|
247
|
+
});
|
|
248
|
+
const data = await request<{ rule: TrustRule | null }>(
|
|
249
|
+
"GET",
|
|
250
|
+
`/v1/trust-rules/match?${params.toString()}`,
|
|
251
|
+
);
|
|
252
|
+
return data.rule;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/** Accept the starter approval bundle, seeding common low-risk allow rules. */
|
|
256
|
+
export async function acceptStarterBundle(): Promise<AcceptStarterBundleResult> {
|
|
257
|
+
return request<AcceptStarterBundleResult>(
|
|
258
|
+
"POST",
|
|
259
|
+
"/v1/trust-rules/starter-bundle",
|
|
260
|
+
);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
// ---------------------------------------------------------------------------
|
|
264
|
+
// Synchronous API — used by the gateway trust store adapter
|
|
265
|
+
// ---------------------------------------------------------------------------
|
|
266
|
+
|
|
267
|
+
/** Fetch all trust rules from the gateway (synchronous). */
|
|
268
|
+
export function getAllRulesSync(): TrustRule[] {
|
|
269
|
+
const data = requestSync<{ rules: TrustRule[] }>("GET", "/v1/trust-rules");
|
|
270
|
+
return data.rules;
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** Create a new trust rule (synchronous). */
|
|
274
|
+
export function addRuleSync(params: {
|
|
275
|
+
tool: string;
|
|
276
|
+
pattern: string;
|
|
277
|
+
scope: string;
|
|
278
|
+
decision?: TrustRule["decision"];
|
|
279
|
+
priority?: number;
|
|
280
|
+
allowHighRisk?: boolean;
|
|
281
|
+
executionTarget?: string;
|
|
282
|
+
}): TrustRule {
|
|
283
|
+
const data = requestSync<{ rule: TrustRule }>(
|
|
284
|
+
"POST",
|
|
285
|
+
"/v1/trust-rules",
|
|
286
|
+
params,
|
|
287
|
+
);
|
|
288
|
+
return data.rule;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/** Update an existing trust rule by ID (synchronous). */
|
|
292
|
+
export function updateRuleSync(
|
|
293
|
+
id: string,
|
|
294
|
+
updates: {
|
|
295
|
+
tool?: string;
|
|
296
|
+
pattern?: string;
|
|
297
|
+
scope?: string;
|
|
298
|
+
decision?: TrustRule["decision"];
|
|
299
|
+
priority?: number;
|
|
300
|
+
allowHighRisk?: boolean;
|
|
301
|
+
executionTarget?: string;
|
|
302
|
+
},
|
|
303
|
+
): TrustRule {
|
|
304
|
+
const data = requestSync<{ rule: TrustRule }>(
|
|
305
|
+
"PATCH",
|
|
306
|
+
`/v1/trust-rules/${encodeURIComponent(id)}`,
|
|
307
|
+
updates,
|
|
308
|
+
);
|
|
309
|
+
return data.rule;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/** Remove a trust rule by ID (synchronous). Returns true if deleted. */
|
|
313
|
+
export function removeRuleSync(id: string): boolean {
|
|
314
|
+
const data = requestSync<{ success: boolean }>(
|
|
315
|
+
"DELETE",
|
|
316
|
+
`/v1/trust-rules/${encodeURIComponent(id)}`,
|
|
317
|
+
);
|
|
318
|
+
return data.success;
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
/** Clear all user trust rules (synchronous). */
|
|
322
|
+
export function clearRulesSync(): void {
|
|
323
|
+
requestSync<{ success: boolean }>("POST", "/v1/trust-rules/clear");
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
/** Accept the starter approval bundle (synchronous). */
|
|
327
|
+
export function acceptStarterBundleSync(): AcceptStarterBundleResult {
|
|
328
|
+
return requestSync<AcceptStarterBundleResult>(
|
|
329
|
+
"POST",
|
|
330
|
+
"/v1/trust-rules/starter-bundle",
|
|
331
|
+
);
|
|
332
|
+
}
|
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
import type { PolicyContext, TrustRule } from "./types.js";
|
|
2
|
+
|
|
3
|
+
export interface StarterBundleRule {
|
|
4
|
+
id: string;
|
|
5
|
+
tool: string;
|
|
6
|
+
pattern: string;
|
|
7
|
+
scope: string;
|
|
8
|
+
decision: "allow";
|
|
9
|
+
priority: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface AcceptStarterBundleResult {
|
|
13
|
+
accepted: boolean;
|
|
14
|
+
rulesAdded: number;
|
|
15
|
+
alreadyAccepted: boolean;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Backend interface for trust rule storage and retrieval.
|
|
20
|
+
*
|
|
21
|
+
* The file-based implementation reads/writes `~/.vellum/protected/trust.json`.
|
|
22
|
+
* A future gateway-backed implementation will proxy these operations through
|
|
23
|
+
* the gateway HTTP API for containerized deployments.
|
|
24
|
+
*/
|
|
25
|
+
export interface TrustStoreBackend {
|
|
26
|
+
/** Return a copy of all trust rules (file-based rules + defaults). */
|
|
27
|
+
getAllRules(): TrustRule[];
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Find the highest-priority rule that matches any of the command candidates.
|
|
31
|
+
* Rules are pre-sorted by priority descending, so the first match wins.
|
|
32
|
+
*/
|
|
33
|
+
findHighestPriorityRule(
|
|
34
|
+
tool: string,
|
|
35
|
+
commands: string[],
|
|
36
|
+
scope: string,
|
|
37
|
+
ctx?: PolicyContext,
|
|
38
|
+
): TrustRule | null;
|
|
39
|
+
|
|
40
|
+
/** Find the first matching allow rule for a tool/command/scope. */
|
|
41
|
+
findMatchingRule(
|
|
42
|
+
tool: string,
|
|
43
|
+
command: string,
|
|
44
|
+
scope: string,
|
|
45
|
+
): TrustRule | null;
|
|
46
|
+
|
|
47
|
+
/** Find the first matching deny rule for a tool/command/scope. */
|
|
48
|
+
findDenyRule(
|
|
49
|
+
tool: string,
|
|
50
|
+
command: string,
|
|
51
|
+
scope: string,
|
|
52
|
+
): TrustRule | null;
|
|
53
|
+
|
|
54
|
+
/** Add a new trust rule and persist it. */
|
|
55
|
+
addRule(
|
|
56
|
+
tool: string,
|
|
57
|
+
pattern: string,
|
|
58
|
+
scope: string,
|
|
59
|
+
decision?: "allow" | "deny" | "ask",
|
|
60
|
+
priority?: number,
|
|
61
|
+
options?: {
|
|
62
|
+
allowHighRisk?: boolean;
|
|
63
|
+
executionTarget?: string;
|
|
64
|
+
},
|
|
65
|
+
): TrustRule;
|
|
66
|
+
|
|
67
|
+
/** Update an existing trust rule by ID and persist it. */
|
|
68
|
+
updateRule(
|
|
69
|
+
id: string,
|
|
70
|
+
updates: {
|
|
71
|
+
tool?: string;
|
|
72
|
+
pattern?: string;
|
|
73
|
+
scope?: string;
|
|
74
|
+
decision?: "allow" | "deny" | "ask";
|
|
75
|
+
priority?: number;
|
|
76
|
+
},
|
|
77
|
+
): TrustRule;
|
|
78
|
+
|
|
79
|
+
/** Remove a trust rule by ID. Returns true if the rule existed. */
|
|
80
|
+
removeRule(id: string): boolean;
|
|
81
|
+
|
|
82
|
+
/** Clear all user-created rules (default rules are re-backfilled). */
|
|
83
|
+
clearAllRules(): void;
|
|
84
|
+
|
|
85
|
+
/** Accept the starter approval bundle, seeding low-risk allow rules. */
|
|
86
|
+
acceptStarterBundle(): AcceptStarterBundleResult;
|
|
87
|
+
|
|
88
|
+
/** Whether the user has previously accepted the starter bundle. */
|
|
89
|
+
isStarterBundleAccepted(): boolean;
|
|
90
|
+
|
|
91
|
+
/** Register a callback to be invoked whenever trust rules change. */
|
|
92
|
+
onRulesChanged(listener: () => void): void;
|
|
93
|
+
|
|
94
|
+
/** Invalidate in-memory caches, forcing a re-read from the backing store. */
|
|
95
|
+
clearCache(): void;
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Check whether a minimatch pattern matches a candidate string.
|
|
99
|
+
* Reuses the compiled pattern cache from trust rule evaluation.
|
|
100
|
+
*/
|
|
101
|
+
patternMatchesCandidate(pattern: string, candidate: string): boolean;
|
|
102
|
+
|
|
103
|
+
/** Returns the starter bundle rule definitions. */
|
|
104
|
+
getStarterBundleRules(): StarterBundleRule[];
|
|
105
|
+
}
|