@vellumai/assistant 0.4.9 → 0.4.11
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/ARCHITECTURE.md +24 -0
- package/Dockerfile +1 -1
- package/README.md +16 -9
- package/package.json +1 -1
- package/src/__tests__/account-registry.test.ts +1 -0
- package/src/__tests__/actor-token-service.test.ts +1 -0
- package/src/__tests__/app-builder-tool-scripts.test.ts +1 -0
- package/src/__tests__/asset-materialize-tool.test.ts +7 -0
- package/src/__tests__/asset-search-tool.test.ts +7 -0
- package/src/__tests__/browser-fill-credential.test.ts +1 -0
- package/src/__tests__/call-start-guardian-guard.test.ts +1 -0
- package/src/__tests__/channel-approval-routes.test.ts +29 -0
- package/src/__tests__/channel-guardian.test.ts +2143 -1546
- package/src/__tests__/channel-retry-sweep.test.ts +169 -14
- package/src/__tests__/claude-code-tool-profiles.test.ts +1 -0
- package/src/__tests__/computer-use-tools.test.ts +1 -0
- package/src/__tests__/contacts-tools.test.ts +1 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +1 -0
- package/src/__tests__/credential-policy-validate.test.ts +97 -0
- package/src/__tests__/credential-security-e2e.test.ts +1 -0
- package/src/__tests__/credential-vault-unit.test.ts +1 -0
- package/src/__tests__/credential-vault.test.ts +1 -0
- package/src/__tests__/delete-managed-skill-tool.test.ts +1 -0
- package/src/__tests__/file-edit-tool.test.ts +1 -0
- package/src/__tests__/file-read-tool.test.ts +1 -0
- package/src/__tests__/file-write-tool.test.ts +1 -0
- package/src/__tests__/followup-tools.test.ts +1 -0
- package/src/__tests__/gateway-only-guard.test.ts +1 -1
- package/src/__tests__/guardian-control-plane-policy.test.ts +5 -4
- package/src/__tests__/guardian-grant-minting.test.ts +3 -0
- package/src/__tests__/guardian-principal-id-roundtrip.test.ts +4 -3
- package/src/__tests__/guardian-routing-state.test.ts +8 -0
- package/src/__tests__/headless-browser-interactions.test.ts +1 -0
- package/src/__tests__/headless-browser-navigate.test.ts +1 -0
- package/src/__tests__/headless-browser-read-tools.test.ts +1 -0
- package/src/__tests__/headless-browser-snapshot.test.ts +1 -0
- package/src/__tests__/host-file-edit-tool.test.ts +1 -0
- package/src/__tests__/host-file-read-tool.test.ts +1 -0
- package/src/__tests__/host-file-write-tool.test.ts +1 -0
- package/src/__tests__/host-shell-tool.test.ts +1 -0
- package/src/__tests__/lifecycle-docs-guard.test.ts +207 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +1 -0
- package/src/__tests__/media-reuse-story.e2e.test.ts +8 -0
- package/src/__tests__/messaging-send-tool.test.ts +1 -0
- package/src/__tests__/playbook-execution.test.ts +1 -0
- package/src/__tests__/playbook-tools.test.ts +1 -0
- package/src/__tests__/relay-server.test.ts +4 -0
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +1 -0
- package/src/__tests__/schedule-tools.test.ts +1 -0
- package/src/__tests__/secret-onetime-send.test.ts +4 -0
- package/src/__tests__/secret-scanner-executor.test.ts +2 -0
- package/src/__tests__/send-notification-tool.test.ts +2 -0
- package/src/__tests__/shell-credential-ref.test.ts +1 -0
- package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
- package/src/__tests__/skill-load-tool.test.ts +1 -0
- package/src/__tests__/skill-script-runner-host.test.ts +1 -0
- package/src/__tests__/skill-script-runner-sandbox.test.ts +1 -0
- package/src/__tests__/skill-script-runner.test.ts +1 -0
- package/src/__tests__/skill-tool-factory.test.ts +1 -0
- package/src/__tests__/subagent-tools.test.ts +1 -1
- package/src/__tests__/swarm-recursion.test.ts +1 -0
- package/src/__tests__/swarm-session-integration.test.ts +1 -0
- package/src/__tests__/swarm-tool.test.ts +1 -0
- package/src/__tests__/task-management-tools.test.ts +1 -0
- package/src/__tests__/task-tools.test.ts +1 -0
- package/src/__tests__/terminal-tools.test.ts +1 -0
- package/src/__tests__/tool-approval-handler.test.ts +2 -2
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -0
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -0
- package/src/__tests__/tool-executor-shell-integration.test.ts +1 -0
- package/src/__tests__/tool-executor.test.ts +1 -0
- package/src/__tests__/trust-context-guards.test.ts +218 -0
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +6 -0
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +6 -0
- package/src/__tests__/trusted-contact-multichannel.test.ts +1 -0
- package/src/__tests__/trusted-contact-verification.test.ts +1 -0
- package/src/__tests__/view-image-tool.test.ts +1 -0
- package/src/calls/guardian-dispatch.ts +4 -4
- package/src/cli/mcp.ts +183 -3
- package/src/config/bundled-skills/agentmail/SKILL.md +4 -4
- package/src/config/bundled-skills/google-oauth-setup/SKILL.md +1 -0
- package/src/config/bundled-skills/phone-calls/SKILL.md +17 -119
- package/src/config/system-prompt.ts +4 -2
- package/src/config/vellum-skills/twilio-setup/SKILL.md +1 -1
- package/src/daemon/computer-use-session.ts +1 -0
- package/src/daemon/session-agent-loop.ts +1 -1
- package/src/daemon/session-memory.ts +2 -2
- package/src/daemon/session-runtime-assembly.ts +2 -2
- package/src/daemon/session-tool-setup.ts +1 -1
- package/src/mcp/client.ts +55 -6
- package/src/mcp/manager.ts +9 -0
- package/src/mcp/mcp-oauth-provider.ts +347 -0
- package/src/memory/channel-delivery-store.ts +1 -0
- package/src/memory/db-init.ts +4 -0
- package/src/memory/delivery-status.ts +43 -0
- package/src/memory/guardian-bindings.ts +3 -3
- package/src/memory/migrations/127-guardian-principal-id-not-null.ts +108 -0
- package/src/memory/migrations/index.ts +1 -0
- package/src/memory/migrations/registry.ts +6 -0
- package/src/memory/schema.ts +1 -1
- package/src/runtime/actor-trust-resolver.ts +13 -4
- package/src/runtime/channel-retry-sweep.ts +31 -14
- package/src/runtime/guardian-context-resolver.ts +25 -64
- package/src/runtime/guardian-outbound-actions.ts +399 -108
- package/src/runtime/guardian-vellum-migration.ts +1 -23
- package/src/runtime/guardian-verification-templates.ts +66 -30
- package/src/runtime/local-actor-identity.ts +4 -6
- package/src/runtime/middleware/actor-token.ts +2 -8
- package/src/runtime/routes/channel-route-shared.ts +0 -1
- package/src/runtime/routes/inbound-message-handler.ts +3 -4
- package/src/runtime/tool-grant-request-helper.ts +1 -1
- package/src/tools/credentials/policy-validate.ts +22 -0
- package/src/tools/guardian-control-plane-policy.ts +2 -2
- package/src/tools/types.ts +1 -1
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import { existsSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
|
|
5
|
+
import { describe, expect, it } from 'bun:test';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Guard test: prevent stale lifecycle instructions from being reintroduced
|
|
9
|
+
* into documentation. The canonical lifecycle commands are `vellum wake`,
|
|
10
|
+
* `vellum ps`, and `vellum sleep`. Repo-local slash commands live in
|
|
11
|
+
* `.claude/skills/`, not `.claude/commands/`.
|
|
12
|
+
*
|
|
13
|
+
* See AGENTS.md for the conventions these tests enforce.
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
const REPO_ROOT = join(import.meta.dir, '../../..');
|
|
17
|
+
|
|
18
|
+
describe('lifecycle docs guard', () => {
|
|
19
|
+
it('repo-local commands live in skills directory, not commands directory', () => {
|
|
20
|
+
const staleLocations = [
|
|
21
|
+
'.claude/commands/update.md',
|
|
22
|
+
'.claude/commands/release.md',
|
|
23
|
+
];
|
|
24
|
+
|
|
25
|
+
const violations = staleLocations.filter((p) =>
|
|
26
|
+
existsSync(join(REPO_ROOT, p)),
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
if (violations.length > 0) {
|
|
30
|
+
const message = [
|
|
31
|
+
'Found repo-local commands in .claude/commands/ — they should live in .claude/skills/.',
|
|
32
|
+
'',
|
|
33
|
+
'Stale files:',
|
|
34
|
+
...violations.map((f) => ` - ${f}`),
|
|
35
|
+
'',
|
|
36
|
+
'Move them to .claude/skills/<name>/SKILL.md instead.',
|
|
37
|
+
].join('\n');
|
|
38
|
+
|
|
39
|
+
expect(violations, message).toEqual([]);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
// Verify the correct locations exist
|
|
43
|
+
const expectedLocations = [
|
|
44
|
+
'.claude/skills/update/SKILL.md',
|
|
45
|
+
'.claude/skills/release/SKILL.md',
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
const missing = expectedLocations.filter(
|
|
49
|
+
(p) => !existsSync(join(REPO_ROOT, p)),
|
|
50
|
+
);
|
|
51
|
+
|
|
52
|
+
if (missing.length > 0) {
|
|
53
|
+
const message = [
|
|
54
|
+
'Expected repo-local skill files are missing:',
|
|
55
|
+
...missing.map((f) => ` - ${f}`),
|
|
56
|
+
].join('\n');
|
|
57
|
+
|
|
58
|
+
expect(missing, message).toEqual([]);
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('key docs reference vellum lifecycle commands', () => {
|
|
63
|
+
const checks: Array<{
|
|
64
|
+
file: string;
|
|
65
|
+
pattern: string;
|
|
66
|
+
description: string;
|
|
67
|
+
}> = [
|
|
68
|
+
{
|
|
69
|
+
file: 'README.md',
|
|
70
|
+
pattern: 'vellum wake\\|vellum ps\\|vellum sleep',
|
|
71
|
+
description:
|
|
72
|
+
'README.md should mention vellum wake, vellum ps, or vellum sleep',
|
|
73
|
+
},
|
|
74
|
+
{
|
|
75
|
+
file: 'assistant/README.md',
|
|
76
|
+
pattern: 'vellum wake\\|vellum ps',
|
|
77
|
+
description:
|
|
78
|
+
'assistant/README.md should mention vellum wake or vellum ps',
|
|
79
|
+
},
|
|
80
|
+
{
|
|
81
|
+
file: 'AGENTS.md',
|
|
82
|
+
pattern: 'vellum ps\\|vellum sleep\\|vellum wake',
|
|
83
|
+
description:
|
|
84
|
+
'AGENTS.md should mention vellum ps, vellum sleep, or vellum wake in the /update command description',
|
|
85
|
+
},
|
|
86
|
+
];
|
|
87
|
+
|
|
88
|
+
const failures: string[] = [];
|
|
89
|
+
|
|
90
|
+
for (const check of checks) {
|
|
91
|
+
try {
|
|
92
|
+
execSync(`git grep -q '${check.pattern}' -- '${check.file}'`, {
|
|
93
|
+
encoding: 'utf-8',
|
|
94
|
+
cwd: REPO_ROOT,
|
|
95
|
+
});
|
|
96
|
+
} catch {
|
|
97
|
+
failures.push(check.description);
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (failures.length > 0) {
|
|
102
|
+
const message = [
|
|
103
|
+
'Key docs are missing vellum lifecycle command references:',
|
|
104
|
+
'',
|
|
105
|
+
...failures.map((f) => ` - ${f}`),
|
|
106
|
+
'',
|
|
107
|
+
'These docs should reference vellum CLI lifecycle commands (wake/ps/sleep).',
|
|
108
|
+
].join('\n');
|
|
109
|
+
|
|
110
|
+
expect(failures, message).toEqual([]);
|
|
111
|
+
}
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
it('no docs use stale daemon startup as primary instruction', () => {
|
|
115
|
+
// Files that are allowed to contain these patterns
|
|
116
|
+
const allowedPrefixes = [
|
|
117
|
+
'cli/', // CLI source code
|
|
118
|
+
'assistant/src/', // assistant runtime source
|
|
119
|
+
'CLAUDE.md', // project instructions
|
|
120
|
+
'AGENTS.md', // agent conventions (may reference patterns for context)
|
|
121
|
+
];
|
|
122
|
+
|
|
123
|
+
const stalePatterns = [
|
|
124
|
+
{
|
|
125
|
+
pattern: 'bun run src/index.ts daemon start',
|
|
126
|
+
label: 'bun run src/index.ts daemon start',
|
|
127
|
+
},
|
|
128
|
+
];
|
|
129
|
+
|
|
130
|
+
const violations: string[] = [];
|
|
131
|
+
|
|
132
|
+
for (const { pattern, label } of stalePatterns) {
|
|
133
|
+
let grepOutput = '';
|
|
134
|
+
try {
|
|
135
|
+
grepOutput = execSync(
|
|
136
|
+
`git grep -n '${pattern}' -- '*.md'`,
|
|
137
|
+
{ encoding: 'utf-8', cwd: REPO_ROOT },
|
|
138
|
+
).trim();
|
|
139
|
+
} catch {
|
|
140
|
+
// No matches — happy path
|
|
141
|
+
continue;
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const lines = grepOutput.split('\n').filter((l) => l.length > 0);
|
|
145
|
+
|
|
146
|
+
for (const line of lines) {
|
|
147
|
+
const filePath = line.split(':')[0];
|
|
148
|
+
|
|
149
|
+
// Skip allowed file prefixes
|
|
150
|
+
if (allowedPrefixes.some((prefix) => filePath.startsWith(prefix))) {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
// Skip test files
|
|
155
|
+
if (filePath.includes('__tests__') || filePath.endsWith('.test.ts')) {
|
|
156
|
+
continue;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// Check if this specific occurrence is inside a <details> section or
|
|
160
|
+
// a "Development" / "raw bun commands" context by examining only the
|
|
161
|
+
// 10 lines before this match. We extract the line number from the
|
|
162
|
+
// grep output (format "filePath:lineNum:content") and use sed to
|
|
163
|
+
// get a targeted range, so each match is evaluated independently.
|
|
164
|
+
const parts = line.split(':');
|
|
165
|
+
const lineNum = parseInt(parts[1], 10);
|
|
166
|
+
|
|
167
|
+
if (!Number.isNaN(lineNum)) {
|
|
168
|
+
try {
|
|
169
|
+
const startLine = Math.max(1, lineNum - 10);
|
|
170
|
+
const context = execSync(
|
|
171
|
+
`sed -n '${startLine},${lineNum}p' '${filePath}'`,
|
|
172
|
+
{ encoding: 'utf-8', cwd: REPO_ROOT },
|
|
173
|
+
);
|
|
174
|
+
|
|
175
|
+
const contextLower = context.toLowerCase();
|
|
176
|
+
const isInDetails = contextLower.includes('<details>');
|
|
177
|
+
const isDevContext =
|
|
178
|
+
contextLower.includes('development:') ||
|
|
179
|
+
contextLower.includes('low-level development') ||
|
|
180
|
+
contextLower.includes('raw bun commands');
|
|
181
|
+
|
|
182
|
+
if (isInDetails || isDevContext) {
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
} catch {
|
|
186
|
+
// If context extraction fails, treat as a violation
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
violations.push(`${filePath}: contains "${label}" as primary instruction`);
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
if (violations.length > 0) {
|
|
195
|
+
const message = [
|
|
196
|
+
'Found docs using stale daemon startup patterns as primary instructions.',
|
|
197
|
+
'Use `vellum wake` / `vellum sleep` instead. Raw bun commands are acceptable',
|
|
198
|
+
'only in collapsed <details> sections or dev-only contexts.',
|
|
199
|
+
'',
|
|
200
|
+
'Violations:',
|
|
201
|
+
...violations.map((v) => ` - ${v}`),
|
|
202
|
+
].join('\n');
|
|
203
|
+
|
|
204
|
+
expect(violations, message).toEqual([]);
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
});
|
|
@@ -235,6 +235,7 @@ describe('Story E2E: selfie yesterday -> generated image today', () => {
|
|
|
235
235
|
workingDir: sandboxDir,
|
|
236
236
|
sessionId: 'sess-story',
|
|
237
237
|
conversationId: threadB.id,
|
|
238
|
+
guardianTrustClass: 'guardian',
|
|
238
239
|
};
|
|
239
240
|
|
|
240
241
|
const result = await assetSearchTool.execute(
|
|
@@ -253,6 +254,7 @@ describe('Story E2E: selfie yesterday -> generated image today', () => {
|
|
|
253
254
|
workingDir: sandboxDir,
|
|
254
255
|
sessionId: 'sess-story',
|
|
255
256
|
conversationId: threadB.id,
|
|
257
|
+
guardianTrustClass: 'guardian',
|
|
256
258
|
};
|
|
257
259
|
|
|
258
260
|
const result = await assetSearchTool.execute(
|
|
@@ -269,6 +271,7 @@ describe('Story E2E: selfie yesterday -> generated image today', () => {
|
|
|
269
271
|
workingDir: sandboxDir,
|
|
270
272
|
sessionId: 'sess-story',
|
|
271
273
|
conversationId: threadB.id,
|
|
274
|
+
guardianTrustClass: 'guardian',
|
|
272
275
|
};
|
|
273
276
|
|
|
274
277
|
const result = await assetMaterializeTool.execute(
|
|
@@ -296,6 +299,7 @@ describe('Story E2E: selfie yesterday -> generated image today', () => {
|
|
|
296
299
|
workingDir: sandboxDir,
|
|
297
300
|
sessionId: 'sess-story',
|
|
298
301
|
conversationId: threadB.id,
|
|
302
|
+
guardianTrustClass: 'guardian',
|
|
299
303
|
};
|
|
300
304
|
|
|
301
305
|
// Step 3a: Search for the selfie
|
|
@@ -486,6 +490,7 @@ describe('Private-thread variant: cross-thread media blocking', () => {
|
|
|
486
490
|
workingDir: sandboxDir,
|
|
487
491
|
sessionId: 'sess-priv-test',
|
|
488
492
|
conversationId: standardThread.id,
|
|
493
|
+
guardianTrustClass: 'guardian',
|
|
489
494
|
};
|
|
490
495
|
|
|
491
496
|
const result = await assetSearchTool.execute(
|
|
@@ -510,6 +515,7 @@ describe('Private-thread variant: cross-thread media blocking', () => {
|
|
|
510
515
|
workingDir: sandboxDir,
|
|
511
516
|
sessionId: 'sess-priv-test',
|
|
512
517
|
conversationId: standardThread.id,
|
|
518
|
+
guardianTrustClass: 'guardian',
|
|
513
519
|
};
|
|
514
520
|
|
|
515
521
|
const result = await assetMaterializeTool.execute(
|
|
@@ -533,6 +539,7 @@ describe('Private-thread variant: cross-thread media blocking', () => {
|
|
|
533
539
|
workingDir: sandboxDir,
|
|
534
540
|
sessionId: 'sess-priv-test',
|
|
535
541
|
conversationId: privateThread.id,
|
|
542
|
+
guardianTrustClass: 'guardian',
|
|
536
543
|
};
|
|
537
544
|
|
|
538
545
|
const searchResult = await assetSearchTool.execute(
|
|
@@ -563,6 +570,7 @@ describe('Private-thread variant: cross-thread media blocking', () => {
|
|
|
563
570
|
workingDir: sandboxDir,
|
|
564
571
|
sessionId: 'sess-priv-test',
|
|
565
572
|
conversationId: privateThreadB.id,
|
|
573
|
+
guardianTrustClass: 'guardian',
|
|
566
574
|
};
|
|
567
575
|
|
|
568
576
|
const searchResult = await assetSearchTool.execute(
|
|
@@ -1277,6 +1277,7 @@ describe('relay-server', () => {
|
|
|
1277
1277
|
channel: 'voice',
|
|
1278
1278
|
guardianExternalUserId: '+15550001111',
|
|
1279
1279
|
guardianDeliveryChatId: '+15550001111',
|
|
1280
|
+
guardianPrincipalId: '+15550001111',
|
|
1280
1281
|
});
|
|
1281
1282
|
|
|
1282
1283
|
mockSendMessage.mockImplementation(createMockProviderResponse(['Hello there.']));
|
|
@@ -1313,6 +1314,7 @@ describe('relay-server', () => {
|
|
|
1313
1314
|
channel: 'voice',
|
|
1314
1315
|
guardianExternalUserId: '+15550009999',
|
|
1315
1316
|
guardianDeliveryChatId: '+15550009999',
|
|
1317
|
+
guardianPrincipalId: '+15550009999',
|
|
1316
1318
|
});
|
|
1317
1319
|
addTrustedVoiceContact('+15550002222', 'self');
|
|
1318
1320
|
|
|
@@ -1360,6 +1362,7 @@ describe('relay-server', () => {
|
|
|
1360
1362
|
channel: 'voice',
|
|
1361
1363
|
guardianExternalUserId: '+15550001111',
|
|
1362
1364
|
guardianDeliveryChatId: '+15550001111',
|
|
1365
|
+
guardianPrincipalId: '+15550001111',
|
|
1363
1366
|
});
|
|
1364
1367
|
|
|
1365
1368
|
mockSendMessage.mockImplementation(createMockProviderResponse(['Hello there.']));
|
|
@@ -1404,6 +1407,7 @@ describe('relay-server', () => {
|
|
|
1404
1407
|
channel: 'telegram',
|
|
1405
1408
|
guardianExternalUserId: 'tg-guardian-user',
|
|
1406
1409
|
guardianDeliveryChatId: 'tg-guardian-chat',
|
|
1410
|
+
guardianPrincipalId: 'tg-guardian-user',
|
|
1407
1411
|
});
|
|
1408
1412
|
|
|
1409
1413
|
// Number matches the configured owner number, but there is no active
|
|
@@ -61,6 +61,7 @@ describe('one-time send override', () => {
|
|
|
61
61
|
workingDir: '/tmp',
|
|
62
62
|
sessionId: 's1',
|
|
63
63
|
conversationId: 'c1',
|
|
64
|
+
guardianTrustClass: 'guardian' as const,
|
|
64
65
|
requestSecret: async () => ({ value: 'v1', delivery: 'transient_send' as const }),
|
|
65
66
|
};
|
|
66
67
|
|
|
@@ -80,6 +81,7 @@ describe('one-time send override', () => {
|
|
|
80
81
|
workingDir: '/tmp',
|
|
81
82
|
sessionId: 's1',
|
|
82
83
|
conversationId: 'c1',
|
|
84
|
+
guardianTrustClass: 'guardian' as const,
|
|
83
85
|
requestSecret: async () => ({ value: 'v1', delivery: 'transient_send' as const }),
|
|
84
86
|
};
|
|
85
87
|
|
|
@@ -99,6 +101,7 @@ describe('one-time send override', () => {
|
|
|
99
101
|
workingDir: '/tmp',
|
|
100
102
|
sessionId: 's1',
|
|
101
103
|
conversationId: 'c1',
|
|
104
|
+
guardianTrustClass: 'guardian' as const,
|
|
102
105
|
requestSecret: async () => ({ value: 'v1', delivery: 'store' as const }),
|
|
103
106
|
};
|
|
104
107
|
|
|
@@ -118,6 +121,7 @@ describe('one-time send override', () => {
|
|
|
118
121
|
workingDir: '/tmp',
|
|
119
122
|
sessionId: 's1',
|
|
120
123
|
conversationId: 'c1',
|
|
124
|
+
guardianTrustClass: 'guardian' as const,
|
|
121
125
|
requestSecret: async () => ({ value: secretVal, delivery: 'transient_send' as const }),
|
|
122
126
|
};
|
|
123
127
|
|
|
@@ -95,6 +95,7 @@ function makeContext(overrides?: Partial<{
|
|
|
95
95
|
workingDir: '/tmp',
|
|
96
96
|
sessionId: 'test-session',
|
|
97
97
|
conversationId: 'test-conversation',
|
|
98
|
+
guardianTrustClass: 'guardian' as const,
|
|
98
99
|
onToolLifecycleEvent: (event: ToolLifecycleEvent) => {
|
|
99
100
|
auditListener(event);
|
|
100
101
|
return overrides?.onToolLifecycleEvent?.(event);
|
|
@@ -313,6 +314,7 @@ describe('Secret scanner executor integration', () => {
|
|
|
313
314
|
workingDir: '/tmp',
|
|
314
315
|
sessionId: 'test-session',
|
|
315
316
|
conversationId: 'test-conversation',
|
|
317
|
+
guardianTrustClass: 'guardian' as const,
|
|
316
318
|
};
|
|
317
319
|
|
|
318
320
|
const result = await executor.execute('file_read', {}, ctx);
|
|
@@ -33,6 +33,7 @@ describe('send-notification tool', () => {
|
|
|
33
33
|
sessionId: 'sess-1',
|
|
34
34
|
conversationId: 'conv-1',
|
|
35
35
|
assistantId: 'ast-alpha',
|
|
36
|
+
guardianTrustClass: 'guardian' as const,
|
|
36
37
|
},
|
|
37
38
|
);
|
|
38
39
|
|
|
@@ -76,6 +77,7 @@ describe('send-notification tool', () => {
|
|
|
76
77
|
sessionId: 'sess-1',
|
|
77
78
|
conversationId: 'conv-1',
|
|
78
79
|
assistantId: 'ast-alpha',
|
|
80
|
+
guardianTrustClass: 'guardian' as const,
|
|
79
81
|
},
|
|
80
82
|
);
|
|
81
83
|
|
|
@@ -81,6 +81,7 @@ async function executeSkillLoad(input: Record<string, unknown>): Promise<{ conte
|
|
|
81
81
|
workingDir: '/tmp',
|
|
82
82
|
sessionId: 'session-1',
|
|
83
83
|
conversationId: 'conversation-1',
|
|
84
|
+
guardianTrustClass: 'guardian',
|
|
84
85
|
});
|
|
85
86
|
return { content: result.content, isError: result.isError };
|
|
86
87
|
}
|
|
@@ -76,6 +76,7 @@ async function executeSkillLoad(input: Record<string, unknown>): Promise<{ conte
|
|
|
76
76
|
workingDir: '/tmp',
|
|
77
77
|
sessionId: 'session-1',
|
|
78
78
|
conversationId: 'conversation-1',
|
|
79
|
+
guardianTrustClass: 'guardian',
|
|
79
80
|
});
|
|
80
81
|
return { content: result.content, isError: result.isError };
|
|
81
82
|
}
|
|
@@ -88,7 +88,7 @@ function injectSubagent(
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
function makeContext(sessionId: string, extras: Record<string, unknown> = {}) {
|
|
91
|
-
return { workingDir: '/tmp', sessionId, conversationId: 'conv-1', ...extras };
|
|
91
|
+
return { workingDir: '/tmp', sessionId, conversationId: 'conv-1', guardianTrustClass: 'guardian' as const, ...extras } as import('../tools/types.js').ToolContext;
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
// ── Tool definitions ────────────────────────────────────────────────
|
|
@@ -286,11 +286,11 @@ describe('ToolApprovalHandler / pre-exec gate grant check', () => {
|
|
|
286
286
|
expect(result.allowed).toBe(true);
|
|
287
287
|
});
|
|
288
288
|
|
|
289
|
-
test('
|
|
289
|
+
test('guardian actor role (desktop) bypasses grant check', async () => {
|
|
290
290
|
const toolName = 'bash';
|
|
291
291
|
const input = { command: 'deploy' };
|
|
292
292
|
|
|
293
|
-
const context = makeContext({ guardianTrustClass:
|
|
293
|
+
const context = makeContext({ guardianTrustClass: 'guardian' });
|
|
294
294
|
const result = await handler.checkPreExecutionGates(
|
|
295
295
|
toolName, input, context, 'host', 'high', Date.now(), emitLifecycleEvent,
|
|
296
296
|
);
|
|
@@ -138,6 +138,7 @@ function makeContext(events: ToolLifecycleEvent[]) {
|
|
|
138
138
|
workingDir: '/tmp/project',
|
|
139
139
|
sessionId: 'session-1',
|
|
140
140
|
conversationId: 'conversation-1',
|
|
141
|
+
guardianTrustClass: 'guardian' as const,
|
|
141
142
|
onToolLifecycleEvent: (event: ToolLifecycleEvent) => {
|
|
142
143
|
events.push(event);
|
|
143
144
|
},
|
|
@@ -424,6 +425,7 @@ describe('ToolExecutor lifecycle events', () => {
|
|
|
424
425
|
workingDir: '/tmp/project',
|
|
425
426
|
sessionId: 'session-1',
|
|
426
427
|
conversationId: 'conversation-1',
|
|
428
|
+
guardianTrustClass: 'guardian',
|
|
427
429
|
onToolLifecycleEvent: () => new Promise<void>(() => {}),
|
|
428
430
|
});
|
|
429
431
|
|
|
@@ -125,6 +125,7 @@ function makeContext(overrides?: Partial<ToolContext>): ToolContext {
|
|
|
125
125
|
workingDir: '/tmp/project',
|
|
126
126
|
sessionId: 'session-integration',
|
|
127
127
|
conversationId: 'conversation-integration',
|
|
128
|
+
guardianTrustClass: 'guardian',
|
|
128
129
|
...overrides,
|
|
129
130
|
};
|
|
130
131
|
}
|