palaryn 0.1.0
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/LICENSE +21 -0
- package/README.md +716 -0
- package/dist/sdk/typescript/src/client.d.ts +71 -0
- package/dist/sdk/typescript/src/client.d.ts.map +1 -0
- package/dist/sdk/typescript/src/client.js +176 -0
- package/dist/sdk/typescript/src/client.js.map +1 -0
- package/dist/sdk/typescript/src/errors.d.ts +50 -0
- package/dist/sdk/typescript/src/errors.d.ts.map +1 -0
- package/dist/sdk/typescript/src/errors.js +103 -0
- package/dist/sdk/typescript/src/errors.js.map +1 -0
- package/dist/sdk/typescript/src/index.d.ts +4 -0
- package/dist/sdk/typescript/src/index.d.ts.map +1 -0
- package/dist/sdk/typescript/src/index.js +15 -0
- package/dist/sdk/typescript/src/index.js.map +1 -0
- package/dist/sdk/typescript/src/types.d.ts +101 -0
- package/dist/sdk/typescript/src/types.d.ts.map +1 -0
- package/dist/sdk/typescript/src/types.js +6 -0
- package/dist/sdk/typescript/src/types.js.map +1 -0
- package/dist/src/admin/index.d.ts +2 -0
- package/dist/src/admin/index.d.ts.map +1 -0
- package/dist/src/admin/index.js +6 -0
- package/dist/src/admin/index.js.map +1 -0
- package/dist/src/admin/routes.d.ts +5 -0
- package/dist/src/admin/routes.d.ts.map +1 -0
- package/dist/src/admin/routes.js +471 -0
- package/dist/src/admin/routes.js.map +1 -0
- package/dist/src/admin/templates.d.ts +51 -0
- package/dist/src/admin/templates.d.ts.map +1 -0
- package/dist/src/admin/templates.js +500 -0
- package/dist/src/admin/templates.js.map +1 -0
- package/dist/src/anomaly/detector.d.ts +141 -0
- package/dist/src/anomaly/detector.d.ts.map +1 -0
- package/dist/src/anomaly/detector.js +554 -0
- package/dist/src/anomaly/detector.js.map +1 -0
- package/dist/src/anomaly/index.d.ts +2 -0
- package/dist/src/anomaly/index.d.ts.map +1 -0
- package/dist/src/anomaly/index.js +7 -0
- package/dist/src/anomaly/index.js.map +1 -0
- package/dist/src/approval/manager.d.ts +147 -0
- package/dist/src/approval/manager.d.ts.map +1 -0
- package/dist/src/approval/manager.js +511 -0
- package/dist/src/approval/manager.js.map +1 -0
- package/dist/src/approval/webhook.d.ts +36 -0
- package/dist/src/approval/webhook.d.ts.map +1 -0
- package/dist/src/approval/webhook.js +135 -0
- package/dist/src/approval/webhook.js.map +1 -0
- package/dist/src/audit/logger.d.ts +70 -0
- package/dist/src/audit/logger.d.ts.map +1 -0
- package/dist/src/audit/logger.js +440 -0
- package/dist/src/audit/logger.js.map +1 -0
- package/dist/src/auth/index.d.ts +6 -0
- package/dist/src/auth/index.d.ts.map +1 -0
- package/dist/src/auth/index.js +22 -0
- package/dist/src/auth/index.js.map +1 -0
- package/dist/src/auth/password.d.ts +3 -0
- package/dist/src/auth/password.d.ts.map +1 -0
- package/dist/src/auth/password.js +25 -0
- package/dist/src/auth/password.js.map +1 -0
- package/dist/src/auth/pkce.d.ts +13 -0
- package/dist/src/auth/pkce.d.ts.map +1 -0
- package/dist/src/auth/pkce.js +58 -0
- package/dist/src/auth/pkce.js.map +1 -0
- package/dist/src/auth/providers.d.ts +28 -0
- package/dist/src/auth/providers.d.ts.map +1 -0
- package/dist/src/auth/providers.js +198 -0
- package/dist/src/auth/providers.js.map +1 -0
- package/dist/src/auth/routes.d.ts +14 -0
- package/dist/src/auth/routes.d.ts.map +1 -0
- package/dist/src/auth/routes.js +431 -0
- package/dist/src/auth/routes.js.map +1 -0
- package/dist/src/auth/session.d.ts +24 -0
- package/dist/src/auth/session.d.ts.map +1 -0
- package/dist/src/auth/session.js +105 -0
- package/dist/src/auth/session.js.map +1 -0
- package/dist/src/billing/index.d.ts +7 -0
- package/dist/src/billing/index.d.ts.map +1 -0
- package/dist/src/billing/index.js +14 -0
- package/dist/src/billing/index.js.map +1 -0
- package/dist/src/billing/plan-enforcer.d.ts +44 -0
- package/dist/src/billing/plan-enforcer.d.ts.map +1 -0
- package/dist/src/billing/plan-enforcer.js +110 -0
- package/dist/src/billing/plan-enforcer.js.map +1 -0
- package/dist/src/billing/routes.d.ts +15 -0
- package/dist/src/billing/routes.d.ts.map +1 -0
- package/dist/src/billing/routes.js +193 -0
- package/dist/src/billing/routes.js.map +1 -0
- package/dist/src/billing/stripe-client.d.ts +14 -0
- package/dist/src/billing/stripe-client.d.ts.map +1 -0
- package/dist/src/billing/stripe-client.js +51 -0
- package/dist/src/billing/stripe-client.js.map +1 -0
- package/dist/src/billing/webhook-handler.d.ts +19 -0
- package/dist/src/billing/webhook-handler.d.ts.map +1 -0
- package/dist/src/billing/webhook-handler.js +169 -0
- package/dist/src/billing/webhook-handler.js.map +1 -0
- package/dist/src/billing/webhook-routes.d.ts +5 -0
- package/dist/src/billing/webhook-routes.d.ts.map +1 -0
- package/dist/src/billing/webhook-routes.js +30 -0
- package/dist/src/billing/webhook-routes.js.map +1 -0
- package/dist/src/budget/manager.d.ts +95 -0
- package/dist/src/budget/manager.d.ts.map +1 -0
- package/dist/src/budget/manager.js +547 -0
- package/dist/src/budget/manager.js.map +1 -0
- package/dist/src/budget/usage-extractor.d.ts +38 -0
- package/dist/src/budget/usage-extractor.d.ts.map +1 -0
- package/dist/src/budget/usage-extractor.js +165 -0
- package/dist/src/budget/usage-extractor.js.map +1 -0
- package/dist/src/cli.d.ts +3 -0
- package/dist/src/cli.d.ts.map +1 -0
- package/dist/src/cli.js +115 -0
- package/dist/src/cli.js.map +1 -0
- package/dist/src/config/defaults.d.ts +3 -0
- package/dist/src/config/defaults.d.ts.map +1 -0
- package/dist/src/config/defaults.js +243 -0
- package/dist/src/config/defaults.js.map +1 -0
- package/dist/src/config/validate.d.ts +15 -0
- package/dist/src/config/validate.d.ts.map +1 -0
- package/dist/src/config/validate.js +105 -0
- package/dist/src/config/validate.js.map +1 -0
- package/dist/src/dlp/composite-scanner.d.ts +47 -0
- package/dist/src/dlp/composite-scanner.d.ts.map +1 -0
- package/dist/src/dlp/composite-scanner.js +186 -0
- package/dist/src/dlp/composite-scanner.js.map +1 -0
- package/dist/src/dlp/index.d.ts +10 -0
- package/dist/src/dlp/index.d.ts.map +1 -0
- package/dist/src/dlp/index.js +26 -0
- package/dist/src/dlp/index.js.map +1 -0
- package/dist/src/dlp/interfaces.d.ts +33 -0
- package/dist/src/dlp/interfaces.d.ts.map +1 -0
- package/dist/src/dlp/interfaces.js +3 -0
- package/dist/src/dlp/interfaces.js.map +1 -0
- package/dist/src/dlp/patterns.d.ts +9 -0
- package/dist/src/dlp/patterns.d.ts.map +1 -0
- package/dist/src/dlp/patterns.js +25 -0
- package/dist/src/dlp/patterns.js.map +1 -0
- package/dist/src/dlp/prompt-injection-backend.d.ts +68 -0
- package/dist/src/dlp/prompt-injection-backend.d.ts.map +1 -0
- package/dist/src/dlp/prompt-injection-backend.js +148 -0
- package/dist/src/dlp/prompt-injection-backend.js.map +1 -0
- package/dist/src/dlp/prompt-injection-patterns.d.ts +32 -0
- package/dist/src/dlp/prompt-injection-patterns.d.ts.map +1 -0
- package/dist/src/dlp/prompt-injection-patterns.js +290 -0
- package/dist/src/dlp/prompt-injection-patterns.js.map +1 -0
- package/dist/src/dlp/regex-backend.d.ts +32 -0
- package/dist/src/dlp/regex-backend.d.ts.map +1 -0
- package/dist/src/dlp/regex-backend.js +153 -0
- package/dist/src/dlp/regex-backend.js.map +1 -0
- package/dist/src/dlp/scanner.d.ts +122 -0
- package/dist/src/dlp/scanner.d.ts.map +1 -0
- package/dist/src/dlp/scanner.js +444 -0
- package/dist/src/dlp/scanner.js.map +1 -0
- package/dist/src/dlp/text-normalizer.d.ts +41 -0
- package/dist/src/dlp/text-normalizer.d.ts.map +1 -0
- package/dist/src/dlp/text-normalizer.js +203 -0
- package/dist/src/dlp/text-normalizer.js.map +1 -0
- package/dist/src/dlp/trufflehog-backend.d.ts +64 -0
- package/dist/src/dlp/trufflehog-backend.d.ts.map +1 -0
- package/dist/src/dlp/trufflehog-backend.js +151 -0
- package/dist/src/dlp/trufflehog-backend.js.map +1 -0
- package/dist/src/executor/http-executor.d.ts +25 -0
- package/dist/src/executor/http-executor.d.ts.map +1 -0
- package/dist/src/executor/http-executor.js +333 -0
- package/dist/src/executor/http-executor.js.map +1 -0
- package/dist/src/executor/index.d.ts +6 -0
- package/dist/src/executor/index.d.ts.map +1 -0
- package/dist/src/executor/index.js +12 -0
- package/dist/src/executor/index.js.map +1 -0
- package/dist/src/executor/interfaces.d.ts +11 -0
- package/dist/src/executor/interfaces.d.ts.map +1 -0
- package/dist/src/executor/interfaces.js +3 -0
- package/dist/src/executor/interfaces.js.map +1 -0
- package/dist/src/executor/noop-executor.d.ts +13 -0
- package/dist/src/executor/noop-executor.d.ts.map +1 -0
- package/dist/src/executor/noop-executor.js +21 -0
- package/dist/src/executor/noop-executor.js.map +1 -0
- package/dist/src/executor/registry.d.ts +30 -0
- package/dist/src/executor/registry.d.ts.map +1 -0
- package/dist/src/executor/registry.js +62 -0
- package/dist/src/executor/registry.js.map +1 -0
- package/dist/src/executor/slack-executor.d.ts +24 -0
- package/dist/src/executor/slack-executor.d.ts.map +1 -0
- package/dist/src/executor/slack-executor.js +147 -0
- package/dist/src/executor/slack-executor.js.map +1 -0
- package/dist/src/index.d.ts +25 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +74 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/mcp/auth-verifier.d.ts +23 -0
- package/dist/src/mcp/auth-verifier.d.ts.map +1 -0
- package/dist/src/mcp/auth-verifier.js +162 -0
- package/dist/src/mcp/auth-verifier.js.map +1 -0
- package/dist/src/mcp/bridge.d.ts +132 -0
- package/dist/src/mcp/bridge.d.ts.map +1 -0
- package/dist/src/mcp/bridge.js +734 -0
- package/dist/src/mcp/bridge.js.map +1 -0
- package/dist/src/mcp/http-transport.d.ts +32 -0
- package/dist/src/mcp/http-transport.d.ts.map +1 -0
- package/dist/src/mcp/http-transport.js +538 -0
- package/dist/src/mcp/http-transport.js.map +1 -0
- package/dist/src/mcp/index.d.ts +10 -0
- package/dist/src/mcp/index.d.ts.map +1 -0
- package/dist/src/mcp/index.js +17 -0
- package/dist/src/mcp/index.js.map +1 -0
- package/dist/src/mcp/oauth-pages.d.ts +23 -0
- package/dist/src/mcp/oauth-pages.d.ts.map +1 -0
- package/dist/src/mcp/oauth-pages.js +121 -0
- package/dist/src/mcp/oauth-pages.js.map +1 -0
- package/dist/src/mcp/oauth-postgres-stores.d.ts +55 -0
- package/dist/src/mcp/oauth-postgres-stores.d.ts.map +1 -0
- package/dist/src/mcp/oauth-postgres-stores.js +226 -0
- package/dist/src/mcp/oauth-postgres-stores.js.map +1 -0
- package/dist/src/mcp/oauth-provider.d.ts +95 -0
- package/dist/src/mcp/oauth-provider.d.ts.map +1 -0
- package/dist/src/mcp/oauth-provider.js +360 -0
- package/dist/src/mcp/oauth-provider.js.map +1 -0
- package/dist/src/mcp/oauth-stores.d.ts +62 -0
- package/dist/src/mcp/oauth-stores.d.ts.map +1 -0
- package/dist/src/mcp/oauth-stores.js +154 -0
- package/dist/src/mcp/oauth-stores.js.map +1 -0
- package/dist/src/mcp/server.d.ts +18 -0
- package/dist/src/mcp/server.d.ts.map +1 -0
- package/dist/src/mcp/server.js +51 -0
- package/dist/src/mcp/server.js.map +1 -0
- package/dist/src/metrics/collector.d.ts +106 -0
- package/dist/src/metrics/collector.d.ts.map +1 -0
- package/dist/src/metrics/collector.js +311 -0
- package/dist/src/metrics/collector.js.map +1 -0
- package/dist/src/metrics/index.d.ts +2 -0
- package/dist/src/metrics/index.d.ts.map +1 -0
- package/dist/src/metrics/index.js +6 -0
- package/dist/src/metrics/index.js.map +1 -0
- package/dist/src/middleware/auth.d.ts +77 -0
- package/dist/src/middleware/auth.d.ts.map +1 -0
- package/dist/src/middleware/auth.js +720 -0
- package/dist/src/middleware/auth.js.map +1 -0
- package/dist/src/middleware/session.d.ts +18 -0
- package/dist/src/middleware/session.d.ts.map +1 -0
- package/dist/src/middleware/session.js +67 -0
- package/dist/src/middleware/session.js.map +1 -0
- package/dist/src/middleware/validate.d.ts +3 -0
- package/dist/src/middleware/validate.d.ts.map +1 -0
- package/dist/src/middleware/validate.js +85 -0
- package/dist/src/middleware/validate.js.map +1 -0
- package/dist/src/policy/engine.d.ts +107 -0
- package/dist/src/policy/engine.d.ts.map +1 -0
- package/dist/src/policy/engine.js +646 -0
- package/dist/src/policy/engine.js.map +1 -0
- package/dist/src/policy/index.d.ts +3 -0
- package/dist/src/policy/index.d.ts.map +1 -0
- package/dist/src/policy/index.js +8 -0
- package/dist/src/policy/index.js.map +1 -0
- package/dist/src/policy/opa-engine.d.ts +176 -0
- package/dist/src/policy/opa-engine.d.ts.map +1 -0
- package/dist/src/policy/opa-engine.js +790 -0
- package/dist/src/policy/opa-engine.js.map +1 -0
- package/dist/src/proxy/forward-proxy.d.ts +30 -0
- package/dist/src/proxy/forward-proxy.d.ts.map +1 -0
- package/dist/src/proxy/forward-proxy.js +580 -0
- package/dist/src/proxy/forward-proxy.js.map +1 -0
- package/dist/src/proxy/index.d.ts +2 -0
- package/dist/src/proxy/index.d.ts.map +1 -0
- package/dist/src/proxy/index.js +8 -0
- package/dist/src/proxy/index.js.map +1 -0
- package/dist/src/ratelimit/limiter.d.ts +45 -0
- package/dist/src/ratelimit/limiter.d.ts.map +1 -0
- package/dist/src/ratelimit/limiter.js +158 -0
- package/dist/src/ratelimit/limiter.js.map +1 -0
- package/dist/src/replay/engine.d.ts +40 -0
- package/dist/src/replay/engine.d.ts.map +1 -0
- package/dist/src/replay/engine.js +106 -0
- package/dist/src/replay/engine.js.map +1 -0
- package/dist/src/replay/index.d.ts +2 -0
- package/dist/src/replay/index.d.ts.map +1 -0
- package/dist/src/replay/index.js +6 -0
- package/dist/src/replay/index.js.map +1 -0
- package/dist/src/saas/index.d.ts +2 -0
- package/dist/src/saas/index.d.ts.map +1 -0
- package/dist/src/saas/index.js +18 -0
- package/dist/src/saas/index.js.map +1 -0
- package/dist/src/saas/routes.d.ts +18 -0
- package/dist/src/saas/routes.d.ts.map +1 -0
- package/dist/src/saas/routes.js +1566 -0
- package/dist/src/saas/routes.js.map +1 -0
- package/dist/src/server/app.d.ts +44 -0
- package/dist/src/server/app.d.ts.map +1 -0
- package/dist/src/server/app.js +854 -0
- package/dist/src/server/app.js.map +1 -0
- package/dist/src/server/errors.d.ts +32 -0
- package/dist/src/server/errors.d.ts.map +1 -0
- package/dist/src/server/errors.js +39 -0
- package/dist/src/server/errors.js.map +1 -0
- package/dist/src/server/gateway.d.ts +165 -0
- package/dist/src/server/gateway.d.ts.map +1 -0
- package/dist/src/server/gateway.js +964 -0
- package/dist/src/server/gateway.js.map +1 -0
- package/dist/src/server/index.d.ts +2 -0
- package/dist/src/server/index.d.ts.map +1 -0
- package/dist/src/server/index.js +295 -0
- package/dist/src/server/index.js.map +1 -0
- package/dist/src/server/logger.d.ts +33 -0
- package/dist/src/server/logger.d.ts.map +1 -0
- package/dist/src/server/logger.js +230 -0
- package/dist/src/server/logger.js.map +1 -0
- package/dist/src/server/stream-proxy.d.ts +32 -0
- package/dist/src/server/stream-proxy.d.ts.map +1 -0
- package/dist/src/server/stream-proxy.js +184 -0
- package/dist/src/server/stream-proxy.js.map +1 -0
- package/dist/src/storage/file-persistence.d.ts +48 -0
- package/dist/src/storage/file-persistence.d.ts.map +1 -0
- package/dist/src/storage/file-persistence.js +280 -0
- package/dist/src/storage/file-persistence.js.map +1 -0
- package/dist/src/storage/index.d.ts +5 -0
- package/dist/src/storage/index.d.ts.map +1 -0
- package/dist/src/storage/index.js +21 -0
- package/dist/src/storage/index.js.map +1 -0
- package/dist/src/storage/interfaces.d.ts +237 -0
- package/dist/src/storage/interfaces.d.ts.map +1 -0
- package/dist/src/storage/interfaces.js +3 -0
- package/dist/src/storage/interfaces.js.map +1 -0
- package/dist/src/storage/memory.d.ts +162 -0
- package/dist/src/storage/memory.d.ts.map +1 -0
- package/dist/src/storage/memory.js +603 -0
- package/dist/src/storage/memory.js.map +1 -0
- package/dist/src/storage/postgres.d.ts +267 -0
- package/dist/src/storage/postgres.d.ts.map +1 -0
- package/dist/src/storage/postgres.js +1555 -0
- package/dist/src/storage/postgres.js.map +1 -0
- package/dist/src/storage/redis.d.ts +202 -0
- package/dist/src/storage/redis.d.ts.map +1 -0
- package/dist/src/storage/redis.js +629 -0
- package/dist/src/storage/redis.js.map +1 -0
- package/dist/src/tracing/index.d.ts +2 -0
- package/dist/src/tracing/index.d.ts.map +1 -0
- package/dist/src/tracing/index.js +6 -0
- package/dist/src/tracing/index.js.map +1 -0
- package/dist/src/tracing/provider.d.ts +43 -0
- package/dist/src/tracing/provider.d.ts.map +1 -0
- package/dist/src/tracing/provider.js +74 -0
- package/dist/src/tracing/provider.js.map +1 -0
- package/dist/src/trust/calculator.d.ts +54 -0
- package/dist/src/trust/calculator.d.ts.map +1 -0
- package/dist/src/trust/calculator.js +102 -0
- package/dist/src/trust/calculator.js.map +1 -0
- package/dist/src/trust/index.d.ts +2 -0
- package/dist/src/trust/index.d.ts.map +1 -0
- package/dist/src/trust/index.js +7 -0
- package/dist/src/trust/index.js.map +1 -0
- package/dist/src/types/budget.d.ts +30 -0
- package/dist/src/types/budget.d.ts.map +1 -0
- package/dist/src/types/budget.js +3 -0
- package/dist/src/types/budget.js.map +1 -0
- package/dist/src/types/config.d.ts +176 -0
- package/dist/src/types/config.d.ts.map +1 -0
- package/dist/src/types/config.js +3 -0
- package/dist/src/types/config.js.map +1 -0
- package/dist/src/types/events.d.ts +24 -0
- package/dist/src/types/events.d.ts.map +1 -0
- package/dist/src/types/events.js +3 -0
- package/dist/src/types/events.js.map +1 -0
- package/dist/src/types/index.d.ts +8 -0
- package/dist/src/types/index.d.ts.map +1 -0
- package/dist/src/types/index.js +24 -0
- package/dist/src/types/index.js.map +1 -0
- package/dist/src/types/policy.d.ts +60 -0
- package/dist/src/types/policy.d.ts.map +1 -0
- package/dist/src/types/policy.js +3 -0
- package/dist/src/types/policy.js.map +1 -0
- package/dist/src/types/stripe-config.d.ts +12 -0
- package/dist/src/types/stripe-config.d.ts.map +1 -0
- package/dist/src/types/stripe-config.js +3 -0
- package/dist/src/types/stripe-config.js.map +1 -0
- package/dist/src/types/subscription.d.ts +24 -0
- package/dist/src/types/subscription.d.ts.map +1 -0
- package/dist/src/types/subscription.js +38 -0
- package/dist/src/types/subscription.js.map +1 -0
- package/dist/src/types/tool-call.d.ts +42 -0
- package/dist/src/types/tool-call.d.ts.map +1 -0
- package/dist/src/types/tool-call.js +3 -0
- package/dist/src/types/tool-call.js.map +1 -0
- package/dist/src/types/tool-result.d.ts +58 -0
- package/dist/src/types/tool-result.d.ts.map +1 -0
- package/dist/src/types/tool-result.js +3 -0
- package/dist/src/types/tool-result.js.map +1 -0
- package/dist/src/types/user.d.ts +101 -0
- package/dist/src/types/user.d.ts.map +1 -0
- package/dist/src/types/user.js +6 -0
- package/dist/src/types/user.js.map +1 -0
- package/dist/tests/integration/api.test.d.ts +2 -0
- package/dist/tests/integration/api.test.d.ts.map +1 -0
- package/dist/tests/integration/api.test.js +1199 -0
- package/dist/tests/integration/api.test.js.map +1 -0
- package/dist/tests/integration/proxy.test.d.ts +2 -0
- package/dist/tests/integration/proxy.test.d.ts.map +1 -0
- package/dist/tests/integration/proxy.test.js +251 -0
- package/dist/tests/integration/proxy.test.js.map +1 -0
- package/dist/tests/integration/storage.test.d.ts +16 -0
- package/dist/tests/integration/storage.test.d.ts.map +1 -0
- package/dist/tests/integration/storage.test.js +826 -0
- package/dist/tests/integration/storage.test.js.map +1 -0
- package/dist/tests/unit/admin.test.d.ts +2 -0
- package/dist/tests/unit/admin.test.d.ts.map +1 -0
- package/dist/tests/unit/admin.test.js +698 -0
- package/dist/tests/unit/admin.test.js.map +1 -0
- package/dist/tests/unit/anomaly-detector.test.d.ts +2 -0
- package/dist/tests/unit/anomaly-detector.test.d.ts.map +1 -0
- package/dist/tests/unit/anomaly-detector.test.js +903 -0
- package/dist/tests/unit/anomaly-detector.test.js.map +1 -0
- package/dist/tests/unit/approval-manager.test.d.ts +2 -0
- package/dist/tests/unit/approval-manager.test.d.ts.map +1 -0
- package/dist/tests/unit/approval-manager.test.js +528 -0
- package/dist/tests/unit/approval-manager.test.js.map +1 -0
- package/dist/tests/unit/approval-webhook.test.d.ts +2 -0
- package/dist/tests/unit/approval-webhook.test.d.ts.map +1 -0
- package/dist/tests/unit/approval-webhook.test.js +355 -0
- package/dist/tests/unit/approval-webhook.test.js.map +1 -0
- package/dist/tests/unit/audit-logger.test.d.ts +2 -0
- package/dist/tests/unit/audit-logger.test.d.ts.map +1 -0
- package/dist/tests/unit/audit-logger.test.js +635 -0
- package/dist/tests/unit/audit-logger.test.js.map +1 -0
- package/dist/tests/unit/auth-routes.test.d.ts +2 -0
- package/dist/tests/unit/auth-routes.test.d.ts.map +1 -0
- package/dist/tests/unit/auth-routes.test.js +281 -0
- package/dist/tests/unit/auth-routes.test.js.map +1 -0
- package/dist/tests/unit/auth.test.d.ts +2 -0
- package/dist/tests/unit/auth.test.d.ts.map +1 -0
- package/dist/tests/unit/auth.test.js +1382 -0
- package/dist/tests/unit/auth.test.js.map +1 -0
- package/dist/tests/unit/billing.test.d.ts +2 -0
- package/dist/tests/unit/billing.test.d.ts.map +1 -0
- package/dist/tests/unit/billing.test.js +579 -0
- package/dist/tests/unit/billing.test.js.map +1 -0
- package/dist/tests/unit/budget-manager.test.d.ts +2 -0
- package/dist/tests/unit/budget-manager.test.d.ts.map +1 -0
- package/dist/tests/unit/budget-manager.test.js +778 -0
- package/dist/tests/unit/budget-manager.test.js.map +1 -0
- package/dist/tests/unit/budget-race.test.d.ts +2 -0
- package/dist/tests/unit/budget-race.test.d.ts.map +1 -0
- package/dist/tests/unit/budget-race.test.js +58 -0
- package/dist/tests/unit/budget-race.test.js.map +1 -0
- package/dist/tests/unit/cli.test.d.ts +2 -0
- package/dist/tests/unit/cli.test.d.ts.map +1 -0
- package/dist/tests/unit/cli.test.js +93 -0
- package/dist/tests/unit/cli.test.js.map +1 -0
- package/dist/tests/unit/concurrency.test.d.ts +2 -0
- package/dist/tests/unit/concurrency.test.d.ts.map +1 -0
- package/dist/tests/unit/concurrency.test.js +1270 -0
- package/dist/tests/unit/concurrency.test.js.map +1 -0
- package/dist/tests/unit/config-validate.test.d.ts +2 -0
- package/dist/tests/unit/config-validate.test.d.ts.map +1 -0
- package/dist/tests/unit/config-validate.test.js +230 -0
- package/dist/tests/unit/config-validate.test.js.map +1 -0
- package/dist/tests/unit/defaults.test.d.ts +2 -0
- package/dist/tests/unit/defaults.test.d.ts.map +1 -0
- package/dist/tests/unit/defaults.test.js +364 -0
- package/dist/tests/unit/defaults.test.js.map +1 -0
- package/dist/tests/unit/dlp-backends.test.d.ts +2 -0
- package/dist/tests/unit/dlp-backends.test.d.ts.map +1 -0
- package/dist/tests/unit/dlp-backends.test.js +563 -0
- package/dist/tests/unit/dlp-backends.test.js.map +1 -0
- package/dist/tests/unit/dlp-scanner.test.d.ts +2 -0
- package/dist/tests/unit/dlp-scanner.test.d.ts.map +1 -0
- package/dist/tests/unit/dlp-scanner.test.js +739 -0
- package/dist/tests/unit/dlp-scanner.test.js.map +1 -0
- package/dist/tests/unit/error-responses.test.d.ts +2 -0
- package/dist/tests/unit/error-responses.test.d.ts.map +1 -0
- package/dist/tests/unit/error-responses.test.js +101 -0
- package/dist/tests/unit/error-responses.test.js.map +1 -0
- package/dist/tests/unit/executor-registry.test.d.ts +2 -0
- package/dist/tests/unit/executor-registry.test.d.ts.map +1 -0
- package/dist/tests/unit/executor-registry.test.js +390 -0
- package/dist/tests/unit/executor-registry.test.js.map +1 -0
- package/dist/tests/unit/forward-proxy.test.d.ts +2 -0
- package/dist/tests/unit/forward-proxy.test.d.ts.map +1 -0
- package/dist/tests/unit/forward-proxy.test.js +621 -0
- package/dist/tests/unit/forward-proxy.test.js.map +1 -0
- package/dist/tests/unit/gateway-features.test.d.ts +2 -0
- package/dist/tests/unit/gateway-features.test.d.ts.map +1 -0
- package/dist/tests/unit/gateway-features.test.js +753 -0
- package/dist/tests/unit/gateway-features.test.js.map +1 -0
- package/dist/tests/unit/http-executor.test.d.ts +2 -0
- package/dist/tests/unit/http-executor.test.d.ts.map +1 -0
- package/dist/tests/unit/http-executor.test.js +310 -0
- package/dist/tests/unit/http-executor.test.js.map +1 -0
- package/dist/tests/unit/mcp-bridge.test.d.ts +2 -0
- package/dist/tests/unit/mcp-bridge.test.d.ts.map +1 -0
- package/dist/tests/unit/mcp-bridge.test.js +1136 -0
- package/dist/tests/unit/mcp-bridge.test.js.map +1 -0
- package/dist/tests/unit/mcp-http-transport.test.d.ts +2 -0
- package/dist/tests/unit/mcp-http-transport.test.d.ts.map +1 -0
- package/dist/tests/unit/mcp-http-transport.test.js +899 -0
- package/dist/tests/unit/mcp-http-transport.test.js.map +1 -0
- package/dist/tests/unit/mcp-oauth.test.d.ts +2 -0
- package/dist/tests/unit/mcp-oauth.test.d.ts.map +1 -0
- package/dist/tests/unit/mcp-oauth.test.js +759 -0
- package/dist/tests/unit/mcp-oauth.test.js.map +1 -0
- package/dist/tests/unit/mcp-server.test.d.ts +15 -0
- package/dist/tests/unit/mcp-server.test.d.ts.map +1 -0
- package/dist/tests/unit/mcp-server.test.js +158 -0
- package/dist/tests/unit/mcp-server.test.js.map +1 -0
- package/dist/tests/unit/metrics.test.d.ts +2 -0
- package/dist/tests/unit/metrics.test.d.ts.map +1 -0
- package/dist/tests/unit/metrics.test.js +208 -0
- package/dist/tests/unit/metrics.test.js.map +1 -0
- package/dist/tests/unit/oauth.test.d.ts +2 -0
- package/dist/tests/unit/oauth.test.d.ts.map +1 -0
- package/dist/tests/unit/oauth.test.js +281 -0
- package/dist/tests/unit/oauth.test.js.map +1 -0
- package/dist/tests/unit/opa-circuit-breaker.test.d.ts +2 -0
- package/dist/tests/unit/opa-circuit-breaker.test.d.ts.map +1 -0
- package/dist/tests/unit/opa-circuit-breaker.test.js +297 -0
- package/dist/tests/unit/opa-circuit-breaker.test.js.map +1 -0
- package/dist/tests/unit/opa-engine.test.d.ts +2 -0
- package/dist/tests/unit/opa-engine.test.d.ts.map +1 -0
- package/dist/tests/unit/opa-engine.test.js +1813 -0
- package/dist/tests/unit/opa-engine.test.js.map +1 -0
- package/dist/tests/unit/pipeline-timing.test.d.ts +2 -0
- package/dist/tests/unit/pipeline-timing.test.d.ts.map +1 -0
- package/dist/tests/unit/pipeline-timing.test.js +528 -0
- package/dist/tests/unit/pipeline-timing.test.js.map +1 -0
- package/dist/tests/unit/policy-engine.test.d.ts +2 -0
- package/dist/tests/unit/policy-engine.test.d.ts.map +1 -0
- package/dist/tests/unit/policy-engine.test.js +1345 -0
- package/dist/tests/unit/policy-engine.test.js.map +1 -0
- package/dist/tests/unit/policy-store.test.d.ts +2 -0
- package/dist/tests/unit/policy-store.test.d.ts.map +1 -0
- package/dist/tests/unit/policy-store.test.js +60 -0
- package/dist/tests/unit/policy-store.test.js.map +1 -0
- package/dist/tests/unit/postgres-storage.test.d.ts +2 -0
- package/dist/tests/unit/postgres-storage.test.d.ts.map +1 -0
- package/dist/tests/unit/postgres-storage.test.js +614 -0
- package/dist/tests/unit/postgres-storage.test.js.map +1 -0
- package/dist/tests/unit/prompt-injection-backend.test.d.ts +2 -0
- package/dist/tests/unit/prompt-injection-backend.test.d.ts.map +1 -0
- package/dist/tests/unit/prompt-injection-backend.test.js +621 -0
- package/dist/tests/unit/prompt-injection-backend.test.js.map +1 -0
- package/dist/tests/unit/proxy-hardening.test.d.ts +2 -0
- package/dist/tests/unit/proxy-hardening.test.d.ts.map +1 -0
- package/dist/tests/unit/proxy-hardening.test.js +166 -0
- package/dist/tests/unit/proxy-hardening.test.js.map +1 -0
- package/dist/tests/unit/rate-limiter.test.d.ts +2 -0
- package/dist/tests/unit/rate-limiter.test.d.ts.map +1 -0
- package/dist/tests/unit/rate-limiter.test.js +443 -0
- package/dist/tests/unit/rate-limiter.test.js.map +1 -0
- package/dist/tests/unit/redis-storage.test.d.ts +2 -0
- package/dist/tests/unit/redis-storage.test.d.ts.map +1 -0
- package/dist/tests/unit/redis-storage.test.js +766 -0
- package/dist/tests/unit/redis-storage.test.js.map +1 -0
- package/dist/tests/unit/replay-engine.test.d.ts +2 -0
- package/dist/tests/unit/replay-engine.test.d.ts.map +1 -0
- package/dist/tests/unit/replay-engine.test.js +371 -0
- package/dist/tests/unit/replay-engine.test.js.map +1 -0
- package/dist/tests/unit/saas-routes.test.d.ts +2 -0
- package/dist/tests/unit/saas-routes.test.d.ts.map +1 -0
- package/dist/tests/unit/saas-routes.test.js +1399 -0
- package/dist/tests/unit/saas-routes.test.js.map +1 -0
- package/dist/tests/unit/session.test.d.ts +2 -0
- package/dist/tests/unit/session.test.d.ts.map +1 -0
- package/dist/tests/unit/session.test.js +532 -0
- package/dist/tests/unit/session.test.js.map +1 -0
- package/dist/tests/unit/slack-executor.test.d.ts +2 -0
- package/dist/tests/unit/slack-executor.test.d.ts.map +1 -0
- package/dist/tests/unit/slack-executor.test.js +209 -0
- package/dist/tests/unit/slack-executor.test.js.map +1 -0
- package/dist/tests/unit/storage-hardening.test.d.ts +2 -0
- package/dist/tests/unit/storage-hardening.test.d.ts.map +1 -0
- package/dist/tests/unit/storage-hardening.test.js +165 -0
- package/dist/tests/unit/storage-hardening.test.js.map +1 -0
- package/dist/tests/unit/storage.test.d.ts +2 -0
- package/dist/tests/unit/storage.test.d.ts.map +1 -0
- package/dist/tests/unit/storage.test.js +698 -0
- package/dist/tests/unit/storage.test.js.map +1 -0
- package/dist/tests/unit/text-normalizer.test.d.ts +2 -0
- package/dist/tests/unit/text-normalizer.test.d.ts.map +1 -0
- package/dist/tests/unit/text-normalizer.test.js +229 -0
- package/dist/tests/unit/text-normalizer.test.js.map +1 -0
- package/dist/tests/unit/tracing.test.d.ts +2 -0
- package/dist/tests/unit/tracing.test.d.ts.map +1 -0
- package/dist/tests/unit/tracing.test.js +611 -0
- package/dist/tests/unit/tracing.test.js.map +1 -0
- package/dist/tests/unit/trust-calculator.test.d.ts +2 -0
- package/dist/tests/unit/trust-calculator.test.d.ts.map +1 -0
- package/dist/tests/unit/trust-calculator.test.js +497 -0
- package/dist/tests/unit/trust-calculator.test.js.map +1 -0
- package/dist/tests/unit/ts-sdk.test.d.ts +2 -0
- package/dist/tests/unit/ts-sdk.test.d.ts.map +1 -0
- package/dist/tests/unit/ts-sdk.test.js +421 -0
- package/dist/tests/unit/ts-sdk.test.js.map +1 -0
- package/dist/tests/unit/usage-extractor-llm.test.d.ts +2 -0
- package/dist/tests/unit/usage-extractor-llm.test.d.ts.map +1 -0
- package/dist/tests/unit/usage-extractor-llm.test.js +139 -0
- package/dist/tests/unit/usage-extractor-llm.test.js.map +1 -0
- package/dist/tests/unit/usage-extractor.test.d.ts +2 -0
- package/dist/tests/unit/usage-extractor.test.d.ts.map +1 -0
- package/dist/tests/unit/usage-extractor.test.js +271 -0
- package/dist/tests/unit/usage-extractor.test.js.map +1 -0
- package/dist/tests/unit/user-stores.test.d.ts +2 -0
- package/dist/tests/unit/user-stores.test.d.ts.map +1 -0
- package/dist/tests/unit/user-stores.test.js +687 -0
- package/dist/tests/unit/user-stores.test.js.map +1 -0
- package/dist/tests/unit/validate.test.d.ts +2 -0
- package/dist/tests/unit/validate.test.d.ts.map +1 -0
- package/dist/tests/unit/validate.test.js +545 -0
- package/dist/tests/unit/validate.test.js.map +1 -0
- package/package.json +86 -0
- package/policy-packs/README.md +42 -0
- package/policy-packs/default.yaml +46 -0
- package/policy-packs/dev_fast.yaml +54 -0
- package/policy-packs/prod_strict.yaml +83 -0
|
@@ -0,0 +1,739 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const crypto_1 = require("crypto");
|
|
37
|
+
const scanner_1 = require("../../src/dlp/scanner");
|
|
38
|
+
// ---------------------------------------------------------------------------
|
|
39
|
+
// Helpers
|
|
40
|
+
// ---------------------------------------------------------------------------
|
|
41
|
+
/** Build a DLPConfig with sensible defaults for testing. */
|
|
42
|
+
function buildConfig(overrides = {}) {
|
|
43
|
+
return {
|
|
44
|
+
enabled: true,
|
|
45
|
+
scan_args: true,
|
|
46
|
+
scan_output: true,
|
|
47
|
+
secrets_detection: true,
|
|
48
|
+
pii_detection: true,
|
|
49
|
+
default_redaction_method: 'mask',
|
|
50
|
+
...overrides,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
// Tests
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
describe('DLPScanner', () => {
|
|
57
|
+
// -----------------------------------------------------------------------
|
|
58
|
+
// Secret Detection
|
|
59
|
+
// -----------------------------------------------------------------------
|
|
60
|
+
describe('secret detection', () => {
|
|
61
|
+
it('should detect AWS access keys', () => {
|
|
62
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
63
|
+
const report = scanner.scan({ key: 'AKIAIOSFODNN7EXAMPLE' });
|
|
64
|
+
expect(report.detected).toContain('aws_access_key');
|
|
65
|
+
expect(report.severity).toBe('high');
|
|
66
|
+
expect(report.redactions.length).toBeGreaterThan(0);
|
|
67
|
+
});
|
|
68
|
+
it('should detect AWS secret access keys', () => {
|
|
69
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
70
|
+
const report = scanner.scan({
|
|
71
|
+
config: 'aws_secret_access_key=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY01',
|
|
72
|
+
});
|
|
73
|
+
expect(report.detected).toContain('aws_secret_key');
|
|
74
|
+
expect(report.severity).toBe('high');
|
|
75
|
+
});
|
|
76
|
+
it('should detect GitHub tokens (ghp_, gho_, ghu_, ghs_, ghr_)', () => {
|
|
77
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
78
|
+
const ghpToken = 'ghp_ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef0123456789';
|
|
79
|
+
const report = scanner.scan({ token: ghpToken });
|
|
80
|
+
expect(report.detected).toContain('github_token');
|
|
81
|
+
expect(report.severity).toBe('high');
|
|
82
|
+
});
|
|
83
|
+
it('should detect Bearer tokens', () => {
|
|
84
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
85
|
+
const report = scanner.scan({
|
|
86
|
+
headers: { Authorization: 'Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.payload.signature' },
|
|
87
|
+
});
|
|
88
|
+
expect(report.detected).toContain('bearer_token');
|
|
89
|
+
expect(report.severity).toBe('high');
|
|
90
|
+
});
|
|
91
|
+
it('should detect JWT tokens', () => {
|
|
92
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
93
|
+
const jwt = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIn0.dozjgNryP4J3jVmNHl0w5N_XgL0n3I9PlFUP0THsR8U';
|
|
94
|
+
const report = scanner.scan({ token: jwt });
|
|
95
|
+
expect(report.detected).toContain('jwt_token');
|
|
96
|
+
expect(report.severity).toBe('high');
|
|
97
|
+
});
|
|
98
|
+
it('should detect private keys', () => {
|
|
99
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
100
|
+
const report = scanner.scan({
|
|
101
|
+
key: '-----BEGIN RSA PRIVATE KEY-----\nMIIEowIBAAKCAQEA...',
|
|
102
|
+
});
|
|
103
|
+
expect(report.detected).toContain('private_key');
|
|
104
|
+
expect(report.severity).toBe('high');
|
|
105
|
+
});
|
|
106
|
+
it('should detect EC private keys', () => {
|
|
107
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
108
|
+
const report = scanner.scan({
|
|
109
|
+
key: '-----BEGIN EC PRIVATE KEY-----\nMHQCAQEEIBkg...',
|
|
110
|
+
});
|
|
111
|
+
expect(report.detected).toContain('private_key');
|
|
112
|
+
});
|
|
113
|
+
it('should detect plain private keys (without algorithm prefix)', () => {
|
|
114
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
115
|
+
const report = scanner.scan({
|
|
116
|
+
key: '-----BEGIN PRIVATE KEY-----\nMIIEvgIBADANBg...',
|
|
117
|
+
});
|
|
118
|
+
expect(report.detected).toContain('private_key');
|
|
119
|
+
});
|
|
120
|
+
it('should detect password fields', () => {
|
|
121
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
122
|
+
const report = scanner.scan({
|
|
123
|
+
config: 'password=SuperSecret123!',
|
|
124
|
+
});
|
|
125
|
+
expect(report.detected).toContain('password_field');
|
|
126
|
+
expect(report.severity).toBe('high');
|
|
127
|
+
});
|
|
128
|
+
it('should detect password fields with various prefixes (passwd, pwd)', () => {
|
|
129
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
130
|
+
const report1 = scanner.scan({ field: 'passwd=MyS3cur3Pa55!' });
|
|
131
|
+
expect(report1.detected).toContain('password_field');
|
|
132
|
+
const report2 = scanner.scan({ field: 'pwd:LongEnoughPassword1' });
|
|
133
|
+
expect(report2.detected).toContain('password_field');
|
|
134
|
+
});
|
|
135
|
+
it('should detect generic API keys', () => {
|
|
136
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
137
|
+
const report = scanner.scan({
|
|
138
|
+
config: 'api_key=sk_live_abcdefghij1234567890',
|
|
139
|
+
});
|
|
140
|
+
expect(report.detected).toContain('generic_api_key');
|
|
141
|
+
});
|
|
142
|
+
it('should detect generic API keys with various formats', () => {
|
|
143
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
144
|
+
const report1 = scanner.scan({ value: 'apikey: abcdef1234567890abcdef' });
|
|
145
|
+
expect(report1.detected).toContain('generic_api_key');
|
|
146
|
+
const report2 = scanner.scan({ value: 'api-key=abcdefghijklmnopqrst' });
|
|
147
|
+
expect(report2.detected).toContain('generic_api_key');
|
|
148
|
+
});
|
|
149
|
+
it('should detect Slack tokens', () => {
|
|
150
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
151
|
+
const report = scanner.scan({
|
|
152
|
+
token: 'xoxb-123456789012-1234567890123-AbCdEfGhIjKl',
|
|
153
|
+
});
|
|
154
|
+
expect(report.detected).toContain('slack_token');
|
|
155
|
+
expect(report.severity).toBe('high');
|
|
156
|
+
});
|
|
157
|
+
it('should detect generic secrets', () => {
|
|
158
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
159
|
+
const report = scanner.scan({
|
|
160
|
+
env: 'secret=abcdefghijklmnop1234',
|
|
161
|
+
});
|
|
162
|
+
expect(report.detected).toContain('generic_secret');
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
// -----------------------------------------------------------------------
|
|
166
|
+
// PII Detection
|
|
167
|
+
// -----------------------------------------------------------------------
|
|
168
|
+
describe('PII detection', () => {
|
|
169
|
+
it('should detect email addresses', () => {
|
|
170
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
171
|
+
const report = scanner.scan({ contact: 'user@example.com' });
|
|
172
|
+
expect(report.detected).toContain('email');
|
|
173
|
+
expect(report.severity).toBe('medium');
|
|
174
|
+
});
|
|
175
|
+
it('should detect various email formats', () => {
|
|
176
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
177
|
+
const report = scanner.scan({
|
|
178
|
+
emails: 'john.doe+test@sub.domain.co.uk, admin@company.io',
|
|
179
|
+
});
|
|
180
|
+
expect(report.detected).toContain('email');
|
|
181
|
+
});
|
|
182
|
+
it('should detect US phone numbers', () => {
|
|
183
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
184
|
+
const report = scanner.scan({ phone: '(555) 123-4567' });
|
|
185
|
+
expect(report.detected).toContain('phone_us');
|
|
186
|
+
expect(report.severity).toBe('medium');
|
|
187
|
+
});
|
|
188
|
+
it('should detect phone numbers with +1 prefix', () => {
|
|
189
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
190
|
+
const report = scanner.scan({ phone: '+1-555-123-4567' });
|
|
191
|
+
expect(report.detected).toContain('phone_us');
|
|
192
|
+
});
|
|
193
|
+
it('should detect SSNs', () => {
|
|
194
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
195
|
+
const report = scanner.scan({ ssn: '123-45-6789' });
|
|
196
|
+
expect(report.detected).toContain('ssn');
|
|
197
|
+
expect(report.severity).toBe('high');
|
|
198
|
+
});
|
|
199
|
+
it('should detect credit card numbers', () => {
|
|
200
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
201
|
+
const report = scanner.scan({ card: '4111 1111 1111 1111' });
|
|
202
|
+
expect(report.detected).toContain('credit_card');
|
|
203
|
+
expect(report.severity).toBe('high');
|
|
204
|
+
});
|
|
205
|
+
it('should detect credit card numbers with dashes', () => {
|
|
206
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
207
|
+
const report = scanner.scan({ card: '4111-1111-1111-1111' });
|
|
208
|
+
expect(report.detected).toContain('credit_card');
|
|
209
|
+
});
|
|
210
|
+
it('should detect IP addresses', () => {
|
|
211
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
212
|
+
const report = scanner.scan({ ip: '192.168.1.100' });
|
|
213
|
+
expect(report.detected).toContain('ip_address');
|
|
214
|
+
expect(report.severity).toBe('low');
|
|
215
|
+
});
|
|
216
|
+
});
|
|
217
|
+
// -----------------------------------------------------------------------
|
|
218
|
+
// Recursive Scanning
|
|
219
|
+
// -----------------------------------------------------------------------
|
|
220
|
+
describe('recursive scanning', () => {
|
|
221
|
+
it('should scan nested objects recursively', () => {
|
|
222
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
223
|
+
const data = {
|
|
224
|
+
level1: {
|
|
225
|
+
level2: {
|
|
226
|
+
level3: {
|
|
227
|
+
secret: 'password=VerySecretPass1',
|
|
228
|
+
},
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
};
|
|
232
|
+
const report = scanner.scan(data);
|
|
233
|
+
expect(report.detected).toContain('password_field');
|
|
234
|
+
expect(report.redactions.length).toBeGreaterThan(0);
|
|
235
|
+
// Check that the path is correctly computed
|
|
236
|
+
const redaction = report.redactions.find((r) => r.original_type === 'password_field');
|
|
237
|
+
expect(redaction).toBeDefined();
|
|
238
|
+
expect(redaction.path).toBe('level1.level2.level3.secret');
|
|
239
|
+
});
|
|
240
|
+
it('should scan arrays', () => {
|
|
241
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
242
|
+
const data = {
|
|
243
|
+
items: [
|
|
244
|
+
'safe text',
|
|
245
|
+
'AKIAIOSFODNN7EXAMPLE',
|
|
246
|
+
{ nested: 'user@example.com' },
|
|
247
|
+
],
|
|
248
|
+
};
|
|
249
|
+
const report = scanner.scan(data);
|
|
250
|
+
expect(report.detected).toContain('aws_access_key');
|
|
251
|
+
expect(report.detected).toContain('email');
|
|
252
|
+
const awsRedaction = report.redactions.find((r) => r.original_type === 'aws_access_key');
|
|
253
|
+
expect(awsRedaction).toBeDefined();
|
|
254
|
+
expect(awsRedaction.path).toBe('items[1]');
|
|
255
|
+
const emailRedaction = report.redactions.find((r) => r.original_type === 'email');
|
|
256
|
+
expect(emailRedaction).toBeDefined();
|
|
257
|
+
expect(emailRedaction.path).toBe('items[2].nested');
|
|
258
|
+
});
|
|
259
|
+
it('should handle null values gracefully', () => {
|
|
260
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
261
|
+
const report = scanner.scan({ value: null });
|
|
262
|
+
expect(report.detected).toHaveLength(0);
|
|
263
|
+
expect(report.redactions).toHaveLength(0);
|
|
264
|
+
});
|
|
265
|
+
it('should handle undefined values gracefully', () => {
|
|
266
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
267
|
+
const report = scanner.scan(undefined);
|
|
268
|
+
expect(report.detected).toHaveLength(0);
|
|
269
|
+
expect(report.redactions).toHaveLength(0);
|
|
270
|
+
});
|
|
271
|
+
it('should handle top-level null', () => {
|
|
272
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
273
|
+
const report = scanner.scan(null);
|
|
274
|
+
expect(report.detected).toHaveLength(0);
|
|
275
|
+
});
|
|
276
|
+
it('should ignore non-string primitives (numbers, booleans)', () => {
|
|
277
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
278
|
+
const report = scanner.scan({ count: 42, active: true, ratio: 3.14 });
|
|
279
|
+
expect(report.detected).toHaveLength(0);
|
|
280
|
+
});
|
|
281
|
+
it('should use basePath when provided', () => {
|
|
282
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
283
|
+
const report = scanner.scan({ token: 'AKIAIOSFODNN7EXAMPLE' }, 'args');
|
|
284
|
+
const redaction = report.redactions.find((r) => r.original_type === 'aws_access_key');
|
|
285
|
+
expect(redaction).toBeDefined();
|
|
286
|
+
expect(redaction.path).toBe('args.token');
|
|
287
|
+
});
|
|
288
|
+
it('should scan top-level arrays', () => {
|
|
289
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
290
|
+
const report = scanner.scan(['AKIAIOSFODNN7EXAMPLE', 'safe']);
|
|
291
|
+
expect(report.detected).toContain('aws_access_key');
|
|
292
|
+
const redaction = report.redactions.find((r) => r.original_type === 'aws_access_key');
|
|
293
|
+
expect(redaction).toBeDefined();
|
|
294
|
+
expect(redaction.path).toBe('[0]');
|
|
295
|
+
});
|
|
296
|
+
it('should scan a plain string value', () => {
|
|
297
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
298
|
+
const report = scanner.scan('password=MySuperSecret1');
|
|
299
|
+
expect(report.detected).toContain('password_field');
|
|
300
|
+
});
|
|
301
|
+
});
|
|
302
|
+
// -----------------------------------------------------------------------
|
|
303
|
+
// Severity Calculation
|
|
304
|
+
// -----------------------------------------------------------------------
|
|
305
|
+
describe('severity calculation', () => {
|
|
306
|
+
it('should return "low" when no detections are found', () => {
|
|
307
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
308
|
+
const report = scanner.scan({ safe: 'nothing here' });
|
|
309
|
+
expect(report.severity).toBe('low');
|
|
310
|
+
});
|
|
311
|
+
it('should return "medium" when only medium-severity items are detected', () => {
|
|
312
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
313
|
+
// generic_api_key has medium severity, email has medium severity
|
|
314
|
+
const report = scanner.scan({ contact: 'user@example.com' });
|
|
315
|
+
expect(report.severity).toBe('medium');
|
|
316
|
+
});
|
|
317
|
+
it('should return "high" when any high-severity item is detected', () => {
|
|
318
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
319
|
+
// Mix of medium (email) and high (AWS key)
|
|
320
|
+
const report = scanner.scan({
|
|
321
|
+
contact: 'user@example.com',
|
|
322
|
+
key: 'AKIAIOSFODNN7EXAMPLE',
|
|
323
|
+
});
|
|
324
|
+
expect(report.severity).toBe('high');
|
|
325
|
+
});
|
|
326
|
+
it('should return "high" overriding "medium" and "low" detections', () => {
|
|
327
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
328
|
+
const report = scanner.scan({
|
|
329
|
+
ip: '192.168.1.1', // ip_address -> low
|
|
330
|
+
email: 'user@example.com', // email -> medium
|
|
331
|
+
ssn: '123-45-6789', // ssn -> high
|
|
332
|
+
});
|
|
333
|
+
expect(report.severity).toBe('high');
|
|
334
|
+
});
|
|
335
|
+
it('should return "low" for IP-only detection', () => {
|
|
336
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
337
|
+
const report = scanner.scan({ ip: '10.0.0.1' });
|
|
338
|
+
expect(report.severity).toBe('low');
|
|
339
|
+
});
|
|
340
|
+
});
|
|
341
|
+
// -----------------------------------------------------------------------
|
|
342
|
+
// Redaction Methods (static)
|
|
343
|
+
// -----------------------------------------------------------------------
|
|
344
|
+
describe('redact (static)', () => {
|
|
345
|
+
const testValue = 'AKIAIOSFODNN7EXAMPLE';
|
|
346
|
+
it('should mask values (keep first 4 chars, replace rest with x)', () => {
|
|
347
|
+
const result = scanner_1.DLPScanner.redact(testValue, 'mask');
|
|
348
|
+
expect(result).toBe('AKIA' + 'x'.repeat(Math.min(testValue.length - 4, 20)));
|
|
349
|
+
expect(result.startsWith('AKIA')).toBe(true);
|
|
350
|
+
// The rest should be x's
|
|
351
|
+
expect(result.slice(4)).toMatch(/^x+$/);
|
|
352
|
+
});
|
|
353
|
+
it('should mask short values (length <= 4) as "xxxx"', () => {
|
|
354
|
+
expect(scanner_1.DLPScanner.redact('abc', 'mask')).toBe('xxxx');
|
|
355
|
+
expect(scanner_1.DLPScanner.redact('abcd', 'mask')).toBe('xxxx');
|
|
356
|
+
});
|
|
357
|
+
it('should cap mask replacement at 20 x characters', () => {
|
|
358
|
+
const longValue = 'abcd' + 'z'.repeat(50);
|
|
359
|
+
const result = scanner_1.DLPScanner.redact(longValue, 'mask');
|
|
360
|
+
expect(result).toBe('abcd' + 'x'.repeat(20));
|
|
361
|
+
});
|
|
362
|
+
it('should hash values with SHA-256 prefix', () => {
|
|
363
|
+
const result = scanner_1.DLPScanner.redact(testValue, 'hash');
|
|
364
|
+
expect(result).toMatch(/^HASH:[0-9a-f]{16}$/);
|
|
365
|
+
// Verify it matches the expected hash
|
|
366
|
+
const expectedHash = (0, crypto_1.createHash)('sha256').update(testValue).digest('hex').slice(0, 16);
|
|
367
|
+
expect(result).toBe(`HASH:${expectedHash}`);
|
|
368
|
+
});
|
|
369
|
+
it('should drop values entirely', () => {
|
|
370
|
+
expect(scanner_1.DLPScanner.redact(testValue, 'drop')).toBe('[REDACTED]');
|
|
371
|
+
});
|
|
372
|
+
it('should tokenize values with SHA-256 prefix', () => {
|
|
373
|
+
const result = scanner_1.DLPScanner.redact(testValue, 'tokenize');
|
|
374
|
+
expect(result).toMatch(/^\{\{REDACTED_[0-9a-f]{16}\}\}$/);
|
|
375
|
+
// Verify determinism
|
|
376
|
+
const expectedToken = (0, crypto_1.createHash)('sha256').update(testValue).digest('hex').slice(0, 16);
|
|
377
|
+
expect(result).toBe(`{{REDACTED_${expectedToken}}}`);
|
|
378
|
+
});
|
|
379
|
+
it('should default to [REDACTED] for unknown method', () => {
|
|
380
|
+
const result = scanner_1.DLPScanner.redact(testValue, 'unknown');
|
|
381
|
+
expect(result).toBe('[REDACTED]');
|
|
382
|
+
});
|
|
383
|
+
it('should produce deterministic results for hash and tokenize', () => {
|
|
384
|
+
const v = 'consistent_value_for_testing_123';
|
|
385
|
+
expect(scanner_1.DLPScanner.redact(v, 'hash')).toBe(scanner_1.DLPScanner.redact(v, 'hash'));
|
|
386
|
+
expect(scanner_1.DLPScanner.redact(v, 'tokenize')).toBe(scanner_1.DLPScanner.redact(v, 'tokenize'));
|
|
387
|
+
});
|
|
388
|
+
});
|
|
389
|
+
// -----------------------------------------------------------------------
|
|
390
|
+
// Entropy Calculation
|
|
391
|
+
// -----------------------------------------------------------------------
|
|
392
|
+
describe('calculateEntropy (static)', () => {
|
|
393
|
+
it('should return 0 for an empty string', () => {
|
|
394
|
+
expect(scanner_1.DLPScanner.calculateEntropy('')).toBe(0);
|
|
395
|
+
});
|
|
396
|
+
it('should return 0 for a single-character repeated string', () => {
|
|
397
|
+
expect(scanner_1.DLPScanner.calculateEntropy('aaaaaaa')).toBe(0);
|
|
398
|
+
});
|
|
399
|
+
it('should return 1 for a two-character string with equal distribution', () => {
|
|
400
|
+
// "ab" -> each char appears once out of 2 -> -2 * (0.5 * log2(0.5)) = 1
|
|
401
|
+
expect(scanner_1.DLPScanner.calculateEntropy('ab')).toBeCloseTo(1.0, 5);
|
|
402
|
+
});
|
|
403
|
+
it('should return higher entropy for random-looking strings', () => {
|
|
404
|
+
const lowEntropy = 'aaaaaaaabbbbbbbb';
|
|
405
|
+
const highEntropy = 'aB3$xZ9!qW7&mK2@';
|
|
406
|
+
expect(scanner_1.DLPScanner.calculateEntropy(highEntropy)).toBeGreaterThan(scanner_1.DLPScanner.calculateEntropy(lowEntropy));
|
|
407
|
+
});
|
|
408
|
+
it('should compute correct entropy for a known distribution', () => {
|
|
409
|
+
// "aabb" -> a:2, b:2 -> -2*(2/4 * log2(2/4)) = -2*(0.5*-1) = 1.0
|
|
410
|
+
expect(scanner_1.DLPScanner.calculateEntropy('aabb')).toBeCloseTo(1.0, 5);
|
|
411
|
+
});
|
|
412
|
+
it('should return higher entropy for more varied character sets', () => {
|
|
413
|
+
// 'aaabbbcccddd' has 3 unique chars each appearing 4 times -> low entropy
|
|
414
|
+
const lowVariety = 'aaabbbcccdddeeee';
|
|
415
|
+
// 'aB3$xZ9!qW7&mK2@' has 16 unique chars each appearing once -> high entropy
|
|
416
|
+
const highVariety = 'aB3$xZ9!qW7&mK2@';
|
|
417
|
+
expect(scanner_1.DLPScanner.calculateEntropy(highVariety)).toBeGreaterThan(scanner_1.DLPScanner.calculateEntropy(lowVariety));
|
|
418
|
+
});
|
|
419
|
+
});
|
|
420
|
+
// -----------------------------------------------------------------------
|
|
421
|
+
// High Entropy Detection
|
|
422
|
+
// -----------------------------------------------------------------------
|
|
423
|
+
describe('isHighEntropy (static)', () => {
|
|
424
|
+
it('should return false for short strings (< 16 chars)', () => {
|
|
425
|
+
expect(scanner_1.DLPScanner.isHighEntropy('aB3$xZ9!')).toBe(false);
|
|
426
|
+
expect(scanner_1.DLPScanner.isHighEntropy('123456789012345')).toBe(false); // 15 chars
|
|
427
|
+
});
|
|
428
|
+
it('should return false for low-entropy long strings', () => {
|
|
429
|
+
const lowEntropy = 'aaaaaaaaaaaaaaaa'; // 16 chars, entropy = 0
|
|
430
|
+
expect(scanner_1.DLPScanner.isHighEntropy(lowEntropy)).toBe(false);
|
|
431
|
+
});
|
|
432
|
+
it('should return true for high-entropy strings of sufficient length', () => {
|
|
433
|
+
// A base64-encoded random-looking string with many unique chars
|
|
434
|
+
const highEntropyStr = 'aB3$xZ9!qW7&mK2@pL5^tY8#';
|
|
435
|
+
const entropy = scanner_1.DLPScanner.calculateEntropy(highEntropyStr);
|
|
436
|
+
// Verify the string actually has high entropy first
|
|
437
|
+
expect(entropy).toBeGreaterThanOrEqual(4.0);
|
|
438
|
+
expect(scanner_1.DLPScanner.isHighEntropy(highEntropyStr)).toBe(true);
|
|
439
|
+
});
|
|
440
|
+
it('should respect custom threshold parameter', () => {
|
|
441
|
+
// A string with moderate entropy
|
|
442
|
+
const str = 'abcdefghijklmnop'; // 16 unique chars, entropy = 4.0
|
|
443
|
+
const entropy = scanner_1.DLPScanner.calculateEntropy(str);
|
|
444
|
+
// With a threshold below its entropy -> true
|
|
445
|
+
expect(scanner_1.DLPScanner.isHighEntropy(str, entropy - 0.1)).toBe(true);
|
|
446
|
+
// With a threshold above its entropy -> false
|
|
447
|
+
expect(scanner_1.DLPScanner.isHighEntropy(str, entropy + 0.1)).toBe(false);
|
|
448
|
+
});
|
|
449
|
+
it('should use default threshold of 4.5', () => {
|
|
450
|
+
// Entropy of 'abcdefghijklmnop' = log2(16) = 4.0, below 4.5
|
|
451
|
+
expect(scanner_1.DLPScanner.isHighEntropy('abcdefghijklmnop')).toBe(false);
|
|
452
|
+
});
|
|
453
|
+
});
|
|
454
|
+
// -----------------------------------------------------------------------
|
|
455
|
+
// Disabled DLP
|
|
456
|
+
// -----------------------------------------------------------------------
|
|
457
|
+
describe('disabled DLP', () => {
|
|
458
|
+
it('should return empty report when DLP is disabled', () => {
|
|
459
|
+
const scanner = new scanner_1.DLPScanner(buildConfig({ enabled: false }));
|
|
460
|
+
const report = scanner.scan({
|
|
461
|
+
key: 'AKIAIOSFODNN7EXAMPLE',
|
|
462
|
+
email: 'user@example.com',
|
|
463
|
+
password: 'password=SuperSecretPassword1',
|
|
464
|
+
});
|
|
465
|
+
expect(report.detected).toHaveLength(0);
|
|
466
|
+
expect(report.redactions).toHaveLength(0);
|
|
467
|
+
expect(report.severity).toBe('low');
|
|
468
|
+
});
|
|
469
|
+
});
|
|
470
|
+
// -----------------------------------------------------------------------
|
|
471
|
+
// Selective Scanning (secrets only, PII only)
|
|
472
|
+
// -----------------------------------------------------------------------
|
|
473
|
+
describe('selective scanning', () => {
|
|
474
|
+
it('should detect only secrets when PII detection is disabled', () => {
|
|
475
|
+
const scanner = new scanner_1.DLPScanner(buildConfig({ pii_detection: false }));
|
|
476
|
+
const report = scanner.scan({
|
|
477
|
+
key: 'AKIAIOSFODNN7EXAMPLE',
|
|
478
|
+
email: 'user@example.com',
|
|
479
|
+
ssn: '123-45-6789',
|
|
480
|
+
});
|
|
481
|
+
expect(report.detected).toContain('aws_access_key');
|
|
482
|
+
expect(report.detected).not.toContain('email');
|
|
483
|
+
expect(report.detected).not.toContain('ssn');
|
|
484
|
+
});
|
|
485
|
+
it('should detect only PII when secrets detection is disabled', () => {
|
|
486
|
+
const scanner = new scanner_1.DLPScanner(buildConfig({ secrets_detection: false }));
|
|
487
|
+
const report = scanner.scan({
|
|
488
|
+
key: 'AKIAIOSFODNN7EXAMPLE',
|
|
489
|
+
email: 'user@example.com',
|
|
490
|
+
ssn: '123-45-6789',
|
|
491
|
+
});
|
|
492
|
+
expect(report.detected).not.toContain('aws_access_key');
|
|
493
|
+
expect(report.detected).toContain('email');
|
|
494
|
+
expect(report.detected).toContain('ssn');
|
|
495
|
+
});
|
|
496
|
+
it('should detect nothing when both secrets and PII detection are disabled', () => {
|
|
497
|
+
const scanner = new scanner_1.DLPScanner(buildConfig({ secrets_detection: false, pii_detection: false }));
|
|
498
|
+
const report = scanner.scan({
|
|
499
|
+
key: 'AKIAIOSFODNN7EXAMPLE',
|
|
500
|
+
email: 'user@example.com',
|
|
501
|
+
});
|
|
502
|
+
expect(report.detected).toHaveLength(0);
|
|
503
|
+
expect(report.redactions).toHaveLength(0);
|
|
504
|
+
});
|
|
505
|
+
});
|
|
506
|
+
// -----------------------------------------------------------------------
|
|
507
|
+
// Redaction application (applyRedactions)
|
|
508
|
+
// -----------------------------------------------------------------------
|
|
509
|
+
describe('applyRedactions', () => {
|
|
510
|
+
it('should apply mask redaction to a nested path', () => {
|
|
511
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
512
|
+
const data = {
|
|
513
|
+
headers: {
|
|
514
|
+
Authorization: 'Bearer eyJhbGciOiJIUzI1NiJ9.payload.sig',
|
|
515
|
+
},
|
|
516
|
+
};
|
|
517
|
+
const redactions = [
|
|
518
|
+
{ path: 'headers.Authorization', method: 'mask', original_type: 'bearer_token' },
|
|
519
|
+
];
|
|
520
|
+
const result = scanner.applyRedactions(data, redactions);
|
|
521
|
+
// The original should not be mutated
|
|
522
|
+
expect(data.headers.Authorization).toBe('Bearer eyJhbGciOiJIUzI1NiJ9.payload.sig');
|
|
523
|
+
// The redacted result should not contain the original bearer token
|
|
524
|
+
expect(result.headers.Authorization).not.toBe(data.headers.Authorization);
|
|
525
|
+
});
|
|
526
|
+
it('should apply drop redaction', () => {
|
|
527
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
528
|
+
const data = { secret: 'AKIAIOSFODNN7EXAMPLE' };
|
|
529
|
+
const redactions = [
|
|
530
|
+
{ path: 'secret', method: 'drop', original_type: 'aws_access_key' },
|
|
531
|
+
];
|
|
532
|
+
const result = scanner.applyRedactions(data, redactions);
|
|
533
|
+
// The entire matched portion is replaced with [REDACTED]
|
|
534
|
+
expect(result.secret).toContain('[REDACTED]');
|
|
535
|
+
});
|
|
536
|
+
it('should return data unchanged when no redactions are provided', () => {
|
|
537
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
538
|
+
const data = { key: 'value' };
|
|
539
|
+
const result = scanner.applyRedactions(data, []);
|
|
540
|
+
expect(result).toEqual(data);
|
|
541
|
+
});
|
|
542
|
+
it('should handle array paths in redactions', () => {
|
|
543
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
544
|
+
const data = {
|
|
545
|
+
items: ['safe', 'AKIAIOSFODNN7EXAMPLE'],
|
|
546
|
+
};
|
|
547
|
+
const redactions = [
|
|
548
|
+
{ path: 'items[1]', method: 'drop', original_type: 'aws_access_key' },
|
|
549
|
+
];
|
|
550
|
+
const result = scanner.applyRedactions(data, redactions);
|
|
551
|
+
expect(result.items[0]).toBe('safe');
|
|
552
|
+
expect(result.items[1]).toContain('[REDACTED]');
|
|
553
|
+
});
|
|
554
|
+
it('should not mutate the original data', () => {
|
|
555
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
556
|
+
const original = { secret: 'AKIAIOSFODNN7EXAMPLE' };
|
|
557
|
+
const redactions = [
|
|
558
|
+
{ path: 'secret', method: 'drop', original_type: 'aws_access_key' },
|
|
559
|
+
];
|
|
560
|
+
scanner.applyRedactions(original, redactions);
|
|
561
|
+
expect(original.secret).toBe('AKIAIOSFODNN7EXAMPLE');
|
|
562
|
+
});
|
|
563
|
+
it('should skip silently when path cannot be resolved', () => {
|
|
564
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
565
|
+
const data = { key: 'value' };
|
|
566
|
+
const redactions = [
|
|
567
|
+
{ path: 'nonexistent.deep.path', method: 'drop' },
|
|
568
|
+
];
|
|
569
|
+
const result = scanner.applyRedactions(data, redactions);
|
|
570
|
+
expect(result).toEqual({ key: 'value' });
|
|
571
|
+
});
|
|
572
|
+
it('should skip silently when the leaf is not a string', () => {
|
|
573
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
574
|
+
const data = { count: 42 };
|
|
575
|
+
const redactions = [
|
|
576
|
+
{ path: 'count', method: 'mask' },
|
|
577
|
+
];
|
|
578
|
+
const result = scanner.applyRedactions(data, redactions);
|
|
579
|
+
expect(result.count).toBe(42);
|
|
580
|
+
});
|
|
581
|
+
});
|
|
582
|
+
// -----------------------------------------------------------------------
|
|
583
|
+
// parsePath (static)
|
|
584
|
+
// -----------------------------------------------------------------------
|
|
585
|
+
describe('parsePath (static)', () => {
|
|
586
|
+
it('should parse dot-notation paths', () => {
|
|
587
|
+
expect(scanner_1.DLPScanner.parsePath('a.b.c')).toEqual(['a', 'b', 'c']);
|
|
588
|
+
});
|
|
589
|
+
it('should parse bracket-notation paths', () => {
|
|
590
|
+
expect(scanner_1.DLPScanner.parsePath('items[0]')).toEqual(['items', '0']);
|
|
591
|
+
});
|
|
592
|
+
it('should parse mixed dot and bracket notation', () => {
|
|
593
|
+
expect(scanner_1.DLPScanner.parsePath('items[0].value')).toEqual(['items', '0', 'value']);
|
|
594
|
+
});
|
|
595
|
+
it('should parse standalone bracket path', () => {
|
|
596
|
+
expect(scanner_1.DLPScanner.parsePath('[0]')).toEqual(['0']);
|
|
597
|
+
});
|
|
598
|
+
it('should return empty array for empty string', () => {
|
|
599
|
+
expect(scanner_1.DLPScanner.parsePath('')).toEqual([]);
|
|
600
|
+
});
|
|
601
|
+
it('should parse single segment', () => {
|
|
602
|
+
expect(scanner_1.DLPScanner.parsePath('key')).toEqual(['key']);
|
|
603
|
+
});
|
|
604
|
+
});
|
|
605
|
+
// -----------------------------------------------------------------------
|
|
606
|
+
// deepClone (static)
|
|
607
|
+
// -----------------------------------------------------------------------
|
|
608
|
+
describe('deepClone (static)', () => {
|
|
609
|
+
it('should deep clone objects', () => {
|
|
610
|
+
const original = { a: { b: { c: 1 } } };
|
|
611
|
+
const cloned = scanner_1.DLPScanner.deepClone(original);
|
|
612
|
+
expect(cloned).toEqual(original);
|
|
613
|
+
cloned.a.b.c = 99;
|
|
614
|
+
expect(original.a.b.c).toBe(1);
|
|
615
|
+
});
|
|
616
|
+
it('should deep clone arrays', () => {
|
|
617
|
+
const original = [1, [2, 3], { a: 4 }];
|
|
618
|
+
const cloned = scanner_1.DLPScanner.deepClone(original);
|
|
619
|
+
expect(cloned).toEqual(original);
|
|
620
|
+
cloned[2].a = 99;
|
|
621
|
+
expect(original[2].a).toBe(4);
|
|
622
|
+
});
|
|
623
|
+
it('should return null for null', () => {
|
|
624
|
+
expect(scanner_1.DLPScanner.deepClone(null)).toBe(null);
|
|
625
|
+
});
|
|
626
|
+
it('should return undefined for undefined', () => {
|
|
627
|
+
expect(scanner_1.DLPScanner.deepClone(undefined)).toBe(undefined);
|
|
628
|
+
});
|
|
629
|
+
it('should return primitives as-is', () => {
|
|
630
|
+
expect(scanner_1.DLPScanner.deepClone(42)).toBe(42);
|
|
631
|
+
expect(scanner_1.DLPScanner.deepClone('hello')).toBe('hello');
|
|
632
|
+
expect(scanner_1.DLPScanner.deepClone(true)).toBe(true);
|
|
633
|
+
});
|
|
634
|
+
});
|
|
635
|
+
// -----------------------------------------------------------------------
|
|
636
|
+
// Deduplication
|
|
637
|
+
// -----------------------------------------------------------------------
|
|
638
|
+
describe('detection deduplication', () => {
|
|
639
|
+
it('should deduplicate detection names in the report', () => {
|
|
640
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
641
|
+
const report = scanner.scan({
|
|
642
|
+
key1: 'AKIAIOSFODNN7EXAMPLE',
|
|
643
|
+
key2: 'AKIAIOSFODNN7FOOBAR1',
|
|
644
|
+
});
|
|
645
|
+
// Both are aws_access_key but should appear only once in detected
|
|
646
|
+
const awsCount = report.detected.filter((d) => d === 'aws_access_key').length;
|
|
647
|
+
expect(awsCount).toBe(1);
|
|
648
|
+
// But there should be 2 redactions (one per field)
|
|
649
|
+
const awsRedactions = report.redactions.filter((r) => r.original_type === 'aws_access_key');
|
|
650
|
+
expect(awsRedactions.length).toBe(2);
|
|
651
|
+
});
|
|
652
|
+
});
|
|
653
|
+
// -----------------------------------------------------------------------
|
|
654
|
+
// Redaction method from config
|
|
655
|
+
// -----------------------------------------------------------------------
|
|
656
|
+
describe('uses configured default_redaction_method', () => {
|
|
657
|
+
it('should use "hash" as the redaction method when configured', () => {
|
|
658
|
+
const scanner = new scanner_1.DLPScanner(buildConfig({ default_redaction_method: 'hash' }));
|
|
659
|
+
const report = scanner.scan({ key: 'AKIAIOSFODNN7EXAMPLE' });
|
|
660
|
+
for (const redaction of report.redactions) {
|
|
661
|
+
expect(redaction.method).toBe('hash');
|
|
662
|
+
}
|
|
663
|
+
});
|
|
664
|
+
it('should use "drop" as the redaction method when configured', () => {
|
|
665
|
+
const scanner = new scanner_1.DLPScanner(buildConfig({ default_redaction_method: 'drop' }));
|
|
666
|
+
const report = scanner.scan({ email: 'user@example.com' });
|
|
667
|
+
for (const redaction of report.redactions) {
|
|
668
|
+
expect(redaction.method).toBe('drop');
|
|
669
|
+
}
|
|
670
|
+
});
|
|
671
|
+
it('should use "tokenize" as the redaction method when configured', () => {
|
|
672
|
+
const scanner = new scanner_1.DLPScanner(buildConfig({ default_redaction_method: 'tokenize' }));
|
|
673
|
+
const report = scanner.scan({ key: 'AKIAIOSFODNN7EXAMPLE' });
|
|
674
|
+
for (const redaction of report.redactions) {
|
|
675
|
+
expect(redaction.method).toBe('tokenize');
|
|
676
|
+
}
|
|
677
|
+
});
|
|
678
|
+
});
|
|
679
|
+
// -----------------------------------------------------------------------
|
|
680
|
+
// Multiple detections in single string
|
|
681
|
+
// -----------------------------------------------------------------------
|
|
682
|
+
describe('multiple detections in a single string', () => {
|
|
683
|
+
it('should detect multiple secret types in one string', () => {
|
|
684
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
685
|
+
const combined = 'key=AKIAIOSFODNN7EXAMPLE token=xoxb-1234567890-1234567890-abcdefghij';
|
|
686
|
+
const report = scanner.scan({ value: combined });
|
|
687
|
+
expect(report.detected).toContain('aws_access_key');
|
|
688
|
+
expect(report.detected).toContain('slack_token');
|
|
689
|
+
});
|
|
690
|
+
});
|
|
691
|
+
// -----------------------------------------------------------------------
|
|
692
|
+
// DLP Bypass Vector Tests
|
|
693
|
+
// -----------------------------------------------------------------------
|
|
694
|
+
describe('DLP bypass vectors', () => {
|
|
695
|
+
// Use RegexDLPBackend directly for these tests since it has the
|
|
696
|
+
// normalization logic (zero-width stripping, homoglyph replacement, base64 decode)
|
|
697
|
+
let backend;
|
|
698
|
+
beforeAll(async () => {
|
|
699
|
+
const { RegexDLPBackend } = await Promise.resolve().then(() => __importStar(require('../../src/dlp/regex-backend')));
|
|
700
|
+
backend = new RegexDLPBackend();
|
|
701
|
+
});
|
|
702
|
+
it('should detect base64-encoded AWS key', () => {
|
|
703
|
+
const awsKey = 'AKIAIOSFODNN7EXAMPLE';
|
|
704
|
+
const encoded = Buffer.from(awsKey).toString('base64');
|
|
705
|
+
const detections = backend.scanString(encoded);
|
|
706
|
+
// Should detect the AWS key either directly or via base64 decoding
|
|
707
|
+
const hasAwsDetection = detections.some(d => d.pattern_name === 'aws_access_key' || d.pattern_name === 'base64:aws_access_key');
|
|
708
|
+
expect(hasAwsDetection).toBe(true);
|
|
709
|
+
});
|
|
710
|
+
it('should detect AWS key with Unicode homoglyph (Cyrillic A)', () => {
|
|
711
|
+
// Replace ASCII 'A' with Cyrillic 'A' (U+0410) in the AKIA prefix
|
|
712
|
+
const homoglyphKey = '\u0410KI\u0410IOSFODNN7EXAMPLE';
|
|
713
|
+
const detections = backend.scanString(homoglyphKey);
|
|
714
|
+
const hasAwsDetection = detections.some(d => d.pattern_name === 'aws_access_key');
|
|
715
|
+
expect(hasAwsDetection).toBe(true);
|
|
716
|
+
});
|
|
717
|
+
it('should detect AWS key with zero-width characters inserted', () => {
|
|
718
|
+
// Insert zero-width space (U+200B) inside the key
|
|
719
|
+
const zwKey = 'AKI\u200BAIOSFODNN7EXAMPLE';
|
|
720
|
+
const detections = backend.scanString(zwKey);
|
|
721
|
+
const hasAwsDetection = detections.some(d => d.pattern_name === 'aws_access_key');
|
|
722
|
+
expect(hasAwsDetection).toBe(true);
|
|
723
|
+
});
|
|
724
|
+
it('should NOT detect secrets nested beyond depth limit (> 32 levels)', () => {
|
|
725
|
+
const scanner = new scanner_1.DLPScanner(buildConfig());
|
|
726
|
+
// Build an object nested 33 levels deep with a secret at the bottom
|
|
727
|
+
let obj = { secret: 'AKIAIOSFODNN7EXAMPLE' };
|
|
728
|
+
for (let i = 0; i < 33; i++) {
|
|
729
|
+
obj = { nested: obj };
|
|
730
|
+
}
|
|
731
|
+
const report = scanner.scan(obj);
|
|
732
|
+
// The secret is at depth 34 (33 wrapping levels + 1 for the 'secret' key),
|
|
733
|
+
// which exceeds MAX_SCAN_DEPTH of 32, so it should NOT be detected
|
|
734
|
+
expect(report.detected).not.toContain('aws_access_key');
|
|
735
|
+
expect(report.redactions).toHaveLength(0);
|
|
736
|
+
});
|
|
737
|
+
});
|
|
738
|
+
});
|
|
739
|
+
//# sourceMappingURL=dlp-scanner.test.js.map
|