@vellumai/assistant 0.4.34 → 0.4.36
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/AGENTS.md +1 -1
- package/ARCHITECTURE.md +44 -49
- package/README.md +32 -20
- package/docs/architecture/keychain-broker.md +186 -0
- package/docs/architecture/security.md +110 -116
- package/docs/runbook-trusted-contacts.md +2 -2
- package/docs/skills.md +25 -25
- package/package.json +4 -1
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +11 -2
- package/src/__tests__/actor-token-service.test.ts +1 -0
- package/src/__tests__/amazon-cdp-integration.test.ts +74 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +38 -9
- package/src/__tests__/assistant-id-boundary-guard.test.ts +91 -43
- package/src/__tests__/browser-fill-credential.test.ts +1 -1
- package/src/__tests__/bundle-scanner.test.ts +1 -1
- package/src/__tests__/channel-guardian.test.ts +102 -102
- package/src/__tests__/channel-invite-transport.test.ts +155 -256
- package/src/__tests__/channel-readiness-routes.test.ts +336 -0
- package/src/__tests__/checker.test.ts +6 -6
- package/src/__tests__/chrome-cdp.test.ts +350 -0
- package/src/__tests__/computer-use-session-lifecycle.test.ts +3 -3
- package/src/__tests__/computer-use-session-working-dir.test.ts +86 -52
- package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +1 -1
- package/src/__tests__/config-loader-migration.test.ts +85 -0
- package/src/__tests__/conversation-pairing.test.ts +370 -5
- package/src/__tests__/credential-broker-browser-fill.test.ts +1 -10
- package/src/__tests__/credential-broker-server-use.test.ts +1 -10
- package/src/__tests__/credential-security-e2e.test.ts +7 -1
- package/src/__tests__/credential-security-invariants.test.ts +14 -20
- package/src/__tests__/credential-vault-unit.test.ts +1 -11
- package/src/__tests__/credential-vault.test.ts +5 -19
- package/src/__tests__/credentials-cli.test.ts +806 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +23 -4
- package/src/__tests__/email-invite-adapter.test.ts +78 -0
- package/src/__tests__/email-service-config-fallback.test.ts +102 -0
- package/src/__tests__/encrypted-store.test.ts +6 -6
- package/src/__tests__/ephemeral-permissions.test.ts +3 -3
- package/src/__tests__/gateway-only-enforcement.test.ts +5 -1
- package/src/__tests__/guardian-actions-endpoint.test.ts +70 -12
- package/src/__tests__/guardian-outbound-http.test.ts +53 -47
- package/src/__tests__/handle-user-message-secret-resume.test.ts +23 -0
- package/src/__tests__/handlers-add-trust-rule-metadata.test.ts +32 -23
- package/src/__tests__/handlers-telegram-config.test.ts +8 -2
- package/src/__tests__/handlers-twitter-config.test.ts +2 -2
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +108 -7
- package/src/__tests__/ingress-reconcile.test.ts +6 -0
- package/src/__tests__/intent-routing.test.ts +23 -4
- package/src/__tests__/invite-routes-http.test.ts +12 -0
- package/src/__tests__/ipc-snapshot.test.ts +8 -2
- package/src/__tests__/keychain-broker-client.test.ts +543 -0
- package/src/__tests__/llm-usage-store.test.ts +344 -0
- package/src/__tests__/mcp-client-auth.test.ts +2 -2
- package/src/__tests__/media-reuse-story.e2e.test.ts +1 -1
- package/src/__tests__/migration-transport.test.ts +49 -0
- package/src/__tests__/notification-broadcaster.test.ts +205 -5
- package/src/__tests__/notification-deep-link.test.ts +365 -1
- package/src/__tests__/oauth-connect-handler.test.ts +2 -2
- package/src/__tests__/onboarding-starter-tasks.test.ts +17 -4
- package/src/__tests__/proxy-approval-callback.test.ts +1 -1
- package/src/__tests__/recording-handler.test.ts +1 -1
- package/src/__tests__/recording-intent-handler.test.ts +6 -1
- package/src/__tests__/recording-state-machine.test.ts +1 -1
- package/src/__tests__/relay-server.test.ts +9 -1
- package/src/__tests__/ride-shotgun-handler.test.ts +499 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +160 -1
- package/src/__tests__/script-proxy-injection-runtime.test.ts +299 -2
- package/src/__tests__/script-proxy-profile-template-fallback.test.ts +1 -1
- package/src/__tests__/secret-onetime-send.test.ts +8 -2
- package/src/__tests__/secure-keys.test.ts +175 -216
- package/src/__tests__/session-confirmation-signals.test.ts +1 -1
- package/src/__tests__/session-messaging-secret-redirect.test.ts +1 -1
- package/src/__tests__/session-queue.test.ts +2 -1
- package/src/__tests__/session-tool-setup-app-refresh.test.ts +2 -2
- package/src/__tests__/skill-feature-flags-integration.test.ts +29 -4
- package/src/__tests__/skill-feature-flags.test.ts +12 -9
- package/src/__tests__/skill-load-feature-flag.test.ts +26 -5
- package/src/__tests__/skill-projection.benchmark.test.ts +0 -1
- package/src/__tests__/skills.test.ts +34 -4
- package/src/__tests__/slack-channel-config.test.ts +2 -2
- package/src/__tests__/system-prompt.test.ts +26 -4
- package/src/__tests__/telegram-bot-username-resolution.test.ts +212 -0
- package/src/__tests__/telegram-invite-adapter.test.ts +164 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
- package/src/__tests__/tool-permission-simulate-handler.test.ts +8 -2
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +9 -1
- package/src/__tests__/twitter-auth-handler.test.ts +2 -2
- package/src/__tests__/twitter-oauth-client.test.ts +1 -1
- package/src/__tests__/usage-routes.test.ts +339 -0
- package/src/__tests__/whatsapp-invite-adapter.test.ts +94 -0
- package/src/agent/loop.ts +3 -0
- package/src/amazon/checkout.ts +0 -1
- package/src/approvals/guardian-request-resolvers.ts +9 -1
- package/src/bundler/app-bundler.ts +28 -12
- package/src/bundler/bundle-scanner.ts +1 -1
- package/src/bundler/bundle-signer.ts +3 -3
- package/src/bundler/manifest.ts +1 -1
- package/src/bundler/signature-verifier.ts +3 -3
- package/src/channels/config.ts +1 -1
- package/src/cli/AGENTS.md +63 -0
- package/src/cli/__tests__/notifications.test.ts +470 -0
- package/src/cli/amazon.ts +344 -167
- package/src/cli/audit.ts +85 -0
- package/src/cli/autonomy.ts +369 -0
- package/src/cli/channels.ts +51 -0
- package/src/cli/completions.ts +208 -0
- package/src/cli/config.ts +220 -0
- package/src/cli/contacts.ts +471 -0
- package/src/cli/credentials.ts +564 -0
- package/src/cli/default-action.ts +14 -0
- package/src/cli/dev.ts +131 -0
- package/src/cli/doctor.ts +398 -0
- package/src/cli/email.ts +491 -0
- package/src/cli/influencer.ts +72 -0
- package/src/cli/integrations.ts +248 -57
- package/src/cli/keys.ts +114 -0
- package/src/cli/map.ts +46 -54
- package/src/cli/mcp.ts +111 -3
- package/src/cli/{config-commands.ts → memory.ts} +133 -242
- package/src/cli/notifications.ts +407 -0
- package/src/cli/program.ts +65 -0
- package/src/cli/reference.ts +48 -0
- package/src/cli/sequence.ts +154 -0
- package/src/cli/sessions.ts +262 -0
- package/src/cli/trust.ts +177 -0
- package/src/cli/twitter.ts +323 -106
- package/src/config/__tests__/build-cli-reference-section.test.ts +49 -0
- package/src/config/bundled-skills/amazon/SKILL.md +2 -2
- package/src/config/bundled-skills/app-builder/TOOLS.json +26 -0
- package/src/config/bundled-skills/app-builder/tools/app-generate-icon.ts +13 -0
- package/src/config/bundled-skills/contacts/SKILL.md +178 -10
- package/src/config/bundled-skills/doordash/doordash-cli.ts +23 -168
- package/src/config/bundled-skills/google-oauth-setup/SKILL.md +175 -145
- package/src/config/bundled-skills/messaging/tools/shared.ts +4 -1
- package/src/config/bundled-skills/twilio-setup/SKILL.md +70 -17
- package/src/config/bundled-tool-registry.ts +2 -0
- package/src/config/core-schema.ts +7 -0
- package/src/config/feature-flag-registry.json +16 -0
- package/src/config/loader.ts +26 -0
- package/src/config/schema.ts +4 -0
- package/src/config/skill-state.ts +0 -13
- package/src/config/system-prompt.ts +27 -0
- package/src/contacts/contact-store.ts +25 -0
- package/src/daemon/computer-use-session.ts +1 -1
- package/src/daemon/handlers/apps.ts +1 -0
- package/src/daemon/handlers/config-channels.ts +3 -3
- package/src/daemon/handlers/config-dispatch.ts +29 -0
- package/src/daemon/handlers/config-inbox.ts +4 -3
- package/src/daemon/handlers/config.ts +3 -43
- package/src/daemon/handlers/contacts.ts +34 -0
- package/src/daemon/handlers/index.ts +17 -3
- package/src/daemon/handlers/session-user-message.ts +7 -0
- package/src/daemon/handlers/sessions.ts +21 -2
- package/src/daemon/handlers/shared.ts +17 -0
- package/src/daemon/ipc-contract/apps.ts +2 -0
- package/src/daemon/ipc-contract/computer-use.ts +9 -0
- package/src/daemon/ipc-contract/contacts.ts +3 -3
- package/src/daemon/ipc-contract/inbox.ts +2 -0
- package/src/daemon/ipc-contract/messages.ts +4 -0
- package/src/daemon/ipc-contract/sessions.ts +8 -0
- package/src/daemon/ipc-contract-inventory.json +1 -0
- package/src/daemon/lifecycle.ts +0 -5
- package/src/daemon/ride-shotgun-handler.ts +139 -25
- package/src/daemon/session-agent-loop-handlers.ts +100 -0
- package/src/daemon/session-agent-loop.ts +72 -0
- package/src/daemon/session-tool-setup.ts +7 -0
- package/src/daemon/session.ts +23 -1
- package/src/daemon/tool-side-effects.ts +39 -1
- package/src/email/service.ts +59 -2
- package/src/index.ts +2 -60
- package/src/mcp/mcp-oauth-provider.ts +90 -8
- package/src/media/app-icon-generator.ts +86 -0
- package/src/memory/db-init.ts +12 -1
- package/src/memory/llm-usage-store.ts +186 -0
- package/src/memory/migrations/026-guardian-verification-sessions.ts +28 -9
- package/src/memory/migrations/027a-guardian-bootstrap-token.ts +16 -3
- package/src/memory/migrations/038-actor-token-records.ts +8 -1
- package/src/memory/migrations/039-actor-refresh-token-records.ts +11 -2
- package/src/memory/migrations/110-channel-guardian.ts +27 -6
- package/src/memory/migrations/112-assistant-inbox.ts +39 -15
- package/src/memory/migrations/114-notifications.ts +37 -15
- package/src/memory/migrations/117-conversation-attention.ts +33 -9
- package/src/memory/migrations/137-usage-dashboard-indexes.ts +26 -0
- package/src/memory/migrations/139-drop-usage-composite-indexes.ts +30 -0
- package/src/memory/migrations/index.ts +2 -0
- package/src/memory/migrations/schema-introspection.ts +18 -0
- package/src/memory/schema-migration.ts +1 -0
- package/src/memory/shared-app-links-store.ts +1 -1
- package/src/messaging/registry.ts +27 -0
- package/src/notifications/README.md +79 -70
- package/src/notifications/broadcaster.ts +2 -1
- package/src/notifications/conversation-pairing.ts +147 -13
- package/src/notifications/copy-composer.ts +7 -3
- package/src/notifications/destination-resolver.ts +14 -1
- package/src/notifications/emit-signal.ts +3 -2
- package/src/notifications/signal.ts +105 -1
- package/src/notifications/types.ts +16 -0
- package/src/permissions/checker.ts +29 -3
- package/src/permissions/prompter.ts +11 -3
- package/src/runtime/access-request-helper.ts +2 -1
- package/src/runtime/auth/route-policy.ts +7 -1
- package/src/runtime/channel-invite-transport.ts +40 -63
- package/src/runtime/channel-invite-transports/email.ts +13 -39
- package/src/runtime/channel-invite-transports/slack.ts +5 -34
- package/src/runtime/channel-invite-transports/sms.ts +8 -29
- package/src/runtime/channel-invite-transports/telegram.ts +69 -28
- package/src/runtime/channel-invite-transports/voice.ts +0 -7
- package/src/runtime/channel-invite-transports/whatsapp.ts +43 -0
- package/src/runtime/channel-readiness-service.ts +202 -45
- package/src/runtime/confirmation-request-guardian-bridge.ts +2 -1
- package/src/runtime/guardian-outbound-actions.ts +8 -5
- package/src/runtime/http-server.ts +5 -9
- package/src/runtime/http-types.ts +13 -1
- package/src/runtime/invite-instruction-generator.ts +178 -0
- package/src/runtime/invite-service.ts +22 -25
- package/src/runtime/migrations/migration-transport.ts +13 -0
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +8 -7
- package/src/runtime/routes/channel-readiness-routes.ts +30 -11
- package/src/runtime/routes/contact-routes.ts +54 -26
- package/src/runtime/routes/guardian-bootstrap-routes.ts +1 -1
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +1 -1
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +2 -1
- package/src/runtime/routes/inbound-stages/verification-intercept.ts +2 -1
- package/src/runtime/routes/integration-routes.ts +1 -1
- package/src/runtime/routes/invite-routes.ts +1 -1
- package/src/runtime/routes/secret-routes.ts +31 -7
- package/src/runtime/routes/surface-content-routes.ts +104 -0
- package/src/runtime/routes/twilio-routes.ts +32 -1
- package/src/runtime/routes/usage-routes.ts +114 -0
- package/src/runtime/tool-grant-request-helper.ts +2 -1
- package/src/security/encrypted-store.ts +9 -5
- package/src/security/keychain-broker-client.ts +393 -0
- package/src/security/secure-keys.ts +106 -321
- package/src/tools/apps/executors.ts +73 -0
- package/src/tools/browser/auto-navigate.ts +15 -6
- package/src/tools/browser/chrome-cdp.ts +211 -0
- package/src/tools/browser/network-recorder.test.ts +83 -0
- package/src/tools/browser/network-recorder.ts +8 -7
- package/src/tools/browser/x-auto-navigate.ts +12 -6
- package/src/tools/credentials/policy-types.ts +24 -0
- package/src/tools/credentials/vault.ts +22 -27
- package/src/tools/network/script-proxy/session-manager.ts +47 -3
- package/src/tools/permission-checker.ts +1 -0
- package/src/tools/types.ts +2 -0
- package/src/tools/ui-surface/definitions.ts +1 -2
- package/src/tools/watch/watch-state.ts +2 -0
- package/src/__tests__/key-migration.test.ts +0 -240
- package/src/__tests__/keychain.test.ts +0 -286
- package/src/cli/core-commands.ts +0 -899
- package/src/security/keychain-to-encrypted-migration.ts +0 -66
- package/src/security/keychain.ts +0 -490
|
@@ -4,7 +4,7 @@ Permission, trust, and credential-security architecture details.
|
|
|
4
4
|
|
|
5
5
|
## Permission and Trust Security Model
|
|
6
6
|
|
|
7
|
-
The permission system controls which tool actions the agent can execute without explicit user approval. It supports
|
|
7
|
+
The permission system controls which tool actions the agent can execute without explicit user approval. It supports two operating modes (`workspace` and `strict`), execution-target-scoped trust rules, and risk-based escalation to provide defense-in-depth against unintended or malicious tool execution.
|
|
8
8
|
|
|
9
9
|
### Permission Evaluation Flow
|
|
10
10
|
|
|
@@ -32,50 +32,46 @@ graph TB
|
|
|
32
32
|
RISK_FALLBACK_WS -->|"Low"| AUTO_WS_LOW["decision: allow<br/>Low risk auto-allow"]
|
|
33
33
|
RISK_FALLBACK_WS -->|"Medium"| PROMPT_WS_MED["decision: prompt"]
|
|
34
34
|
RISK_FALLBACK_WS -->|"High"| PROMPT_WS_HIGH["decision: prompt"]
|
|
35
|
-
NO_MATCH -->|"legacy mode"| RISK_FALLBACK{"Risk level?"}
|
|
36
|
-
RISK_FALLBACK -->|"Low"| AUTO_LOW["decision: allow<br/>Low risk auto-allow"]
|
|
37
|
-
RISK_FALLBACK -->|"Medium"| PROMPT_MED["decision: prompt"]
|
|
38
|
-
RISK_FALLBACK -->|"High"| PROMPT_HIGH2["decision: prompt"]
|
|
39
35
|
```
|
|
40
36
|
|
|
41
|
-
### Permission Modes: Workspace
|
|
37
|
+
### Permission Modes: Workspace and Strict
|
|
42
38
|
|
|
43
|
-
The `permissions.mode` config option (`workspace
|
|
39
|
+
The `permissions.mode` config option (`workspace` or `strict`) controls the default behavior when no trust rule matches a tool invocation. The default is `workspace`.
|
|
44
40
|
|
|
45
|
-
| Behavior
|
|
46
|
-
|
|
47
|
-
| Workspace-scoped ops with no matching rule
|
|
48
|
-
| Non-workspace low-risk tools with no matching rule | Auto-allowed
|
|
49
|
-
| Medium-risk tools with no matching rule
|
|
50
|
-
| High-risk tools with no matching rule
|
|
51
|
-
| `skill_load` with no matching rule
|
|
52
|
-
| `skill_load` with system default rule
|
|
53
|
-
| `browser_*` skill tools with system default rules
|
|
54
|
-
| Skill-origin tools with no matching rule
|
|
55
|
-
| Allow rules for non-high-risk tools
|
|
56
|
-
| Allow rules with `allowHighRisk: true`
|
|
57
|
-
| Deny rules
|
|
41
|
+
| Behavior | Workspace mode (default) | Strict mode |
|
|
42
|
+
| -------------------------------------------------- | --------------------------------------------- | --------------------------------------------- |
|
|
43
|
+
| Workspace-scoped ops with no matching rule | Auto-allowed | Prompted |
|
|
44
|
+
| Non-workspace low-risk tools with no matching rule | Auto-allowed | Prompted |
|
|
45
|
+
| Medium-risk tools with no matching rule | Prompted | Prompted |
|
|
46
|
+
| High-risk tools with no matching rule | Prompted | Prompted |
|
|
47
|
+
| `skill_load` with no matching rule | Prompted | Prompted |
|
|
48
|
+
| `skill_load` with system default rule | Auto-allowed (`skill_load:*` at priority 100) | Auto-allowed (`skill_load:*` at priority 100) |
|
|
49
|
+
| `browser_*` skill tools with system default rules | Auto-allowed (priority 100 allow rules) | Auto-allowed (priority 100 allow rules) |
|
|
50
|
+
| Skill-origin tools with no matching rule | Prompted | Prompted |
|
|
51
|
+
| Allow rules for non-high-risk tools | Auto-allowed | Auto-allowed |
|
|
52
|
+
| Allow rules with `allowHighRisk: true` | Auto-allowed (even high risk) | Auto-allowed (even high risk) |
|
|
53
|
+
| Deny rules | Blocked | Blocked |
|
|
58
54
|
|
|
59
55
|
**Workspace mode** (default) auto-allows operations scoped to the workspace (file reads/writes/edits within the workspace directory, sandboxed bash) without prompting. Host operations, network requests, and operations outside the workspace still follow the normal approval flow. Explicit deny and ask rules override auto-allow.
|
|
60
56
|
|
|
61
57
|
**Strict mode** is designed for security-conscious deployments where every tool action must have an explicit matching rule in the trust store. It eliminates implicit auto-allow for any risk level, ensuring the user has consciously approved each class of tool usage.
|
|
62
58
|
|
|
63
|
-
|
|
59
|
+
> **Migration note:** Existing config files with `permissions.mode = "legacy"` are automatically migrated to `workspace` during config loading. The `legacy` value is not a supported steady-state mode.
|
|
64
60
|
|
|
65
61
|
### Trust Rules (v3 Schema)
|
|
66
62
|
|
|
67
63
|
Rules are stored in `~/.vellum/protected/trust.json` with version `3`. Each rule can include the following fields:
|
|
68
64
|
|
|
69
|
-
| Field
|
|
70
|
-
|
|
71
|
-
| `id`
|
|
72
|
-
| `tool`
|
|
73
|
-
| `pattern`
|
|
74
|
-
| `scope`
|
|
75
|
-
| `decision`
|
|
76
|
-
| `priority`
|
|
77
|
-
| `executionTarget` | `string?`
|
|
78
|
-
| `allowHighRisk`
|
|
65
|
+
| Field | Type | Purpose |
|
|
66
|
+
| ----------------- | ---------------------- | ------------------------------------------------------------------------ |
|
|
67
|
+
| `id` | `string` | Unique identifier (UUID for user rules, `default:*` for system defaults) |
|
|
68
|
+
| `tool` | `string` | Tool name to match (e.g., `bash`, `file_write`, `skill_load`) |
|
|
69
|
+
| `pattern` | `string` | Minimatch glob pattern for the command/target string |
|
|
70
|
+
| `scope` | `string` | Path prefix or `everywhere` — restricts where the rule applies |
|
|
71
|
+
| `decision` | `allow \| deny \| ask` | What to do when the rule matches |
|
|
72
|
+
| `priority` | `number` | Higher priority wins; deny wins ties at equal priority |
|
|
73
|
+
| `executionTarget` | `string?` | `sandbox` or `host` — restricts by execution context |
|
|
74
|
+
| `allowHighRisk` | `boolean?` | When true, auto-allows even high-risk invocations |
|
|
79
75
|
|
|
80
76
|
Missing optional fields act as wildcards. A rule with no `executionTarget` matches any target.
|
|
81
77
|
|
|
@@ -83,16 +79,16 @@ Missing optional fields act as wildcards. A rule with no `executionTarget` match
|
|
|
83
79
|
|
|
84
80
|
The `classifyRisk()` function determines the risk level for each tool invocation:
|
|
85
81
|
|
|
86
|
-
| Tool
|
|
87
|
-
|
|
88
|
-
| `file_read`, `web_search`, `skill_load`
|
|
89
|
-
| `file_write`, `file_edit`
|
|
90
|
-
| `file_write`, `file_edit` targeting skill source paths
|
|
91
|
-
| `host_file_write`, `host_file_edit` targeting skill source paths | **High**
|
|
92
|
-
| `bash`, `host_bash`
|
|
93
|
-
| `scaffold_managed_skill`, `delete_managed_skill`
|
|
94
|
-
| `evaluate_typescript_code`
|
|
95
|
-
| Skill-origin tools with no matching rule
|
|
82
|
+
| Tool | Risk level | Notes |
|
|
83
|
+
| ---------------------------------------------------------------- | --------------------------- | -------------------------------------------------------------------------------------------- |
|
|
84
|
+
| `file_read`, `web_search`, `skill_load` | Low | Read-only or informational |
|
|
85
|
+
| `file_write`, `file_edit` | Medium (default) | Filesystem mutations |
|
|
86
|
+
| `file_write`, `file_edit` targeting skill source paths | **High** | `isSkillSourcePath()` detects managed/bundled/workspace/extra skill roots |
|
|
87
|
+
| `host_file_write`, `host_file_edit` targeting skill source paths | **High** | Same path classification, host variant |
|
|
88
|
+
| `bash`, `host_bash` | Varies | Parsed via tree-sitter: low-risk programs = Low, high-risk programs = High, unknown = Medium |
|
|
89
|
+
| `scaffold_managed_skill`, `delete_managed_skill` | High | Skill lifecycle mutations always high-risk |
|
|
90
|
+
| `evaluate_typescript_code` | High | Arbitrary code execution |
|
|
91
|
+
| Skill-origin tools with no matching rule | Prompted regardless of risk | Even Low-risk skill tools default to `ask` |
|
|
96
92
|
|
|
97
93
|
The escalation of skill source file mutations to High risk is a privilege-escalation defense: modifying skill source code could grant the agent new capabilities, so such operations always require explicit approval.
|
|
98
94
|
|
|
@@ -104,20 +100,20 @@ The `skill_load` tool generates version-aware command candidates for rule matchi
|
|
|
104
100
|
2. `skill_load:<skill-id>` — matches any-version rules
|
|
105
101
|
3. `skill_load:<raw-selector>` — matches the raw user-provided selector
|
|
106
102
|
|
|
107
|
-
In strict mode, `skill_load` without a matching rule is always prompted.
|
|
103
|
+
In strict mode, `skill_load` without a matching rule is always prompted. The allowlist options presented to the user include both version-specific and any-version patterns. Note: the system default allow rule `skill_load:*` (priority 100) now globally allows all skill loads in both modes (see "System Default Allow Rules" below).
|
|
108
104
|
|
|
109
105
|
### Starter Approval Bundle
|
|
110
106
|
|
|
111
107
|
The starter bundle is an opt-in set of low-risk allow rules that reduces prompt noise, particularly in strict mode. It covers read-only tools that never mutate the filesystem or execute arbitrary code:
|
|
112
108
|
|
|
113
|
-
| Rule
|
|
114
|
-
|
|
115
|
-
| `file_read`
|
|
116
|
-
| `glob`
|
|
117
|
-
| `grep`
|
|
109
|
+
| Rule | Tool | Pattern |
|
|
110
|
+
| ---------------- | ---------------- | ------------------- |
|
|
111
|
+
| `file_read` | `file_read` | `file_read:**` |
|
|
112
|
+
| `glob` | `glob` | `glob:**` |
|
|
113
|
+
| `grep` | `grep` | `grep:**` |
|
|
118
114
|
| `list_directory` | `list_directory` | `list_directory:**` |
|
|
119
|
-
| `web_search`
|
|
120
|
-
| `web_fetch`
|
|
115
|
+
| `web_search` | `web_search` | `web_search:**` |
|
|
116
|
+
| `web_fetch` | `web_fetch` | `web_fetch:**` |
|
|
121
117
|
|
|
122
118
|
Acceptance is idempotent and persisted as `starterBundleAccepted: true` in `trust.json`. Rules are seeded at priority 90 (below user rules at 100, above system defaults at 50).
|
|
123
119
|
|
|
@@ -125,21 +121,21 @@ Acceptance is idempotent and persisted as `starterBundleAccepted: true` in `trus
|
|
|
125
121
|
|
|
126
122
|
In addition to the opt-in starter bundle, the permission system seeds unconditional default allow rules at priority 100 for two categories:
|
|
127
123
|
|
|
128
|
-
| Rule ID
|
|
129
|
-
|
|
130
|
-
| `default:allow-skill_load-global`
|
|
131
|
-
| `default:allow-browser_navigate-global`
|
|
132
|
-
| `default:allow-browser_snapshot-global`
|
|
133
|
-
| `default:allow-browser_screenshot-global`
|
|
134
|
-
| `default:allow-browser_close-global`
|
|
135
|
-
| `default:allow-browser_click-global`
|
|
136
|
-
| `default:allow-browser_type-global`
|
|
137
|
-
| `default:allow-browser_press_key-global`
|
|
138
|
-
| `default:allow-browser_wait_for-global`
|
|
139
|
-
| `default:allow-browser_extract-global`
|
|
140
|
-
| `default:allow-browser_fill_credential-global` | `browser_fill_credential` | `browser_fill_credential:*` | (same)
|
|
141
|
-
|
|
142
|
-
These rules are emitted by `getDefaultRuleTemplates()` in `assistant/src/permissions/defaults.ts`. Because they use priority 100 (equal to user rules), they take effect in both
|
|
124
|
+
| Rule ID | Tool | Pattern | Rationale |
|
|
125
|
+
| ---------------------------------------------- | ------------------------- | --------------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
126
|
+
| `default:allow-skill_load-global` | `skill_load` | `skill_load:*` | Loading any skill is globally allowed — no prompt for activating bundled, managed, or workspace skills |
|
|
127
|
+
| `default:allow-browser_navigate-global` | `browser_navigate` | `browser_navigate:*` | Browser tools migrated from core to the bundled `browser` skill; default allow preserves frictionless UX |
|
|
128
|
+
| `default:allow-browser_snapshot-global` | `browser_snapshot` | `browser_snapshot:*` | (same) |
|
|
129
|
+
| `default:allow-browser_screenshot-global` | `browser_screenshot` | `browser_screenshot:*` | (same) |
|
|
130
|
+
| `default:allow-browser_close-global` | `browser_close` | `browser_close:*` | (same) |
|
|
131
|
+
| `default:allow-browser_click-global` | `browser_click` | `browser_click:*` | (same) |
|
|
132
|
+
| `default:allow-browser_type-global` | `browser_type` | `browser_type:*` | (same) |
|
|
133
|
+
| `default:allow-browser_press_key-global` | `browser_press_key` | `browser_press_key:*` | (same) |
|
|
134
|
+
| `default:allow-browser_wait_for-global` | `browser_wait_for` | `browser_wait_for:*` | (same) |
|
|
135
|
+
| `default:allow-browser_extract-global` | `browser_extract` | `browser_extract:*` | (same) |
|
|
136
|
+
| `default:allow-browser_fill_credential-global` | `browser_fill_credential` | `browser_fill_credential:*` | (same) |
|
|
137
|
+
|
|
138
|
+
These rules are emitted by `getDefaultRuleTemplates()` in `assistant/src/permissions/defaults.ts`. Because they use priority 100 (equal to user rules), they take effect in both workspace and strict modes. The `skill_load` rule means skill activation never prompts; the `browser_*` rules mean the browser skill's tools behave identically to the old core `headless-browser` tool from a permission standpoint.
|
|
143
139
|
|
|
144
140
|
### Shell Command Identity and Allowlist Options
|
|
145
141
|
|
|
@@ -160,14 +156,14 @@ For `bash` and `host_bash` tool invocations, the permission system uses parser-d
|
|
|
160
156
|
|
|
161
157
|
When a permission prompt is sent to the client (via `confirmation_request` IPC message), it includes:
|
|
162
158
|
|
|
163
|
-
| Field
|
|
164
|
-
|
|
165
|
-
| `toolName`
|
|
166
|
-
| `input`
|
|
167
|
-
| `riskLevel`
|
|
168
|
-
| `executionTarget`
|
|
169
|
-
| `allowlistOptions` | Suggested patterns for "always allow" rules
|
|
170
|
-
| `scopeOptions`
|
|
159
|
+
| Field | Content |
|
|
160
|
+
| ------------------ | --------------------------------------------------- |
|
|
161
|
+
| `toolName` | The tool being invoked |
|
|
162
|
+
| `input` | Redacted tool input (sensitive fields removed) |
|
|
163
|
+
| `riskLevel` | `low`, `medium`, or `high` |
|
|
164
|
+
| `executionTarget` | `sandbox` or `host` — where the action will execute |
|
|
165
|
+
| `allowlistOptions` | Suggested patterns for "always allow" rules |
|
|
166
|
+
| `scopeOptions` | Suggested scopes for rule persistence |
|
|
171
167
|
|
|
172
168
|
The user can respond with: `allow` (one-time), `always_allow` (create allow rule), `always_allow_high_risk` (create allow rule with `allowHighRisk: true`), `deny` (one-time), or `always_deny` (create deny rule).
|
|
173
169
|
|
|
@@ -177,19 +173,19 @@ File tool candidates include canonical (symlink-resolved) absolute paths via `no
|
|
|
177
173
|
|
|
178
174
|
### Key Source Files
|
|
179
175
|
|
|
180
|
-
| File
|
|
181
|
-
|
|
182
|
-
| `assistant/src/permissions/types.ts`
|
|
183
|
-
| `assistant/src/permissions/checker.ts`
|
|
176
|
+
| File | Role |
|
|
177
|
+
| --------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
178
|
+
| `assistant/src/permissions/types.ts` | `TrustRule`, `PolicyContext`, `RiskLevel`, `UserDecision` types |
|
|
179
|
+
| `assistant/src/permissions/checker.ts` | `classifyRisk()`, `check()`, `buildCommandCandidates()`, allowlist/scope generation |
|
|
184
180
|
| `assistant/src/permissions/shell-identity.ts` | `analyzeShellCommand()`, `deriveShellActionKeys()`, `buildShellCommandCandidates()`, `buildShellAllowlistOptions()` — parser-based shell command identity and action key derivation |
|
|
185
|
-
| `assistant/src/permissions/trust-store.ts`
|
|
186
|
-
| `assistant/src/permissions/prompter.ts`
|
|
187
|
-
| `assistant/src/permissions/defaults.ts`
|
|
188
|
-
| `assistant/src/skills/version-hash.ts`
|
|
189
|
-
| `assistant/src/skills/path-classifier.ts`
|
|
190
|
-
| `assistant/src/config/schema.ts`
|
|
191
|
-
| `assistant/src/tools/executor.ts`
|
|
192
|
-
| `assistant/src/daemon/handlers/config.ts`
|
|
181
|
+
| `assistant/src/permissions/trust-store.ts` | Rule persistence, `findHighestPriorityRule()`, execution-target matching, starter bundle |
|
|
182
|
+
| `assistant/src/permissions/prompter.ts` | IPC prompt flow: `confirmation_request` → `confirmation_response` |
|
|
183
|
+
| `assistant/src/permissions/defaults.ts` | Default rule templates (system ask rules for host tools, CU, etc.) |
|
|
184
|
+
| `assistant/src/skills/version-hash.ts` | `computeSkillVersionHash()` — deterministic SHA-256 of skill source files |
|
|
185
|
+
| `assistant/src/skills/path-classifier.ts` | `isSkillSourcePath()`, `normalizeFilePath()`, skill root detection |
|
|
186
|
+
| `assistant/src/config/schema.ts` | `PermissionsConfigSchema` — `permissions.mode` (`workspace` / `strict`) |
|
|
187
|
+
| `assistant/src/tools/executor.ts` | `ToolExecutor` — orchestrates risk classification, permission check, and execution |
|
|
188
|
+
| `assistant/src/daemon/handlers/config.ts` | `handleToolPermissionSimulate()` — dry-run simulation handler |
|
|
193
189
|
|
|
194
190
|
### Permission Simulation (Tool Permission Tester)
|
|
195
191
|
|
|
@@ -206,7 +202,6 @@ The `tool_permission_simulate` IPC message lets clients dry-run a tool invocatio
|
|
|
206
202
|
|
|
207
203
|
---
|
|
208
204
|
|
|
209
|
-
|
|
210
205
|
---
|
|
211
206
|
|
|
212
207
|
## Credential Storage and Secret Security
|
|
@@ -293,25 +288,25 @@ The `allowOneTimeSend` config gate (default: `false`) enables a secondary "Send
|
|
|
293
288
|
|
|
294
289
|
### Storage Layout
|
|
295
290
|
|
|
296
|
-
| Component
|
|
297
|
-
|
|
298
|
-
| Secret values
|
|
299
|
-
| Credential metadata | `~/.vellum/workspace/data/credentials/metadata.json` | Service, field, label, policy (allowedTools, allowedDomains), timestamps
|
|
300
|
-
| Config
|
|
291
|
+
| Component | Location | What it stores |
|
|
292
|
+
| ------------------- | ---------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ |
|
|
293
|
+
| Secret values | macOS Keychain (primary) or encrypted file fallback | Encrypted credential values keyed as `credential:{service}:{field}`. Falls back to encrypted file backend on Linux/headless or when Keychain is unavailable. |
|
|
294
|
+
| Credential metadata | `~/.vellum/workspace/data/credentials/metadata.json` | Service, field, label, policy (allowedTools, allowedDomains), timestamps |
|
|
295
|
+
| Config | `~/.vellum/workspace/config.*` | `secretDetection` settings: enabled, action, entropyThreshold, allowOneTimeSend |
|
|
301
296
|
|
|
302
297
|
### Key Files
|
|
303
298
|
|
|
304
|
-
| File
|
|
305
|
-
|
|
306
|
-
| `assistant/src/tools/credentials/vault.ts`
|
|
307
|
-
| `assistant/src/security/secure-keys.ts`
|
|
308
|
-
| `assistant/src/tools/credentials/metadata-store.ts`
|
|
309
|
-
| `assistant/src/tools/credentials/broker.ts`
|
|
310
|
-
| `assistant/src/tools/credentials/policy-validate.ts` | Policy input validation (allowedTools, allowedDomains)
|
|
311
|
-
| `assistant/src/permissions/secret-prompter.ts`
|
|
312
|
-
| `assistant/src/security/secret-scanner.ts`
|
|
313
|
-
| `assistant/src/security/secret-ingress.ts`
|
|
314
|
-
| `clients/macos/.../SecretPromptManager.swift`
|
|
299
|
+
| File | Role |
|
|
300
|
+
| ---------------------------------------------------- | --------------------------------------------------------------------- |
|
|
301
|
+
| `assistant/src/tools/credentials/vault.ts` | `credential_store` tool — store, list, delete, prompt actions |
|
|
302
|
+
| `assistant/src/security/secure-keys.ts` | Keychain read/write via `/usr/bin/security` CLI |
|
|
303
|
+
| `assistant/src/tools/credentials/metadata-store.ts` | JSON file metadata CRUD for credential records |
|
|
304
|
+
| `assistant/src/tools/credentials/broker.ts` | Brokered credential access with policy enforcement and transient send |
|
|
305
|
+
| `assistant/src/tools/credentials/policy-validate.ts` | Policy input validation (allowedTools, allowedDomains) |
|
|
306
|
+
| `assistant/src/permissions/secret-prompter.ts` | IPC secret_request/secret_response flow |
|
|
307
|
+
| `assistant/src/security/secret-scanner.ts` | Regex + entropy-based secret detection |
|
|
308
|
+
| `assistant/src/security/secret-ingress.ts` | Inbound message secret blocking |
|
|
309
|
+
| `clients/macos/.../SecretPromptManager.swift` | Floating panel UI for secure credential entry |
|
|
315
310
|
|
|
316
311
|
---
|
|
317
312
|
|
|
@@ -323,9 +318,9 @@ Scoped approval grants are a channel-agnostic primitive that allows a guardian's
|
|
|
323
318
|
|
|
324
319
|
Two scope modes exist:
|
|
325
320
|
|
|
326
|
-
| Mode
|
|
327
|
-
|
|
328
|
-
| `request_id`
|
|
321
|
+
| Mode | Key fields | Use case |
|
|
322
|
+
| ---------------- | -------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
323
|
+
| `request_id` | `requestId` | Grant is bound to a specific pending confirmation request. Consumed by matching the request ID. |
|
|
329
324
|
| `tool_signature` | `toolName` + `inputDigest` | Grant is bound to a specific tool invocation identified by tool name and a canonical SHA-256 digest of the input. Consumed by matching both fields plus optional context constraints. |
|
|
330
325
|
|
|
331
326
|
### Lifecycle Flow
|
|
@@ -376,22 +371,21 @@ sequenceDiagram
|
|
|
376
371
|
|
|
377
372
|
### Key Source Files
|
|
378
373
|
|
|
379
|
-
| File
|
|
380
|
-
|
|
381
|
-
| `assistant/src/memory/scoped-approval-grants.ts`
|
|
382
|
-
| `assistant/src/memory/migrations/033-scoped-approval-grants.ts`
|
|
383
|
-
| `assistant/src/security/tool-approval-digest.ts`
|
|
374
|
+
| File | Role |
|
|
375
|
+
| ---------------------------------------------------------------- | ----------------------------------------------------------------------------- |
|
|
376
|
+
| `assistant/src/memory/scoped-approval-grants.ts` | CRUD, atomic CAS consume, expiry sweep, context-based revocation |
|
|
377
|
+
| `assistant/src/memory/migrations/033-scoped-approval-grants.ts` | SQLite schema migration for the `scoped_approval_grants` table |
|
|
378
|
+
| `assistant/src/security/tool-approval-digest.ts` | Canonical JSON serialization + SHA-256 digest for tool signatures |
|
|
384
379
|
| `assistant/src/runtime/routes/guardian-approval-interception.ts` | Grant minting on guardian approve_once decisions (`tryMintToolApprovalGrant`) |
|
|
385
|
-
| `assistant/src/calls/voice-session-bridge.ts`
|
|
380
|
+
| `assistant/src/calls/voice-session-bridge.ts` | Voice consumer: checks and consumes grants before auto-denying |
|
|
386
381
|
|
|
387
382
|
### Test Coverage
|
|
388
383
|
|
|
389
|
-
| Test file
|
|
390
|
-
|
|
391
|
-
| `assistant/src/__tests__/scoped-approval-grants.test.ts`
|
|
392
|
-
| `assistant/src/__tests__/voice-scoped-grant-consumer.test.ts`
|
|
393
|
-
| `assistant/src/__tests__/guardian-grant-minting.test.ts`
|
|
384
|
+
| Test file | Scenarios covered |
|
|
385
|
+
| -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
|
|
386
|
+
| `assistant/src/__tests__/scoped-approval-grants.test.ts` | Store CRUD, request_id consume, tool_signature consume, expiry, revocation, digest stability |
|
|
387
|
+
| `assistant/src/__tests__/voice-scoped-grant-consumer.test.ts` | Voice bridge integration: grant-allowed, no-grant-denied, tool-mismatch, guardian-bypass, one-time-use, revocation on call end |
|
|
388
|
+
| `assistant/src/__tests__/guardian-grant-minting.test.ts` | Grant minting: callback/engine/legacy paths, informational-skip, reject-skip, identity-mismatch, stale-skip, TTL verification |
|
|
394
389
|
| `assistant/src/__tests__/scoped-grant-security-matrix.test.ts` | Security matrix: requester identity mismatch, concurrent CAS, persistence across restart, fail-closed default, cross-scope invariants |
|
|
395
390
|
|
|
396
391
|
---
|
|
397
|
-
|
|
@@ -142,7 +142,7 @@ CHANNEL_ID=$(curl -s "$BASE/v1/contacts?channelType=telegram" \
|
|
|
142
142
|
-H "Authorization: Bearer $TOKEN" | jq -r '.contacts[] | select(.channels[] | select(.externalUserId == "TARGET_USER_ID")) | .channels[] | select(.externalUserId == "TARGET_USER_ID") | .id')
|
|
143
143
|
|
|
144
144
|
# Revoke with reason
|
|
145
|
-
curl -s -X PATCH "$BASE/v1/
|
|
145
|
+
curl -s -X PATCH "$BASE/v1/contact-channels/$CHANNEL_ID" \
|
|
146
146
|
-H "Authorization: Bearer $TOKEN" \
|
|
147
147
|
-H "Content-Type: application/json" \
|
|
148
148
|
-d '{"status": "revoked", "reason": "Revoked by operator"}' | jq
|
|
@@ -153,7 +153,7 @@ curl -s -X PATCH "$BASE/v1/contacts/channels/$CHANNEL_ID" \
|
|
|
153
153
|
Blocking prevents the contact from re-entering the flow without explicit unblocking.
|
|
154
154
|
|
|
155
155
|
```bash
|
|
156
|
-
curl -s -X PATCH "$BASE/v1/
|
|
156
|
+
curl -s -X PATCH "$BASE/v1/contact-channels/$CHANNEL_ID" \
|
|
157
157
|
-H "Authorization: Bearer $TOKEN" \
|
|
158
158
|
-H "Content-Type: application/json" \
|
|
159
159
|
-d '{"status": "blocked", "reason": "Blocked by operator"}' | jq
|
package/docs/skills.md
CHANGED
|
@@ -12,20 +12,20 @@ Because skills can introduce arbitrary tool behavior, they are subject to strict
|
|
|
12
12
|
|
|
13
13
|
Skill-origin tools follow a stricter default permission policy than core tools:
|
|
14
14
|
|
|
15
|
-
| Scenario
|
|
16
|
-
|
|
17
|
-
| Low risk, no matching rule
|
|
18
|
-
| Medium risk, no matching rule
|
|
19
|
-
| High risk, no matching rule
|
|
20
|
-
| Allow rule matches, non-high risk
|
|
21
|
-
| Allow rule matches, high risk, `allowHighRisk: true`
|
|
22
|
-
| Allow rule matches, high risk, `allowHighRisk` absent | Prompted
|
|
15
|
+
| Scenario | Core tool behavior | Skill tool behavior |
|
|
16
|
+
| ----------------------------------------------------- | ----------------------------- | ------------------- |
|
|
17
|
+
| Low risk, no matching rule | Auto-allowed (workspace mode) | **Prompted** |
|
|
18
|
+
| Medium risk, no matching rule | Prompted | Prompted |
|
|
19
|
+
| High risk, no matching rule | Prompted | Prompted |
|
|
20
|
+
| Allow rule matches, non-high risk | Auto-allowed | Auto-allowed |
|
|
21
|
+
| Allow rule matches, high risk, `allowHighRisk: true` | Auto-allowed | Auto-allowed |
|
|
22
|
+
| Allow rule matches, high risk, `allowHighRisk` absent | Prompted | Prompted |
|
|
23
23
|
|
|
24
24
|
Even if a skill's `TOOLS.json` declares `"risk": "low"` for one of its tools, the permission checker will prompt the user unless an explicit trust rule in `~/.vellum/protected/trust.json` allows it. This prevents third-party skill tools from silently auto-executing.
|
|
25
25
|
|
|
26
26
|
## Skill Load Approval
|
|
27
27
|
|
|
28
|
-
The `skill_load` tool activates a skill within the current session. In **strict mode** (`permissions.mode = 'strict'`), loading a skill requires an explicit matching trust rule. In **
|
|
28
|
+
The `skill_load` tool activates a skill within the current session. In **strict mode** (`permissions.mode = 'strict'`), loading a skill requires an explicit matching trust rule. In **workspace mode** (default), `skill_load` is prompted unless a matching trust rule exists.
|
|
29
29
|
|
|
30
30
|
When `skill_load` is invoked, the permission checker generates multiple command candidates for rule matching:
|
|
31
31
|
|
|
@@ -57,10 +57,10 @@ When a skill's source files change (any file added, removed, or modified), the h
|
|
|
57
57
|
|
|
58
58
|
### Choosing between version-specific and any-version rules
|
|
59
59
|
|
|
60
|
-
| Approval type
|
|
61
|
-
|
|
60
|
+
| Approval type | Rule pattern | Behavior |
|
|
61
|
+
| ---------------- | ---------------------------------- | ---------------------------------------------------------------------------- |
|
|
62
62
|
| Version-specific | `skill_load:my-skill@v1:abc123...` | Only this exact version is auto-allowed. Any code change triggers re-prompt. |
|
|
63
|
-
| Any-version
|
|
63
|
+
| Any-version | `skill_load:my-skill` | All versions of this skill are auto-allowed. No re-prompt on code changes. |
|
|
64
64
|
|
|
65
65
|
Version-specific rules are more secure but require re-approval after every skill update. Any-version rules are more convenient but grant persistent access regardless of code changes.
|
|
66
66
|
|
|
@@ -91,7 +91,7 @@ The `normalizeFilePath()` function walks up the directory tree to find the neare
|
|
|
91
91
|
|
|
92
92
|
When `permissions.mode` is set to `strict` in the assistant configuration, **all** tool actions require a matching trust rule. There is no implicit auto-allow for any risk level. This means:
|
|
93
93
|
|
|
94
|
-
- Low-risk tools that would normally auto-execute in
|
|
94
|
+
- Low-risk tools that would normally auto-execute in workspace mode (e.g., `file_read`, `web_search`) will prompt unless a trust rule allows them.
|
|
95
95
|
- `skill_load` requires an explicit rule match, even though it is classified as low risk.
|
|
96
96
|
- The **starter bundle** can be accepted to seed common safe rules and reduce prompt noise.
|
|
97
97
|
|
|
@@ -99,14 +99,14 @@ When `permissions.mode` is set to `strict` in the assistant configuration, **all
|
|
|
99
99
|
|
|
100
100
|
The starter bundle is an opt-in set of allow rules for read-only tools that most users would approve individually. Accepting the bundle seeds these rules at once:
|
|
101
101
|
|
|
102
|
-
| Tool
|
|
103
|
-
|
|
104
|
-
| `file_read`
|
|
105
|
-
| `glob`
|
|
106
|
-
| `grep`
|
|
102
|
+
| Tool | Pattern |
|
|
103
|
+
| ---------------- | ------------------- |
|
|
104
|
+
| `file_read` | `file_read:**` |
|
|
105
|
+
| `glob` | `glob:**` |
|
|
106
|
+
| `grep` | `grep:**` |
|
|
107
107
|
| `list_directory` | `list_directory:**` |
|
|
108
|
-
| `web_search`
|
|
109
|
-
| `web_fetch`
|
|
108
|
+
| `web_search` | `web_search:**` |
|
|
109
|
+
| `web_fetch` | `web_fetch:**` |
|
|
110
110
|
|
|
111
111
|
Acceptance is idempotent and recorded in `trust.json`. The bundle does not include any tools that mutate the filesystem or execute arbitrary code.
|
|
112
112
|
|
|
@@ -114,10 +114,10 @@ Acceptance is idempotent and recorded in `trust.json`. The bundle does not inclu
|
|
|
114
114
|
|
|
115
115
|
Tools can execute in two contexts:
|
|
116
116
|
|
|
117
|
-
| Target
|
|
118
|
-
|
|
117
|
+
| Target | Description |
|
|
118
|
+
| --------- | -------------------------------------------------------------------------------------- |
|
|
119
119
|
| `sandbox` | Isolated execution within `~/.vellum/workspace` (Docker container or OS-level sandbox) |
|
|
120
|
-
| `host`
|
|
120
|
+
| `host` | Direct execution on the host machine |
|
|
121
121
|
|
|
122
122
|
Trust rules can include an `executionTarget` field to bind the rule to a specific context. A rule without `executionTarget` matches both sandbox and host invocations.
|
|
123
123
|
|
|
@@ -143,9 +143,9 @@ Strict mode requires an explicit trust rule for every tool action. There is no i
|
|
|
143
143
|
|
|
144
144
|
**Fix**: Accept the starter approval bundle to seed common safe rules. Then approve additional tools as needed — each approval creates a persistent trust rule.
|
|
145
145
|
|
|
146
|
-
### "Why does skill_load prompt in strict mode but not in
|
|
146
|
+
### "Why does skill_load prompt in strict mode but not in workspace mode?"
|
|
147
147
|
|
|
148
|
-
In
|
|
148
|
+
In workspace mode, `skill_load` may be auto-allowed by system default rules (e.g., `skill_load:*` at priority 100). In strict mode, low-risk auto-allow is disabled, so an explicit rule is needed.
|
|
149
149
|
|
|
150
150
|
**Fix**: Create a rule for the specific skill (version-specific or any-version) or accept the starter bundle if it covers your needs.
|
|
151
151
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vellumai/assistant",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.36",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"vellum": "./src/index.ts"
|
|
@@ -56,6 +56,9 @@
|
|
|
56
56
|
"web-tree-sitter": "0.26.5",
|
|
57
57
|
"zod": "^4.3.6"
|
|
58
58
|
},
|
|
59
|
+
"engines": {
|
|
60
|
+
"node": ">=20.12.0"
|
|
61
|
+
},
|
|
59
62
|
"devDependencies": {
|
|
60
63
|
"@pydantic/logfire-node": "^0.13.0",
|
|
61
64
|
"@types/archiver": "^7.0.0",
|
|
@@ -495,7 +495,7 @@ exports[`IPC message snapshots ClientMessage types fork_shared_app serializes to
|
|
|
495
495
|
|
|
496
496
|
exports[`IPC message snapshots ClientMessage types open_bundle serializes to expected JSON 1`] = `
|
|
497
497
|
{
|
|
498
|
-
"filePath": "/tmp/My_App.
|
|
498
|
+
"filePath": "/tmp/My_App.vellum",
|
|
499
499
|
"type": "open_bundle",
|
|
500
500
|
}
|
|
501
501
|
`;
|
|
@@ -1641,6 +1641,15 @@ exports[`IPC message snapshots ServerMessage types task_routed serializes to exp
|
|
|
1641
1641
|
}
|
|
1642
1642
|
`;
|
|
1643
1643
|
|
|
1644
|
+
exports[`IPC message snapshots ServerMessage types ride_shotgun_error serializes to expected JSON 1`] = `
|
|
1645
|
+
{
|
|
1646
|
+
"message": "Failed to start browser — Chrome CDP could not be launched.",
|
|
1647
|
+
"sessionId": "sess-shotgun-001",
|
|
1648
|
+
"type": "ride_shotgun_error",
|
|
1649
|
+
"watchId": "watch-shotgun-001",
|
|
1650
|
+
}
|
|
1651
|
+
`;
|
|
1652
|
+
|
|
1644
1653
|
exports[`IPC message snapshots ServerMessage types ride_shotgun_progress serializes to expected JSON 1`] = `
|
|
1645
1654
|
{
|
|
1646
1655
|
"message": "Observing user activity...",
|
|
@@ -1988,7 +1997,7 @@ exports[`IPC message snapshots ServerMessage types reminders_list_response seria
|
|
|
1988
1997
|
|
|
1989
1998
|
exports[`IPC message snapshots ServerMessage types bundle_app_response serializes to expected JSON 1`] = `
|
|
1990
1999
|
{
|
|
1991
|
-
"bundlePath": "/tmp/My_App-abc12345.
|
|
2000
|
+
"bundlePath": "/tmp/My_App-abc12345.vellum",
|
|
1992
2001
|
"manifest": {
|
|
1993
2002
|
"capabilities": [],
|
|
1994
2003
|
"content_id": "a1b2c3d4e5f6a7b8",
|
|
@@ -19,6 +19,7 @@ mock.module("../util/platform.js", () => ({
|
|
|
19
19
|
getDbPath: () => join(testDir, "test.db"),
|
|
20
20
|
normalizeAssistantId: (id: string) => (id === "self" ? "self" : id),
|
|
21
21
|
readLockfile: () => null,
|
|
22
|
+
writeLockfile: () => {},
|
|
22
23
|
isMacOS: () => process.platform === "darwin",
|
|
23
24
|
isLinux: () => process.platform === "linux",
|
|
24
25
|
isWindows: () => process.platform === "win32",
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Verify that the Amazon CLI delegates CDP management to the shared
|
|
3
|
+
* chrome-cdp helper instead of owning its own launch/window logic.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { readFileSync } from "node:fs";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { describe, expect, test } from "bun:test";
|
|
9
|
+
|
|
10
|
+
const AMAZON_CLI_PATH = join(
|
|
11
|
+
import.meta.dirname ?? __dirname,
|
|
12
|
+
"..",
|
|
13
|
+
"cli",
|
|
14
|
+
"amazon.ts",
|
|
15
|
+
);
|
|
16
|
+
const amazonSource = readFileSync(AMAZON_CLI_PATH, "utf-8");
|
|
17
|
+
|
|
18
|
+
describe("Amazon CLI CDP integration", () => {
|
|
19
|
+
test("imports shared CDP helpers instead of defining its own", () => {
|
|
20
|
+
// Should import from the shared module
|
|
21
|
+
expect(amazonSource).toContain('from "../tools/browser/chrome-cdp.js"');
|
|
22
|
+
|
|
23
|
+
// Should import the key entrypoints
|
|
24
|
+
expect(amazonSource).toContain("ensureChromeWithCdp");
|
|
25
|
+
expect(amazonSource).toContain("minimizeChromeWindow");
|
|
26
|
+
expect(amazonSource).toContain("restoreChromeWindow");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("does not define its own CDP_BASE constant", () => {
|
|
30
|
+
// The old inline constant was: const CDP_BASE = "http://localhost:9222";
|
|
31
|
+
expect(amazonSource).not.toMatch(/const\s+CDP_BASE\s*=/);
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("does not define its own Chrome data dir constant", () => {
|
|
35
|
+
expect(amazonSource).not.toMatch(/const\s+CHROME_DATA_DIR\s*=/);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
test("does not define a local isCdpReady function", () => {
|
|
39
|
+
expect(amazonSource).not.toMatch(/async\s+function\s+isCdpReady\s*\(/);
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
test("does not define a local ensureChromeWithCDP function", () => {
|
|
43
|
+
expect(amazonSource).not.toMatch(
|
|
44
|
+
/async\s+function\s+ensureChromeWithCDP\s*\(/,
|
|
45
|
+
);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("does not define local minimize/restore window functions", () => {
|
|
49
|
+
expect(amazonSource).not.toMatch(
|
|
50
|
+
/async\s+function\s+minimizeChromeWindow\s*\(/,
|
|
51
|
+
);
|
|
52
|
+
expect(amazonSource).not.toMatch(
|
|
53
|
+
/async\s+function\s+restoreChromeWindow\s*\(/,
|
|
54
|
+
);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("does not spawn Chrome directly", () => {
|
|
58
|
+
// The old code imported spawn and called it with the Chrome app path.
|
|
59
|
+
// After migration, spawn should not be imported or used.
|
|
60
|
+
expect(amazonSource).not.toMatch(/spawn\s+as\s+spawnChild/);
|
|
61
|
+
expect(amazonSource).not.toContain(
|
|
62
|
+
"/Applications/Google Chrome.app/Contents/MacOS/Google Chrome",
|
|
63
|
+
);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("still calls ensureChromeWithCdp in the learn session flow", () => {
|
|
67
|
+
// The learn session helper should delegate to the shared entrypoint
|
|
68
|
+
expect(amazonSource).toMatch(/await\s+ensureChromeWithCdp\s*\(/);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
test("passes amazon.com as the start URL", () => {
|
|
72
|
+
expect(amazonSource).toContain("https://www.amazon.com/");
|
|
73
|
+
});
|
|
74
|
+
});
|