@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,17 +1,10 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
-
_hasSecretContext,
|
|
5
4
|
_isPlaceholder,
|
|
6
|
-
_redact,
|
|
7
|
-
_tryDecodeBase64,
|
|
8
|
-
_tryDecodeContinuousHex,
|
|
9
|
-
_tryDecodeHexEscapes,
|
|
10
|
-
_tryDecodePercentEncoded,
|
|
11
5
|
redactSecrets,
|
|
12
6
|
scanText,
|
|
13
7
|
type SecretMatch,
|
|
14
|
-
shannonEntropy,
|
|
15
8
|
} from "../security/secret-scanner.js";
|
|
16
9
|
|
|
17
10
|
// ---------------------------------------------------------------------------
|
|
@@ -412,20 +405,6 @@ describe("placeholder detection", () => {
|
|
|
412
405
|
// Redaction
|
|
413
406
|
// ---------------------------------------------------------------------------
|
|
414
407
|
describe("redaction", () => {
|
|
415
|
-
test("redact masks the middle of a string", () => {
|
|
416
|
-
const result = _redact("AKIAIOSFODNN7REALKEY");
|
|
417
|
-
// Should show first few + last few with stars in between
|
|
418
|
-
expect(result).toContain("*");
|
|
419
|
-
expect(result.length).toBeLessThanOrEqual(30);
|
|
420
|
-
// First chars visible
|
|
421
|
-
expect(result.startsWith("AKIA")).toBe(false); // only ~15% visible
|
|
422
|
-
expect(result.startsWith("AK")).toBe(true);
|
|
423
|
-
});
|
|
424
|
-
|
|
425
|
-
test("redact handles short strings", () => {
|
|
426
|
-
expect(_redact("short")).toBe("***");
|
|
427
|
-
});
|
|
428
|
-
|
|
429
408
|
test("redactSecrets replaces secrets in text", () => {
|
|
430
409
|
const input = `export AWS_ACCESS_KEY_ID=AKIAIOSFODNN7REALKEY`;
|
|
431
410
|
const result = redactSecrets(input);
|
|
@@ -546,154 +525,9 @@ describe("false positive resistance", () => {
|
|
|
546
525
|
});
|
|
547
526
|
|
|
548
527
|
// ---------------------------------------------------------------------------
|
|
549
|
-
//
|
|
550
|
-
// ---------------------------------------------------------------------------
|
|
551
|
-
describe("shannonEntropy", () => {
|
|
552
|
-
test("returns 0 for empty string", () => {
|
|
553
|
-
expect(shannonEntropy("")).toBe(0);
|
|
554
|
-
});
|
|
555
|
-
|
|
556
|
-
test("returns 0 for single repeated character", () => {
|
|
557
|
-
expect(shannonEntropy("aaaaaa")).toBe(0);
|
|
558
|
-
});
|
|
559
|
-
|
|
560
|
-
test("returns 1.0 for two equally distributed characters", () => {
|
|
561
|
-
expect(shannonEntropy("ababab")).toBeCloseTo(1.0, 5);
|
|
562
|
-
});
|
|
563
|
-
|
|
564
|
-
test("returns high entropy for random-looking strings", () => {
|
|
565
|
-
// A high-entropy hex string
|
|
566
|
-
const entropy = shannonEntropy("a3f8c1b2d9e4f5a6b7c8d9e0f1a2b3c4");
|
|
567
|
-
expect(entropy).toBeGreaterThan(3.0);
|
|
568
|
-
});
|
|
569
|
-
|
|
570
|
-
test("returns lower entropy for structured/repetitive content", () => {
|
|
571
|
-
const entropy = shannonEntropy("abcabcabcabcabcabc");
|
|
572
|
-
expect(entropy).toBeLessThan(2.0);
|
|
573
|
-
});
|
|
574
|
-
});
|
|
575
|
-
|
|
576
|
-
// ---------------------------------------------------------------------------
|
|
577
|
-
// Entropy-based secret detection
|
|
528
|
+
// Pass-through cases (allowlist-shaped strings that look secret-ish)
|
|
578
529
|
// ---------------------------------------------------------------------------
|
|
579
|
-
describe("
|
|
580
|
-
test("detects high-entropy hex token near secret keyword", () => {
|
|
581
|
-
const hexSecret = "a3f8c1b2d9e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8";
|
|
582
|
-
// Use context that triggers entropy detection but not generic assignment pattern
|
|
583
|
-
const input = `The signing_key is ${hexSecret}`;
|
|
584
|
-
const matches = scanText(input);
|
|
585
|
-
const entropyMatch = matches.find(
|
|
586
|
-
(m) => m.type === "High-Entropy Hex Token",
|
|
587
|
-
);
|
|
588
|
-
expect(entropyMatch).toBeDefined();
|
|
589
|
-
expect(entropyMatch!.startIndex).toBe(input.indexOf(hexSecret));
|
|
590
|
-
});
|
|
591
|
-
|
|
592
|
-
test("detects high-entropy base64 token near secret keyword", () => {
|
|
593
|
-
const b64Secret = "aB3cD4eF5gH6iJ7kL8mN+pQ/rS0tU1vW2xY3zA=";
|
|
594
|
-
// Use "is" instead of ": " to avoid triggering the generic assignment pattern
|
|
595
|
-
const input = `The token is ${b64Secret}`;
|
|
596
|
-
const matches = scanText(input);
|
|
597
|
-
const entropyMatch = matches.find(
|
|
598
|
-
(m) => m.type === "High-Entropy Base64 Token",
|
|
599
|
-
);
|
|
600
|
-
expect(entropyMatch).toBeDefined();
|
|
601
|
-
});
|
|
602
|
-
|
|
603
|
-
test("does not flag high-entropy hex without secret context", () => {
|
|
604
|
-
const hexString = "a3f8c1b2d9e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8";
|
|
605
|
-
// No secret keyword nearby — just "checksum"
|
|
606
|
-
const input = `checksum: ${hexString}`;
|
|
607
|
-
const matches = scanText(input);
|
|
608
|
-
const entropyMatches = matches.filter((m) =>
|
|
609
|
-
m.type.startsWith("High-Entropy"),
|
|
610
|
-
);
|
|
611
|
-
expect(entropyMatches).toHaveLength(0);
|
|
612
|
-
});
|
|
613
|
-
|
|
614
|
-
test("does not flag low-entropy tokens even with context", () => {
|
|
615
|
-
// Repeated pattern = low entropy
|
|
616
|
-
const lowEntropy = "abcabcabcabcabcabcabcabc";
|
|
617
|
-
const input = `secret = ${lowEntropy}`;
|
|
618
|
-
const matches = scanText(input);
|
|
619
|
-
const entropyMatches = matches.filter((m) =>
|
|
620
|
-
m.type.startsWith("High-Entropy"),
|
|
621
|
-
);
|
|
622
|
-
expect(entropyMatches).toHaveLength(0);
|
|
623
|
-
});
|
|
624
|
-
|
|
625
|
-
test("does not flag tokens shorter than minLength", () => {
|
|
626
|
-
const shortToken = "a3f8c1b2d9e4f5a6";
|
|
627
|
-
const input = `api_key = ${shortToken}`;
|
|
628
|
-
const matches = scanText(input);
|
|
629
|
-
const entropyMatches = matches.filter((m) =>
|
|
630
|
-
m.type.startsWith("High-Entropy"),
|
|
631
|
-
);
|
|
632
|
-
expect(entropyMatches).toHaveLength(0);
|
|
633
|
-
});
|
|
634
|
-
|
|
635
|
-
test("can be disabled via config", () => {
|
|
636
|
-
const hexSecret = "a3f8c1b2d9e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8";
|
|
637
|
-
const input = `api_key = ${hexSecret}`;
|
|
638
|
-
const matches = scanText(input, { enabled: false });
|
|
639
|
-
const entropyMatches = matches.filter((m) =>
|
|
640
|
-
m.type.startsWith("High-Entropy"),
|
|
641
|
-
);
|
|
642
|
-
expect(entropyMatches).toHaveLength(0);
|
|
643
|
-
});
|
|
644
|
-
|
|
645
|
-
test("respects custom threshold", () => {
|
|
646
|
-
const hexSecret = "a3f8c1b2d9e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8";
|
|
647
|
-
const input = `The signing_key is ${hexSecret}`;
|
|
648
|
-
|
|
649
|
-
// With extremely high threshold, nothing matches
|
|
650
|
-
const matchesHigh = scanText(input, { hexThreshold: 10.0 });
|
|
651
|
-
const entropyHigh = matchesHigh.filter((m) =>
|
|
652
|
-
m.type.startsWith("High-Entropy"),
|
|
653
|
-
);
|
|
654
|
-
expect(entropyHigh).toHaveLength(0);
|
|
655
|
-
|
|
656
|
-
// With low threshold, it matches
|
|
657
|
-
const matchesLow = scanText(input, { hexThreshold: 1.0 });
|
|
658
|
-
const entropyLow = matchesLow.filter((m) =>
|
|
659
|
-
m.type.startsWith("High-Entropy"),
|
|
660
|
-
);
|
|
661
|
-
expect(entropyLow.length).toBeGreaterThan(0);
|
|
662
|
-
});
|
|
663
|
-
|
|
664
|
-
test("does not double-count tokens already matched by patterns", () => {
|
|
665
|
-
// An AWS access key should only appear once (pattern match), not again as entropy
|
|
666
|
-
const input = `api_key = AKIAIOSFODNN7REALKEY`;
|
|
667
|
-
const matches = scanText(input);
|
|
668
|
-
const awsMatches = matches.filter((m) => m.type === "AWS Access Key");
|
|
669
|
-
const entropyMatches = matches.filter((m) =>
|
|
670
|
-
m.type.startsWith("High-Entropy"),
|
|
671
|
-
);
|
|
672
|
-
expect(awsMatches).toHaveLength(1);
|
|
673
|
-
// Should not have an entropy match for the same range
|
|
674
|
-
expect(entropyMatches).toHaveLength(0);
|
|
675
|
-
});
|
|
676
|
-
|
|
677
|
-
test("recognizes various secret context keywords", () => {
|
|
678
|
-
const hexSecret = "a3f8c1b2d9e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8";
|
|
679
|
-
// Use "is" instead of "=" to avoid matching the generic assignment pattern
|
|
680
|
-
const keywords = [
|
|
681
|
-
"bearer",
|
|
682
|
-
"credential",
|
|
683
|
-
"private_key",
|
|
684
|
-
"signing_key",
|
|
685
|
-
"encryption_key",
|
|
686
|
-
];
|
|
687
|
-
for (const kw of keywords) {
|
|
688
|
-
const input = `The ${kw} is ${hexSecret}`;
|
|
689
|
-
const matches = scanText(input);
|
|
690
|
-
const entropyMatches = matches.filter((m) =>
|
|
691
|
-
m.type.startsWith("High-Entropy"),
|
|
692
|
-
);
|
|
693
|
-
expect(entropyMatches.length).toBeGreaterThanOrEqual(1);
|
|
694
|
-
}
|
|
695
|
-
});
|
|
696
|
-
|
|
530
|
+
describe("pass-through behavior", () => {
|
|
697
531
|
test("does not redact Telegram invite deep links", () => {
|
|
698
532
|
const invite =
|
|
699
533
|
"https://t.me/credence_the_bot?start=iv_AbCdEfGhIjKlMnOpQrStUvWxYz0123456789-_ABCDE";
|
|
@@ -704,26 +538,6 @@ describe("entropy-based detection", () => {
|
|
|
704
538
|
});
|
|
705
539
|
});
|
|
706
540
|
|
|
707
|
-
// ---------------------------------------------------------------------------
|
|
708
|
-
// hasSecretContext helper
|
|
709
|
-
// ---------------------------------------------------------------------------
|
|
710
|
-
describe("hasSecretContext", () => {
|
|
711
|
-
test("detects keyword in prefix", () => {
|
|
712
|
-
const text = "api_key = abc123";
|
|
713
|
-
expect(_hasSecretContext(text, 10)).toBe(true);
|
|
714
|
-
});
|
|
715
|
-
|
|
716
|
-
test("returns false without keyword", () => {
|
|
717
|
-
const text = "username = abc123";
|
|
718
|
-
expect(_hasSecretContext(text, 11)).toBe(false);
|
|
719
|
-
});
|
|
720
|
-
|
|
721
|
-
test("detects keyword case-insensitively", () => {
|
|
722
|
-
const text = "API_KEY = abc123";
|
|
723
|
-
expect(_hasSecretContext(text, 10)).toBe(true);
|
|
724
|
-
});
|
|
725
|
-
});
|
|
726
|
-
|
|
727
541
|
// ---------------------------------------------------------------------------
|
|
728
542
|
// Overlapping match handling in redactSecrets (#166 feedback)
|
|
729
543
|
// ---------------------------------------------------------------------------
|
|
@@ -855,360 +669,3 @@ describe("unquoted generic secret assignments", () => {
|
|
|
855
669
|
expect(generic).toHaveLength(0);
|
|
856
670
|
});
|
|
857
671
|
});
|
|
858
|
-
|
|
859
|
-
// ---------------------------------------------------------------------------
|
|
860
|
-
// Base64 padding in entropy detection (#169 feedback)
|
|
861
|
-
// ---------------------------------------------------------------------------
|
|
862
|
-
describe("base64 padding handling", () => {
|
|
863
|
-
test("includes trailing = padding in the match", () => {
|
|
864
|
-
const b64 = "aB3cD4eF5gH6iJ7kL8mN9pQrS0tU1vW2xY3zA=";
|
|
865
|
-
const input = `token: ${b64}`;
|
|
866
|
-
const matches = scanText(input);
|
|
867
|
-
const entropyMatch = matches.find(
|
|
868
|
-
(m) => m.type === "High-Entropy Base64 Token",
|
|
869
|
-
);
|
|
870
|
-
expect(entropyMatch).toBeDefined();
|
|
871
|
-
// endIndex should include the '='
|
|
872
|
-
expect(
|
|
873
|
-
input.slice(entropyMatch!.startIndex, entropyMatch!.endIndex),
|
|
874
|
-
).toContain("=");
|
|
875
|
-
});
|
|
876
|
-
|
|
877
|
-
test("includes trailing == padding in the match", () => {
|
|
878
|
-
const b64 = "aB3cD4eF5gH6iJ7kL8mN9pQrS0tU1vW2x==";
|
|
879
|
-
const input = `token: ${b64}`;
|
|
880
|
-
const matches = scanText(input);
|
|
881
|
-
const entropyMatch = matches.find(
|
|
882
|
-
(m) => m.type === "High-Entropy Base64 Token",
|
|
883
|
-
);
|
|
884
|
-
expect(entropyMatch).toBeDefined();
|
|
885
|
-
expect(
|
|
886
|
-
input.slice(entropyMatch!.startIndex, entropyMatch!.endIndex),
|
|
887
|
-
).toContain("==");
|
|
888
|
-
});
|
|
889
|
-
|
|
890
|
-
test("redactSecrets fully redacts padded base64 tokens", () => {
|
|
891
|
-
const b64 = "aB3cD4eF5gH6iJ7kL8mN9pQrS0tU1vW2xY3zA=";
|
|
892
|
-
const input = `token: "${b64}"`;
|
|
893
|
-
const result = redactSecrets(input);
|
|
894
|
-
// No trailing '=' should leak after redaction
|
|
895
|
-
expect(result).not.toMatch(/<redacted type="[^"]+" \/>=/);
|
|
896
|
-
expect(result).toContain('<redacted type="');
|
|
897
|
-
});
|
|
898
|
-
});
|
|
899
|
-
|
|
900
|
-
// ---------------------------------------------------------------------------
|
|
901
|
-
// Word-boundary context keyword matching (#169 feedback)
|
|
902
|
-
// ---------------------------------------------------------------------------
|
|
903
|
-
describe("word-boundary context keywords", () => {
|
|
904
|
-
test('does not match "key" inside "monkey"', () => {
|
|
905
|
-
const hexSecret = "a3f8c1b2d9e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8";
|
|
906
|
-
const input = `monkey: ${hexSecret}`;
|
|
907
|
-
const matches = scanText(input);
|
|
908
|
-
const entropy = matches.filter((m) => m.type.startsWith("High-Entropy"));
|
|
909
|
-
expect(entropy).toHaveLength(0);
|
|
910
|
-
});
|
|
911
|
-
|
|
912
|
-
test('does not match "key" inside "keyboard"', () => {
|
|
913
|
-
const hexSecret = "a3f8c1b2d9e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8";
|
|
914
|
-
const input = `keyboard = ${hexSecret}`;
|
|
915
|
-
const matches = scanText(input);
|
|
916
|
-
const entropy = matches.filter((m) => m.type.startsWith("High-Entropy"));
|
|
917
|
-
expect(entropy).toHaveLength(0);
|
|
918
|
-
});
|
|
919
|
-
|
|
920
|
-
test('does not match "token" inside "tokenizer"', () => {
|
|
921
|
-
const hexSecret = "a3f8c1b2d9e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8";
|
|
922
|
-
const input = `tokenizer: ${hexSecret}`;
|
|
923
|
-
const matches = scanText(input);
|
|
924
|
-
const entropy = matches.filter((m) => m.type.startsWith("High-Entropy"));
|
|
925
|
-
expect(entropy).toHaveLength(0);
|
|
926
|
-
});
|
|
927
|
-
|
|
928
|
-
test('still matches "key" as a standalone word', () => {
|
|
929
|
-
const hexSecret = "a3f8c1b2d9e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8";
|
|
930
|
-
const input = `The key is ${hexSecret}`;
|
|
931
|
-
const matches = scanText(input);
|
|
932
|
-
const entropy = matches.filter((m) => m.type.startsWith("High-Entropy"));
|
|
933
|
-
expect(entropy.length).toBeGreaterThan(0);
|
|
934
|
-
});
|
|
935
|
-
|
|
936
|
-
test('still matches "api_key" with underscores', () => {
|
|
937
|
-
const hexSecret = "a3f8c1b2d9e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8";
|
|
938
|
-
const input = `The api_key is ${hexSecret}`;
|
|
939
|
-
const matches = scanText(input);
|
|
940
|
-
const entropy = matches.filter((m) => m.type.startsWith("High-Entropy"));
|
|
941
|
-
expect(entropy.length).toBeGreaterThan(0);
|
|
942
|
-
});
|
|
943
|
-
|
|
944
|
-
test('still matches "api-key" with hyphens', () => {
|
|
945
|
-
const hexSecret = "a3f8c1b2d9e4f5a6b7c8d9e0f1a2b3c4d5e6f7a8";
|
|
946
|
-
const input = `The api-key is ${hexSecret}`;
|
|
947
|
-
const matches = scanText(input);
|
|
948
|
-
const entropy = matches.filter((m) => m.type.startsWith("High-Entropy"));
|
|
949
|
-
expect(entropy.length).toBeGreaterThan(0);
|
|
950
|
-
});
|
|
951
|
-
});
|
|
952
|
-
|
|
953
|
-
// ---------------------------------------------------------------------------
|
|
954
|
-
// Encoded secret detection — decode + re-scan
|
|
955
|
-
// ---------------------------------------------------------------------------
|
|
956
|
-
describe("encoded secret detection", () => {
|
|
957
|
-
// -- Base64-encoded secrets --
|
|
958
|
-
describe("base64-encoded", () => {
|
|
959
|
-
test("detects base64-encoded Stripe key", () => {
|
|
960
|
-
const secret = "sk_live_abcdefghijklmnopqrstuvwx";
|
|
961
|
-
const encoded = Buffer.from(secret).toString("base64");
|
|
962
|
-
const input = `config: ${encoded}`;
|
|
963
|
-
const matches = scanText(input);
|
|
964
|
-
const found = matches.find(
|
|
965
|
-
(m) => m.type === "Stripe Secret Key (base64-encoded)",
|
|
966
|
-
);
|
|
967
|
-
expect(found).toBeDefined();
|
|
968
|
-
});
|
|
969
|
-
|
|
970
|
-
test("detects base64-encoded GitHub token", () => {
|
|
971
|
-
const secret = `ghp_${"A".repeat(36)}`;
|
|
972
|
-
const encoded = Buffer.from(secret).toString("base64");
|
|
973
|
-
const input = `value=${encoded}`;
|
|
974
|
-
const matches = scanText(input);
|
|
975
|
-
const found = matches.find(
|
|
976
|
-
(m) => m.type === "GitHub Token (base64-encoded)",
|
|
977
|
-
);
|
|
978
|
-
expect(found).toBeDefined();
|
|
979
|
-
});
|
|
980
|
-
|
|
981
|
-
test("detects base64-encoded private key header", () => {
|
|
982
|
-
const secret = "-----BEGIN RSA PRIVATE KEY-----";
|
|
983
|
-
const encoded = Buffer.from(secret).toString("base64");
|
|
984
|
-
const input = `data: ${encoded}`;
|
|
985
|
-
const matches = scanText(input);
|
|
986
|
-
const found = matches.find(
|
|
987
|
-
(m) => m.type === "Private Key (base64-encoded)",
|
|
988
|
-
);
|
|
989
|
-
expect(found).toBeDefined();
|
|
990
|
-
});
|
|
991
|
-
|
|
992
|
-
test("does not flag base64 that decodes to non-secret text", () => {
|
|
993
|
-
const encoded = Buffer.from("Hello, this is just normal text!").toString(
|
|
994
|
-
"base64",
|
|
995
|
-
);
|
|
996
|
-
const input = `data: ${encoded}`;
|
|
997
|
-
const matches = scanText(input);
|
|
998
|
-
const encoded_matches = matches.filter((m) =>
|
|
999
|
-
m.type.includes("base64-encoded"),
|
|
1000
|
-
);
|
|
1001
|
-
expect(encoded_matches).toHaveLength(0);
|
|
1002
|
-
});
|
|
1003
|
-
|
|
1004
|
-
test("does not flag base64 that decodes to binary data", () => {
|
|
1005
|
-
// Create a base64 string that decodes to non-printable bytes
|
|
1006
|
-
const binary = Buffer.from([
|
|
1007
|
-
0x00, 0x01, 0x02, 0x80, 0xff, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09,
|
|
1008
|
-
0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15,
|
|
1009
|
-
]);
|
|
1010
|
-
const encoded = binary.toString("base64");
|
|
1011
|
-
const input = `data: ${encoded}`;
|
|
1012
|
-
const matches = scanText(input);
|
|
1013
|
-
const encoded_matches = matches.filter((m) =>
|
|
1014
|
-
m.type.includes("base64-encoded"),
|
|
1015
|
-
);
|
|
1016
|
-
expect(encoded_matches).toHaveLength(0);
|
|
1017
|
-
});
|
|
1018
|
-
|
|
1019
|
-
test("does not double-count secrets already detected by raw patterns", () => {
|
|
1020
|
-
// A JWT is already detected directly — should not be re-detected as base64-encoded
|
|
1021
|
-
const header = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9";
|
|
1022
|
-
const payload =
|
|
1023
|
-
"eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ";
|
|
1024
|
-
const signature = "SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c";
|
|
1025
|
-
const jwt = `${header}.${payload}.${signature}`;
|
|
1026
|
-
const input = `token: ${jwt}`;
|
|
1027
|
-
const matches = scanText(input);
|
|
1028
|
-
const jwtMatches = matches.filter((m) => m.type === "JSON Web Token");
|
|
1029
|
-
const encodedMatches = matches.filter((m) =>
|
|
1030
|
-
m.type.includes("base64-encoded"),
|
|
1031
|
-
);
|
|
1032
|
-
expect(jwtMatches).toHaveLength(1);
|
|
1033
|
-
expect(encodedMatches).toHaveLength(0);
|
|
1034
|
-
});
|
|
1035
|
-
});
|
|
1036
|
-
|
|
1037
|
-
// -- Percent-encoded secrets --
|
|
1038
|
-
describe("percent-encoded", () => {
|
|
1039
|
-
test("detects percent-encoded database connection string", () => {
|
|
1040
|
-
const secret = "postgres://user:secret@db.example.com:5432/mydb";
|
|
1041
|
-
const encoded = encodeURIComponent(secret);
|
|
1042
|
-
const input = `url=${encoded}`;
|
|
1043
|
-
const matches = scanText(input);
|
|
1044
|
-
const found = matches.find(
|
|
1045
|
-
(m) => m.type === "Database Connection String (percent-encoded)",
|
|
1046
|
-
);
|
|
1047
|
-
expect(found).toBeDefined();
|
|
1048
|
-
});
|
|
1049
|
-
|
|
1050
|
-
test("detects percent-encoded secret assignment", () => {
|
|
1051
|
-
const encoded = "password%3D%22SuperSecret123%21%22";
|
|
1052
|
-
const input = `data=${encoded}`;
|
|
1053
|
-
const matches = scanText(input);
|
|
1054
|
-
const found = matches.find((m) => m.type.includes("percent-encoded"));
|
|
1055
|
-
expect(found).toBeDefined();
|
|
1056
|
-
});
|
|
1057
|
-
|
|
1058
|
-
test("does not flag percent-encoded non-secret text", () => {
|
|
1059
|
-
const encoded = "hello%20world%20this%20is%20normal";
|
|
1060
|
-
const input = `text=${encoded}`;
|
|
1061
|
-
const matches = scanText(input);
|
|
1062
|
-
const encoded_matches = matches.filter((m) =>
|
|
1063
|
-
m.type.includes("percent-encoded"),
|
|
1064
|
-
);
|
|
1065
|
-
expect(encoded_matches).toHaveLength(0);
|
|
1066
|
-
});
|
|
1067
|
-
});
|
|
1068
|
-
|
|
1069
|
-
// -- Hex-escaped secrets --
|
|
1070
|
-
describe("hex-escaped", () => {
|
|
1071
|
-
test("detects hex-escaped Stripe key", () => {
|
|
1072
|
-
const secret = "sk_live_abcdefghijklmnopqrstuvwx";
|
|
1073
|
-
const escaped = Array.from(secret)
|
|
1074
|
-
.map((c) => `\\x${c.charCodeAt(0).toString(16).padStart(2, "0")}`)
|
|
1075
|
-
.join("");
|
|
1076
|
-
const input = `value = "${escaped}"`;
|
|
1077
|
-
const matches = scanText(input);
|
|
1078
|
-
const found = matches.find(
|
|
1079
|
-
(m) => m.type === "Stripe Secret Key (hex-escaped)",
|
|
1080
|
-
);
|
|
1081
|
-
expect(found).toBeDefined();
|
|
1082
|
-
});
|
|
1083
|
-
|
|
1084
|
-
test("does not flag hex-escaped non-secret text", () => {
|
|
1085
|
-
const escaped = "\\x48\\x65\\x6c\\x6c\\x6f";
|
|
1086
|
-
const input = `value = "${escaped}"`;
|
|
1087
|
-
const matches = scanText(input);
|
|
1088
|
-
const encoded_matches = matches.filter((m) =>
|
|
1089
|
-
m.type.includes("hex-escaped"),
|
|
1090
|
-
);
|
|
1091
|
-
expect(encoded_matches).toHaveLength(0);
|
|
1092
|
-
});
|
|
1093
|
-
});
|
|
1094
|
-
|
|
1095
|
-
// -- Continuous hex-encoded secrets --
|
|
1096
|
-
describe("hex-encoded (continuous)", () => {
|
|
1097
|
-
test("detects hex-encoded GitHub token", () => {
|
|
1098
|
-
const secret = `ghp_${"A".repeat(36)}`;
|
|
1099
|
-
const hexEncoded = Buffer.from(secret).toString("hex");
|
|
1100
|
-
const input = `payload: ${hexEncoded}`;
|
|
1101
|
-
const matches = scanText(input);
|
|
1102
|
-
const found = matches.find(
|
|
1103
|
-
(m) => m.type === "GitHub Token (hex-encoded)",
|
|
1104
|
-
);
|
|
1105
|
-
expect(found).toBeDefined();
|
|
1106
|
-
});
|
|
1107
|
-
|
|
1108
|
-
test("detects hex-encoded AWS access key", () => {
|
|
1109
|
-
const secret = "AKIAIOSFODNN7REALKEY";
|
|
1110
|
-
const hexEncoded = Buffer.from(secret).toString("hex");
|
|
1111
|
-
const input = `data: ${hexEncoded}`;
|
|
1112
|
-
const matches = scanText(input);
|
|
1113
|
-
const found = matches.find(
|
|
1114
|
-
(m) => m.type === "AWS Access Key (hex-encoded)",
|
|
1115
|
-
);
|
|
1116
|
-
expect(found).toBeDefined();
|
|
1117
|
-
});
|
|
1118
|
-
|
|
1119
|
-
test("does not flag hex strings that decode to non-secret text", () => {
|
|
1120
|
-
const hexEncoded = Buffer.from(
|
|
1121
|
-
"This is just normal harmless text",
|
|
1122
|
-
).toString("hex");
|
|
1123
|
-
const input = `data: ${hexEncoded}`;
|
|
1124
|
-
const matches = scanText(input);
|
|
1125
|
-
const encoded_matches = matches.filter((m) =>
|
|
1126
|
-
m.type.includes("hex-encoded"),
|
|
1127
|
-
);
|
|
1128
|
-
expect(encoded_matches).toHaveLength(0);
|
|
1129
|
-
});
|
|
1130
|
-
|
|
1131
|
-
test("does not flag git SHAs or similar hex hashes", () => {
|
|
1132
|
-
// 40-char hex SHA — too short to decode to a meaningful secret
|
|
1133
|
-
const sha = "4b825dc642cb6eb9a060e54bf899d15f13fe1d7a";
|
|
1134
|
-
const input = `commit: ${sha}`;
|
|
1135
|
-
const matches = scanText(input);
|
|
1136
|
-
const encoded_matches = matches.filter((m) =>
|
|
1137
|
-
m.type.includes("hex-encoded"),
|
|
1138
|
-
);
|
|
1139
|
-
expect(encoded_matches).toHaveLength(0);
|
|
1140
|
-
});
|
|
1141
|
-
});
|
|
1142
|
-
|
|
1143
|
-
// -- Redaction of encoded secrets --
|
|
1144
|
-
describe("redaction of encoded secrets", () => {
|
|
1145
|
-
test("redactSecrets replaces base64-encoded secrets", () => {
|
|
1146
|
-
const secret = "sk_live_abcdefghijklmnopqrstuvwx";
|
|
1147
|
-
const encoded = Buffer.from(secret).toString("base64");
|
|
1148
|
-
const input = `config: ${encoded}`;
|
|
1149
|
-
const result = redactSecrets(input);
|
|
1150
|
-
expect(result).toContain(
|
|
1151
|
-
'<redacted type="Stripe Secret Key (base64-encoded)" />',
|
|
1152
|
-
);
|
|
1153
|
-
expect(result).not.toContain(encoded);
|
|
1154
|
-
});
|
|
1155
|
-
|
|
1156
|
-
test("redactSecrets replaces hex-encoded secrets", () => {
|
|
1157
|
-
const secret = `ghp_${"A".repeat(36)}`;
|
|
1158
|
-
const hexEncoded = Buffer.from(secret).toString("hex");
|
|
1159
|
-
const input = `data: ${hexEncoded}`;
|
|
1160
|
-
const result = redactSecrets(input);
|
|
1161
|
-
expect(result).toContain(
|
|
1162
|
-
'<redacted type="GitHub Token (hex-encoded)" />',
|
|
1163
|
-
);
|
|
1164
|
-
expect(result).not.toContain(hexEncoded);
|
|
1165
|
-
});
|
|
1166
|
-
});
|
|
1167
|
-
});
|
|
1168
|
-
|
|
1169
|
-
// ---------------------------------------------------------------------------
|
|
1170
|
-
// Decode helper unit tests
|
|
1171
|
-
// ---------------------------------------------------------------------------
|
|
1172
|
-
describe("decode helpers", () => {
|
|
1173
|
-
test("tryDecodeBase64 returns decoded text for valid base64", () => {
|
|
1174
|
-
const encoded = Buffer.from("sk_live_abcdefghijklmnopqrstuvwx").toString(
|
|
1175
|
-
"base64",
|
|
1176
|
-
);
|
|
1177
|
-
expect(_tryDecodeBase64(encoded)).toBe("sk_live_abcdefghijklmnopqrstuvwx");
|
|
1178
|
-
});
|
|
1179
|
-
|
|
1180
|
-
test("tryDecodeBase64 returns null for binary content", () => {
|
|
1181
|
-
const binary = Buffer.from([0x00, 0x01, 0x80, 0xff]).toString("base64");
|
|
1182
|
-
expect(_tryDecodeBase64(binary)).toBeNull();
|
|
1183
|
-
});
|
|
1184
|
-
|
|
1185
|
-
test("tryDecodeBase64 returns null for invalid base64", () => {
|
|
1186
|
-
expect(_tryDecodeBase64("not!!valid!!base64!!")).toBeNull();
|
|
1187
|
-
});
|
|
1188
|
-
|
|
1189
|
-
test("tryDecodePercentEncoded returns decoded text", () => {
|
|
1190
|
-
expect(_tryDecodePercentEncoded("hello%20world%21")).toBe("hello world!");
|
|
1191
|
-
});
|
|
1192
|
-
|
|
1193
|
-
test("tryDecodePercentEncoded returns null when nothing to decode", () => {
|
|
1194
|
-
expect(_tryDecodePercentEncoded("no-encoding-here")).toBeNull();
|
|
1195
|
-
});
|
|
1196
|
-
|
|
1197
|
-
test("tryDecodeHexEscapes returns decoded text", () => {
|
|
1198
|
-
expect(_tryDecodeHexEscapes("\\x48\\x65\\x6c\\x6c\\x6f")).toBe("Hello");
|
|
1199
|
-
});
|
|
1200
|
-
|
|
1201
|
-
test("tryDecodeHexEscapes returns null when no escapes", () => {
|
|
1202
|
-
expect(_tryDecodeHexEscapes("plain text")).toBeNull();
|
|
1203
|
-
});
|
|
1204
|
-
|
|
1205
|
-
test("tryDecodeContinuousHex returns decoded text", () => {
|
|
1206
|
-
const hex = Buffer.from("Hello").toString("hex");
|
|
1207
|
-
expect(_tryDecodeContinuousHex(hex)).toBe("Hello");
|
|
1208
|
-
});
|
|
1209
|
-
|
|
1210
|
-
test("tryDecodeContinuousHex returns null for non-printable result", () => {
|
|
1211
|
-
// Hex that decodes to binary
|
|
1212
|
-
expect(_tryDecodeContinuousHex("0001ff80")).toBeNull();
|
|
1213
|
-
});
|
|
1214
|
-
});
|