@wopr-network/platform-core 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/biome.json +61 -0
- package/dist/admin/admin-audit-log-repository.d.ts +33 -0
- package/dist/admin/admin-audit-log-repository.js +102 -0
- package/dist/admin/audit-log.d.ts +49 -0
- package/dist/admin/audit-log.js +63 -0
- package/dist/admin/index.d.ts +6 -0
- package/dist/admin/index.js +3 -0
- package/dist/admin/role-store.d.ts +37 -0
- package/dist/admin/role-store.js +106 -0
- package/dist/auth/api-key-repository.d.ts +11 -0
- package/dist/auth/api-key-repository.js +33 -0
- package/dist/auth/api-key-repository.test.d.ts +1 -0
- package/dist/auth/api-key-repository.test.js +46 -0
- package/dist/auth/auth.test.d.ts +1 -0
- package/dist/auth/auth.test.js +140 -0
- package/dist/auth/better-auth.d.ts +42 -0
- package/dist/auth/better-auth.js +196 -0
- package/dist/auth/index.d.ts +186 -0
- package/dist/auth/index.js +422 -0
- package/dist/auth/login-history-repository.d.ts +14 -0
- package/dist/auth/login-history-repository.js +15 -0
- package/dist/auth/login-history-repository.test.d.ts +1 -0
- package/dist/auth/login-history-repository.test.js +47 -0
- package/dist/auth/middleware.d.ts +55 -0
- package/dist/auth/middleware.js +101 -0
- package/dist/auth/middleware.test.d.ts +1 -0
- package/dist/auth/middleware.test.js +213 -0
- package/dist/auth/scoped-tokens.test.d.ts +1 -0
- package/dist/auth/scoped-tokens.test.js +306 -0
- package/dist/auth/tenant-access.test.d.ts +1 -0
- package/dist/auth/tenant-access.test.js +62 -0
- package/dist/auth/user-creator.d.ts +9 -0
- package/dist/auth/user-creator.js +47 -0
- package/dist/auth/user-creator.test.d.ts +1 -0
- package/dist/auth/user-creator.test.js +78 -0
- package/dist/auth/user-role-repository.d.ts +31 -0
- package/dist/auth/user-role-repository.js +53 -0
- package/dist/auth/user-role-repository.test.d.ts +1 -0
- package/dist/auth/user-role-repository.test.js +122 -0
- package/dist/billing/drizzle-webhook-seen-repository.d.ts +10 -0
- package/dist/billing/drizzle-webhook-seen-repository.js +28 -0
- package/dist/billing/index.d.ts +7 -0
- package/dist/billing/index.js +7 -0
- package/dist/billing/payment-processor.d.ts +127 -0
- package/dist/billing/payment-processor.js +8 -0
- package/dist/billing/payment-processor.test.d.ts +1 -0
- package/dist/billing/payment-processor.test.js +71 -0
- package/dist/billing/payram/cents-credits-boundary.test.d.ts +1 -0
- package/dist/billing/payram/cents-credits-boundary.test.js +75 -0
- package/dist/billing/payram/charge-store.d.ts +41 -0
- package/dist/billing/payram/charge-store.js +72 -0
- package/dist/billing/payram/charge-store.test.d.ts +1 -0
- package/dist/billing/payram/charge-store.test.js +64 -0
- package/dist/billing/payram/checkout.d.ts +15 -0
- package/dist/billing/payram/checkout.js +24 -0
- package/dist/billing/payram/checkout.test.d.ts +1 -0
- package/dist/billing/payram/checkout.test.js +74 -0
- package/dist/billing/payram/client.d.ts +7 -0
- package/dist/billing/payram/client.js +15 -0
- package/dist/billing/payram/client.test.d.ts +1 -0
- package/dist/billing/payram/client.test.js +52 -0
- package/dist/billing/payram/index.d.ts +8 -0
- package/dist/billing/payram/index.js +4 -0
- package/dist/billing/payram/types.d.ts +40 -0
- package/dist/billing/payram/types.js +1 -0
- package/dist/billing/payram/webhook.d.ts +19 -0
- package/dist/billing/payram/webhook.js +67 -0
- package/dist/billing/payram/webhook.test.d.ts +7 -0
- package/dist/billing/payram/webhook.test.js +248 -0
- package/dist/billing/stripe/cents-credits-boundary.test.d.ts +1 -0
- package/dist/billing/stripe/cents-credits-boundary.test.js +62 -0
- package/dist/billing/stripe/checkout.d.ts +20 -0
- package/dist/billing/stripe/checkout.js +63 -0
- package/dist/billing/stripe/checkout.test.d.ts +1 -0
- package/dist/billing/stripe/checkout.test.js +148 -0
- package/dist/billing/stripe/client.d.ts +14 -0
- package/dist/billing/stripe/client.js +33 -0
- package/dist/billing/stripe/client.test.d.ts +1 -0
- package/dist/billing/stripe/client.test.js +58 -0
- package/dist/billing/stripe/credit-prices.d.ts +63 -0
- package/dist/billing/stripe/credit-prices.js +81 -0
- package/dist/billing/stripe/credit-prices.test.d.ts +1 -0
- package/dist/billing/stripe/credit-prices.test.js +87 -0
- package/dist/billing/stripe/index.d.ts +14 -0
- package/dist/billing/stripe/index.js +8 -0
- package/dist/billing/stripe/payment-methods-detach-all.test.d.ts +1 -0
- package/dist/billing/stripe/payment-methods-detach-all.test.js +40 -0
- package/dist/billing/stripe/payment-methods.d.ts +25 -0
- package/dist/billing/stripe/payment-methods.js +53 -0
- package/dist/billing/stripe/payment-methods.test.d.ts +1 -0
- package/dist/billing/stripe/payment-methods.test.js +122 -0
- package/dist/billing/stripe/portal.d.ts +10 -0
- package/dist/billing/stripe/portal.js +16 -0
- package/dist/billing/stripe/portal.test.d.ts +1 -0
- package/dist/billing/stripe/portal.test.js +48 -0
- package/dist/billing/stripe/setup-intent.d.ts +16 -0
- package/dist/billing/stripe/setup-intent.js +22 -0
- package/dist/billing/stripe/setup-intent.test.d.ts +1 -0
- package/dist/billing/stripe/setup-intent.test.js +58 -0
- package/dist/billing/stripe/stripe-payment-processor.d.ts +49 -0
- package/dist/billing/stripe/stripe-payment-processor.js +166 -0
- package/dist/billing/stripe/stripe-payment-processor.test.d.ts +1 -0
- package/dist/billing/stripe/stripe-payment-processor.test.js +413 -0
- package/dist/billing/stripe/tenant-store.d.ts +56 -0
- package/dist/billing/stripe/tenant-store.js +119 -0
- package/dist/billing/stripe/tenant-store.test.d.ts +1 -0
- package/dist/billing/stripe/tenant-store.test.js +97 -0
- package/dist/billing/stripe/types.d.ts +49 -0
- package/dist/billing/stripe/types.js +1 -0
- package/dist/billing/webhook-seen-repository.d.ts +14 -0
- package/dist/billing/webhook-seen-repository.js +13 -0
- package/dist/config/billing-env.test.d.ts +1 -0
- package/dist/config/billing-env.test.js +48 -0
- package/dist/config/index.d.ts +46 -0
- package/dist/config/index.js +38 -0
- package/dist/config/logger.d.ts +2 -0
- package/dist/config/logger.js +11 -0
- package/dist/config/provider-endpoints.d.ts +6 -0
- package/dist/config/provider-endpoints.js +12 -0
- package/dist/credits/auto-topup-charge.d.ts +27 -0
- package/dist/credits/auto-topup-charge.js +139 -0
- package/dist/credits/auto-topup-charge.test.d.ts +1 -0
- package/dist/credits/auto-topup-charge.test.js +242 -0
- package/dist/credits/auto-topup-event-log-repository.d.ts +16 -0
- package/dist/credits/auto-topup-event-log-repository.js +18 -0
- package/dist/credits/auto-topup-event-log-repository.test.d.ts +1 -0
- package/dist/credits/auto-topup-event-log-repository.test.js +83 -0
- package/dist/credits/auto-topup-schedule.d.ts +27 -0
- package/dist/credits/auto-topup-schedule.js +66 -0
- package/dist/credits/auto-topup-schedule.test.d.ts +1 -0
- package/dist/credits/auto-topup-schedule.test.js +145 -0
- package/dist/credits/auto-topup-settings-repository.d.ts +54 -0
- package/dist/credits/auto-topup-settings-repository.js +184 -0
- package/dist/credits/auto-topup-settings-repository.test.d.ts +1 -0
- package/dist/credits/auto-topup-settings-repository.test.js +104 -0
- package/dist/credits/auto-topup-usage.d.ts +22 -0
- package/dist/credits/auto-topup-usage.js +56 -0
- package/dist/credits/auto-topup-usage.test.d.ts +1 -0
- package/dist/credits/auto-topup-usage.test.js +181 -0
- package/dist/credits/credit-expiry-cron.d.ts +19 -0
- package/dist/credits/credit-expiry-cron.js +50 -0
- package/dist/credits/credit-expiry-cron.test.d.ts +1 -0
- package/dist/credits/credit-expiry-cron.test.js +67 -0
- package/dist/credits/credit-ledger-extra.test.d.ts +1 -0
- package/dist/credits/credit-ledger-extra.test.js +40 -0
- package/dist/credits/credit-ledger.bench.d.ts +1 -0
- package/dist/credits/credit-ledger.bench.js +33 -0
- package/dist/credits/credit-ledger.d.ts +130 -0
- package/dist/credits/credit-ledger.js +293 -0
- package/dist/credits/credit-ledger.test.d.ts +4 -0
- package/dist/credits/credit-ledger.test.js +203 -0
- package/dist/credits/credit-transaction-repository.d.ts +17 -0
- package/dist/credits/credit-transaction-repository.js +35 -0
- package/dist/credits/credit-transaction-repository.test.d.ts +1 -0
- package/dist/credits/credit-transaction-repository.test.js +232 -0
- package/dist/credits/credit.d.ts +75 -0
- package/dist/credits/credit.js +139 -0
- package/dist/credits/credit.test.d.ts +1 -0
- package/dist/credits/credit.test.js +196 -0
- package/dist/credits/dividend-cron.d.ts +29 -0
- package/dist/credits/dividend-cron.js +88 -0
- package/dist/credits/dividend-cron.test.d.ts +1 -0
- package/dist/credits/dividend-cron.test.js +128 -0
- package/dist/credits/dividend-repository.d.ts +29 -0
- package/dist/credits/dividend-repository.js +126 -0
- package/dist/credits/dividend-repository.test.d.ts +1 -0
- package/dist/credits/dividend-repository.test.js +176 -0
- package/dist/credits/index.d.ts +9 -0
- package/dist/credits/index.js +5 -0
- package/dist/credits/repository-types.d.ts +29 -0
- package/dist/credits/repository-types.js +1 -0
- package/dist/credits/signup-grant.d.ts +12 -0
- package/dist/credits/signup-grant.js +35 -0
- package/dist/credits/signup-grant.test.d.ts +1 -0
- package/dist/credits/signup-grant.test.js +51 -0
- package/dist/credits/tenant-customer-repository.d.ts +30 -0
- package/dist/credits/tenant-customer-repository.js +5 -0
- package/dist/db/auth-user-repository.d.ts +46 -0
- package/dist/db/auth-user-repository.js +90 -0
- package/dist/db/credit-column.d.ts +27 -0
- package/dist/db/credit-column.js +13 -0
- package/dist/db/index.d.ts +14 -0
- package/dist/db/index.js +8 -0
- package/dist/db/schema/account-deletion-requests.d.ts +203 -0
- package/dist/db/schema/account-deletion-requests.js +36 -0
- package/dist/db/schema/account-export-requests.d.ts +148 -0
- package/dist/db/schema/account-export-requests.js +19 -0
- package/dist/db/schema/admin-audit.d.ts +194 -0
- package/dist/db/schema/admin-audit.js +21 -0
- package/dist/db/schema/admin-users.d.ts +177 -0
- package/dist/db/schema/admin-users.js +23 -0
- package/dist/db/schema/affiliate-fraud.d.ts +160 -0
- package/dist/db/schema/affiliate-fraud.js +18 -0
- package/dist/db/schema/affiliate.d.ts +277 -0
- package/dist/db/schema/affiliate.js +32 -0
- package/dist/db/schema/coupon-codes.d.ts +143 -0
- package/dist/db/schema/coupon-codes.js +17 -0
- package/dist/db/schema/credit-auto-topup-settings.d.ts +232 -0
- package/dist/db/schema/credit-auto-topup-settings.js +27 -0
- package/dist/db/schema/credit-auto-topup.d.ts +130 -0
- package/dist/db/schema/credit-auto-topup.js +21 -0
- package/dist/db/schema/credits.d.ts +283 -0
- package/dist/db/schema/credits.js +38 -0
- package/dist/db/schema/dividend-distributions.d.ts +130 -0
- package/dist/db/schema/dividend-distributions.js +19 -0
- package/dist/db/schema/email-notifications.d.ts +99 -0
- package/dist/db/schema/email-notifications.js +21 -0
- package/dist/db/schema/index.d.ts +33 -0
- package/dist/db/schema/index.js +33 -0
- package/dist/db/schema/meter-events.d.ts +599 -0
- package/dist/db/schema/meter-events.js +55 -0
- package/dist/db/schema/notification-preferences.d.ts +165 -0
- package/dist/db/schema/notification-preferences.js +18 -0
- package/dist/db/schema/notification-queue.d.ts +236 -0
- package/dist/db/schema/notification-queue.js +40 -0
- package/dist/db/schema/org-memberships.d.ts +63 -0
- package/dist/db/schema/org-memberships.js +15 -0
- package/dist/db/schema/organization-members.d.ts +235 -0
- package/dist/db/schema/organization-members.js +27 -0
- package/dist/db/schema/payram.d.ts +164 -0
- package/dist/db/schema/payram.js +21 -0
- package/dist/db/schema/platform-api-keys.d.ts +143 -0
- package/dist/db/schema/platform-api-keys.js +20 -0
- package/dist/db/schema/promotion-redemptions.d.ts +143 -0
- package/dist/db/schema/promotion-redemptions.js +18 -0
- package/dist/db/schema/promotions.d.ts +445 -0
- package/dist/db/schema/promotions.js +48 -0
- package/dist/db/schema/provider-credentials.d.ts +201 -0
- package/dist/db/schema/provider-credentials.js +36 -0
- package/dist/db/schema/rate-limit-entries.d.ts +75 -0
- package/dist/db/schema/rate-limit-entries.js +7 -0
- package/dist/db/schema/secret-audit-log.d.ts +109 -0
- package/dist/db/schema/secret-audit-log.js +15 -0
- package/dist/db/schema/session-usage.d.ts +194 -0
- package/dist/db/schema/session-usage.js +19 -0
- package/dist/db/schema/spending-limits.d.ts +92 -0
- package/dist/db/schema/spending-limits.js +8 -0
- package/dist/db/schema/tenant-addons.d.ts +58 -0
- package/dist/db/schema/tenant-addons.js +9 -0
- package/dist/db/schema/tenant-api-keys.d.ts +131 -0
- package/dist/db/schema/tenant-api-keys.js +21 -0
- package/dist/db/schema/tenant-capability-settings.d.ts +79 -0
- package/dist/db/schema/tenant-capability-settings.js +12 -0
- package/dist/db/schema/tenant-customers.d.ts +303 -0
- package/dist/db/schema/tenant-customers.js +25 -0
- package/dist/db/schema/tenants.d.ts +126 -0
- package/dist/db/schema/tenants.js +18 -0
- package/dist/db/schema/user-roles.d.ts +98 -0
- package/dist/db/schema/user-roles.js +18 -0
- package/dist/db/schema/webhook-seen-events.d.ts +58 -0
- package/dist/db/schema/webhook-seen-events.js +9 -0
- package/dist/email/billing-emails.d.ts +51 -0
- package/dist/email/billing-emails.js +163 -0
- package/dist/email/billing-emails.test.d.ts +1 -0
- package/dist/email/billing-emails.test.js +162 -0
- package/dist/email/client.d.ts +51 -0
- package/dist/email/client.js +102 -0
- package/dist/email/client.test.d.ts +1 -0
- package/dist/email/client.test.js +120 -0
- package/dist/email/drizzle-billing-email-repository.d.ts +21 -0
- package/dist/email/drizzle-billing-email-repository.js +36 -0
- package/dist/email/drizzle-billing-email-repository.test.d.ts +1 -0
- package/dist/email/drizzle-billing-email-repository.test.js +42 -0
- package/dist/email/index.d.ts +33 -0
- package/dist/email/index.js +22 -0
- package/dist/email/notification-preferences-store.d.ts +12 -0
- package/dist/email/notification-preferences-store.js +82 -0
- package/dist/email/notification-preferences-store.test.d.ts +1 -0
- package/dist/email/notification-preferences-store.test.js +86 -0
- package/dist/email/notification-queue-store.d.ts +25 -0
- package/dist/email/notification-queue-store.js +97 -0
- package/dist/email/notification-queue-store.test.d.ts +1 -0
- package/dist/email/notification-queue-store.test.js +177 -0
- package/dist/email/notification-repository-types.d.ts +70 -0
- package/dist/email/notification-repository-types.js +6 -0
- package/dist/email/notification-service.d.ts +41 -0
- package/dist/email/notification-service.js +196 -0
- package/dist/email/notification-service.test.d.ts +1 -0
- package/dist/email/notification-service.test.js +160 -0
- package/dist/email/notification-templates.d.ts +18 -0
- package/dist/email/notification-templates.js +574 -0
- package/dist/email/notification-templates.test.d.ts +1 -0
- package/dist/email/notification-templates.test.js +238 -0
- package/dist/email/notification-worker.d.ts +24 -0
- package/dist/email/notification-worker.js +109 -0
- package/dist/email/notification-worker.test.d.ts +1 -0
- package/dist/email/notification-worker.test.js +153 -0
- package/dist/email/require-verified.d.ts +25 -0
- package/dist/email/require-verified.js +52 -0
- package/dist/email/require-verified.test.d.ts +1 -0
- package/dist/email/require-verified.test.js +62 -0
- package/dist/email/resend-adapter.d.ts +47 -0
- package/dist/email/resend-adapter.js +137 -0
- package/dist/email/resend-adapter.test.d.ts +1 -0
- package/dist/email/resend-adapter.test.js +190 -0
- package/dist/email/templates.d.ts +22 -0
- package/dist/email/templates.js +359 -0
- package/dist/email/templates.test.d.ts +1 -0
- package/dist/email/templates.test.js +170 -0
- package/dist/email/verification.d.ts +42 -0
- package/dist/email/verification.js +83 -0
- package/dist/email/verification.test.d.ts +1 -0
- package/dist/email/verification.test.js +141 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +23 -0
- package/dist/metering/aggregator.d.ts +54 -0
- package/dist/metering/aggregator.js +123 -0
- package/dist/metering/aggregator.test.d.ts +1 -0
- package/dist/metering/aggregator.test.js +179 -0
- package/dist/metering/dlq.d.ts +31 -0
- package/dist/metering/dlq.js +82 -0
- package/dist/metering/dlq.test.d.ts +1 -0
- package/dist/metering/dlq.test.js +117 -0
- package/dist/metering/drizzle-usage-summary-repository.d.ts +67 -0
- package/dist/metering/drizzle-usage-summary-repository.js +98 -0
- package/dist/metering/emitter.d.ts +66 -0
- package/dist/metering/emitter.js +185 -0
- package/dist/metering/emitter.test.d.ts +1 -0
- package/dist/metering/emitter.test.js +171 -0
- package/dist/metering/index.d.ts +11 -0
- package/dist/metering/index.js +5 -0
- package/dist/metering/load-test.bench.d.ts +1 -0
- package/dist/metering/load-test.bench.js +103 -0
- package/dist/metering/meter-event-repository.d.ts +33 -0
- package/dist/metering/meter-event-repository.js +58 -0
- package/dist/metering/meter-repositories.test.d.ts +1 -0
- package/dist/metering/meter-repositories.test.js +419 -0
- package/dist/metering/metering.test.d.ts +1 -0
- package/dist/metering/metering.test.js +1046 -0
- package/dist/metering/reconciliation-cron.d.ts +37 -0
- package/dist/metering/reconciliation-cron.js +85 -0
- package/dist/metering/reconciliation-cron.test.d.ts +1 -0
- package/dist/metering/reconciliation-cron.test.js +162 -0
- package/dist/metering/reconciliation-repository.d.ts +27 -0
- package/dist/metering/reconciliation-repository.js +43 -0
- package/dist/metering/reconciliation-repository.test.d.ts +1 -0
- package/dist/metering/reconciliation-repository.test.js +160 -0
- package/dist/metering/types.d.ts +88 -0
- package/dist/metering/types.js +1 -0
- package/dist/metering/wal.d.ts +49 -0
- package/dist/metering/wal.js +124 -0
- package/dist/metering/wal.test.d.ts +1 -0
- package/dist/metering/wal.test.js +175 -0
- package/dist/middleware/csrf.d.ts +24 -0
- package/dist/middleware/csrf.js +80 -0
- package/dist/middleware/csrf.test.d.ts +1 -0
- package/dist/middleware/csrf.test.js +152 -0
- package/dist/middleware/drizzle-rate-limit-repository.d.ts +9 -0
- package/dist/middleware/drizzle-rate-limit-repository.js +52 -0
- package/dist/middleware/drizzle-rate-limit-repository.test.d.ts +1 -0
- package/dist/middleware/drizzle-rate-limit-repository.test.js +74 -0
- package/dist/middleware/get-client-ip.d.ts +22 -0
- package/dist/middleware/get-client-ip.js +51 -0
- package/dist/middleware/get-client-ip.test.d.ts +1 -0
- package/dist/middleware/get-client-ip.test.js +40 -0
- package/dist/middleware/index.d.ts +5 -0
- package/dist/middleware/index.js +4 -0
- package/dist/middleware/rate-limit-repository.d.ts +19 -0
- package/dist/middleware/rate-limit-repository.js +1 -0
- package/dist/middleware/rate-limit.d.ts +57 -0
- package/dist/middleware/rate-limit.js +109 -0
- package/dist/middleware/rate-limit.test.d.ts +1 -0
- package/dist/middleware/rate-limit.test.js +247 -0
- package/dist/security/credential-vault/audit-repository.d.ts +27 -0
- package/dist/security/credential-vault/audit-repository.js +42 -0
- package/dist/security/credential-vault/audit-repository.test.d.ts +1 -0
- package/dist/security/credential-vault/audit-repository.test.js +78 -0
- package/dist/security/credential-vault/credential-repository.d.ts +94 -0
- package/dist/security/credential-vault/credential-repository.js +145 -0
- package/dist/security/credential-vault/credential-repository.test.d.ts +1 -0
- package/dist/security/credential-vault/credential-repository.test.js +206 -0
- package/dist/security/credential-vault/index.d.ts +12 -0
- package/dist/security/credential-vault/index.js +6 -0
- package/dist/security/credential-vault/key-rotation.d.ts +18 -0
- package/dist/security/credential-vault/key-rotation.js +52 -0
- package/dist/security/credential-vault/key-rotation.test.d.ts +1 -0
- package/dist/security/credential-vault/key-rotation.test.js +95 -0
- package/dist/security/credential-vault/migrate-plaintext.d.ts +15 -0
- package/dist/security/credential-vault/migrate-plaintext.js +80 -0
- package/dist/security/credential-vault/migrate-plaintext.test.d.ts +1 -0
- package/dist/security/credential-vault/migrate-plaintext.test.js +111 -0
- package/dist/security/credential-vault/migration-check.d.ts +15 -0
- package/dist/security/credential-vault/migration-check.js +71 -0
- package/dist/security/credential-vault/migration-check.test.d.ts +1 -0
- package/dist/security/credential-vault/migration-check.test.js +457 -0
- package/dist/security/credential-vault/store.d.ts +106 -0
- package/dist/security/credential-vault/store.js +181 -0
- package/dist/security/credential-vault/store.test.d.ts +1 -0
- package/dist/security/credential-vault/store.test.js +482 -0
- package/dist/security/encryption.d.ts +22 -0
- package/dist/security/encryption.js +53 -0
- package/dist/security/encryption.test.d.ts +1 -0
- package/dist/security/encryption.test.js +95 -0
- package/dist/security/host-validation.d.ts +11 -0
- package/dist/security/host-validation.js +108 -0
- package/dist/security/host-validation.test.d.ts +1 -0
- package/dist/security/host-validation.test.js +106 -0
- package/dist/security/index.d.ts +11 -0
- package/dist/security/index.js +11 -0
- package/dist/security/key-audit.d.ts +16 -0
- package/dist/security/key-audit.js +35 -0
- package/dist/security/key-audit.test.d.ts +1 -0
- package/dist/security/key-audit.test.js +50 -0
- package/dist/security/key-injection.d.ts +28 -0
- package/dist/security/key-injection.js +57 -0
- package/dist/security/key-injection.test.d.ts +1 -0
- package/dist/security/key-injection.test.js +97 -0
- package/dist/security/key-validation.d.ts +16 -0
- package/dist/security/key-validation.js +78 -0
- package/dist/security/key-validation.test.d.ts +1 -0
- package/dist/security/key-validation.test.js +87 -0
- package/dist/security/redirect-allowlist.d.ts +6 -0
- package/dist/security/redirect-allowlist.js +36 -0
- package/dist/security/redirect-allowlist.test.d.ts +1 -0
- package/dist/security/redirect-allowlist.test.js +55 -0
- package/dist/security/tenant-keys/capability-settings-store.d.ts +22 -0
- package/dist/security/tenant-keys/capability-settings-store.js +33 -0
- package/dist/security/tenant-keys/capability-settings-store.test.d.ts +1 -0
- package/dist/security/tenant-keys/capability-settings-store.test.js +77 -0
- package/dist/security/tenant-keys/index.d.ts +10 -0
- package/dist/security/tenant-keys/index.js +5 -0
- package/dist/security/tenant-keys/key-resolution-repository.d.ts +15 -0
- package/dist/security/tenant-keys/key-resolution-repository.js +18 -0
- package/dist/security/tenant-keys/key-resolution-repository.test.d.ts +1 -0
- package/dist/security/tenant-keys/key-resolution-repository.test.js +72 -0
- package/dist/security/tenant-keys/key-resolution.d.ts +39 -0
- package/dist/security/tenant-keys/key-resolution.js +59 -0
- package/dist/security/tenant-keys/key-resolution.test.d.ts +1 -0
- package/dist/security/tenant-keys/key-resolution.test.js +97 -0
- package/dist/security/tenant-keys/org-key-resolution.d.ts +30 -0
- package/dist/security/tenant-keys/org-key-resolution.js +50 -0
- package/dist/security/tenant-keys/org-key-resolution.test.d.ts +1 -0
- package/dist/security/tenant-keys/org-key-resolution.test.js +103 -0
- package/dist/security/tenant-keys/tenant-key-repository.d.ts +36 -0
- package/dist/security/tenant-keys/tenant-key-repository.js +96 -0
- package/dist/security/tenant-keys/tenant-key-repository.test.d.ts +1 -0
- package/dist/security/tenant-keys/tenant-key-repository.test.js +114 -0
- package/dist/security/types.d.ts +35 -0
- package/dist/security/types.js +15 -0
- package/dist/tenancy/drizzle-org-repository.d.ts +40 -0
- package/dist/tenancy/drizzle-org-repository.js +126 -0
- package/dist/tenancy/index.d.ts +6 -0
- package/dist/tenancy/index.js +3 -0
- package/dist/tenancy/org-member-repository.d.ts +57 -0
- package/dist/tenancy/org-member-repository.js +99 -0
- package/dist/tenancy/org-repository.test.d.ts +1 -0
- package/dist/tenancy/org-repository.test.js +143 -0
- package/dist/tenancy/org-service.d.ts +70 -0
- package/dist/tenancy/org-service.js +223 -0
- package/dist/tenancy/org-service.test.d.ts +1 -0
- package/dist/tenancy/org-service.test.js +550 -0
- package/dist/test/db.d.ts +33 -0
- package/dist/test/db.js +65 -0
- package/dist/trpc/index.d.ts +1 -0
- package/dist/trpc/index.js +1 -0
- package/dist/trpc/init.d.ts +49 -0
- package/dist/trpc/init.js +108 -0
- package/dist/trpc/init.test.d.ts +1 -0
- package/dist/trpc/init.test.js +154 -0
- package/drizzle/migrations/0000_slippery_mandrill.sql +559 -0
- package/drizzle/migrations/meta/0000_snapshot.json +4374 -0
- package/drizzle/migrations/meta/_journal.json +13 -0
- package/drizzle.config.ts +41 -0
- package/package.json +64 -0
- package/src/admin/admin-audit-log-repository.ts +135 -0
- package/src/admin/audit-log.ts +111 -0
- package/src/admin/index.ts +6 -0
- package/src/admin/role-store.ts +134 -0
- package/src/auth/api-key-repository.test.ts +63 -0
- package/src/auth/api-key-repository.ts +46 -0
- package/src/auth/auth.test.ts +166 -0
- package/src/auth/better-auth.ts +216 -0
- package/src/auth/index.ts +520 -0
- package/src/auth/login-history-repository.test.ts +54 -0
- package/src/auth/login-history-repository.ts +28 -0
- package/src/auth/middleware.test.ts +264 -0
- package/src/auth/middleware.ts +117 -0
- package/src/auth/scoped-tokens.test.ts +362 -0
- package/src/auth/tenant-access.test.ts +69 -0
- package/src/auth/user-creator.test.ts +98 -0
- package/src/auth/user-creator.ts +54 -0
- package/src/auth/user-role-repository.test.ts +149 -0
- package/src/auth/user-role-repository.ts +67 -0
- package/src/billing/drizzle-webhook-seen-repository.ts +34 -0
- package/src/billing/index.ts +22 -0
- package/src/billing/payment-processor.test.ts +93 -0
- package/src/billing/payment-processor.ts +150 -0
- package/src/billing/payram/cents-credits-boundary.test.ts +84 -0
- package/src/billing/payram/charge-store.test.ts +84 -0
- package/src/billing/payram/charge-store.ts +109 -0
- package/src/billing/payram/checkout.test.ts +99 -0
- package/src/billing/payram/checkout.ts +40 -0
- package/src/billing/payram/client.test.ts +62 -0
- package/src/billing/payram/client.ts +21 -0
- package/src/billing/payram/index.ts +14 -0
- package/src/billing/payram/types.ts +44 -0
- package/src/billing/payram/webhook.test.ts +318 -0
- package/src/billing/payram/webhook.ts +97 -0
- package/src/billing/stripe/cents-credits-boundary.test.ts +70 -0
- package/src/billing/stripe/checkout.test.ts +186 -0
- package/src/billing/stripe/checkout.ts +82 -0
- package/src/billing/stripe/client.test.ts +64 -0
- package/src/billing/stripe/client.ts +39 -0
- package/src/billing/stripe/credit-prices.test.ts +114 -0
- package/src/billing/stripe/credit-prices.ts +113 -0
- package/src/billing/stripe/index.ts +14 -0
- package/src/billing/stripe/payment-methods-detach-all.test.ts +53 -0
- package/src/billing/stripe/payment-methods.test.ts +157 -0
- package/src/billing/stripe/payment-methods.ts +76 -0
- package/src/billing/stripe/portal.test.ts +63 -0
- package/src/billing/stripe/portal.ts +25 -0
- package/src/billing/stripe/setup-intent.test.ts +78 -0
- package/src/billing/stripe/setup-intent.ts +34 -0
- package/src/billing/stripe/stripe-payment-processor.test.ts +517 -0
- package/src/billing/stripe/stripe-payment-processor.ts +255 -0
- package/src/billing/stripe/tenant-store.test.ts +124 -0
- package/src/billing/stripe/tenant-store.ts +151 -0
- package/src/billing/stripe/types.ts +53 -0
- package/src/billing/webhook-seen-repository.ts +24 -0
- package/src/config/billing-env.test.ts +54 -0
- package/src/config/index.ts +44 -0
- package/src/config/logger.ts +12 -0
- package/src/config/provider-endpoints.ts +14 -0
- package/src/credits/auto-topup-charge.test.ts +292 -0
- package/src/credits/auto-topup-charge.ts +171 -0
- package/src/credits/auto-topup-event-log-repository.test.ts +99 -0
- package/src/credits/auto-topup-event-log-repository.ts +30 -0
- package/src/credits/auto-topup-schedule.test.ts +179 -0
- package/src/credits/auto-topup-schedule.ts +93 -0
- package/src/credits/auto-topup-settings-repository.test.ts +123 -0
- package/src/credits/auto-topup-settings-repository.ts +245 -0
- package/src/credits/auto-topup-usage.test.ts +220 -0
- package/src/credits/auto-topup-usage.ts +68 -0
- package/src/credits/credit-expiry-cron.test.ts +125 -0
- package/src/credits/credit-expiry-cron.ts +76 -0
- package/src/credits/credit-ledger-extra.test.ts +57 -0
- package/src/credits/credit-ledger.bench.ts +56 -0
- package/src/credits/credit-ledger.test.ts +276 -0
- package/src/credits/credit-ledger.ts +450 -0
- package/src/credits/credit-transaction-repository.test.ts +274 -0
- package/src/credits/credit-transaction-repository.ts +62 -0
- package/src/credits/credit.test.ts +234 -0
- package/src/credits/credit.ts +160 -0
- package/src/credits/dividend-cron.test.ts +158 -0
- package/src/credits/dividend-cron.ts +127 -0
- package/src/credits/dividend-repository.test.ts +223 -0
- package/src/credits/dividend-repository.ts +182 -0
- package/src/credits/index.ts +25 -0
- package/src/credits/repository-types.ts +33 -0
- package/src/credits/signup-grant.test.ts +63 -0
- package/src/credits/signup-grant.ts +44 -0
- package/src/credits/tenant-customer-repository.ts +28 -0
- package/src/db/auth-user-repository.ts +124 -0
- package/src/db/credit-column.ts +17 -0
- package/src/db/index.ts +21 -0
- package/src/db/schema/account-deletion-requests.ts +41 -0
- package/src/db/schema/account-export-requests.ts +24 -0
- package/src/db/schema/admin-audit.ts +26 -0
- package/src/db/schema/admin-users.ts +31 -0
- package/src/db/schema/affiliate-fraud.ts +23 -0
- package/src/db/schema/affiliate.ts +38 -0
- package/src/db/schema/coupon-codes.ts +22 -0
- package/src/db/schema/credit-auto-topup-settings.ts +32 -0
- package/src/db/schema/credit-auto-topup.ts +26 -0
- package/src/db/schema/credits.ts +44 -0
- package/src/db/schema/dividend-distributions.ts +24 -0
- package/src/db/schema/email-notifications.ts +26 -0
- package/src/db/schema/index.ts +33 -0
- package/src/db/schema/meter-events.ts +70 -0
- package/src/db/schema/notification-preferences.ts +19 -0
- package/src/db/schema/notification-queue.ts +45 -0
- package/src/db/schema/org-memberships.ts +20 -0
- package/src/db/schema/organization-members.ts +37 -0
- package/src/db/schema/payram.ts +26 -0
- package/src/db/schema/platform-api-keys.ts +25 -0
- package/src/db/schema/promotion-redemptions.ts +23 -0
- package/src/db/schema/promotions.ts +57 -0
- package/src/db/schema/provider-credentials.ts +41 -0
- package/src/db/schema/rate-limit-entries.ts +12 -0
- package/src/db/schema/secret-audit-log.ts +20 -0
- package/src/db/schema/session-usage.ts +24 -0
- package/src/db/schema/spending-limits.ts +9 -0
- package/src/db/schema/tenant-addons.ts +14 -0
- package/src/db/schema/tenant-api-keys.ts +26 -0
- package/src/db/schema/tenant-capability-settings.ts +17 -0
- package/src/db/schema/tenant-customers.ts +35 -0
- package/src/db/schema/tenants.ts +23 -0
- package/src/db/schema/user-roles.ts +23 -0
- package/src/db/schema/webhook-seen-events.ts +14 -0
- package/src/email/billing-emails.test.ts +198 -0
- package/src/email/billing-emails.ts +211 -0
- package/src/email/client.test.ts +149 -0
- package/src/email/client.ts +137 -0
- package/src/email/drizzle-billing-email-repository.test.ts +52 -0
- package/src/email/drizzle-billing-email-repository.ts +59 -0
- package/src/email/index.ts +57 -0
- package/src/email/notification-preferences-store.test.ts +102 -0
- package/src/email/notification-preferences-store.ts +90 -0
- package/src/email/notification-queue-store.test.ts +215 -0
- package/src/email/notification-queue-store.ts +127 -0
- package/src/email/notification-repository-types.ts +101 -0
- package/src/email/notification-service.test.ts +178 -0
- package/src/email/notification-service.ts +265 -0
- package/src/email/notification-templates.test.ts +261 -0
- package/src/email/notification-templates.ts +727 -0
- package/src/email/notification-worker.test.ts +189 -0
- package/src/email/notification-worker.ts +133 -0
- package/src/email/require-verified.ts +65 -0
- package/src/email/resend-adapter.test.ts +253 -0
- package/src/email/resend-adapter.ts +157 -0
- package/src/email/templates.test.ts +217 -0
- package/src/email/templates.ts +469 -0
- package/src/email/verification.test.ts +185 -0
- package/src/email/verification.ts +110 -0
- package/src/index.ts +51 -0
- package/src/metering/aggregator.test.ts +239 -0
- package/src/metering/aggregator.ts +160 -0
- package/src/metering/dlq.test.ts +134 -0
- package/src/metering/dlq.ts +102 -0
- package/src/metering/drizzle-usage-summary-repository.ts +167 -0
- package/src/metering/emitter.test.ts +202 -0
- package/src/metering/emitter.ts +227 -0
- package/src/metering/index.ts +21 -0
- package/src/metering/load-test.bench.ts +130 -0
- package/src/metering/meter-event-repository.ts +87 -0
- package/src/metering/meter-repositories.test.ts +491 -0
- package/src/metering/metering.test.ts +1317 -0
- package/src/metering/reconciliation-cron.test.ts +202 -0
- package/src/metering/reconciliation-cron.ts +134 -0
- package/src/metering/reconciliation-repository.test.ts +196 -0
- package/src/metering/reconciliation-repository.ts +83 -0
- package/src/metering/types.ts +93 -0
- package/src/metering/wal.test.ts +222 -0
- package/src/metering/wal.ts +139 -0
- package/src/middleware/csrf.test.ts +178 -0
- package/src/middleware/csrf.ts +101 -0
- package/src/middleware/drizzle-rate-limit-repository.test.ts +97 -0
- package/src/middleware/drizzle-rate-limit-repository.ts +57 -0
- package/src/middleware/get-client-ip.test.ts +49 -0
- package/src/middleware/get-client-ip.ts +62 -0
- package/src/middleware/index.ts +12 -0
- package/src/middleware/rate-limit-repository.ts +22 -0
- package/src/middleware/rate-limit.test.ts +338 -0
- package/src/middleware/rate-limit.ts +169 -0
- package/src/security/credential-vault/audit-repository.test.ts +91 -0
- package/src/security/credential-vault/audit-repository.ts +64 -0
- package/src/security/credential-vault/credential-repository.test.ts +264 -0
- package/src/security/credential-vault/credential-repository.ts +233 -0
- package/src/security/credential-vault/index.ts +26 -0
- package/src/security/credential-vault/key-rotation.test.ts +139 -0
- package/src/security/credential-vault/key-rotation.ts +70 -0
- package/src/security/credential-vault/migrate-plaintext.test.ts +138 -0
- package/src/security/credential-vault/migrate-plaintext.ts +101 -0
- package/src/security/credential-vault/migration-check.test.ts +533 -0
- package/src/security/credential-vault/migration-check.ts +88 -0
- package/src/security/credential-vault/store.test.ts +569 -0
- package/src/security/credential-vault/store.ts +284 -0
- package/src/security/encryption.test.ts +114 -0
- package/src/security/encryption.ts +65 -0
- package/src/security/host-validation.test.ts +136 -0
- package/src/security/host-validation.ts +116 -0
- package/src/security/index.ts +59 -0
- package/src/security/key-audit.test.ts +57 -0
- package/src/security/key-audit.ts +45 -0
- package/src/security/key-injection.test.ts +131 -0
- package/src/security/key-injection.ts +71 -0
- package/src/security/key-validation.test.ts +111 -0
- package/src/security/key-validation.ts +84 -0
- package/src/security/redirect-allowlist.test.ts +70 -0
- package/src/security/redirect-allowlist.ts +35 -0
- package/src/security/tenant-keys/capability-settings-store.test.ts +98 -0
- package/src/security/tenant-keys/capability-settings-store.ts +53 -0
- package/src/security/tenant-keys/index.ts +10 -0
- package/src/security/tenant-keys/key-resolution-repository.test.ts +95 -0
- package/src/security/tenant-keys/key-resolution-repository.ts +31 -0
- package/src/security/tenant-keys/key-resolution.test.ts +173 -0
- package/src/security/tenant-keys/key-resolution.ts +87 -0
- package/src/security/tenant-keys/org-key-resolution.test.ts +217 -0
- package/src/security/tenant-keys/org-key-resolution.ts +76 -0
- package/src/security/tenant-keys/tenant-key-repository.test.ts +143 -0
- package/src/security/tenant-keys/tenant-key-repository.ts +130 -0
- package/src/security/types.ts +43 -0
- package/src/tenancy/drizzle-org-repository.ts +169 -0
- package/src/tenancy/index.ts +6 -0
- package/src/tenancy/org-member-repository.ts +159 -0
- package/src/tenancy/org-repository.test.ts +172 -0
- package/src/tenancy/org-service.test.ts +634 -0
- package/src/tenancy/org-service.ts +290 -0
- package/src/test/db.ts +97 -0
- package/src/trpc/index.ts +11 -0
- package/src/trpc/init.test.ts +196 -0
- package/src/trpc/init.ts +138 -0
- package/tsconfig.json +20 -0
- package/vitest.config.ts +8 -0
|
@@ -0,0 +1,457 @@
|
|
|
1
|
+
import { eq } from "drizzle-orm";
|
|
2
|
+
import { afterAll, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
|
3
|
+
import { providerCredentials, tenantApiKeys } from "../../db/schema/index.js";
|
|
4
|
+
import { createTestDb, truncateAllTables } from "../../test/db.js";
|
|
5
|
+
import { decrypt, encrypt, generateInstanceKey } from "../encryption.js";
|
|
6
|
+
import { DrizzleCredentialRepository, DrizzleMigrationTenantKeyAccess } from "./credential-repository.js";
|
|
7
|
+
import { reEncryptAllCredentials } from "./key-rotation.js";
|
|
8
|
+
import { migratePlaintextCredentials } from "./migrate-plaintext.js";
|
|
9
|
+
import { auditCredentialEncryption } from "./migration-check.js";
|
|
10
|
+
import { CredentialVaultStore, getVaultEncryptionKey } from "./store.js";
|
|
11
|
+
// TOP OF FILE - shared across ALL describes
|
|
12
|
+
let pool;
|
|
13
|
+
let db;
|
|
14
|
+
beforeAll(async () => {
|
|
15
|
+
({ db, pool } = await createTestDb());
|
|
16
|
+
});
|
|
17
|
+
afterAll(async () => {
|
|
18
|
+
await pool.close();
|
|
19
|
+
});
|
|
20
|
+
describe("auditCredentialEncryption", () => {
|
|
21
|
+
beforeEach(async () => {
|
|
22
|
+
await truncateAllTables(pool);
|
|
23
|
+
});
|
|
24
|
+
it("returns empty array when all credentials are properly encrypted", async () => {
|
|
25
|
+
const key = generateInstanceKey();
|
|
26
|
+
const encrypted = JSON.stringify(encrypt("sk-ant-test123", key));
|
|
27
|
+
await db.insert(providerCredentials).values({
|
|
28
|
+
id: "cred-1",
|
|
29
|
+
provider: "anthropic",
|
|
30
|
+
keyName: "Test",
|
|
31
|
+
encryptedValue: encrypted,
|
|
32
|
+
authType: "header",
|
|
33
|
+
createdBy: "admin",
|
|
34
|
+
});
|
|
35
|
+
const findings = await auditCredentialEncryption(db);
|
|
36
|
+
expect(findings).toEqual([]);
|
|
37
|
+
});
|
|
38
|
+
it("detects plaintext API keys", async () => {
|
|
39
|
+
await db.insert(providerCredentials).values({
|
|
40
|
+
id: "cred-1",
|
|
41
|
+
provider: "anthropic",
|
|
42
|
+
keyName: "Test",
|
|
43
|
+
encryptedValue: "sk-ant-api12345678901234567890",
|
|
44
|
+
authType: "header",
|
|
45
|
+
createdBy: "admin",
|
|
46
|
+
});
|
|
47
|
+
const findings = await auditCredentialEncryption(db);
|
|
48
|
+
expect(findings).toHaveLength(1);
|
|
49
|
+
expect(findings[0].table).toBe("provider_credentials");
|
|
50
|
+
expect(findings[0].rowId).toBe("cred-1");
|
|
51
|
+
});
|
|
52
|
+
it("detects malformed encrypted payloads (missing fields)", async () => {
|
|
53
|
+
await db.insert(providerCredentials).values({
|
|
54
|
+
id: "cred-1",
|
|
55
|
+
provider: "anthropic",
|
|
56
|
+
keyName: "Test",
|
|
57
|
+
encryptedValue: JSON.stringify({ iv: "aa" }), // missing authTag and ciphertext
|
|
58
|
+
authType: "header",
|
|
59
|
+
createdBy: "admin",
|
|
60
|
+
});
|
|
61
|
+
const findings = await auditCredentialEncryption(db);
|
|
62
|
+
expect(findings).toHaveLength(1);
|
|
63
|
+
});
|
|
64
|
+
it("returns empty array when table has no rows", async () => {
|
|
65
|
+
const findings = await auditCredentialEncryption(db);
|
|
66
|
+
expect(findings).toEqual([]);
|
|
67
|
+
});
|
|
68
|
+
it("handles missing tenant_api_keys gracefully (no plaintext tenant keys)", async () => {
|
|
69
|
+
// tenant_api_keys table exists but is empty — should not throw
|
|
70
|
+
const findings = await auditCredentialEncryption(db);
|
|
71
|
+
expect(findings).toEqual([]);
|
|
72
|
+
});
|
|
73
|
+
it("detects plaintext in tenant_api_keys when table exists", async () => {
|
|
74
|
+
await db.insert(tenantApiKeys).values({
|
|
75
|
+
id: "tk-1",
|
|
76
|
+
tenantId: "tenant-a",
|
|
77
|
+
provider: "anthropic",
|
|
78
|
+
label: "Test",
|
|
79
|
+
encryptedKey: "sk-ant-api12345678901234567890",
|
|
80
|
+
createdAt: Date.now(),
|
|
81
|
+
updatedAt: Date.now(),
|
|
82
|
+
});
|
|
83
|
+
const findings = await auditCredentialEncryption(db);
|
|
84
|
+
expect(findings).toHaveLength(1);
|
|
85
|
+
expect(findings[0].table).toBe("tenant_api_keys");
|
|
86
|
+
expect(findings[0].rowId).toBe("tk-1");
|
|
87
|
+
});
|
|
88
|
+
});
|
|
89
|
+
describe("migratePlaintextCredentials", () => {
|
|
90
|
+
let vaultKey;
|
|
91
|
+
let credRepo;
|
|
92
|
+
let tenantAccess;
|
|
93
|
+
beforeEach(async () => {
|
|
94
|
+
await truncateAllTables(pool);
|
|
95
|
+
vaultKey = generateInstanceKey();
|
|
96
|
+
credRepo = new DrizzleCredentialRepository(db);
|
|
97
|
+
tenantAccess = new DrizzleMigrationTenantKeyAccess(db);
|
|
98
|
+
});
|
|
99
|
+
it("skips already-encrypted rows", async () => {
|
|
100
|
+
const encrypted = JSON.stringify(encrypt("sk-ant-test", vaultKey));
|
|
101
|
+
await db.insert(providerCredentials).values({
|
|
102
|
+
id: "cred-1",
|
|
103
|
+
provider: "anthropic",
|
|
104
|
+
keyName: "Test",
|
|
105
|
+
encryptedValue: encrypted,
|
|
106
|
+
authType: "header",
|
|
107
|
+
createdBy: "admin",
|
|
108
|
+
});
|
|
109
|
+
const results = await migratePlaintextCredentials(credRepo, vaultKey, () => vaultKey, tenantAccess);
|
|
110
|
+
expect(results[0].migratedCount).toBe(0);
|
|
111
|
+
expect(results[0].errors).toHaveLength(0);
|
|
112
|
+
});
|
|
113
|
+
it("encrypts plaintext rows", async () => {
|
|
114
|
+
await db.insert(providerCredentials).values({
|
|
115
|
+
id: "cred-1",
|
|
116
|
+
provider: "anthropic",
|
|
117
|
+
keyName: "Test",
|
|
118
|
+
encryptedValue: "sk-ant-plaintext-key-1234567890",
|
|
119
|
+
authType: "header",
|
|
120
|
+
createdBy: "admin",
|
|
121
|
+
});
|
|
122
|
+
const results = await migratePlaintextCredentials(credRepo, vaultKey, () => vaultKey, tenantAccess);
|
|
123
|
+
expect(results[0].migratedCount).toBe(1);
|
|
124
|
+
// Verify the value is now encrypted JSON
|
|
125
|
+
const rows = await db
|
|
126
|
+
.select({ encryptedValue: providerCredentials.encryptedValue })
|
|
127
|
+
.from(providerCredentials)
|
|
128
|
+
.where(eq(providerCredentials.id, "cred-1"));
|
|
129
|
+
const parsed = JSON.parse(rows[0].encryptedValue);
|
|
130
|
+
expect(parsed).toHaveProperty("iv");
|
|
131
|
+
expect(parsed).toHaveProperty("authTag");
|
|
132
|
+
expect(parsed).toHaveProperty("ciphertext");
|
|
133
|
+
});
|
|
134
|
+
it("handles empty provider_credentials gracefully", async () => {
|
|
135
|
+
// Should not throw when table is empty
|
|
136
|
+
const results = await migratePlaintextCredentials(credRepo, vaultKey, () => vaultKey, tenantAccess);
|
|
137
|
+
expect(results[0].table).toBe("provider_credentials");
|
|
138
|
+
});
|
|
139
|
+
it("migrates tenant_api_keys when table exists", async () => {
|
|
140
|
+
await db.insert(tenantApiKeys).values({
|
|
141
|
+
id: "tk-1",
|
|
142
|
+
tenantId: "tenant-a",
|
|
143
|
+
provider: "anthropic",
|
|
144
|
+
label: "Test",
|
|
145
|
+
encryptedKey: "sk-ant-plaintext-key-1234567890",
|
|
146
|
+
createdAt: Date.now(),
|
|
147
|
+
updatedAt: Date.now(),
|
|
148
|
+
});
|
|
149
|
+
const results = await migratePlaintextCredentials(credRepo, vaultKey, () => vaultKey, tenantAccess);
|
|
150
|
+
const tenantResult = results.find((r) => r.table === "tenant_api_keys");
|
|
151
|
+
expect(tenantResult).not.toBeNull();
|
|
152
|
+
expect(tenantResult?.migratedCount).toBe(1);
|
|
153
|
+
});
|
|
154
|
+
it("returns table name in results", async () => {
|
|
155
|
+
const results = await migratePlaintextCredentials(credRepo, vaultKey, () => vaultKey, tenantAccess);
|
|
156
|
+
expect(results[0].table).toBe("provider_credentials");
|
|
157
|
+
});
|
|
158
|
+
it("migrated row is subsequently detected as already-encrypted", async () => {
|
|
159
|
+
await db.insert(providerCredentials).values({
|
|
160
|
+
id: "cred-1",
|
|
161
|
+
provider: "anthropic",
|
|
162
|
+
keyName: "Test",
|
|
163
|
+
encryptedValue: "sk-ant-plaintext-key-1234567890",
|
|
164
|
+
authType: "header",
|
|
165
|
+
createdBy: "admin",
|
|
166
|
+
});
|
|
167
|
+
// First migration: should encrypt
|
|
168
|
+
const results1 = await migratePlaintextCredentials(credRepo, vaultKey, () => vaultKey, tenantAccess);
|
|
169
|
+
expect(results1[0].migratedCount).toBe(1);
|
|
170
|
+
// Second migration: row is now encrypted, should be skipped
|
|
171
|
+
const results2 = await migratePlaintextCredentials(credRepo, vaultKey, () => vaultKey, tenantAccess);
|
|
172
|
+
expect(results2[0].migratedCount).toBe(0);
|
|
173
|
+
});
|
|
174
|
+
it("migrating already-migrated credential is a no-op (value unchanged)", async () => {
|
|
175
|
+
await db.insert(providerCredentials).values({
|
|
176
|
+
id: "cred-1",
|
|
177
|
+
provider: "anthropic",
|
|
178
|
+
keyName: "Test",
|
|
179
|
+
encryptedValue: "sk-ant-plaintext-key-1234567890",
|
|
180
|
+
authType: "header",
|
|
181
|
+
createdBy: "admin",
|
|
182
|
+
});
|
|
183
|
+
// Migrate once
|
|
184
|
+
await migratePlaintextCredentials(credRepo, vaultKey, () => vaultKey, tenantAccess);
|
|
185
|
+
// Capture the encrypted value
|
|
186
|
+
const rowsBefore = await db
|
|
187
|
+
.select({ encryptedValue: providerCredentials.encryptedValue })
|
|
188
|
+
.from(providerCredentials)
|
|
189
|
+
.where(eq(providerCredentials.id, "cred-1"));
|
|
190
|
+
const valueBefore = rowsBefore[0].encryptedValue;
|
|
191
|
+
// Migrate again — should be no-op
|
|
192
|
+
const results = await migratePlaintextCredentials(credRepo, vaultKey, () => vaultKey, tenantAccess);
|
|
193
|
+
expect(results[0].migratedCount).toBe(0);
|
|
194
|
+
// Value should be identical (not re-encrypted)
|
|
195
|
+
const rowsAfter = await db
|
|
196
|
+
.select({ encryptedValue: providerCredentials.encryptedValue })
|
|
197
|
+
.from(providerCredentials)
|
|
198
|
+
.where(eq(providerCredentials.id, "cred-1"));
|
|
199
|
+
expect(rowsAfter[0].encryptedValue).toBe(valueBefore);
|
|
200
|
+
});
|
|
201
|
+
it("batch migrates 100 plaintext credentials with no plaintext remaining", async () => {
|
|
202
|
+
// Insert 100 plaintext credentials
|
|
203
|
+
for (let i = 0; i < 100; i++) {
|
|
204
|
+
await db.insert(providerCredentials).values({
|
|
205
|
+
id: `cred-${i}`,
|
|
206
|
+
provider: "anthropic",
|
|
207
|
+
keyName: `Key-${i}`,
|
|
208
|
+
encryptedValue: `sk-ant-plaintext-batch-key-${String(i).padStart(4, "0")}`,
|
|
209
|
+
authType: "header",
|
|
210
|
+
createdBy: "admin",
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
const results = await migratePlaintextCredentials(credRepo, vaultKey, () => vaultKey, tenantAccess);
|
|
214
|
+
expect(results[0].migratedCount).toBe(100);
|
|
215
|
+
expect(results[0].errors).toHaveLength(0);
|
|
216
|
+
// Verify no plaintext remains
|
|
217
|
+
const allRows = await db
|
|
218
|
+
.select({ id: providerCredentials.id, encryptedValue: providerCredentials.encryptedValue })
|
|
219
|
+
.from(providerCredentials);
|
|
220
|
+
expect(allRows).toHaveLength(100);
|
|
221
|
+
for (const row of allRows) {
|
|
222
|
+
const parsed = JSON.parse(row.encryptedValue);
|
|
223
|
+
expect(parsed).toHaveProperty("iv");
|
|
224
|
+
expect(parsed).toHaveProperty("authTag");
|
|
225
|
+
expect(parsed).toHaveProperty("ciphertext");
|
|
226
|
+
// Ensure the raw value does not contain any plaintext key pattern
|
|
227
|
+
expect(row.encryptedValue).not.toMatch(/sk-ant-plaintext/);
|
|
228
|
+
}
|
|
229
|
+
});
|
|
230
|
+
});
|
|
231
|
+
describe("credential vault migration path", () => {
|
|
232
|
+
let vaultKey;
|
|
233
|
+
let credRepo;
|
|
234
|
+
let tenantAccess;
|
|
235
|
+
beforeEach(async () => {
|
|
236
|
+
await truncateAllTables(pool);
|
|
237
|
+
vaultKey = generateInstanceKey();
|
|
238
|
+
credRepo = new DrizzleCredentialRepository(db);
|
|
239
|
+
tenantAccess = new DrizzleMigrationTenantKeyAccess(db);
|
|
240
|
+
});
|
|
241
|
+
it("pre-migration plaintext credential is readable after migratePlaintextCredentials", async () => {
|
|
242
|
+
// Insert a plaintext credential (simulating legacy state)
|
|
243
|
+
await db.insert(providerCredentials).values({
|
|
244
|
+
id: "cred-legacy",
|
|
245
|
+
provider: "anthropic",
|
|
246
|
+
keyName: "Legacy Key",
|
|
247
|
+
encryptedValue: "sk-ant-legacy-plaintext-key-999",
|
|
248
|
+
authType: "header",
|
|
249
|
+
authHeader: "x-api-key",
|
|
250
|
+
createdBy: "admin",
|
|
251
|
+
});
|
|
252
|
+
// Pre-migration: raw value is plaintext
|
|
253
|
+
const rowsBefore = await db
|
|
254
|
+
.select({ encryptedValue: providerCredentials.encryptedValue })
|
|
255
|
+
.from(providerCredentials)
|
|
256
|
+
.where(eq(providerCredentials.id, "cred-legacy"));
|
|
257
|
+
expect(rowsBefore[0].encryptedValue).toBe("sk-ant-legacy-plaintext-key-999");
|
|
258
|
+
// Migrate
|
|
259
|
+
const results = await migratePlaintextCredentials(credRepo, vaultKey, () => vaultKey, tenantAccess);
|
|
260
|
+
expect(results[0].migratedCount).toBe(1);
|
|
261
|
+
expect(results[0].errors).toHaveLength(0);
|
|
262
|
+
// Post-migration: decrypt through CredentialVaultStore
|
|
263
|
+
const repo = new DrizzleCredentialRepository(db);
|
|
264
|
+
const store = new CredentialVaultStore(repo, vaultKey);
|
|
265
|
+
const decrypted = await store.decrypt("cred-legacy");
|
|
266
|
+
expect(decrypted).not.toBeNull();
|
|
267
|
+
const cred = decrypted;
|
|
268
|
+
expect(cred.plaintextKey).toBe("sk-ant-legacy-plaintext-key-999");
|
|
269
|
+
expect(cred.provider).toBe("anthropic");
|
|
270
|
+
expect(cred.keyName).toBe("Legacy Key");
|
|
271
|
+
expect(cred.authType).toBe("header");
|
|
272
|
+
expect(cred.authHeader).toBe("x-api-key");
|
|
273
|
+
});
|
|
274
|
+
it("post-migration credential metadata is fully preserved", async () => {
|
|
275
|
+
await db.insert(providerCredentials).values({
|
|
276
|
+
id: "cred-meta",
|
|
277
|
+
provider: "openai",
|
|
278
|
+
keyName: "Metadata Test",
|
|
279
|
+
encryptedValue: "sk-openai-meta-test-key-12345",
|
|
280
|
+
authType: "bearer",
|
|
281
|
+
authHeader: null,
|
|
282
|
+
createdBy: "admin-user",
|
|
283
|
+
});
|
|
284
|
+
await migratePlaintextCredentials(credRepo, vaultKey, () => vaultKey, tenantAccess);
|
|
285
|
+
const repo = new DrizzleCredentialRepository(db);
|
|
286
|
+
const store = new CredentialVaultStore(repo, vaultKey);
|
|
287
|
+
// Verify summary metadata is intact
|
|
288
|
+
const summary = await store.getById("cred-meta");
|
|
289
|
+
expect(summary).not.toBeNull();
|
|
290
|
+
const s = summary;
|
|
291
|
+
expect(s.provider).toBe("openai");
|
|
292
|
+
expect(s.keyName).toBe("Metadata Test");
|
|
293
|
+
expect(s.authType).toBe("bearer");
|
|
294
|
+
expect(s.authHeader).toBeNull();
|
|
295
|
+
expect(s.createdBy).toBe("admin-user");
|
|
296
|
+
expect(s.isActive).toBe(true);
|
|
297
|
+
});
|
|
298
|
+
it("migration idempotency: running twice does not corrupt and encrypted value is unchanged", async () => {
|
|
299
|
+
await db.insert(providerCredentials).values({
|
|
300
|
+
id: "cred-idem",
|
|
301
|
+
provider: "anthropic",
|
|
302
|
+
keyName: "Idempotent",
|
|
303
|
+
encryptedValue: "sk-ant-idempotent-test-key-000",
|
|
304
|
+
authType: "header",
|
|
305
|
+
createdBy: "admin",
|
|
306
|
+
});
|
|
307
|
+
// First migration
|
|
308
|
+
const r1 = await migratePlaintextCredentials(credRepo, vaultKey, () => vaultKey, tenantAccess);
|
|
309
|
+
expect(r1[0].migratedCount).toBe(1);
|
|
310
|
+
// Capture encrypted value
|
|
311
|
+
const rowsAfterFirst = await db
|
|
312
|
+
.select({ encryptedValue: providerCredentials.encryptedValue })
|
|
313
|
+
.from(providerCredentials)
|
|
314
|
+
.where(eq(providerCredentials.id, "cred-idem"));
|
|
315
|
+
const encryptedAfterFirst = rowsAfterFirst[0].encryptedValue;
|
|
316
|
+
// Second migration (should be no-op)
|
|
317
|
+
const r2 = await migratePlaintextCredentials(credRepo, vaultKey, () => vaultKey, tenantAccess);
|
|
318
|
+
expect(r2[0].migratedCount).toBe(0);
|
|
319
|
+
// Encrypted value must be byte-identical
|
|
320
|
+
const rowsAfterSecond = await db
|
|
321
|
+
.select({ encryptedValue: providerCredentials.encryptedValue })
|
|
322
|
+
.from(providerCredentials)
|
|
323
|
+
.where(eq(providerCredentials.id, "cred-idem"));
|
|
324
|
+
expect(rowsAfterSecond[0].encryptedValue).toBe(encryptedAfterFirst);
|
|
325
|
+
// Still decryptable through the store
|
|
326
|
+
const repo = new DrizzleCredentialRepository(db);
|
|
327
|
+
const store = new CredentialVaultStore(repo, vaultKey);
|
|
328
|
+
const decrypted = await store.decrypt("cred-idem");
|
|
329
|
+
expect(decrypted.plaintextKey).toBe("sk-ant-idempotent-test-key-000");
|
|
330
|
+
});
|
|
331
|
+
it("partial migration failure: valid rows are migrated, invalid rows produce errors, valid rows remain readable", async () => {
|
|
332
|
+
// Row 1: valid plaintext
|
|
333
|
+
await db.insert(providerCredentials).values({
|
|
334
|
+
id: "cred-valid",
|
|
335
|
+
provider: "anthropic",
|
|
336
|
+
keyName: "Valid",
|
|
337
|
+
encryptedValue: "sk-ant-valid-plaintext-key-111",
|
|
338
|
+
authType: "header",
|
|
339
|
+
createdBy: "admin",
|
|
340
|
+
});
|
|
341
|
+
// Row 2: already encrypted (should be skipped, not an error)
|
|
342
|
+
const alreadyEncrypted = JSON.stringify(encrypt("sk-ant-already-encrypted", vaultKey));
|
|
343
|
+
await db.insert(providerCredentials).values({
|
|
344
|
+
id: "cred-encrypted",
|
|
345
|
+
provider: "openai",
|
|
346
|
+
keyName: "Already Encrypted",
|
|
347
|
+
encryptedValue: alreadyEncrypted,
|
|
348
|
+
authType: "bearer",
|
|
349
|
+
createdBy: "admin",
|
|
350
|
+
});
|
|
351
|
+
const results = await migratePlaintextCredentials(credRepo, vaultKey, () => vaultKey, tenantAccess);
|
|
352
|
+
expect(results[0].migratedCount).toBe(1); // only the plaintext row
|
|
353
|
+
expect(results[0].errors).toHaveLength(0);
|
|
354
|
+
// Both rows are now readable through the store
|
|
355
|
+
const repo = new DrizzleCredentialRepository(db);
|
|
356
|
+
const store = new CredentialVaultStore(repo, vaultKey);
|
|
357
|
+
const d1 = await store.decrypt("cred-valid");
|
|
358
|
+
expect(d1.plaintextKey).toBe("sk-ant-valid-plaintext-key-111");
|
|
359
|
+
const d2 = await store.decrypt("cred-encrypted");
|
|
360
|
+
expect(d2.plaintextKey).toBe("sk-ant-already-encrypted");
|
|
361
|
+
});
|
|
362
|
+
it("key rotation after plaintext migration: full chain works", async () => {
|
|
363
|
+
const oldSecret = "old-platform-secret-rotation-test";
|
|
364
|
+
const newSecret = "new-platform-secret-rotation-test";
|
|
365
|
+
const oldKey = getVaultEncryptionKey(oldSecret);
|
|
366
|
+
// Start with plaintext
|
|
367
|
+
await db.insert(providerCredentials).values({
|
|
368
|
+
id: "cred-chain",
|
|
369
|
+
provider: "anthropic",
|
|
370
|
+
keyName: "Chain Test",
|
|
371
|
+
encryptedValue: "sk-ant-chain-test-key-xyz",
|
|
372
|
+
authType: "header",
|
|
373
|
+
authHeader: "x-api-key",
|
|
374
|
+
createdBy: "admin",
|
|
375
|
+
});
|
|
376
|
+
// Step 1: Migrate plaintext to encrypted with old key
|
|
377
|
+
const oldCredRepo = new DrizzleCredentialRepository(db);
|
|
378
|
+
const migrateResults = await migratePlaintextCredentials(oldCredRepo, oldKey, () => oldKey);
|
|
379
|
+
expect(migrateResults[0].migratedCount).toBe(1);
|
|
380
|
+
// Verify readable with old key
|
|
381
|
+
const repo1 = new DrizzleCredentialRepository(db);
|
|
382
|
+
const store1 = new CredentialVaultStore(repo1, oldKey);
|
|
383
|
+
const d1 = await store1.decrypt("cred-chain");
|
|
384
|
+
expect(d1.plaintextKey).toBe("sk-ant-chain-test-key-xyz");
|
|
385
|
+
// Step 2: Rotate keys from old secret to new secret
|
|
386
|
+
const rotCredAccess = new DrizzleCredentialRepository(db);
|
|
387
|
+
const rotTenantKeyAccess = new DrizzleMigrationTenantKeyAccess(db);
|
|
388
|
+
const rotResult = await reEncryptAllCredentials(rotCredAccess, rotTenantKeyAccess, oldSecret, newSecret);
|
|
389
|
+
expect(rotResult.providerCredentials.migrated).toBe(1);
|
|
390
|
+
expect(rotResult.providerCredentials.errors).toHaveLength(0);
|
|
391
|
+
// Verify readable with new key
|
|
392
|
+
const newKey = getVaultEncryptionKey(newSecret);
|
|
393
|
+
const repo2 = new DrizzleCredentialRepository(db);
|
|
394
|
+
const store2 = new CredentialVaultStore(repo2, newKey);
|
|
395
|
+
const d2 = await store2.decrypt("cred-chain");
|
|
396
|
+
const d2cred = d2;
|
|
397
|
+
expect(d2cred.plaintextKey).toBe("sk-ant-chain-test-key-xyz");
|
|
398
|
+
expect(d2cred.provider).toBe("anthropic");
|
|
399
|
+
expect(d2cred.authHeader).toBe("x-api-key");
|
|
400
|
+
// Old key can no longer decrypt
|
|
401
|
+
const rowRaw = await db
|
|
402
|
+
.select({ encryptedValue: providerCredentials.encryptedValue })
|
|
403
|
+
.from(providerCredentials)
|
|
404
|
+
.where(eq(providerCredentials.id, "cred-chain"));
|
|
405
|
+
const payload = JSON.parse(rowRaw[0].encryptedValue);
|
|
406
|
+
expect(() => decrypt(payload, oldKey)).toThrow();
|
|
407
|
+
});
|
|
408
|
+
it("tenant_api_keys migration: plaintext tenant key is readable post-migration", async () => {
|
|
409
|
+
await db.insert(tenantApiKeys).values({
|
|
410
|
+
id: "tk-migrate",
|
|
411
|
+
tenantId: "tenant-test",
|
|
412
|
+
provider: "anthropic",
|
|
413
|
+
label: "Tenant Migration Test",
|
|
414
|
+
encryptedKey: "sk-ant-tenant-plaintext-key-888",
|
|
415
|
+
createdAt: Date.now(),
|
|
416
|
+
updatedAt: Date.now(),
|
|
417
|
+
});
|
|
418
|
+
const tenantKeyDeriver = (_tenantId) => vaultKey;
|
|
419
|
+
const localTenantAccess = new DrizzleMigrationTenantKeyAccess(db);
|
|
420
|
+
const results = await migratePlaintextCredentials(credRepo, vaultKey, tenantKeyDeriver, localTenantAccess);
|
|
421
|
+
const tenantResult = results.find((r) => r.table === "tenant_api_keys");
|
|
422
|
+
expect(tenantResult).not.toBeNull();
|
|
423
|
+
const tr = tenantResult;
|
|
424
|
+
expect(tr.migratedCount).toBe(1);
|
|
425
|
+
expect(tr.errors).toHaveLength(0);
|
|
426
|
+
// Verify the encrypted value is valid
|
|
427
|
+
const rows = await db
|
|
428
|
+
.select({ encryptedKey: tenantApiKeys.encryptedKey })
|
|
429
|
+
.from(tenantApiKeys)
|
|
430
|
+
.where(eq(tenantApiKeys.id, "tk-migrate"));
|
|
431
|
+
const payload = JSON.parse(rows[0].encryptedKey);
|
|
432
|
+
const decrypted = decrypt(payload, vaultKey);
|
|
433
|
+
expect(decrypted).toBe("sk-ant-tenant-plaintext-key-888");
|
|
434
|
+
});
|
|
435
|
+
it("audit after migration: no plaintext findings remain", async () => {
|
|
436
|
+
// Insert 3 plaintext credentials
|
|
437
|
+
for (let i = 0; i < 3; i++) {
|
|
438
|
+
await db.insert(providerCredentials).values({
|
|
439
|
+
id: `cred-audit-${i}`,
|
|
440
|
+
provider: "anthropic",
|
|
441
|
+
keyName: `Audit Key ${i}`,
|
|
442
|
+
encryptedValue: `sk-ant-audit-plaintext-key-${i}`,
|
|
443
|
+
authType: "header",
|
|
444
|
+
createdBy: "admin",
|
|
445
|
+
});
|
|
446
|
+
}
|
|
447
|
+
// Pre-migration audit should find 3 plaintext entries
|
|
448
|
+
const findingsBefore = await auditCredentialEncryption(db);
|
|
449
|
+
expect(findingsBefore).toHaveLength(3);
|
|
450
|
+
// Migrate
|
|
451
|
+
const results = await migratePlaintextCredentials(credRepo, vaultKey, () => vaultKey, tenantAccess);
|
|
452
|
+
expect(results[0].migratedCount).toBe(3);
|
|
453
|
+
// Post-migration audit should find 0 plaintext entries
|
|
454
|
+
const findingsAfter = await auditCredentialEncryption(db);
|
|
455
|
+
expect(findingsAfter).toHaveLength(0);
|
|
456
|
+
});
|
|
457
|
+
});
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { AdminAuditLog } from "../../admin/audit-log.js";
|
|
2
|
+
import type { ISecretAuditRepository } from "./audit-repository.js";
|
|
3
|
+
import type { ICredentialRepository } from "./credential-repository.js";
|
|
4
|
+
/** Auth mechanism for injecting the key into upstream requests. */
|
|
5
|
+
export type AuthType = "header" | "bearer" | "basic";
|
|
6
|
+
/** Input for creating a new credential. */
|
|
7
|
+
export interface CreateCredentialInput {
|
|
8
|
+
provider: string;
|
|
9
|
+
keyName: string;
|
|
10
|
+
/** Plaintext API key — encrypted before storage, never persisted raw. */
|
|
11
|
+
plaintextKey: string;
|
|
12
|
+
authType: AuthType;
|
|
13
|
+
authHeader?: string;
|
|
14
|
+
createdBy: string;
|
|
15
|
+
}
|
|
16
|
+
/** Input for rotating an existing credential's key. */
|
|
17
|
+
export interface RotateCredentialInput {
|
|
18
|
+
id: string;
|
|
19
|
+
/** New plaintext API key. */
|
|
20
|
+
plaintextKey: string;
|
|
21
|
+
rotatedBy: string;
|
|
22
|
+
}
|
|
23
|
+
/** A credential record with the encrypted value omitted for listing. */
|
|
24
|
+
export interface CredentialSummary {
|
|
25
|
+
id: string;
|
|
26
|
+
provider: string;
|
|
27
|
+
keyName: string;
|
|
28
|
+
authType: string;
|
|
29
|
+
authHeader: string | null;
|
|
30
|
+
isActive: boolean;
|
|
31
|
+
lastValidated: string | null;
|
|
32
|
+
createdAt: string;
|
|
33
|
+
rotatedAt: string | null;
|
|
34
|
+
createdBy: string;
|
|
35
|
+
}
|
|
36
|
+
/** A decrypted credential ready for gateway injection. */
|
|
37
|
+
export interface DecryptedCredential {
|
|
38
|
+
id: string;
|
|
39
|
+
provider: string;
|
|
40
|
+
keyName: string;
|
|
41
|
+
/** The plaintext API key. MUST be discarded after use. */
|
|
42
|
+
plaintextKey: string;
|
|
43
|
+
authType: string;
|
|
44
|
+
authHeader: string | null;
|
|
45
|
+
}
|
|
46
|
+
export interface ICredentialVaultStore {
|
|
47
|
+
create(input: CreateCredentialInput): Promise<string>;
|
|
48
|
+
list(provider?: string): Promise<CredentialSummary[]>;
|
|
49
|
+
getById(id: string): Promise<CredentialSummary | null>;
|
|
50
|
+
decrypt(id: string): Promise<DecryptedCredential | null>;
|
|
51
|
+
getActiveForProvider(provider: string): Promise<DecryptedCredential[]>;
|
|
52
|
+
rotate(input: RotateCredentialInput): Promise<boolean>;
|
|
53
|
+
setActive(id: string, isActive: boolean, changedBy: string): Promise<boolean>;
|
|
54
|
+
markValidated(id: string): Promise<boolean>;
|
|
55
|
+
delete(id: string, deletedBy: string): Promise<boolean>;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Credential vault store — encrypted CRUD for platform-level provider API keys.
|
|
59
|
+
*
|
|
60
|
+
* SECURITY:
|
|
61
|
+
* - Keys are encrypted with AES-256-GCM before storage.
|
|
62
|
+
* - The encryption key is derived from a platform secret (env var).
|
|
63
|
+
* - Plaintext keys are never logged, persisted, or returned in list operations.
|
|
64
|
+
* - All mutations are audit-logged.
|
|
65
|
+
*/
|
|
66
|
+
export declare class CredentialVaultStore implements ICredentialVaultStore {
|
|
67
|
+
private readonly repo;
|
|
68
|
+
private readonly encryptionKey;
|
|
69
|
+
private readonly auditLog;
|
|
70
|
+
private readonly secretAuditRepo;
|
|
71
|
+
constructor(repo: ICredentialRepository, encryptionKey: Buffer, auditLog?: AdminAuditLog, secretAuditRepo?: ISecretAuditRepository);
|
|
72
|
+
private recordSecretAudit;
|
|
73
|
+
/** Create a new provider credential. Returns the record ID. */
|
|
74
|
+
create(input: CreateCredentialInput): Promise<string>;
|
|
75
|
+
/** List all credentials for a provider (or all providers). Never returns encrypted values. */
|
|
76
|
+
list(provider?: string): Promise<CredentialSummary[]>;
|
|
77
|
+
/** Get a single credential summary by ID. */
|
|
78
|
+
getById(id: string): Promise<CredentialSummary | null>;
|
|
79
|
+
/**
|
|
80
|
+
* Decrypt and return a credential's key. For gateway use only.
|
|
81
|
+
*
|
|
82
|
+
* SECURITY: The returned plaintext key MUST be discarded after use.
|
|
83
|
+
*/
|
|
84
|
+
decrypt(id: string): Promise<DecryptedCredential | null>;
|
|
85
|
+
/**
|
|
86
|
+
* Get the active credential(s) for a provider, decrypted.
|
|
87
|
+
* Returns all active keys for load distribution; caller picks one.
|
|
88
|
+
*
|
|
89
|
+
* SECURITY: Returned keys MUST be discarded after use.
|
|
90
|
+
*/
|
|
91
|
+
getActiveForProvider(provider: string): Promise<DecryptedCredential[]>;
|
|
92
|
+
/** Rotate a credential's key. Encrypts the new key and records the rotation timestamp. */
|
|
93
|
+
rotate(input: RotateCredentialInput): Promise<boolean>;
|
|
94
|
+
/** Mark a credential as active or inactive. */
|
|
95
|
+
setActive(id: string, isActive: boolean, changedBy: string): Promise<boolean>;
|
|
96
|
+
/** Record a successful validation timestamp. */
|
|
97
|
+
markValidated(id: string): Promise<boolean>;
|
|
98
|
+
/** Permanently delete a credential. */
|
|
99
|
+
delete(id: string, deletedBy: string): Promise<boolean>;
|
|
100
|
+
private audit;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Derive the credential vault encryption key from a platform secret.
|
|
104
|
+
* If no secret is provided, generates a random key (suitable for tests only).
|
|
105
|
+
*/
|
|
106
|
+
export declare function getVaultEncryptionKey(platformSecret?: string): Buffer;
|