@vellumai/assistant 0.7.0 → 0.7.1
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 +6 -7
- package/Dockerfile +1 -0
- package/README.md +2 -2
- package/__tests__/permissions/gateway-threshold-reader.test.ts +79 -139
- package/bun.lock +3 -0
- package/docs/architecture/security.md +18 -16
- package/knip.json +1 -0
- package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +1 -5
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -5
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -16
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +1 -9
- package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +12 -12
- package/node_modules/@vellumai/slack-text/bun.lock +24 -0
- package/node_modules/@vellumai/slack-text/package.json +18 -0
- package/node_modules/@vellumai/slack-text/src/index.test.ts +153 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +235 -0
- package/node_modules/@vellumai/slack-text/tsconfig.json +20 -0
- package/openapi.yaml +294 -107
- package/package.json +4 -2
- package/scripts/generate-openapi.ts +16 -111
- package/src/__tests__/agent-wake-override-profile.test.ts +23 -1
- package/src/__tests__/anthropic-provider.test.ts +56 -13
- package/src/__tests__/app-conversation-ids-backfill.test.ts +278 -0
- package/src/__tests__/app-conversation-ids.test.ts +151 -0
- package/src/__tests__/approval-cascade.test.ts +0 -15
- package/src/__tests__/approval-routes-http.test.ts +6 -17
- package/src/__tests__/assistant-event-hub.test.ts +126 -77
- package/src/__tests__/assistant-event.test.ts +0 -5
- package/src/__tests__/assistant-events-sse-hardening.test.ts +37 -15
- package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -29
- package/src/__tests__/background-shell-host-bash.test.ts +34 -43
- package/src/__tests__/call-controller.test.ts +1 -1
- package/src/__tests__/call-site-routing-provider.test.ts +193 -0
- package/src/__tests__/channel-approval-routes.test.ts +10 -296
- package/src/__tests__/channel-approvals.test.ts +25 -17
- package/src/__tests__/channel-guardian.test.ts +100 -146
- package/src/__tests__/checker.test.ts +20 -34
- package/src/__tests__/compact-event-conversation-id-guard.test.ts +50 -0
- package/src/__tests__/compaction-events.test.ts +2 -0
- package/src/__tests__/config-schema.test.ts +6 -48
- package/src/__tests__/config-watcher.test.ts +12 -0
- package/src/__tests__/connection-policy.test.ts +1 -52
- package/src/__tests__/contacts-write.test.ts +2 -64
- package/src/__tests__/context-image-dimensions.test.ts +1 -1
- package/src/__tests__/context-search-memory-source.test.ts +120 -1
- package/src/__tests__/context-search-memory-v2-source.test.ts +383 -0
- package/src/__tests__/context-search-pkb-source.test.ts +49 -0
- package/src/__tests__/context-search-workspace-source.test.ts +9 -22
- package/src/__tests__/context-window-manager.test.ts +46 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +102 -29
- package/src/__tests__/conversation-agent-loop.test.ts +980 -13
- package/src/__tests__/conversation-analysis-routes.test.ts +12 -10
- package/src/__tests__/conversation-attention-telegram.test.ts +11 -3
- package/src/__tests__/conversation-confirmation-signals.test.ts +0 -291
- package/src/__tests__/conversation-history-web-search.test.ts +4 -3
- package/src/__tests__/conversation-inference-profile-route.test.ts +12 -23
- package/src/__tests__/conversation-lifecycle.test.ts +4 -4
- package/src/__tests__/conversation-process-callsite.test.ts +79 -2
- package/src/__tests__/conversation-queue.test.ts +3 -8
- package/src/__tests__/conversation-routes-disk-view.test.ts +1 -161
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -32
- package/src/__tests__/conversation-routes-slash-commands.test.ts +75 -66
- package/src/__tests__/conversation-runtime-assembly.test.ts +257 -3
- package/src/__tests__/conversation-slash-commands.test.ts +24 -4
- package/src/__tests__/conversation-slash-queue.test.ts +2 -0
- package/src/__tests__/conversation-speed-override.test.ts +0 -3
- package/src/__tests__/conversation-starter-routes.test.ts +79 -2
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -5
- package/src/__tests__/conversation-surfaces-standalone.test.ts +18 -14
- package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -2
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +8 -46
- package/src/__tests__/conversation-usage.test.ts +253 -3
- package/src/__tests__/credential-execution-shell-lockdown.test.ts +0 -39
- package/src/__tests__/credential-health-service.test.ts +68 -0
- package/src/__tests__/credential-security-e2e.test.ts +4 -3
- package/src/__tests__/credential-security-invariants.test.ts +1 -5
- package/src/__tests__/credential-token-resolver.test.ts +180 -0
- package/src/__tests__/cu-unified-flow.test.ts +33 -16
- package/src/__tests__/daemon-assistant-events.test.ts +34 -21
- package/src/__tests__/daemon-credential-client.test.ts +4 -1
- package/src/__tests__/db-connection-isolation.test.ts +125 -0
- package/src/__tests__/db-migration-rollback.test.ts +101 -0
- package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +169 -0
- package/src/__tests__/deterministic-verification-control-plane.test.ts +7 -80
- package/src/__tests__/document-conversations.test.ts +332 -0
- package/src/__tests__/embedding-managed-proxy-selection.test.ts +2 -2
- package/src/__tests__/emit-event-signal.test.ts +4 -6
- package/src/__tests__/events-client-registration.test.ts +193 -49
- package/src/__tests__/filing-service.test.ts +58 -7
- package/src/__tests__/first-greeting.test.ts +156 -150
- package/src/__tests__/fixtures/mock-chrome-extension.ts +108 -66
- package/src/__tests__/get-skill-detail-audit.test.ts +3 -8
- package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
- package/src/__tests__/guardian-dispatch.test.ts +1 -1
- package/src/__tests__/guardian-grant-minting.test.ts +7 -2
- package/src/__tests__/guardian-routing-invariants.test.ts +7 -2
- package/src/__tests__/guardian-routing-state.test.ts +1 -1
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +32 -11
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +2 -83
- package/src/__tests__/headless-browser-mode.test.ts +4 -9
- package/src/__tests__/headless-browser-navigate.test.ts +21 -20
- package/src/__tests__/heartbeat-service.test.ts +289 -7
- package/src/__tests__/helpers/channel-test-adapter.ts +2 -2
- package/src/__tests__/helpers/create-guardian-binding.ts +91 -0
- package/src/__tests__/host-bash-proxy.test.ts +46 -122
- package/src/__tests__/host-browser-e2e-cloud.test.ts +36 -497
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +26 -96
- package/src/__tests__/host-browser-proxy.test.ts +111 -185
- package/src/__tests__/host-browser-routes.test.ts +45 -75
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +26 -30
- package/src/__tests__/host-cu-proxy.test.ts +56 -111
- package/src/__tests__/host-file-proxy.test.ts +44 -98
- package/src/__tests__/host-file-read-tool.test.ts +42 -21
- package/src/__tests__/host-shell-tool.test.ts +33 -68
- package/src/__tests__/host-transfer-pending-interactions.test.ts +2 -18
- package/src/__tests__/host-transfer-proxy.test.ts +43 -53
- package/src/__tests__/http-user-message-parity.test.ts +0 -6
- package/src/__tests__/inbound-slack-persistence.test.ts +31 -0
- package/src/__tests__/injector-chain.test.ts +10 -5
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +124 -0
- package/src/__tests__/inline-command-runner.test.ts +0 -66
- package/src/__tests__/inline-skill-load-permissions.test.ts +0 -2
- package/src/__tests__/install-skill-routing.test.ts +1 -13
- package/src/__tests__/llm-callsite-catalog.test.ts +34 -0
- package/src/__tests__/llm-catalog-parity.test.ts +90 -0
- package/src/__tests__/llm-context-resolution.test.ts +180 -0
- package/src/__tests__/llm-resolver.test.ts +80 -12
- package/src/__tests__/llm-usage-store.test.ts +269 -4
- package/src/__tests__/log-export-routes.test.ts +89 -0
- package/src/__tests__/managed-profile-guard.test.ts +225 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +0 -10
- package/src/__tests__/manual-token-reconciliation.test.ts +334 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +95 -0
- package/src/__tests__/migration-cross-version-compatibility.test.ts +197 -291
- package/src/__tests__/migration-export-http.test.ts +33 -26
- package/src/__tests__/migration-export-streaming.test.ts +18 -10
- package/src/__tests__/migration-export-to-gcs.test.ts +49 -9
- package/src/__tests__/migration-import-commit-http.test.ts +66 -21
- package/src/__tests__/migration-import-from-gcs.test.ts +50 -9
- package/src/__tests__/migration-import-from-url.test.ts +20 -6
- package/src/__tests__/migration-import-preflight-http.test.ts +95 -95
- package/src/__tests__/migration-parity-persistence.test.ts +62 -25
- package/src/__tests__/migration-transport.test.ts +115 -23
- package/src/__tests__/migration-validate-http.test.ts +105 -80
- package/src/__tests__/migration-wizard.test.ts +133 -27
- package/src/__tests__/non-member-access-request.test.ts +1 -1
- package/src/__tests__/notification-guardian-path.test.ts +1 -1
- package/src/__tests__/oauth-store.test.ts +19 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +21 -12
- package/src/__tests__/prechat-onboarding-contract.test.ts +31 -7
- package/src/__tests__/pricing.test.ts +68 -4
- package/src/__tests__/process-message-background-slack.test.ts +331 -0
- package/src/__tests__/provider-managed-proxy-integration.test.ts +153 -17
- package/src/__tests__/provider-send-message-override-profile.test.ts +50 -0
- package/src/__tests__/provider-usage-tracking.test.ts +208 -0
- package/src/__tests__/reaction-persistence.test.ts +9 -6
- package/src/__tests__/rebind-secrets-screen.test.ts +53 -16
- package/src/__tests__/recording-handler.test.ts +64 -81
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +4 -3
- package/src/__tests__/relay-server.test.ts +18 -13
- package/src/__tests__/require-fresh-approval.test.ts +13 -22
- package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
- package/src/__tests__/runtime-events-sse-parity.test.ts +3 -4
- package/src/__tests__/runtime-events-sse.test.ts +3 -12
- package/src/__tests__/search-skills-unified.test.ts +9 -15
- package/src/__tests__/secret-ingress-cli.test.ts +2 -5
- package/src/__tests__/secret-ingress-http.test.ts +0 -4
- package/src/__tests__/secret-onetime-send.test.ts +4 -2
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +24 -7
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +42 -47
- package/src/__tests__/secret-response-routing.test.ts +29 -15
- package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -1
- package/src/__tests__/secret-scanner.test.ts +2 -545
- package/src/__tests__/send-endpoint-busy.test.ts +9 -24
- package/src/__tests__/settings-routes.test.ts +1 -1
- package/src/__tests__/shell-credential-ref.test.ts +0 -8
- package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -56
- package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -11
- package/src/__tests__/skill-tool-factory.test.ts +97 -0
- package/src/__tests__/skills-file-content-endpoint.test.ts +9 -30
- package/src/__tests__/skills-files-catalog-fallback.test.ts +11 -17
- package/src/__tests__/slack-inbound-verification.test.ts +1 -62
- package/src/__tests__/subagent-fork-notifications.test.ts +57 -47
- package/src/__tests__/subagent-manager-notify.test.ts +70 -70
- package/src/__tests__/subagent-notify-parent.test.ts +80 -83
- package/src/__tests__/system-prompt.test.ts +115 -13
- package/src/__tests__/terminal-tools.test.ts +0 -89
- package/src/__tests__/thread-backfill.test.ts +945 -31
- package/src/__tests__/tool-domain-event-publisher.test.ts +0 -36
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -6
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -16
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +9 -19
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -7
- package/src/__tests__/tool-executor.test.ts +12 -19
- package/src/__tests__/tool-metrics-listener.test.ts +0 -35
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
- package/src/__tests__/tool-trace-listener.test.ts +0 -17
- package/src/__tests__/transfer-progress-screen.test.ts +63 -26
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -149
- package/src/__tests__/trusted-contact-multichannel.test.ts +2 -4
- package/src/__tests__/trusted-contact-verification.test.ts +1 -1
- package/src/__tests__/tts-catalog-parity.test.ts +16 -5
- package/src/__tests__/usage-attribution.test.ts +247 -0
- package/src/__tests__/usage-cli.test.ts +143 -0
- package/src/__tests__/usage-grouped-buckets.test.ts +155 -0
- package/src/__tests__/usage-routes.test.ts +150 -0
- package/src/__tests__/validation-results-screen.test.ts +39 -16
- package/src/__tests__/vbundle-pax-and-symlink.test.ts +12 -3
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +49 -137
- package/src/__tests__/verification-control-plane-policy.test.ts +4 -7
- package/src/__tests__/voice-session-bridge.test.ts +5 -5
- package/src/__tests__/workspace-migration-062-drop-memory-v2-edges-json.test.ts +103 -0
- package/src/__tests__/workspace-migration-063-release-notes-dynamic-model-context.test.ts +77 -0
- package/src/__tests__/workspace-migration-064-unwind-main-agent-opus-seed.test.ts +225 -0
- package/src/__tests__/workspace-migration-memory-v2-init.test.ts +8 -30
- package/src/acp/index.ts +0 -15
- package/src/acp/session-manager.ts +37 -34
- package/src/agent/loop.ts +16 -1
- package/src/approvals/AGENTS.md +4 -0
- package/src/approvals/__tests__/guardian-feed-event.test.ts +10 -3
- package/src/approvals/guardian-request-resolvers.ts +10 -2
- package/src/backup/__tests__/backup-worker.test.ts +36 -8
- package/src/backup/__tests__/paths.test.ts +2 -2
- package/src/backup/__tests__/restore.test.ts +45 -28
- package/src/backup/backup-worker.ts +36 -2
- package/src/backup/paths.ts +9 -6
- package/src/browser-session/events.ts +0 -9
- package/src/calls/call-store.ts +1 -34
- package/src/calls/guardian-question-copy.ts +0 -108
- package/src/calls/relay-server.ts +0 -24
- package/src/calls/twilio-rest.ts +0 -38
- package/src/calls/twilio-routes.ts +1 -1
- package/src/calls/voice-session-bridge.ts +7 -38
- package/src/channels/types.ts +1 -36
- package/src/cli/commands/__tests__/cache.test.ts +152 -5
- package/src/cli/commands/__tests__/memory-v2.test.ts +14 -28
- package/src/cli/commands/__tests__/trust.test.ts +21 -387
- package/src/cli/commands/backup.ts +4 -4
- package/src/cli/commands/cache-fs.ts +8 -0
- package/src/cli/commands/cache.ts +153 -82
- package/src/cli/commands/clients.ts +63 -5
- package/src/cli/commands/completions.ts +3 -3
- package/src/cli/commands/contacts.ts +231 -76
- package/src/cli/commands/keys.ts +4 -1
- package/src/cli/commands/memory-v2.ts +24 -52
- package/src/cli/commands/oauth/shared.ts +2 -29
- package/src/cli/commands/pending.ts +102 -0
- package/src/cli/commands/skills.ts +77 -35
- package/src/cli/commands/trust.ts +70 -430
- package/src/cli/commands/usage.ts +25 -16
- package/src/cli/lib/daemon-credential-client.ts +14 -0
- package/src/cli/program.ts +2 -0
- package/src/cli.ts +0 -21
- package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
- package/src/config/bundled-skills/messaging/TOOLS.json +14 -4
- package/src/config/env-registry.ts +12 -2
- package/src/config/env.ts +3 -14
- package/src/config/feature-flag-registry.json +30 -30
- package/src/config/llm-callsite-catalog.ts +12 -0
- package/src/config/llm-context-resolution.ts +80 -0
- package/src/config/llm-resolver.ts +58 -22
- package/src/config/loader.ts +3 -3
- package/src/config/schema.ts +2 -158
- package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
- package/src/config/schemas/call-site-catalog.ts +271 -0
- package/src/config/schemas/calls.ts +5 -5
- package/src/config/schemas/inference.ts +1 -1
- package/src/config/schemas/ingress.ts +1 -1
- package/src/config/schemas/llm.ts +31 -3
- package/src/config/schemas/memory-retrieval.ts +2 -2
- package/src/config/schemas/memory-v2.ts +9 -0
- package/src/config/schemas/security.ts +1 -42
- package/src/config/schemas/services.ts +6 -6
- package/src/config/schemas/skills.ts +5 -5
- package/src/config/schemas/tts.ts +1 -1
- package/src/config/seed-inference-profiles.ts +117 -0
- package/src/config/skills.ts +0 -90
- package/src/config/types.ts +3 -6
- package/src/contacts/contact-store.ts +0 -17
- package/src/contacts/contacts-write.ts +1 -105
- package/src/context/window-manager.ts +44 -5
- package/src/credential-execution/process-manager.ts +34 -10
- package/src/credential-health/credential-health-service.ts +21 -16
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +75 -82
- package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -9
- package/src/daemon/connection-policy.ts +1 -26
- package/src/daemon/conversation-agent-loop-handlers.ts +53 -4
- package/src/daemon/conversation-agent-loop.ts +277 -36
- package/src/daemon/conversation-history.ts +8 -8
- package/src/daemon/conversation-launch.ts +20 -135
- package/src/daemon/conversation-lifecycle.ts +1 -1
- package/src/daemon/conversation-messaging.ts +1 -0
- package/src/daemon/conversation-process.ts +83 -163
- package/src/daemon/conversation-runtime-assembly.ts +219 -76
- package/src/daemon/conversation-slash.ts +47 -5
- package/src/daemon/conversation-store.ts +7 -31
- package/src/daemon/conversation-surfaces.ts +22 -28
- package/src/daemon/conversation-tool-setup.ts +3 -33
- package/src/daemon/conversation-usage.ts +36 -0
- package/src/daemon/conversation.ts +117 -233
- package/src/daemon/daemon-control.ts +3 -71
- package/src/daemon/daemon-skill-host.ts +8 -11
- package/src/daemon/dictation-profile-store.ts +2 -26
- package/src/daemon/first-greeting.ts +44 -156
- package/src/daemon/handlers/config-channels.ts +12 -12
- package/src/daemon/handlers/config-ingress.ts +4 -165
- package/src/daemon/handlers/config-model.ts +1 -1
- package/src/daemon/handlers/config-voice.ts +0 -42
- package/src/daemon/handlers/conversations.ts +11 -190
- package/src/daemon/handlers/recording.ts +26 -158
- package/src/daemon/handlers/shared.ts +23 -71
- package/src/daemon/handlers/skills.ts +42 -93
- package/src/daemon/host-bash-proxy.ts +67 -45
- package/src/daemon/host-browser-proxy.ts +65 -27
- package/src/daemon/host-cu-proxy.ts +40 -39
- package/src/daemon/host-file-proxy.ts +58 -37
- package/src/daemon/host-transfer-proxy.ts +84 -46
- package/src/daemon/lifecycle.ts +49 -15
- package/src/daemon/message-types/conversations.ts +7 -0
- package/src/daemon/message-types/host-bash.ts +1 -0
- package/src/daemon/message-types/host-cu.ts +1 -0
- package/src/daemon/message-types/host-file.ts +1 -0
- package/src/daemon/message-types/host-transfer.ts +1 -0
- package/src/daemon/message-types/messages.ts +10 -9
- package/src/daemon/message-types/workspace.ts +1 -1
- package/src/daemon/process-message.ts +102 -239
- package/src/daemon/server.ts +13 -462
- package/src/daemon/shutdown-handlers.ts +2 -2
- package/src/daemon/tool-side-effects.ts +125 -107
- package/src/daemon/trust-context.ts +13 -0
- package/src/daemon/wake-target-adapter.ts +4 -9
- package/src/events/domain-events.ts +0 -8
- package/src/events/tool-audit-listener.ts +3 -1
- package/src/events/tool-domain-event-publisher.ts +0 -10
- package/src/events/tool-metrics-listener.ts +0 -17
- package/src/events/tool-trace-listener.ts +0 -14
- package/src/filing/filing-service.ts +13 -1
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +6 -2
- package/src/heartbeat/heartbeat-service.ts +23 -5
- package/src/home/__tests__/feed-writer.test.ts +0 -4
- package/src/home/__tests__/relationship-state-writer.test.ts +30 -0
- package/src/home/feed-writer.ts +1 -2
- package/src/home/relationship-state-writer.ts +16 -3
- package/src/ipc/__tests__/browser-ipc.test.ts +2 -12
- package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -1
- package/src/ipc/assistant-server.ts +3 -10
- package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +39 -20
- package/src/ipc/routes/route-adapter.ts +1 -1
- package/src/ipc/routes/trust-rules.test.ts +0 -95
- package/src/ipc/skill-ipc-types.ts +41 -0
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +13 -27
- package/src/ipc/skill-routes/__tests__/identity.test.ts +4 -23
- package/src/ipc/skill-routes/events.ts +12 -23
- package/src/ipc/skill-routes/identity.ts +4 -17
- package/src/ipc/skill-routes/index.ts +1 -1
- package/src/ipc/skill-server.ts +6 -39
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +0 -8
- package/src/live-voice/protocol.ts +4 -13
- package/src/mcp/manager.ts +0 -5
- package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +55 -0
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +127 -0
- package/src/memory/app-git-service.ts +0 -32
- package/src/memory/app-store.ts +154 -0
- package/src/memory/attachments-store.ts +6 -0
- package/src/memory/context-search/sources/memory-v2.ts +578 -0
- package/src/memory/context-search/sources/memory.ts +5 -0
- package/src/memory/context-search/sources/pkb.ts +10 -1
- package/src/memory/context-search/sources/workspace.ts +3 -2
- package/src/memory/conversation-crud.ts +29 -4
- package/src/memory/conversation-disk-view.ts +1 -5
- package/src/memory/conversation-starter-checkpoints.ts +63 -0
- package/src/memory/db-connection.ts +62 -0
- package/src/memory/db-init.ts +14 -0
- package/src/memory/embedding-backend.ts +3 -21
- package/src/memory/embedding-gemini.ts +0 -2
- package/src/memory/embedding-local.ts +6 -6
- package/src/memory/embedding-ollama.ts +6 -6
- package/src/memory/embedding-openai.ts +6 -6
- package/src/memory/embedding-types.ts +21 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +3 -7
- package/src/memory/graph/conversation-graph-memory.ts +35 -13
- package/src/memory/graph/injection.test.ts +2 -2
- package/src/memory/graph/injection.ts +1 -1
- package/src/memory/guardian-action-store.ts +0 -83
- package/src/memory/guardian-approvals.ts +0 -48
- package/src/memory/indexer.ts +1 -15
- package/src/memory/job-handlers/conversation-starters.ts +36 -53
- package/src/memory/job-utils.ts +0 -6
- package/src/memory/jobs-store.ts +0 -1
- package/src/memory/jobs-worker.ts +2 -16
- package/src/memory/llm-request-log-store.ts +0 -41
- package/src/memory/llm-usage-store.ts +129 -43
- package/src/memory/memory-v2-activation-log-store.ts +115 -0
- package/src/memory/migrations/233-document-conversations.ts +54 -0
- package/src/memory/migrations/234-memory-v2-activation-logs.ts +55 -0
- package/src/memory/migrations/235-llm-usage-attribution.ts +31 -0
- package/src/memory/migrations/235-slack-compaction-watermark.ts +44 -0
- package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +26 -0
- package/src/memory/migrations/__tests__/234-memory-v2-activation-logs.test.ts +182 -0
- package/src/memory/migrations/index.ts +14 -0
- package/src/memory/migrations/registry.ts +24 -0
- package/src/memory/raw-query.ts +2 -68
- package/src/memory/schema/conversations.ts +7 -0
- package/src/memory/schema/infrastructure.ts +25 -0
- package/src/memory/search/semantic.ts +5 -16
- package/src/memory/tool-usage-store.ts +2 -0
- package/src/memory/usage-buckets.ts +40 -1
- package/src/memory/usage-grouped-buckets.ts +127 -0
- package/src/memory/v2/__tests__/activation.test.ts +289 -90
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +2 -129
- package/src/memory/v2/__tests__/consolidation-job.test.ts +28 -11
- package/src/memory/v2/__tests__/edge-index.test.ts +278 -0
- package/src/memory/v2/__tests__/injection.test.ts +384 -15
- package/src/memory/v2/__tests__/migration.test.ts +64 -36
- package/src/memory/v2/__tests__/page-store.test.ts +191 -8
- package/src/memory/v2/__tests__/prompts-consolidation.test.ts +181 -0
- package/src/memory/v2/__tests__/skill-store.test.ts +115 -3
- package/src/memory/v2/__tests__/static-context.test.ts +153 -0
- package/src/memory/v2/activation.ts +168 -97
- package/src/memory/v2/backfill-jobs.ts +15 -100
- package/src/memory/v2/consolidation-job.ts +14 -12
- package/src/memory/v2/edge-index.ts +191 -0
- package/src/memory/v2/injection.ts +182 -58
- package/src/memory/v2/migration.ts +57 -64
- package/src/memory/v2/now-text.ts +2 -3
- package/src/memory/v2/page-store.ts +168 -31
- package/src/memory/v2/prompts/consolidation.ts +118 -42
- package/src/memory/v2/prompts/sweep.ts +3 -3
- package/src/memory/v2/skill-store.ts +55 -7
- package/src/memory/v2/static-context.ts +62 -0
- package/src/memory/v2/types.ts +10 -20
- package/src/memory/validation.ts +0 -11
- package/src/messaging/draft-store.ts +0 -6
- package/src/messaging/provider-types.ts +8 -0
- package/src/messaging/provider.ts +7 -0
- package/src/messaging/providers/gmail/client.ts +1 -121
- package/src/messaging/providers/outlook/client.ts +0 -73
- package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +226 -0
- package/src/messaging/providers/slack/adapter.ts +122 -21
- package/src/messaging/providers/slack/backfill.test.ts +95 -6
- package/src/messaging/providers/slack/backfill.ts +89 -11
- package/src/messaging/providers/slack/client.ts +10 -124
- package/src/messaging/providers/slack/message-metadata.ts +12 -2
- package/src/messaging/providers/slack/render-transcript.test.ts +56 -0
- package/src/messaging/providers/slack/render-transcript.ts +126 -25
- package/src/messaging/providers/slack/types.ts +1 -0
- package/src/oauth/connection-resolver.test.ts +8 -0
- package/src/oauth/connection-resolver.ts +8 -16
- package/src/oauth/credential-token-resolver.ts +97 -0
- package/src/oauth/manual-token-connection.ts +30 -34
- package/src/oauth/oauth-store.ts +6 -4
- package/src/outbound-proxy/certs.ts +0 -7
- package/src/outbound-proxy/config.ts +0 -74
- package/src/outbound-proxy/health.ts +0 -44
- package/src/outbound-proxy/index.ts +0 -22
- package/src/permissions/approval-provenance.test.ts +184 -0
- package/src/permissions/approval-provenance.ts +70 -0
- package/src/permissions/checker.ts +4 -1
- package/src/permissions/gateway-threshold-reader.ts +4 -1
- package/src/permissions/prompter.ts +9 -2
- package/src/permissions/secret-prompter.ts +21 -48
- package/src/permissions/types.ts +33 -0
- package/src/permissions/workspace-policy.ts +0 -5
- package/src/platform/sync-identity.ts +0 -8
- package/src/plugins/defaults/injectors.ts +69 -2
- package/src/plugins/defaults/overflow-reduce.ts +3 -2
- package/src/plugins/types.ts +8 -0
- package/src/prompts/system-prompt.ts +34 -70
- package/src/prompts/templates/BOOTSTRAP.md +52 -6
- package/src/prompts/update-bulletin-job.ts +2 -0
- package/src/providers/__tests__/retry-callsite.test.ts +138 -1
- package/src/providers/anthropic/client.ts +72 -33
- package/src/providers/call-site-routing.ts +42 -3
- package/src/providers/gemini/client.ts +18 -2
- package/src/providers/managed-proxy/context.ts +0 -5
- package/src/providers/model-catalog.ts +105 -19
- package/src/providers/openai/chat-completions-provider.ts +6 -0
- package/src/providers/openai/responses-provider.ts +7 -1
- package/src/providers/provider-send-message.ts +45 -2
- package/src/providers/ratelimit.ts +7 -2
- package/src/providers/registry.ts +14 -9
- package/src/providers/retry.ts +96 -8
- package/src/providers/types.ts +13 -0
- package/src/providers/usage-tracking.ts +96 -0
- package/src/runtime/AGENTS.md +10 -6
- package/src/runtime/__tests__/agent-wake.test.ts +89 -0
- package/src/runtime/agent-wake.ts +39 -2
- package/src/runtime/assistant-event-hub.ts +541 -45
- package/src/runtime/assistant-event.ts +1 -6
- package/src/runtime/auth/context.ts +0 -9
- package/src/runtime/auth/middleware.ts +1 -1
- package/src/runtime/auth/route-policy.ts +11 -9
- package/src/runtime/auth/token-service.ts +0 -11
- package/src/runtime/channel-approvals.ts +6 -2
- package/src/runtime/channel-verification-service.ts +3 -5
- package/src/runtime/http-errors.ts +0 -34
- package/src/runtime/http-router.ts +6 -3
- package/src/runtime/http-server.ts +22 -82
- package/src/runtime/http-types.ts +5 -0
- package/src/runtime/interactive-ui.ts +0 -1
- package/src/runtime/middleware/auth.ts +0 -20
- package/src/runtime/migrations/__tests__/v1-test-helpers.ts +112 -0
- package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +11 -4
- package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +253 -0
- package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +19 -6
- package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +71 -27
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +41 -2
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +143 -79
- package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +143 -23
- package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +2 -2
- package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +371 -0
- package/src/runtime/migrations/migration-transport.ts +46 -13
- package/src/runtime/migrations/migration-wizard.ts +2 -2
- package/src/runtime/migrations/origin-mode.ts +40 -0
- package/src/runtime/migrations/vbundle-builder.ts +133 -79
- package/src/runtime/migrations/vbundle-import-analyzer.ts +9 -7
- package/src/runtime/migrations/vbundle-importer.ts +7 -7
- package/src/runtime/migrations/vbundle-metadata-merge.ts +1 -1
- package/src/runtime/migrations/vbundle-streaming-importer.ts +3 -3
- package/src/runtime/migrations/vbundle-streaming-validator.ts +48 -26
- package/src/runtime/migrations/vbundle-validator.ts +214 -41
- package/src/runtime/pending-interactions.ts +13 -4
- package/src/runtime/routes/__tests__/acp-routes.test.ts +0 -1
- package/src/runtime/routes/__tests__/backup-routes.test.ts +28 -19
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +235 -0
- package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +58 -0
- package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +54 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +19 -6
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +7 -7
- package/src/runtime/routes/acp-routes.test.ts +0 -3
- package/src/runtime/routes/acp-routes.ts +3 -7
- package/src/runtime/routes/app-management-routes.ts +18 -9
- package/src/runtime/routes/approval-routes.ts +55 -14
- package/src/runtime/routes/avatar-routes.ts +3 -5
- package/src/runtime/routes/browser-routes.ts +1 -15
- package/src/runtime/routes/channel-guardian-routes.ts +1 -5
- package/src/runtime/routes/channel-readiness-routes.ts +3 -7
- package/src/runtime/routes/channel-route-shared.ts +2 -28
- package/src/runtime/routes/client-routes.ts +45 -12
- package/src/runtime/routes/consolidation-routes.ts +115 -0
- package/src/runtime/routes/conversation-list-routes.ts +12 -29
- package/src/runtime/routes/conversation-management-routes.ts +14 -51
- package/src/runtime/routes/conversation-query-routes.ts +120 -8
- package/src/runtime/routes/conversation-routes.ts +44 -528
- package/src/runtime/routes/conversation-starter-routes.ts +19 -40
- package/src/runtime/routes/documents-routes.ts +53 -18
- package/src/runtime/routes/events-routes.ts +59 -91
- package/src/runtime/routes/filing-routes.ts +18 -1
- package/src/runtime/routes/guardian-action-routes.ts +4 -9
- package/src/runtime/routes/host-bash-routes.ts +3 -2
- package/src/runtime/routes/host-browser-routes.ts +9 -33
- package/src/runtime/routes/host-cu-routes.ts +6 -1
- package/src/runtime/routes/host-file-routes.ts +3 -2
- package/src/runtime/routes/host-transfer-routes.ts +11 -15
- package/src/runtime/routes/identity-routes.ts +78 -6
- package/src/runtime/routes/inbound-message-handler.ts +580 -137
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -88
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +3 -0
- package/src/runtime/routes/index.ts +4 -0
- package/src/runtime/routes/integrations/slack/channel.ts +0 -24
- package/src/runtime/routes/llm-call-sites-routes.ts +22 -0
- package/src/runtime/routes/memory-v2-routes.ts +10 -15
- package/src/runtime/routes/migration-routes.ts +188 -31
- package/src/runtime/routes/playground/guard.ts +1 -1
- package/src/runtime/routes/playground/index.ts +0 -2
- package/src/runtime/routes/recording-routes.ts +4 -24
- package/src/runtime/routes/rename-conversation-routes.ts +2 -6
- package/src/runtime/routes/schedule-routes.ts +3 -6
- package/src/runtime/routes/secret-routes.ts +87 -18
- package/src/runtime/routes/settings-routes.ts +29 -28
- package/src/runtime/routes/skills-routes.ts +12 -31
- package/src/runtime/routes/suggest-trust-rule-routes.ts +32 -1
- package/src/runtime/routes/task-routes.ts +6 -6
- package/src/runtime/routes/trust-rules-routes.ts +3 -94
- package/src/runtime/routes/types.ts +4 -4
- package/src/runtime/routes/upgrade-broadcast-routes.ts +3 -10
- package/src/runtime/routes/usage-routes.ts +87 -10
- package/src/runtime/routes/user-routes.ts +17 -31
- package/src/runtime/routes/work-items-routes.ts +1 -4
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -2
- package/src/runtime/services/analyze-conversation.ts +7 -17
- package/src/runtime/services/conversation-serializer.ts +2 -4
- package/src/runtime/verification-outbound-actions.ts +1 -1
- package/src/runtime/verification-rate-limiter.ts +1 -1
- package/src/schedule/schedule-store.ts +0 -16
- package/src/security/secret-scanner.ts +14 -547
- package/src/security/secure-keys.ts +31 -11
- package/src/security/token-manager.ts +7 -3
- package/src/signals/cancel.ts +16 -25
- package/src/signals/conversation-undo.ts +2 -27
- package/src/signals/emit-event.ts +1 -2
- package/src/signals/user-message.ts +108 -22
- package/src/skills/catalog-install.ts +1 -0
- package/src/skills/clawhub.ts +2 -2
- package/src/skills/inline-command-runner.ts +1 -7
- package/src/subagent/manager.ts +67 -84
- package/src/tasks/task-store.ts +1 -28
- package/src/telemetry/types.ts +6 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +38 -15
- package/src/telemetry/usage-telemetry-reporter.ts +3 -5
- package/src/tools/acp/spawn.test.ts +1 -2
- package/src/tools/acp/steer.test.ts +1 -2
- package/src/tools/browser/__tests__/browser-status.test.ts +44 -127
- package/src/tools/browser/browser-execution.ts +31 -147
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +92 -68
- package/src/tools/browser/cdp-client/factory.ts +48 -76
- package/src/tools/browser/cdp-client/index.ts +1 -14
- package/src/tools/executor.ts +44 -31
- package/src/tools/host-filesystem/edit.ts +3 -2
- package/src/tools/host-filesystem/read.ts +3 -2
- package/src/tools/host-filesystem/transfer.test.ts +45 -42
- package/src/tools/host-filesystem/transfer.ts +4 -3
- package/src/tools/host-filesystem/write.ts +3 -2
- package/src/tools/host-terminal/host-shell.ts +4 -3
- package/src/tools/network/script-proxy/index.ts +1 -10
- package/src/tools/permission-checker.ts +66 -1
- package/src/tools/skills/sandbox-runner.ts +1 -6
- package/src/tools/skills/skill-tool-factory.ts +32 -0
- package/src/tools/terminal/safe-env.ts +1 -0
- package/src/tools/terminal/shell.ts +2 -78
- package/src/tools/types.ts +12 -39
- package/src/tts/__tests__/provider-catalog.test.ts +2 -2
- package/src/tts/provider-catalog.ts +1 -1
- package/src/usage/actors.ts +2 -1
- package/src/usage/attribution.ts +185 -0
- package/src/usage/pricing.ts +166 -0
- package/src/usage/types.ts +14 -0
- package/src/util/json.ts +13 -0
- package/src/util/logger.ts +3 -3
- package/src/util/pricing.ts +50 -3
- package/src/work-items/work-item-runner.ts +15 -42
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +4 -3
- package/src/workspace/migrations/052-seed-default-inference-profiles.ts +3 -3
- package/src/workspace/migrations/060-memory-v2-init.ts +2 -18
- package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +59 -0
- package/src/workspace/migrations/062-drop-memory-v2-edges-json.ts +27 -0
- package/src/workspace/migrations/063-release-notes-dynamic-model-context.ts +70 -0
- package/src/workspace/migrations/064-unwind-main-agent-opus-seed.ts +64 -0
- package/src/workspace/migrations/registry.ts +8 -0
- package/src/workspace/provider-commit-message-generator.ts +3 -3
- package/src/__tests__/sandbox-diagnostics.test.ts +0 -138
- package/src/__tests__/sandbox-host-parity.test.ts +0 -1024
- package/src/__tests__/secret-detection-handler.test.ts +0 -67
- package/src/__tests__/secret-scanner-executor.test.ts +0 -450
- package/src/__tests__/tcc-sandbox-deny.test.ts +0 -198
- package/src/__tests__/terminal-sandbox.test.ts +0 -374
- package/src/__tests__/tool-notification-listener.test.ts +0 -65
- package/src/context/__tests__/microcompact.test.ts +0 -805
- package/src/context/microcompact.ts +0 -443
- package/src/daemon/handlers/slack-channel-oauth-install.ts +0 -197
- package/src/events/tool-notification-listener.ts +0 -17
- package/src/ipc/routes/__tests__/memory-v2-validate.test.ts +0 -219
- package/src/memory/v2/__tests__/edges.test.ts +0 -435
- package/src/memory/v2/edges.ts +0 -217
- package/src/prompts/__tests__/system-prompt-memory-v2.test.ts +0 -197
- package/src/runtime/__tests__/chrome-extension-registry.test.ts +0 -518
- package/src/runtime/__tests__/client-registry.test.ts +0 -271
- package/src/runtime/chrome-extension-registry.ts +0 -368
- package/src/runtime/client-registry.ts +0 -254
- package/src/runtime/routes/inbound-stages/verification-intercept.ts +0 -329
- package/src/tools/secret-detection-handler.ts +0 -269
- package/src/tools/terminal/backends/native.ts +0 -327
- package/src/tools/terminal/backends/types.ts +0 -37
- package/src/tools/terminal/sandbox-diagnostics.ts +0 -87
- package/src/tools/terminal/sandbox.ts +0 -40
|
@@ -39,6 +39,14 @@ mock.module("../security/secure-keys.js", () => ({
|
|
|
39
39
|
getSecureKeyAsync: async () => mockAccessToken,
|
|
40
40
|
}));
|
|
41
41
|
|
|
42
|
+
mock.module("./credential-token-resolver.js", () => ({
|
|
43
|
+
getConnectionAccessTokenResult: async () => ({
|
|
44
|
+
value: mockAccessToken,
|
|
45
|
+
unreachable: false,
|
|
46
|
+
key: "mock-key",
|
|
47
|
+
}),
|
|
48
|
+
}));
|
|
49
|
+
|
|
42
50
|
mock.module("../config/loader.js", () => ({
|
|
43
51
|
getConfig: () => mockConfig,
|
|
44
52
|
}));
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { getConfig, getNestedValue, loadRawConfig } from "../config/loader.js";
|
|
1
|
+
import { getConfig } from "../config/loader.js";
|
|
3
2
|
import {
|
|
4
3
|
getServiceMode,
|
|
5
4
|
type Services,
|
|
6
5
|
ServicesSchema,
|
|
7
6
|
} from "../config/schemas/services.js";
|
|
8
7
|
import { VellumPlatformClient } from "../platform/client.js";
|
|
9
|
-
import { getSecureKeyAsync } from "../security/secure-keys.js";
|
|
10
8
|
import { getLogger } from "../util/logger.js";
|
|
11
9
|
import { BYOOAuthConnection } from "./byo-connection.js";
|
|
12
10
|
import type { OAuthConnection } from "./connection.js";
|
|
11
|
+
import { getConnectionAccessTokenResult } from "./credential-token-resolver.js";
|
|
13
12
|
import { getActiveConnection, getProvider } from "./oauth-store.js";
|
|
14
13
|
import { PlatformOAuthConnection } from "./platform-connection.js";
|
|
15
14
|
|
|
@@ -52,15 +51,7 @@ export async function resolveOAuthConnection(
|
|
|
52
51
|
|
|
53
52
|
if (managedKey && managedKey in ServicesSchema.shape) {
|
|
54
53
|
const services: Services = getConfig().services;
|
|
55
|
-
|
|
56
|
-
// Treat as managed when explicitly configured OR when on a platform
|
|
57
|
-
// instance and the user hasn't explicitly opted into "your-own".
|
|
58
|
-
const effectivelyManaged =
|
|
59
|
-
explicitMode === "managed" ||
|
|
60
|
-
(getIsPlatform() &&
|
|
61
|
-
getNestedValue(loadRawConfig(), `services.${managedKey}.mode`) ===
|
|
62
|
-
undefined);
|
|
63
|
-
if (effectivelyManaged) {
|
|
54
|
+
if (getServiceMode(services, managedKey as keyof Services) === "managed") {
|
|
64
55
|
const client = await VellumPlatformClient.create();
|
|
65
56
|
if (!client || !client.platformAssistantId) {
|
|
66
57
|
const detail = !client
|
|
@@ -105,10 +96,11 @@ export async function resolveOAuthConnection(
|
|
|
105
96
|
);
|
|
106
97
|
}
|
|
107
98
|
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
99
|
+
const tokenResult = await getConnectionAccessTokenResult({
|
|
100
|
+
provider,
|
|
101
|
+
connectionId: conn.id,
|
|
102
|
+
});
|
|
103
|
+
if (!tokenResult.value) {
|
|
112
104
|
throw new Error(
|
|
113
105
|
`OAuth connection for "${provider}" exists but has no access token. Re-authorize with \`assistant oauth connect ${provider}\`.`,
|
|
114
106
|
);
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Centralized access-token key resolution for OAuth and manual-token providers.
|
|
3
|
+
*
|
|
4
|
+
* All code that needs to read or check the presence of a provider's access
|
|
5
|
+
* token should go through {@link getConnectionAccessTokenResult} rather than
|
|
6
|
+
* inlining provider-specific path logic. This ensures that `oauth status`,
|
|
7
|
+
* `oauth ping`, credential health checks, and runtime token lookups all
|
|
8
|
+
* agree on where the access token lives.
|
|
9
|
+
*
|
|
10
|
+
* Manual-token providers (e.g. slack_channel, telegram) store their primary
|
|
11
|
+
* token under `credential/<provider>/<field>` via the generic credential
|
|
12
|
+
* store, while standard OAuth providers use `oauth_connection/<id>/access_token`.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import { oauthConnectionAccessTokenPath } from "@vellumai/credential-storage";
|
|
16
|
+
|
|
17
|
+
import { credentialKey } from "../security/credential-key.js";
|
|
18
|
+
import {
|
|
19
|
+
getSecureKeyResultAsync,
|
|
20
|
+
type SecureKeyResult,
|
|
21
|
+
} from "../security/secure-keys.js";
|
|
22
|
+
|
|
23
|
+
// ── Types ─────────────────────────────────────────────────────────────
|
|
24
|
+
|
|
25
|
+
export interface ConnectionAccessTokenResult {
|
|
26
|
+
/** The access token value, or undefined if not found / backend unreachable. */
|
|
27
|
+
value: string | undefined;
|
|
28
|
+
/** True when the credential backend is temporarily unreachable. */
|
|
29
|
+
unreachable: boolean;
|
|
30
|
+
/** The secure-store key that was resolved for this provider + connection. */
|
|
31
|
+
key: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// ── Helpers ──────────────────────────────────────────────────────────
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Return the secure-store key holding the primary access token for a
|
|
38
|
+
* manual-token provider, or null for OAuth providers whose tokens live at
|
|
39
|
+
* `oauth_connection/<id>/access_token`.
|
|
40
|
+
*
|
|
41
|
+
* Manual-token providers store their tokens under `credential/<provider>/<field>`
|
|
42
|
+
* via the generic credential store, so any code that validates tokens for these
|
|
43
|
+
* providers (e.g. credential-health checks) must resolve the path through here
|
|
44
|
+
* rather than assuming the OAuth access-token path.
|
|
45
|
+
*/
|
|
46
|
+
export function manualTokenAccessCredentialKey(
|
|
47
|
+
provider: string,
|
|
48
|
+
): string | null {
|
|
49
|
+
switch (provider) {
|
|
50
|
+
case "slack_channel":
|
|
51
|
+
return credentialKey("slack_channel", "bot_token");
|
|
52
|
+
case "telegram":
|
|
53
|
+
return credentialKey("telegram", "bot_token");
|
|
54
|
+
default:
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Resolve the secure-store key for a provider's access token.
|
|
61
|
+
*
|
|
62
|
+
* - `slack_channel` -> `credential/slack_channel/bot_token`
|
|
63
|
+
* - `telegram` -> `credential/telegram/bot_token`
|
|
64
|
+
* - all normal OAuth -> `oauth_connection/<connectionId>/access_token`
|
|
65
|
+
*/
|
|
66
|
+
export function resolveAccessTokenKey(
|
|
67
|
+
provider: string,
|
|
68
|
+
connectionId: string,
|
|
69
|
+
): string {
|
|
70
|
+
return (
|
|
71
|
+
manualTokenAccessCredentialKey(provider) ??
|
|
72
|
+
oauthConnectionAccessTokenPath(connectionId)
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// ── Public API ───────────────────────────────────────────────────────
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Look up the access token for a provider/connection pair, resolving the
|
|
80
|
+
* correct secure-store key automatically.
|
|
81
|
+
*
|
|
82
|
+
* Returns the token value, whether the backend was unreachable, and the
|
|
83
|
+
* key that was used — giving callers everything they need to diagnose
|
|
84
|
+
* token-path mismatches.
|
|
85
|
+
*/
|
|
86
|
+
export async function getConnectionAccessTokenResult(opts: {
|
|
87
|
+
provider: string;
|
|
88
|
+
connectionId: string;
|
|
89
|
+
}): Promise<ConnectionAccessTokenResult> {
|
|
90
|
+
const key = resolveAccessTokenKey(opts.provider, opts.connectionId);
|
|
91
|
+
const result: SecureKeyResult = await getSecureKeyResultAsync(key);
|
|
92
|
+
return {
|
|
93
|
+
value: result.value,
|
|
94
|
+
unreachable: result.unreachable,
|
|
95
|
+
key,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
11
|
import { credentialKey } from "../security/credential-key.js";
|
|
12
|
-
import {
|
|
12
|
+
import { getSecureKeyResultAsync } from "../security/secure-keys.js";
|
|
13
|
+
import { getLogger } from "../util/logger.js";
|
|
13
14
|
import {
|
|
14
15
|
createConnection,
|
|
15
16
|
deleteConnection,
|
|
@@ -18,32 +19,15 @@ import {
|
|
|
18
19
|
upsertApp,
|
|
19
20
|
} from "./oauth-store.js";
|
|
20
21
|
|
|
22
|
+
// Re-export from the centralized resolver so existing callers that import
|
|
23
|
+
// from this module continue to work without changes.
|
|
24
|
+
export { manualTokenAccessCredentialKey } from "./credential-token-resolver.js";
|
|
25
|
+
|
|
26
|
+
const log = getLogger("manual-token-connection");
|
|
27
|
+
|
|
21
28
|
/** Sentinel client_id used for non-OAuth providers that don't have a real app. */
|
|
22
29
|
const MANUAL_TOKEN_CLIENT_ID = "manual-config";
|
|
23
30
|
|
|
24
|
-
/**
|
|
25
|
-
* Return the secure-store key holding the primary access token for a
|
|
26
|
-
* manual-token provider, or null for OAuth providers whose tokens live at
|
|
27
|
-
* `oauth_connection/<id>/access_token`.
|
|
28
|
-
*
|
|
29
|
-
* Manual-token providers store their tokens under `credential/<provider>/<field>`
|
|
30
|
-
* via the generic credential store, so any code that validates tokens for these
|
|
31
|
-
* providers (e.g. credential-health checks) must resolve the path through here
|
|
32
|
-
* rather than assuming the OAuth access-token path.
|
|
33
|
-
*/
|
|
34
|
-
export function manualTokenAccessCredentialKey(
|
|
35
|
-
provider: string,
|
|
36
|
-
): string | null {
|
|
37
|
-
switch (provider) {
|
|
38
|
-
case "slack_channel":
|
|
39
|
-
return credentialKey("slack_channel", "bot_token");
|
|
40
|
-
case "telegram":
|
|
41
|
-
return credentialKey("telegram", "bot_token");
|
|
42
|
-
default:
|
|
43
|
-
return null;
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
|
|
47
31
|
/**
|
|
48
32
|
* Ensure an active oauth_connection row exists for the given manual-token
|
|
49
33
|
* provider. Creates the synthetic oauth_app row on first use.
|
|
@@ -101,13 +85,19 @@ export async function syncManualTokenConnection(
|
|
|
101
85
|
): Promise<void> {
|
|
102
86
|
switch (provider) {
|
|
103
87
|
case "telegram": {
|
|
104
|
-
const
|
|
88
|
+
const botTokenResult = await getSecureKeyResultAsync(
|
|
105
89
|
credentialKey("telegram", "bot_token"),
|
|
106
|
-
)
|
|
107
|
-
const
|
|
90
|
+
);
|
|
91
|
+
const webhookSecretResult = await getSecureKeyResultAsync(
|
|
108
92
|
credentialKey("telegram", "webhook_secret"),
|
|
109
|
-
)
|
|
110
|
-
if (
|
|
93
|
+
);
|
|
94
|
+
if (botTokenResult.unreachable || webhookSecretResult.unreachable) {
|
|
95
|
+
log.warn(
|
|
96
|
+
"Skipping telegram manual-token reconciliation — credential backend unreachable",
|
|
97
|
+
);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (botTokenResult.value && webhookSecretResult.value) {
|
|
111
101
|
await ensureManualTokenConnection(provider, accountInfo);
|
|
112
102
|
} else {
|
|
113
103
|
removeManualTokenConnection(provider);
|
|
@@ -116,13 +106,19 @@ export async function syncManualTokenConnection(
|
|
|
116
106
|
}
|
|
117
107
|
|
|
118
108
|
case "slack_channel": {
|
|
119
|
-
const
|
|
109
|
+
const botTokenResult = await getSecureKeyResultAsync(
|
|
120
110
|
credentialKey("slack_channel", "bot_token"),
|
|
121
|
-
)
|
|
122
|
-
const
|
|
111
|
+
);
|
|
112
|
+
const appTokenResult = await getSecureKeyResultAsync(
|
|
123
113
|
credentialKey("slack_channel", "app_token"),
|
|
124
|
-
)
|
|
125
|
-
if (
|
|
114
|
+
);
|
|
115
|
+
if (botTokenResult.unreachable || appTokenResult.unreachable) {
|
|
116
|
+
log.warn(
|
|
117
|
+
"Skipping slack_channel manual-token reconciliation — credential backend unreachable",
|
|
118
|
+
);
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (botTokenResult.value && appTokenResult.value) {
|
|
126
122
|
await ensureManualTokenConnection(provider, accountInfo);
|
|
127
123
|
} else {
|
|
128
124
|
removeManualTokenConnection(provider);
|
package/src/oauth/oauth-store.ts
CHANGED
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
} from "../security/secure-keys.js";
|
|
34
34
|
import { getLogger } from "../util/logger.js";
|
|
35
35
|
import type { AvailableScopes } from "./connect-types.js";
|
|
36
|
+
import { getConnectionAccessTokenResult } from "./credential-token-resolver.js";
|
|
36
37
|
import { tryRevokeOAuthToken } from "./revoke.js";
|
|
37
38
|
|
|
38
39
|
const log = getLogger("oauth-store");
|
|
@@ -895,10 +896,11 @@ export function listActiveConnectionsByProvider(
|
|
|
895
896
|
export async function isProviderConnected(provider: string): Promise<boolean> {
|
|
896
897
|
const conn = getActiveConnection(provider);
|
|
897
898
|
if (!conn || conn.status !== "active") return false;
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
);
|
|
899
|
+
const tokenResult = await getConnectionAccessTokenResult({
|
|
900
|
+
provider,
|
|
901
|
+
connectionId: conn.id,
|
|
902
|
+
});
|
|
903
|
+
return tokenResult.value !== undefined;
|
|
902
904
|
}
|
|
903
905
|
|
|
904
906
|
/**
|
|
@@ -269,13 +269,6 @@ export async function ensureCombinedCABundle(
|
|
|
269
269
|
}
|
|
270
270
|
}
|
|
271
271
|
|
|
272
|
-
/**
|
|
273
|
-
* Return the path to the combined CA bundle for use as SSL_CERT_FILE.
|
|
274
|
-
*/
|
|
275
|
-
export function getCombinedCAPath(dataDir: string): string {
|
|
276
|
-
return join(dataDir, "proxy-ca", COMBINED_CA_FILENAME);
|
|
277
|
-
}
|
|
278
|
-
|
|
279
272
|
/**
|
|
280
273
|
* Return the path to the local CA cert for use as NODE_EXTRA_CA_CERTS.
|
|
281
274
|
*/
|
|
@@ -18,77 +18,3 @@ export interface SidecarConfig {
|
|
|
18
18
|
/** Log level for the sidecar process. */
|
|
19
19
|
logLevel: "debug" | "info" | "warn" | "error";
|
|
20
20
|
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Parse and validate sidecar configuration from environment variables.
|
|
24
|
-
*
|
|
25
|
-
* Environment variables:
|
|
26
|
-
* PROXY_PORT - Port to listen on (default: 8080)
|
|
27
|
-
* PROXY_HOST - Host to bind to (default: "0.0.0.0")
|
|
28
|
-
* PROXY_HEALTH_PORT - Port for health/readiness endpoints (default: 8081)
|
|
29
|
-
* PROXY_CA_DIR - Path to CA directory for MITM (optional)
|
|
30
|
-
* PROXY_LOG_LEVEL - Log level: debug | info | warn | error (default: "info")
|
|
31
|
-
*/
|
|
32
|
-
export function loadConfig(
|
|
33
|
-
env: Record<string, string | undefined> = process.env,
|
|
34
|
-
): SidecarConfig {
|
|
35
|
-
const port = parsePort(env.PROXY_PORT, "PROXY_PORT");
|
|
36
|
-
const defaultHealthPort = port === 8081 ? 8082 : 8081;
|
|
37
|
-
const healthPort = parsePort(
|
|
38
|
-
env.PROXY_HEALTH_PORT,
|
|
39
|
-
"PROXY_HEALTH_PORT",
|
|
40
|
-
defaultHealthPort,
|
|
41
|
-
);
|
|
42
|
-
if (healthPort === port) {
|
|
43
|
-
throw new ConfigError(
|
|
44
|
-
`PROXY_HEALTH_PORT (${healthPort}) must differ from PROXY_PORT (${port})`,
|
|
45
|
-
);
|
|
46
|
-
}
|
|
47
|
-
const host = env.PROXY_HOST ?? "0.0.0.0";
|
|
48
|
-
const caDir = env.PROXY_CA_DIR ?? null;
|
|
49
|
-
const logLevel = parseLogLevel(env.PROXY_LOG_LEVEL);
|
|
50
|
-
|
|
51
|
-
return { port, host, healthPort, caDir, logLevel };
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
function parsePort(
|
|
55
|
-
raw: string | undefined,
|
|
56
|
-
envName: string = "PROXY_PORT",
|
|
57
|
-
defaultPort: number = 8080,
|
|
58
|
-
): number {
|
|
59
|
-
if (raw === undefined || raw === "") return defaultPort;
|
|
60
|
-
|
|
61
|
-
const port = Number(raw);
|
|
62
|
-
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
63
|
-
throw new ConfigError(
|
|
64
|
-
`${envName} must be an integer between 1 and 65535, got "${raw}"`,
|
|
65
|
-
);
|
|
66
|
-
}
|
|
67
|
-
return port;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
const VALID_LOG_LEVELS = new Set(["debug", "info", "warn", "error"] as const);
|
|
71
|
-
type LogLevel = "debug" | "info" | "warn" | "error";
|
|
72
|
-
|
|
73
|
-
function parseLogLevel(raw: string | undefined): LogLevel {
|
|
74
|
-
if (raw === undefined || raw === "") return "info";
|
|
75
|
-
|
|
76
|
-
const lower = raw.toLowerCase();
|
|
77
|
-
if (!VALID_LOG_LEVELS.has(lower as LogLevel)) {
|
|
78
|
-
throw new ConfigError(
|
|
79
|
-
`PROXY_LOG_LEVEL must be one of debug, info, warn, error — got "${raw}"`,
|
|
80
|
-
);
|
|
81
|
-
}
|
|
82
|
-
return lower as LogLevel;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
/**
|
|
86
|
-
* Dedicated error class for configuration validation failures.
|
|
87
|
-
* The entrypoint catches this to print a clean message without a stack trace.
|
|
88
|
-
*/
|
|
89
|
-
export class ConfigError extends Error {
|
|
90
|
-
constructor(message: string) {
|
|
91
|
-
super(message);
|
|
92
|
-
this.name = "ConfigError";
|
|
93
|
-
}
|
|
94
|
-
}
|
|
@@ -9,8 +9,6 @@
|
|
|
9
9
|
* All other paths return 404. Non-GET methods return 405.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { createServer, type Server } from "node:http";
|
|
13
|
-
|
|
14
12
|
export interface HealthServerOptions {
|
|
15
13
|
/**
|
|
16
14
|
* Callback that returns `true` when the proxy server is ready to accept
|
|
@@ -18,45 +16,3 @@ export interface HealthServerOptions {
|
|
|
18
16
|
*/
|
|
19
17
|
isReady: () => boolean;
|
|
20
18
|
}
|
|
21
|
-
|
|
22
|
-
/**
|
|
23
|
-
* Create an HTTP server that serves health and readiness endpoints.
|
|
24
|
-
*
|
|
25
|
-
* The returned server is not yet listening -- the caller is responsible for
|
|
26
|
-
* calling `.listen()`.
|
|
27
|
-
*/
|
|
28
|
-
export function createHealthServer(options: HealthServerOptions): Server {
|
|
29
|
-
const { isReady } = options;
|
|
30
|
-
|
|
31
|
-
const server = createServer((req, res) => {
|
|
32
|
-
// Only support GET requests
|
|
33
|
-
if (req.method !== "GET") {
|
|
34
|
-
res.writeHead(405, { "Content-Type": "text/plain", Allow: "GET" });
|
|
35
|
-
res.end("Method Not Allowed\n");
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
switch (req.url) {
|
|
40
|
-
case "/healthz": {
|
|
41
|
-
res.writeHead(200, { "Content-Type": "application/json" });
|
|
42
|
-
res.end(JSON.stringify({ status: "ok" }));
|
|
43
|
-
return;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
case "/readyz": {
|
|
47
|
-
const ready = isReady();
|
|
48
|
-
const statusCode = ready ? 200 : 503;
|
|
49
|
-
res.writeHead(statusCode, { "Content-Type": "application/json" });
|
|
50
|
-
res.end(JSON.stringify({ status: ready ? "ready" : "not_ready" }));
|
|
51
|
-
return;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
default: {
|
|
55
|
-
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
56
|
-
res.end("Not Found\n");
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
return server;
|
|
62
|
-
}
|
|
@@ -27,19 +27,6 @@ export type {
|
|
|
27
27
|
// ---------------------------------------------------------------------------
|
|
28
28
|
|
|
29
29
|
export type { ManagedSession, SessionStartHooks } from "@vellumai/egress-proxy";
|
|
30
|
-
export {
|
|
31
|
-
cloneSession,
|
|
32
|
-
createSession,
|
|
33
|
-
credentialIdsMatch,
|
|
34
|
-
getActiveSession,
|
|
35
|
-
getOrStartSession,
|
|
36
|
-
getSessionEnv,
|
|
37
|
-
getSessionsForConversation,
|
|
38
|
-
SessionStore,
|
|
39
|
-
startSession,
|
|
40
|
-
stopAllSessions,
|
|
41
|
-
stopSession,
|
|
42
|
-
} from "@vellumai/egress-proxy";
|
|
43
30
|
|
|
44
31
|
// ---------------------------------------------------------------------------
|
|
45
32
|
// Host pattern matching
|
|
@@ -49,36 +36,28 @@ export type {
|
|
|
49
36
|
HostMatchKind,
|
|
50
37
|
MatchHostPatternOptions,
|
|
51
38
|
} from "./host-pattern-match.js";
|
|
52
|
-
export {
|
|
53
|
-
compareMatchSpecificity,
|
|
54
|
-
matchHostPattern,
|
|
55
|
-
} from "./host-pattern-match.js";
|
|
56
39
|
|
|
57
40
|
// Certificate management
|
|
58
41
|
export {
|
|
59
42
|
ensureCombinedCABundle,
|
|
60
43
|
ensureLocalCA,
|
|
61
44
|
getCAPath,
|
|
62
|
-
getCombinedCAPath,
|
|
63
45
|
issueLeafCert,
|
|
64
46
|
} from "./certs.js";
|
|
65
47
|
|
|
66
48
|
// MITM handler
|
|
67
49
|
export type { RewriteCallback } from "./mitm-handler.js";
|
|
68
|
-
export { handleMitm } from "./mitm-handler.js";
|
|
69
50
|
|
|
70
51
|
// Router
|
|
71
52
|
export type { RouteDecision, RouteReason } from "./router.js";
|
|
72
53
|
export { routeConnection } from "./router.js";
|
|
73
54
|
|
|
74
55
|
// CONNECT tunnel
|
|
75
|
-
export { handleConnect } from "./connect-tunnel.js";
|
|
76
56
|
|
|
77
57
|
// Policy engine
|
|
78
58
|
export { evaluateRequest, evaluateRequestWithApproval } from "./policy.js";
|
|
79
59
|
|
|
80
60
|
// HTTP forwarder
|
|
81
|
-
export { forwardHttpRequest } from "./http-forwarder.js";
|
|
82
61
|
|
|
83
62
|
// Proxy server
|
|
84
63
|
export type { MitmHandlerConfig, ProxyServerConfig } from "./server.js";
|
|
@@ -89,7 +68,6 @@ export type { SidecarConfig } from "./config.js";
|
|
|
89
68
|
|
|
90
69
|
// Health / readiness server
|
|
91
70
|
export type { HealthServerOptions } from "./health.js";
|
|
92
|
-
export { createHealthServer } from "./health.js";
|
|
93
71
|
|
|
94
72
|
// Logging/diagnostics
|
|
95
73
|
export type { CredentialRefTrace, ProxyDecisionTrace } from "./logging.js";
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import { mapApprovalProvenance } from "./approval-provenance.js";
|
|
4
|
+
import type { ApprovalMode, RiskThreshold } from "./types.js";
|
|
5
|
+
import { RISK_ORDINAL, THRESHOLD_ORDINAL } from "./types.js";
|
|
6
|
+
|
|
7
|
+
// ── mapApprovalProvenance — one test per row of the decision mapping table ────
|
|
8
|
+
|
|
9
|
+
describe("mapApprovalProvenance", () => {
|
|
10
|
+
test("platform_auto_approve → auto / platform_auto_approve", () => {
|
|
11
|
+
const r = mapApprovalProvenance("platform_auto_approve", {});
|
|
12
|
+
expect(r.approvalMode).toBe("auto");
|
|
13
|
+
expect(r.approvalReason).toBe("platform_auto_approve");
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test("guardian_auto_approve → auto / within_threshold", () => {
|
|
17
|
+
const r = mapApprovalProvenance("guardian_auto_approve", {});
|
|
18
|
+
expect(r.approvalMode).toBe("auto");
|
|
19
|
+
expect(r.approvalReason).toBe("within_threshold");
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("allow + sandbox → auto / sandbox_auto_approve", () => {
|
|
23
|
+
const r = mapApprovalProvenance("allow", { hasSandboxAutoApprove: true });
|
|
24
|
+
expect(r.approvalMode).toBe("auto");
|
|
25
|
+
expect(r.approvalReason).toBe("sandbox_auto_approve");
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test("allow + trust rule → auto / trust_rule_allowed", () => {
|
|
29
|
+
const r = mapApprovalProvenance("allow", { matchedTrustRuleId: "rule-abc" });
|
|
30
|
+
expect(r.approvalMode).toBe("auto");
|
|
31
|
+
expect(r.approvalReason).toBe("trust_rule_allowed");
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
test("allow (no trust rule, no sandbox) → auto / within_threshold", () => {
|
|
35
|
+
const r = mapApprovalProvenance("allow", {});
|
|
36
|
+
expect(r.approvalMode).toBe("auto");
|
|
37
|
+
expect(r.approvalReason).toBe("within_threshold");
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test("allow + wasPrompted → prompted / user_approved", () => {
|
|
41
|
+
const r = mapApprovalProvenance("allow", { wasPrompted: true });
|
|
42
|
+
expect(r.approvalMode).toBe("prompted");
|
|
43
|
+
expect(r.approvalReason).toBe("user_approved");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test("deny (user pressed deny) → prompted / user_denied", () => {
|
|
47
|
+
const r = mapApprovalProvenance("deny", {});
|
|
48
|
+
expect(r.approvalMode).toBe("prompted");
|
|
49
|
+
expect(r.approvalReason).toBe("user_denied");
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
test("deny + wasTimeout → prompted / timed_out", () => {
|
|
53
|
+
const r = mapApprovalProvenance("deny", { wasTimeout: true });
|
|
54
|
+
expect(r.approvalMode).toBe("prompted");
|
|
55
|
+
expect(r.approvalReason).toBe("timed_out");
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
test("deny + wasSystemCancel → prompted / system_cancelled", () => {
|
|
59
|
+
const r = mapApprovalProvenance("deny", { wasSystemCancel: true });
|
|
60
|
+
expect(r.approvalMode).toBe("prompted");
|
|
61
|
+
expect(r.approvalReason).toBe("system_cancelled");
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test("wasSystemCancel takes priority over wasTimeout", () => {
|
|
65
|
+
const r = mapApprovalProvenance("deny", { wasSystemCancel: true, wasTimeout: true });
|
|
66
|
+
expect(r.approvalReason).toBe("system_cancelled");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("denied + matchedTrustRuleId → blocked / trust_rule_denied", () => {
|
|
70
|
+
const r = mapApprovalProvenance("denied", { matchedTrustRuleId: "rule-abc" });
|
|
71
|
+
expect(r.approvalMode).toBe("blocked");
|
|
72
|
+
expect(r.approvalReason).toBe("trust_rule_denied");
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("denied (no matchedTrustRuleId) → blocked / no_interactive_client", () => {
|
|
76
|
+
const r = mapApprovalProvenance("denied", {});
|
|
77
|
+
expect(r.approvalMode).toBe("blocked");
|
|
78
|
+
expect(r.approvalReason).toBe("no_interactive_client");
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("unknown decision → unknown / unknown", () => {
|
|
82
|
+
const r = mapApprovalProvenance("something_unexpected", {});
|
|
83
|
+
expect(r.approvalMode).toBe("unknown");
|
|
84
|
+
expect(r.approvalReason).toBe("unknown");
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("sandbox takes priority over trust rule when both present", () => {
|
|
88
|
+
const r = mapApprovalProvenance("allow", {
|
|
89
|
+
hasSandboxAutoApprove: true,
|
|
90
|
+
matchedTrustRuleId: "rule-xyz",
|
|
91
|
+
});
|
|
92
|
+
expect(r.approvalReason).toBe("sandbox_auto_approve");
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("wasPrompted takes priority over sandbox when both set", () => {
|
|
96
|
+
const r = mapApprovalProvenance("allow", {
|
|
97
|
+
wasPrompted: true,
|
|
98
|
+
hasSandboxAutoApprove: true,
|
|
99
|
+
});
|
|
100
|
+
expect(r.approvalMode).toBe("prompted");
|
|
101
|
+
expect(r.approvalReason).toBe("user_approved");
|
|
102
|
+
});
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// ── RISK_ORDINAL — unknown riskLevel must not map to a safe value ─────────────
|
|
106
|
+
|
|
107
|
+
describe("RISK_ORDINAL semantics", () => {
|
|
108
|
+
test("known risk levels have expected ordinals", () => {
|
|
109
|
+
expect(RISK_ORDINAL["low"]).toBe(0);
|
|
110
|
+
expect(RISK_ORDINAL["medium"]).toBe(1);
|
|
111
|
+
expect(RISK_ORDINAL["high"]).toBe(2);
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
test("unknown riskLevel is absent so callers fall through to ?? 2 (high)", () => {
|
|
115
|
+
expect(RISK_ORDINAL["unknown"]).toBeUndefined();
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
// ── wasExpected derivation — all combinations ─────────────────────────────────
|
|
120
|
+
|
|
121
|
+
function wasExpected(
|
|
122
|
+
approvalMode: ApprovalMode,
|
|
123
|
+
riskLevel: string,
|
|
124
|
+
riskThreshold: RiskThreshold,
|
|
125
|
+
): boolean {
|
|
126
|
+
if (approvalMode !== "auto") return true;
|
|
127
|
+
return RISK_ORDINAL[riskLevel] <= THRESHOLD_ORDINAL[riskThreshold];
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
describe("wasExpected derivation", () => {
|
|
131
|
+
test("prompted outcomes are always expected", () => {
|
|
132
|
+
expect(wasExpected("prompted", "high", "none")).toBe(true);
|
|
133
|
+
expect(wasExpected("prompted", "high", "low")).toBe(true);
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
test("blocked outcomes are always expected", () => {
|
|
137
|
+
expect(wasExpected("blocked", "high", "none")).toBe(true);
|
|
138
|
+
expect(wasExpected("blocked", "medium", "low")).toBe(true);
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
test("unknown (legacy) outcomes are always expected", () => {
|
|
142
|
+
expect(wasExpected("unknown", "high", "none")).toBe(true);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
test("auto: risk within threshold → expected", () => {
|
|
146
|
+
expect(wasExpected("auto", "low", "low")).toBe(true);
|
|
147
|
+
expect(wasExpected("auto", "low", "medium")).toBe(true);
|
|
148
|
+
expect(wasExpected("auto", "medium", "medium")).toBe(true);
|
|
149
|
+
expect(wasExpected("auto", "high", "high")).toBe(true);
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
test("auto: risk above threshold → unexpected", () => {
|
|
153
|
+
expect(wasExpected("auto", "high", "low")).toBe(false);
|
|
154
|
+
expect(wasExpected("auto", "high", "medium")).toBe(false);
|
|
155
|
+
expect(wasExpected("auto", "medium", "low")).toBe(false);
|
|
156
|
+
expect(wasExpected("auto", "high", "none")).toBe(false);
|
|
157
|
+
expect(wasExpected("auto", "medium", "none")).toBe(false);
|
|
158
|
+
expect(wasExpected("auto", "low", "none")).toBe(false);
|
|
159
|
+
});
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// ── Invariant: new records must not emit approvalMode: "unknown" ──────────────
|
|
163
|
+
|
|
164
|
+
describe("approvalMode unknown invariant", () => {
|
|
165
|
+
const knownDecisions = [
|
|
166
|
+
"allow",
|
|
167
|
+
"deny",
|
|
168
|
+
"denied",
|
|
169
|
+
"platform_auto_approve",
|
|
170
|
+
"guardian_auto_approve",
|
|
171
|
+
];
|
|
172
|
+
|
|
173
|
+
test("every known decision produces a non-unknown approvalMode", () => {
|
|
174
|
+
for (const decision of knownDecisions) {
|
|
175
|
+
const r = mapApprovalProvenance(decision, {});
|
|
176
|
+
expect(r.approvalMode).not.toBe("unknown");
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
test("only unrecognised decision strings emit unknown", () => {
|
|
181
|
+
const r = mapApprovalProvenance("__legacy_unknown__", {});
|
|
182
|
+
expect(r.approvalMode).toBe("unknown");
|
|
183
|
+
});
|
|
184
|
+
});
|