@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
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Secret scanner — detects leaked secrets (API keys, tokens,
|
|
3
|
-
*
|
|
4
|
-
*
|
|
2
|
+
* Secret scanner — detects leaked secrets (API keys, tokens, private keys,
|
|
3
|
+
* connection strings, JWTs, and generic credential-style assignments) in
|
|
4
|
+
* arbitrary text via known-prefix and shape-based regex patterns. Patterns
|
|
5
|
+
* are curated from gitleaks and detect-secrets.
|
|
6
|
+
*
|
|
7
|
+
* Used by the explicit `redactSecrets()` callers (shell command summaries,
|
|
8
|
+
* approval prompts, guardian prompts, activity text). Log redaction has its
|
|
9
|
+
* own prefix-only path in `util/log-redact.ts`.
|
|
5
10
|
*/
|
|
6
11
|
|
|
7
|
-
import { getLogger } from "../util/logger.js";
|
|
8
12
|
import { isAllowlisted } from "./secret-allowlist.js";
|
|
9
13
|
import { PREFIX_PATTERNS } from "./secret-patterns.js";
|
|
10
14
|
|
|
11
|
-
const log = getLogger("secret-scanner");
|
|
12
|
-
|
|
13
15
|
export interface SecretMatch {
|
|
14
16
|
/** Human-readable type label, e.g. "AWS Access Key" */
|
|
15
17
|
type: string;
|
|
@@ -21,7 +23,7 @@ export interface SecretMatch {
|
|
|
21
23
|
redactedValue: string;
|
|
22
24
|
}
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
interface SecretPattern {
|
|
25
27
|
type: string;
|
|
26
28
|
regex: RegExp;
|
|
27
29
|
}
|
|
@@ -211,507 +213,6 @@ function isLikelyAwsSecret(value: string): boolean {
|
|
|
211
213
|
return (hasUpper && hasLower) || hasSpecial;
|
|
212
214
|
}
|
|
213
215
|
|
|
214
|
-
// ---------------------------------------------------------------------------
|
|
215
|
-
// Entropy-based detection
|
|
216
|
-
// ---------------------------------------------------------------------------
|
|
217
|
-
|
|
218
|
-
export interface EntropyConfig {
|
|
219
|
-
/** Enable entropy-based scanning. Default: true */
|
|
220
|
-
enabled: boolean;
|
|
221
|
-
/** Minimum Shannon entropy (bits per char) for hex tokens. Default: 3.0 */
|
|
222
|
-
hexThreshold: number;
|
|
223
|
-
/** Minimum Shannon entropy (bits per char) for base64 tokens. Default: 4.0 */
|
|
224
|
-
base64Threshold: number;
|
|
225
|
-
/** Minimum token length to consider. Default: 20 */
|
|
226
|
-
minLength: number;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
export const DEFAULT_ENTROPY_CONFIG: EntropyConfig = {
|
|
230
|
-
enabled: true,
|
|
231
|
-
hexThreshold: 3.0,
|
|
232
|
-
base64Threshold: 4.0,
|
|
233
|
-
minLength: 20,
|
|
234
|
-
};
|
|
235
|
-
|
|
236
|
-
/**
|
|
237
|
-
* Calculate Shannon entropy in bits per character.
|
|
238
|
-
* Higher entropy = more random = more likely to be a secret.
|
|
239
|
-
*/
|
|
240
|
-
export function shannonEntropy(s: string): number {
|
|
241
|
-
if (s.length === 0) return 0;
|
|
242
|
-
const freq = new Map<string, number>();
|
|
243
|
-
for (const ch of s) {
|
|
244
|
-
freq.set(ch, (freq.get(ch) ?? 0) + 1);
|
|
245
|
-
}
|
|
246
|
-
let entropy = 0;
|
|
247
|
-
for (const count of freq.values()) {
|
|
248
|
-
const p = count / s.length;
|
|
249
|
-
entropy -= p * Math.log2(p);
|
|
250
|
-
}
|
|
251
|
-
return entropy;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
/** Keywords that, when adjacent to a high-entropy token, boost confidence. */
|
|
255
|
-
const SECRET_CONTEXT_KEYWORDS = [
|
|
256
|
-
"key",
|
|
257
|
-
"token",
|
|
258
|
-
"secret",
|
|
259
|
-
"password",
|
|
260
|
-
"passwd",
|
|
261
|
-
"pwd",
|
|
262
|
-
"api_key",
|
|
263
|
-
"api-key",
|
|
264
|
-
"apikey",
|
|
265
|
-
"access_key",
|
|
266
|
-
"access-key",
|
|
267
|
-
"accesskey",
|
|
268
|
-
"auth_token",
|
|
269
|
-
"auth-token",
|
|
270
|
-
"authtoken",
|
|
271
|
-
"bearer",
|
|
272
|
-
"authorization",
|
|
273
|
-
"credential",
|
|
274
|
-
"credentials",
|
|
275
|
-
"private_key",
|
|
276
|
-
"private-key",
|
|
277
|
-
"client_secret",
|
|
278
|
-
"client-secret",
|
|
279
|
-
"signing_key",
|
|
280
|
-
"signing-key",
|
|
281
|
-
"encryption_key",
|
|
282
|
-
"encryption-key",
|
|
283
|
-
];
|
|
284
|
-
|
|
285
|
-
/** Match hex strings (20+ chars of [0-9a-fA-F]) */
|
|
286
|
-
const HEX_TOKEN_RE = /\b([0-9a-fA-F]{20,})\b/g;
|
|
287
|
-
|
|
288
|
-
/** Match base64 strings (20+ chars of [A-Za-z0-9+/_-]) with optional = padding.
|
|
289
|
-
* Trailing \b would fail after '=' (non-word char), so we use a lookahead. */
|
|
290
|
-
const BASE64_TOKEN_RE = /\b([A-Za-z0-9+/\-_]{20,}={0,3})(?=\W|$)/g;
|
|
291
|
-
|
|
292
|
-
/**
|
|
293
|
-
* Check whether a token appears near a secret-related keyword in the
|
|
294
|
-
* surrounding text (up to 60 chars before the match).
|
|
295
|
-
*/
|
|
296
|
-
/** Pre-compiled word-boundary regex for each context keyword. */
|
|
297
|
-
const SECRET_CONTEXT_RES = SECRET_CONTEXT_KEYWORDS.map(
|
|
298
|
-
(kw) =>
|
|
299
|
-
new RegExp(
|
|
300
|
-
`(?:^|[^a-z0-9])${kw.replace(/[-]/g, "\\$&")}(?:[^a-z0-9]|$)`,
|
|
301
|
-
"i",
|
|
302
|
-
),
|
|
303
|
-
);
|
|
304
|
-
|
|
305
|
-
function hasSecretContext(text: string, matchStart: number): boolean {
|
|
306
|
-
// Look at up to 60 chars before the token for context keywords
|
|
307
|
-
const contextStart = Math.max(0, matchStart - 60);
|
|
308
|
-
const prefix = text.slice(contextStart, matchStart);
|
|
309
|
-
return SECRET_CONTEXT_RES.some((re) => re.test(prefix));
|
|
310
|
-
}
|
|
311
|
-
|
|
312
|
-
/**
|
|
313
|
-
* Check if a string is purely hex characters.
|
|
314
|
-
*/
|
|
315
|
-
function isHex(s: string): boolean {
|
|
316
|
-
return /^[0-9a-fA-F]+$/.test(s);
|
|
317
|
-
}
|
|
318
|
-
|
|
319
|
-
/**
|
|
320
|
-
* Check if a string looks like base64 (has mixed case or base64 special chars).
|
|
321
|
-
*/
|
|
322
|
-
function isBase64Like(s: string): boolean {
|
|
323
|
-
return /[A-Za-z]/.test(s) && /[0-9]/.test(s) && /[+/\-_=]/.test(s);
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
/**
|
|
327
|
-
* Scan for high-entropy tokens that may be secrets not matching known patterns.
|
|
328
|
-
* Returns matches only for tokens with entropy above the configured threshold
|
|
329
|
-
* AND that appear in a secret-related context (near keywords like "key", "token",
|
|
330
|
-
* "password", etc.).
|
|
331
|
-
*/
|
|
332
|
-
function scanEntropy(
|
|
333
|
-
text: string,
|
|
334
|
-
config: EntropyConfig,
|
|
335
|
-
existingRanges: Set<string>,
|
|
336
|
-
): SecretMatch[] {
|
|
337
|
-
if (!config.enabled) return [];
|
|
338
|
-
const matches: SecretMatch[] = [];
|
|
339
|
-
|
|
340
|
-
// Scan hex tokens
|
|
341
|
-
HEX_TOKEN_RE.lastIndex = 0;
|
|
342
|
-
let m: RegExpExecArray | null;
|
|
343
|
-
while ((m = HEX_TOKEN_RE.exec(text)) != null) {
|
|
344
|
-
const value = m[1];
|
|
345
|
-
if (value.length < config.minLength) continue;
|
|
346
|
-
const startIndex = m.index;
|
|
347
|
-
const endIndex = startIndex + value.length;
|
|
348
|
-
|
|
349
|
-
// Skip if already covered by a pattern match
|
|
350
|
-
const key = `${startIndex}:${endIndex}`;
|
|
351
|
-
if (existingRanges.has(key)) continue;
|
|
352
|
-
|
|
353
|
-
// Skip placeholders and allowlisted values
|
|
354
|
-
if (isPlaceholder(value)) continue;
|
|
355
|
-
if (isAllowlisted(value)) continue;
|
|
356
|
-
|
|
357
|
-
const entropy = shannonEntropy(value);
|
|
358
|
-
if (entropy < config.hexThreshold) continue;
|
|
359
|
-
|
|
360
|
-
// Require secret-related context to reduce false positives
|
|
361
|
-
if (!hasSecretContext(text, startIndex)) continue;
|
|
362
|
-
|
|
363
|
-
existingRanges.add(key);
|
|
364
|
-
matches.push({
|
|
365
|
-
type: "High-Entropy Hex Token",
|
|
366
|
-
startIndex,
|
|
367
|
-
endIndex,
|
|
368
|
-
redactedValue: redact(value),
|
|
369
|
-
});
|
|
370
|
-
}
|
|
371
|
-
|
|
372
|
-
// Scan base64 tokens
|
|
373
|
-
BASE64_TOKEN_RE.lastIndex = 0;
|
|
374
|
-
while ((m = BASE64_TOKEN_RE.exec(text)) != null) {
|
|
375
|
-
const value = m[1];
|
|
376
|
-
if (value.length < config.minLength) continue;
|
|
377
|
-
// Must look like base64 (not pure alphanumeric) or pure hex
|
|
378
|
-
if (isHex(value)) continue; // Already handled above
|
|
379
|
-
if (!isBase64Like(value) && !/[A-Z]/.test(value)) continue;
|
|
380
|
-
|
|
381
|
-
const startIndex = m.index;
|
|
382
|
-
const endIndex = startIndex + value.length;
|
|
383
|
-
|
|
384
|
-
const key = `${startIndex}:${endIndex}`;
|
|
385
|
-
if (existingRanges.has(key)) continue;
|
|
386
|
-
|
|
387
|
-
if (isPlaceholder(value)) continue;
|
|
388
|
-
if (isAllowlisted(value)) continue;
|
|
389
|
-
|
|
390
|
-
const entropy = shannonEntropy(value);
|
|
391
|
-
if (entropy < config.base64Threshold) continue;
|
|
392
|
-
|
|
393
|
-
if (!hasSecretContext(text, startIndex)) continue;
|
|
394
|
-
|
|
395
|
-
existingRanges.add(key);
|
|
396
|
-
matches.push({
|
|
397
|
-
type: "High-Entropy Base64 Token",
|
|
398
|
-
startIndex,
|
|
399
|
-
endIndex,
|
|
400
|
-
redactedValue: redact(value),
|
|
401
|
-
});
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
return matches;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
// ---------------------------------------------------------------------------
|
|
408
|
-
// Encoded secret detection — decode + re-scan pass
|
|
409
|
-
// ---------------------------------------------------------------------------
|
|
410
|
-
|
|
411
|
-
/**
|
|
412
|
-
* Find percent-encoded segments containing 3+ encoded bytes, using a linear
|
|
413
|
-
* scan instead of a regex with nested quantifiers (which caused catastrophic
|
|
414
|
-
* backtracking on long near-miss inputs).
|
|
415
|
-
*/
|
|
416
|
-
function findPercentEncodedSegments(
|
|
417
|
-
text: string,
|
|
418
|
-
): Array<{ start: number; end: number; match: string }> {
|
|
419
|
-
const results: Array<{ start: number; end: number; match: string }> = [];
|
|
420
|
-
const len = text.length;
|
|
421
|
-
const isUrlChar = (ch: string) => /[A-Za-z0-9_.~+/\-]/.test(ch);
|
|
422
|
-
const isHexDigit = (ch: string) => /[0-9A-Fa-f]/.test(ch);
|
|
423
|
-
|
|
424
|
-
let i = 0;
|
|
425
|
-
while (i < len) {
|
|
426
|
-
// Look for the start of a percent-encoded segment
|
|
427
|
-
if (text[i] !== "%" && !isUrlChar(text[i])) {
|
|
428
|
-
i++;
|
|
429
|
-
continue;
|
|
430
|
-
}
|
|
431
|
-
|
|
432
|
-
// Walk a candidate segment of URL-safe chars and %XX sequences
|
|
433
|
-
const start = i;
|
|
434
|
-
let pctCount = 0;
|
|
435
|
-
while (i < len) {
|
|
436
|
-
if (
|
|
437
|
-
text[i] === "%" &&
|
|
438
|
-
i + 2 < len &&
|
|
439
|
-
isHexDigit(text[i + 1]) &&
|
|
440
|
-
isHexDigit(text[i + 2])
|
|
441
|
-
) {
|
|
442
|
-
pctCount++;
|
|
443
|
-
i += 3;
|
|
444
|
-
} else if (isUrlChar(text[i])) {
|
|
445
|
-
i++;
|
|
446
|
-
} else {
|
|
447
|
-
break;
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
if (pctCount >= 3) {
|
|
452
|
-
results.push({ start, end: i, match: text.slice(start, i) });
|
|
453
|
-
}
|
|
454
|
-
// Avoid re-scanning the same position if we didn't advance
|
|
455
|
-
if (i === start) i++;
|
|
456
|
-
}
|
|
457
|
-
return results;
|
|
458
|
-
}
|
|
459
|
-
|
|
460
|
-
/** Hex-escape sequences: \xHH patterns (3+ consecutive) */
|
|
461
|
-
const HEX_ESCAPE_RE = /(?:\\x[0-9A-Fa-f]{2}){3,}/g;
|
|
462
|
-
|
|
463
|
-
/** Candidate base64 segments — 24+ chars that could encode a secret (≥18 decoded bytes) */
|
|
464
|
-
const ENCODED_BASE64_RE = /\b([A-Za-z0-9+/\-_]{24,}={0,3})(?=\W|$)/g;
|
|
465
|
-
|
|
466
|
-
/** Continuous hex-encoded bytes — 32+ hex chars (16+ bytes decoded) */
|
|
467
|
-
const CONTINUOUS_HEX_RE = /\b([0-9a-fA-F]{32,})\b/g;
|
|
468
|
-
|
|
469
|
-
/** Check if decoded content is printable ASCII text */
|
|
470
|
-
function isPrintableText(s: string): boolean {
|
|
471
|
-
return s.length > 0 && /^[\x20-\x7E\t\n\r]+$/.test(s);
|
|
472
|
-
}
|
|
473
|
-
|
|
474
|
-
function tryDecodeBase64(encoded: string): string | null {
|
|
475
|
-
try {
|
|
476
|
-
// Handle both standard and URL-safe base64
|
|
477
|
-
const standardized = encoded.replace(/-/g, "+").replace(/_/g, "/");
|
|
478
|
-
const decoded = Buffer.from(standardized, "base64").toString("utf-8");
|
|
479
|
-
if (!isPrintableText(decoded)) return null;
|
|
480
|
-
// Verify round-trip to reject garbage decodes
|
|
481
|
-
const reEncoded = Buffer.from(decoded, "utf-8")
|
|
482
|
-
.toString("base64")
|
|
483
|
-
.replace(/=+$/, "");
|
|
484
|
-
if (standardized.replace(/=+$/, "") !== reEncoded) return null;
|
|
485
|
-
return decoded;
|
|
486
|
-
} catch {
|
|
487
|
-
return null;
|
|
488
|
-
}
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
function tryDecodePercentEncoded(encoded: string): string | null {
|
|
492
|
-
try {
|
|
493
|
-
const decoded = decodeURIComponent(encoded);
|
|
494
|
-
if (decoded === encoded) return null;
|
|
495
|
-
if (!isPrintableText(decoded)) return null;
|
|
496
|
-
return decoded;
|
|
497
|
-
} catch {
|
|
498
|
-
return null;
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
function tryDecodeHexEscapes(encoded: string): string | null {
|
|
503
|
-
try {
|
|
504
|
-
const decoded = encoded.replace(/\\x([0-9A-Fa-f]{2})/g, (_, hex) =>
|
|
505
|
-
String.fromCharCode(parseInt(hex, 16)),
|
|
506
|
-
);
|
|
507
|
-
if (decoded === encoded) return null;
|
|
508
|
-
if (!isPrintableText(decoded)) return null;
|
|
509
|
-
return decoded;
|
|
510
|
-
} catch {
|
|
511
|
-
return null;
|
|
512
|
-
}
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
function tryDecodeContinuousHex(encoded: string): string | null {
|
|
516
|
-
try {
|
|
517
|
-
// Odd-length strings can't be decoded as pairs of hex digits
|
|
518
|
-
if (encoded.length % 2 !== 0) return null;
|
|
519
|
-
// Decode pairs of hex digits to bytes
|
|
520
|
-
const bytes: number[] = [];
|
|
521
|
-
for (let i = 0; i < encoded.length; i += 2) {
|
|
522
|
-
bytes.push(parseInt(encoded.slice(i, i + 2), 16));
|
|
523
|
-
}
|
|
524
|
-
const decoded = String.fromCharCode(...bytes);
|
|
525
|
-
if (!isPrintableText(decoded)) return null;
|
|
526
|
-
return decoded;
|
|
527
|
-
} catch {
|
|
528
|
-
return null;
|
|
529
|
-
}
|
|
530
|
-
}
|
|
531
|
-
|
|
532
|
-
/** Check if an encoded segment overlaps with any existing match range */
|
|
533
|
-
function overlapsExisting(
|
|
534
|
-
start: number,
|
|
535
|
-
end: number,
|
|
536
|
-
ranges: Set<string>,
|
|
537
|
-
): boolean {
|
|
538
|
-
for (const rangeKey of ranges) {
|
|
539
|
-
const sep = rangeKey.indexOf(":");
|
|
540
|
-
const rStart = Number(rangeKey.slice(0, sep));
|
|
541
|
-
const rEnd = Number(rangeKey.slice(sep + 1));
|
|
542
|
-
if (start < rEnd && end > rStart) return true;
|
|
543
|
-
}
|
|
544
|
-
return false;
|
|
545
|
-
}
|
|
546
|
-
|
|
547
|
-
/**
|
|
548
|
-
* Scan for encoded secrets by decoding candidate segments and running
|
|
549
|
-
* pattern matching on the decoded content. Catches base64-encoded,
|
|
550
|
-
* hex-encoded, and percent-encoded secrets that raw regex would miss.
|
|
551
|
-
*/
|
|
552
|
-
function scanEncoded(
|
|
553
|
-
text: string,
|
|
554
|
-
existingRanges: Set<string>,
|
|
555
|
-
customPatterns?: SecretPattern[],
|
|
556
|
-
): SecretMatch[] {
|
|
557
|
-
const matches: SecretMatch[] = [];
|
|
558
|
-
const allPatterns = customPatterns?.length
|
|
559
|
-
? [...PATTERNS, ...customPatterns]
|
|
560
|
-
: PATTERNS;
|
|
561
|
-
|
|
562
|
-
// Helper: try to match decoded content against known secret patterns
|
|
563
|
-
const tryMatchDecoded = (
|
|
564
|
-
encoded: string,
|
|
565
|
-
decoded: string,
|
|
566
|
-
startIndex: number,
|
|
567
|
-
endIndex: number,
|
|
568
|
-
encoding: string,
|
|
569
|
-
) => {
|
|
570
|
-
for (const pattern of allPatterns) {
|
|
571
|
-
pattern.regex.lastIndex = 0;
|
|
572
|
-
let pm: RegExpExecArray | null;
|
|
573
|
-
while ((pm = pattern.regex.exec(decoded)) != null) {
|
|
574
|
-
if (pm[0].length === 0) {
|
|
575
|
-
pattern.regex.lastIndex++;
|
|
576
|
-
continue;
|
|
577
|
-
}
|
|
578
|
-
const value = pm[1] ?? pm[0];
|
|
579
|
-
if (isPlaceholder(value)) continue;
|
|
580
|
-
if (isAllowlisted(value)) continue;
|
|
581
|
-
if (pattern.type === "AWS Secret Key" && !isLikelyAwsSecret(value))
|
|
582
|
-
continue;
|
|
583
|
-
|
|
584
|
-
const key = `${startIndex}:${endIndex}`;
|
|
585
|
-
existingRanges.add(key);
|
|
586
|
-
matches.push({
|
|
587
|
-
type: `${pattern.type} (${encoding})`,
|
|
588
|
-
startIndex,
|
|
589
|
-
endIndex,
|
|
590
|
-
redactedValue: redact(encoded),
|
|
591
|
-
});
|
|
592
|
-
return;
|
|
593
|
-
}
|
|
594
|
-
}
|
|
595
|
-
};
|
|
596
|
-
|
|
597
|
-
// Percent-encoded segments: use linear-time scanner instead of regex
|
|
598
|
-
if (text.includes("%")) {
|
|
599
|
-
for (const seg of findPercentEncodedSegments(text)) {
|
|
600
|
-
if (seg.match.length > 1000) continue;
|
|
601
|
-
if (overlapsExisting(seg.start, seg.end, existingRanges)) continue;
|
|
602
|
-
const decoded = tryDecodePercentEncoded(seg.match);
|
|
603
|
-
if (!decoded) continue;
|
|
604
|
-
tryMatchDecoded(
|
|
605
|
-
seg.match,
|
|
606
|
-
decoded,
|
|
607
|
-
seg.start,
|
|
608
|
-
seg.end,
|
|
609
|
-
"percent-encoded",
|
|
610
|
-
);
|
|
611
|
-
}
|
|
612
|
-
}
|
|
613
|
-
|
|
614
|
-
// Regex-based decoders for the remaining encodings
|
|
615
|
-
const decoders: Array<{
|
|
616
|
-
regex: RegExp;
|
|
617
|
-
decode: (s: string) => string | null;
|
|
618
|
-
encoding: string;
|
|
619
|
-
quickCheck?: (t: string) => boolean;
|
|
620
|
-
}> = [
|
|
621
|
-
{
|
|
622
|
-
regex: HEX_ESCAPE_RE,
|
|
623
|
-
decode: tryDecodeHexEscapes,
|
|
624
|
-
encoding: "hex-escaped",
|
|
625
|
-
quickCheck: (t) => t.includes("\\x"),
|
|
626
|
-
},
|
|
627
|
-
{
|
|
628
|
-
regex: ENCODED_BASE64_RE,
|
|
629
|
-
decode: tryDecodeBase64,
|
|
630
|
-
encoding: "base64-encoded",
|
|
631
|
-
},
|
|
632
|
-
{
|
|
633
|
-
regex: CONTINUOUS_HEX_RE,
|
|
634
|
-
decode: tryDecodeContinuousHex,
|
|
635
|
-
encoding: "hex-encoded",
|
|
636
|
-
},
|
|
637
|
-
];
|
|
638
|
-
|
|
639
|
-
for (const { regex, decode, encoding, quickCheck } of decoders) {
|
|
640
|
-
if (quickCheck && !quickCheck(text)) continue;
|
|
641
|
-
regex.lastIndex = 0;
|
|
642
|
-
let m: RegExpExecArray | null;
|
|
643
|
-
while ((m = regex.exec(text)) != null) {
|
|
644
|
-
const encoded = m[1] ?? m[0];
|
|
645
|
-
if (encoded.length > 1000) continue;
|
|
646
|
-
const startIndex = m.index + m[0].indexOf(encoded);
|
|
647
|
-
const endIndex = startIndex + encoded.length;
|
|
648
|
-
|
|
649
|
-
if (overlapsExisting(startIndex, endIndex, existingRanges)) continue;
|
|
650
|
-
|
|
651
|
-
const decoded = decode(encoded);
|
|
652
|
-
if (!decoded) continue;
|
|
653
|
-
|
|
654
|
-
tryMatchDecoded(encoded, decoded, startIndex, endIndex, encoding);
|
|
655
|
-
}
|
|
656
|
-
}
|
|
657
|
-
|
|
658
|
-
return matches;
|
|
659
|
-
}
|
|
660
|
-
|
|
661
|
-
// ---------------------------------------------------------------------------
|
|
662
|
-
// Custom pattern support
|
|
663
|
-
// ---------------------------------------------------------------------------
|
|
664
|
-
|
|
665
|
-
export interface CustomPatternInput {
|
|
666
|
-
label: string;
|
|
667
|
-
pattern: string;
|
|
668
|
-
}
|
|
669
|
-
|
|
670
|
-
/**
|
|
671
|
-
* Compile user-provided custom patterns into SecretPattern objects.
|
|
672
|
-
* Invalid regex patterns and patterns that can match empty strings are
|
|
673
|
-
* logged and skipped — an empty-match pattern would cause infinite loops
|
|
674
|
-
* in the `while (regex.exec(...))` scanning loops.
|
|
675
|
-
*/
|
|
676
|
-
export function compileCustomPatterns(
|
|
677
|
-
inputs: CustomPatternInput[],
|
|
678
|
-
): SecretPattern[] {
|
|
679
|
-
const compiled: SecretPattern[] = [];
|
|
680
|
-
for (const { label, pattern } of inputs) {
|
|
681
|
-
try {
|
|
682
|
-
const regex = new RegExp(pattern, "g");
|
|
683
|
-
if (regex.test("")) {
|
|
684
|
-
log.warn(
|
|
685
|
-
{ label, pattern },
|
|
686
|
-
"Skipping custom secret pattern that matches empty strings",
|
|
687
|
-
);
|
|
688
|
-
continue;
|
|
689
|
-
}
|
|
690
|
-
// Zero-width assertions (lookaheads, \b, etc.) pass the empty-string check
|
|
691
|
-
// but still produce zero-length matches on real text, stalling the exec loop.
|
|
692
|
-
regex.lastIndex = 0;
|
|
693
|
-
const sampleMatch = regex.exec(
|
|
694
|
-
"abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_-/+=",
|
|
695
|
-
);
|
|
696
|
-
regex.lastIndex = 0;
|
|
697
|
-
if (sampleMatch && sampleMatch[0].length === 0) {
|
|
698
|
-
log.warn(
|
|
699
|
-
{ label, pattern },
|
|
700
|
-
"Skipping custom secret pattern that produces zero-length matches",
|
|
701
|
-
);
|
|
702
|
-
continue;
|
|
703
|
-
}
|
|
704
|
-
compiled.push({ type: label, regex });
|
|
705
|
-
} catch (err) {
|
|
706
|
-
log.warn(
|
|
707
|
-
{ label, pattern, error: String(err) },
|
|
708
|
-
"Skipping invalid custom secret pattern",
|
|
709
|
-
);
|
|
710
|
-
}
|
|
711
|
-
}
|
|
712
|
-
return compiled;
|
|
713
|
-
}
|
|
714
|
-
|
|
715
216
|
// ---------------------------------------------------------------------------
|
|
716
217
|
// Scan function
|
|
717
218
|
// ---------------------------------------------------------------------------
|
|
@@ -720,25 +221,13 @@ export function compileCustomPatterns(
|
|
|
720
221
|
* Scan text for leaked secrets. Returns an array of matches sorted by
|
|
721
222
|
* position. Each match includes the secret type, position, and a redacted
|
|
722
223
|
* preview of the matched value.
|
|
723
|
-
*
|
|
724
|
-
* @param entropyConfig — optional config for entropy-based scanning.
|
|
725
|
-
* Pass `{ enabled: false }` to disable. Defaults to DEFAULT_ENTROPY_CONFIG.
|
|
726
|
-
* @param customPatterns — optional user-defined patterns to apply alongside built-in ones.
|
|
727
224
|
*/
|
|
728
|
-
export function scanText(
|
|
729
|
-
text: string,
|
|
730
|
-
entropyConfig?: Partial<EntropyConfig>,
|
|
731
|
-
customPatterns?: SecretPattern[],
|
|
732
|
-
): SecretMatch[] {
|
|
225
|
+
export function scanText(text: string): SecretMatch[] {
|
|
733
226
|
const matches: SecretMatch[] = [];
|
|
734
227
|
// De-duplicate overlapping ranges (a match can fire on multiple patterns)
|
|
735
228
|
const seen = new Set<string>();
|
|
736
229
|
|
|
737
|
-
const
|
|
738
|
-
? [...PATTERNS, ...customPatterns]
|
|
739
|
-
: PATTERNS;
|
|
740
|
-
|
|
741
|
-
for (const pattern of allPatterns) {
|
|
230
|
+
for (const pattern of PATTERNS) {
|
|
742
231
|
// Reset lastIndex for global regexes
|
|
743
232
|
pattern.regex.lastIndex = 0;
|
|
744
233
|
let m: RegExpExecArray | null;
|
|
@@ -773,15 +262,6 @@ export function scanText(
|
|
|
773
262
|
}
|
|
774
263
|
}
|
|
775
264
|
|
|
776
|
-
// Entropy-based scanning for tokens that don't match known patterns
|
|
777
|
-
const eConfig = { ...DEFAULT_ENTROPY_CONFIG, ...entropyConfig };
|
|
778
|
-
const entropyMatches = scanEntropy(text, eConfig, seen);
|
|
779
|
-
matches.push(...entropyMatches);
|
|
780
|
-
|
|
781
|
-
// Encoded secret detection — decode candidate segments and re-scan
|
|
782
|
-
const encodedMatches = scanEncoded(text, seen, customPatterns);
|
|
783
|
-
matches.push(...encodedMatches);
|
|
784
|
-
|
|
785
265
|
// Sort by position; at same start, wider match first so redaction covers the full span
|
|
786
266
|
matches.sort(
|
|
787
267
|
(a, b) => a.startIndex - b.startIndex || b.endIndex - a.endIndex,
|
|
@@ -793,12 +273,8 @@ export function scanText(
|
|
|
793
273
|
* Replace detected secrets in text with redaction markers.
|
|
794
274
|
* Returns the modified text.
|
|
795
275
|
*/
|
|
796
|
-
export function redactSecrets(
|
|
797
|
-
text
|
|
798
|
-
entropyConfig?: Partial<EntropyConfig>,
|
|
799
|
-
customPatterns?: SecretPattern[],
|
|
800
|
-
): string {
|
|
801
|
-
const matches = scanText(text, entropyConfig, customPatterns);
|
|
276
|
+
export function redactSecrets(text: string): string {
|
|
277
|
+
const matches = scanText(text);
|
|
802
278
|
if (matches.length === 0) return text;
|
|
803
279
|
|
|
804
280
|
let result = "";
|
|
@@ -822,13 +298,4 @@ export function redactSecrets(
|
|
|
822
298
|
}
|
|
823
299
|
|
|
824
300
|
// Exported for testing only
|
|
825
|
-
export {
|
|
826
|
-
hasSecretContext as _hasSecretContext,
|
|
827
|
-
isPlaceholder as _isPlaceholder,
|
|
828
|
-
PATTERNS as _PATTERNS,
|
|
829
|
-
redact as _redact,
|
|
830
|
-
tryDecodeBase64 as _tryDecodeBase64,
|
|
831
|
-
tryDecodeContinuousHex as _tryDecodeContinuousHex,
|
|
832
|
-
tryDecodeHexEscapes as _tryDecodeHexEscapes,
|
|
833
|
-
tryDecodePercentEncoded as _tryDecodePercentEncoded,
|
|
834
|
-
};
|
|
301
|
+
export { isPlaceholder as _isPlaceholder };
|
|
@@ -36,6 +36,7 @@ import type {
|
|
|
36
36
|
DeleteResult,
|
|
37
37
|
} from "./credential-backend.js";
|
|
38
38
|
import { createEncryptedStoreBackend } from "./credential-backend.js";
|
|
39
|
+
import { credentialKey } from "./credential-key.js";
|
|
39
40
|
|
|
40
41
|
export type {
|
|
41
42
|
CredentialListResult,
|
|
@@ -451,6 +452,8 @@ export async function setSecureKeyAsync(
|
|
|
451
452
|
{ account, backend: backend.name },
|
|
452
453
|
"Credential backend set failed",
|
|
453
454
|
);
|
|
455
|
+
} else {
|
|
456
|
+
log.info({ account, backend: backend.name }, "Credential stored");
|
|
454
457
|
}
|
|
455
458
|
updateCesHttpReachability(backend, !ok);
|
|
456
459
|
return ok;
|
|
@@ -468,6 +471,9 @@ export async function deleteSecureKeyAsync(
|
|
|
468
471
|
return withCredentialTimeout(async () => {
|
|
469
472
|
const backend = await resolveBackendAsync();
|
|
470
473
|
const result = await backend.delete(account);
|
|
474
|
+
if (result === "deleted") {
|
|
475
|
+
log.info({ account, backend: backend.name }, "Credential deleted");
|
|
476
|
+
}
|
|
471
477
|
updateCesHttpReachability(backend, result === "error");
|
|
472
478
|
return result;
|
|
473
479
|
}, "error");
|
|
@@ -485,21 +491,31 @@ export async function bulkSetSecureKeysAsync(
|
|
|
485
491
|
return withCredentialTimeout(
|
|
486
492
|
async () => {
|
|
487
493
|
const backend = await resolveBackendAsync();
|
|
494
|
+
let results: Array<{ account: string; ok: boolean }>;
|
|
488
495
|
if (backend.bulkSet) {
|
|
489
|
-
|
|
496
|
+
results = await backend.bulkSet(credentials);
|
|
490
497
|
const anyFailed = results.some((r) => !r.ok);
|
|
491
498
|
updateCesHttpReachability(backend, anyFailed);
|
|
492
|
-
|
|
499
|
+
} else {
|
|
500
|
+
// Fallback: loop individual sets
|
|
501
|
+
results = [];
|
|
502
|
+
let anyFailed = false;
|
|
503
|
+
for (const { account, value } of credentials) {
|
|
504
|
+
const ok = await backend.set(account, value);
|
|
505
|
+
if (!ok) anyFailed = true;
|
|
506
|
+
results.push({ account, ok });
|
|
507
|
+
}
|
|
508
|
+
updateCesHttpReachability(backend, anyFailed);
|
|
493
509
|
}
|
|
494
|
-
|
|
495
|
-
const
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
510
|
+
const succeeded = results.filter((r) => r.ok).length;
|
|
511
|
+
const failed = results.filter((r) => !r.ok).length;
|
|
512
|
+
if (succeeded > 0 || failed > 0) {
|
|
513
|
+
const level = succeeded > 0 ? "info" : "warn";
|
|
514
|
+
log[level](
|
|
515
|
+
{ succeeded, failed, backend: backend.name },
|
|
516
|
+
"Bulk credential store completed",
|
|
517
|
+
);
|
|
501
518
|
}
|
|
502
|
-
updateCesHttpReachability(backend, anyFailed);
|
|
503
519
|
return results;
|
|
504
520
|
},
|
|
505
521
|
credentials.map((c) => ({ account: c.account, ok: false })),
|
|
@@ -525,7 +541,11 @@ export async function bulkSetSecureKeysAsync(
|
|
|
525
541
|
export async function getProviderKeyAsync(
|
|
526
542
|
provider: string,
|
|
527
543
|
): Promise<string | undefined> {
|
|
528
|
-
|
|
544
|
+
// Check credential namespace first; fall back to bare name for the brief
|
|
545
|
+
// startup window before migration 002 has run.
|
|
546
|
+
const stored =
|
|
547
|
+
(await getSecureKeyAsync(credentialKey(provider, "api_key"))) ??
|
|
548
|
+
(await getSecureKeyAsync(provider));
|
|
529
549
|
if (stored) return stored;
|
|
530
550
|
const envVar = getAnyProviderEnvVar(provider);
|
|
531
551
|
return envVar ? process.env[envVar] : undefined;
|