@cosmicdrift/kumiko-bundled-features 1.0.0 → 2.0.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/package.json +41 -7
- package/src/__tests__/access-invalidation-consumer.integration.test.ts +279 -0
- package/src/__tests__/access-invalidation-stream.integration.test.ts +217 -0
- package/src/admin-shell/__tests__/admin-shell-security.integration.test.ts +200 -0
- package/src/admin-shell/__tests__/admin-shell.boot.test.ts +147 -0
- package/src/admin-shell/__tests__/overview-allowlist.test.ts +43 -0
- package/src/admin-shell/__tests__/overview-screens.boot.test.ts +35 -0
- package/src/admin-shell/constants.ts +11 -0
- package/src/admin-shell/feature.ts +135 -0
- package/src/admin-shell/i18n.ts +36 -0
- package/src/admin-shell/index.ts +17 -0
- package/src/admin-shell/overview-allowlist.ts +37 -0
- package/src/admin-shell/web/client-plugin.tsx +26 -0
- package/src/admin-shell/web/i18n.ts +16 -0
- package/src/admin-shell/web/index.ts +2 -0
- package/src/admin-shell/web/overview-layout.tsx +69 -0
- package/src/admin-shell/web/overview-query.ts +15 -0
- package/src/admin-shell/web/platform-overview-screen.tsx +90 -0
- package/src/admin-shell/web/tenant-overview-screen.tsx +90 -0
- package/src/agent-tools/__tests__/tool-catalog.test.ts +179 -0
- package/src/agent-tools/__tests__/tool-dispatch.integration.test.ts +100 -0
- package/src/agent-tools/__tests__/tool-dispatch.test.ts +126 -0
- package/src/agent-tools/index.ts +9 -0
- package/src/agent-tools/tool-catalog.ts +130 -0
- package/src/agent-tools/tool-dispatch.ts +82 -0
- package/src/agent-tools/types.ts +38 -0
- package/src/audit/__tests__/audit-screens.boot.test.ts +51 -0
- package/src/audit/__tests__/audit-security.integration.test.ts +201 -0
- package/src/audit/__tests__/audit.integration.test.ts +50 -25
- package/src/audit/constants.ts +9 -2
- package/src/audit/feature.ts +33 -1
- package/src/audit/handlers/details.query.ts +47 -0
- package/src/audit/handlers/list.query.ts +3 -2
- package/src/audit/i18n.ts +31 -0
- package/src/audit/web/audit-log-detail-screen.tsx +131 -0
- package/src/audit/web/audit-log-screen.tsx +250 -0
- package/src/audit/web/client-plugin.tsx +22 -0
- package/src/audit/web/i18n.ts +12 -0
- package/src/audit/web/index.ts +5 -0
- package/src/auth-email-password/__tests__/account-lockout-no-redis.integration.test.ts +4 -4
- package/src/auth-email-password/__tests__/account-lockout.integration.test.ts +4 -4
- package/src/auth-email-password/__tests__/account-unlock.integration.test.ts +283 -0
- package/src/auth-email-password/__tests__/auth-claims.integration.test.ts +10 -11
- package/src/auth-email-password/__tests__/auth-user-row.test.ts +36 -0
- package/src/auth-email-password/__tests__/auth.integration.test.ts +33 -6
- package/src/auth-email-password/__tests__/email-verification.integration.test.ts +9 -6
- package/src/auth-email-password/__tests__/feature-options.test.ts +33 -0
- package/src/auth-email-password/__tests__/identity-v3-login.integration.test.ts +3 -3
- package/src/auth-email-password/__tests__/invite-flow-kms.integration.test.ts +283 -0
- package/src/auth-email-password/__tests__/invite-flow.integration.test.ts +35 -1
- package/src/auth-email-password/__tests__/login-mfa-setup-required.integration.test.ts +129 -0
- package/src/auth-email-password/__tests__/multi-roles.integration.test.ts +1 -1
- package/src/auth-email-password/__tests__/password-policy.test.ts +15 -0
- package/src/auth-email-password/__tests__/password-reset.integration.test.ts +19 -6
- package/src/auth-email-password/__tests__/public-routes-rate-limit.integration.test.ts +3 -3
- package/src/auth-email-password/__tests__/seed-admin.integration.test.ts +1 -1
- package/src/auth-email-password/__tests__/self-registration-toggle.integration.test.ts +264 -0
- package/src/auth-email-password/__tests__/session-callbacks.integration.test.ts +20 -4
- package/src/auth-email-password/__tests__/session-strict-mode.integration.test.ts +7 -14
- package/src/auth-email-password/__tests__/signup-flow.integration.test.ts +91 -0
- package/src/auth-email-password/constants.ts +25 -0
- package/src/auth-email-password/email-templates.ts +32 -0
- package/src/auth-email-password/errors.ts +9 -0
- package/src/auth-email-password/feature.ts +59 -11
- package/src/auth-email-password/handlers/change-password.write.ts +14 -13
- package/src/auth-email-password/handlers/confirm-account-unlock.write.ts +59 -0
- package/src/auth-email-password/handlers/confirm-token-flow.ts +34 -105
- package/src/auth-email-password/handlers/invite-accept-with-login.write.ts +12 -5
- package/src/auth-email-password/handlers/invite-accept.write.ts +9 -2
- package/src/auth-email-password/handlers/invite-create.write.ts +2 -2
- package/src/auth-email-password/handlers/invite-signup-complete.write.ts +12 -4
- package/src/auth-email-password/handlers/login.write.ts +86 -16
- package/src/auth-email-password/handlers/logout.write.ts +4 -2
- package/src/auth-email-password/handlers/request-account-unlock.write.ts +38 -0
- package/src/auth-email-password/handlers/reset-password.write.ts +3 -2
- package/src/auth-email-password/handlers/self-registration-status.query.ts +23 -0
- package/src/auth-email-password/handlers/signup-confirm.write.ts +19 -11
- package/src/auth-email-password/handlers/signup-request.write.ts +22 -0
- package/src/auth-email-password/handlers/token-request-handler.ts +4 -2
- package/src/auth-email-password/i18n.ts +52 -0
- package/src/auth-email-password/index.ts +13 -2
- package/src/auth-email-password/lockout-store.ts +10 -5
- package/src/auth-email-password/password-policy.ts +2108 -0
- package/src/auth-email-password/seeding.ts +55 -27
- package/src/auth-email-password/self-registration-toggle.ts +25 -0
- package/src/auth-email-password/signed-token.ts +1 -0
- package/src/auth-email-password/unlock-token.ts +28 -0
- package/src/auth-email-password/web/__tests__/auth-client.test.ts +542 -0
- package/src/auth-email-password/web/__tests__/auth-form-logic.test.ts +44 -0
- package/src/auth-email-password/web/__tests__/auth-gate.test.tsx +194 -6
- package/src/auth-email-password/web/__tests__/client-plugin.test.tsx +34 -0
- package/src/auth-email-password/web/__tests__/confirm-account-unlock-screen.test.tsx +64 -0
- package/src/auth-email-password/web/__tests__/forgot-password-screen.test.tsx +5 -1
- package/src/auth-email-password/web/__tests__/invite-accept-screen.test.tsx +129 -2
- package/src/auth-email-password/web/__tests__/login-screen.test.tsx +149 -5
- package/src/auth-email-password/web/__tests__/request-account-unlock-screen.test.tsx +137 -0
- package/src/auth-email-password/web/__tests__/reset-password-screen.test.tsx +5 -1
- package/src/auth-email-password/web/__tests__/signup-complete-screen.test.tsx +134 -0
- package/src/auth-email-password/web/__tests__/signup-screen.test.tsx +93 -0
- package/src/auth-email-password/web/__tests__/test-utils.tsx +12 -2
- package/src/auth-email-password/web/__tests__/use-url-token.test.tsx +29 -0
- package/src/auth-email-password/web/__tests__/verify-email-screen.test.tsx +5 -1
- package/src/auth-email-password/web/auth-client.ts +96 -18
- package/src/auth-email-password/web/auth-form-logic.ts +30 -0
- package/src/auth-email-password/web/auth-form-primitives.tsx +22 -20
- package/src/auth-email-password/web/auth-gate.tsx +140 -19
- package/src/auth-email-password/web/client-plugin.ts +24 -2
- package/src/auth-email-password/web/confirm-account-unlock-screen.tsx +95 -0
- package/src/auth-email-password/web/forgot-password-screen.tsx +6 -6
- package/src/auth-email-password/web/index.ts +16 -4
- package/src/auth-email-password/web/invite-accept-screen.tsx +5 -5
- package/src/auth-email-password/web/login-screen.tsx +78 -22
- package/src/auth-email-password/web/request-account-unlock-screen.tsx +112 -0
- package/src/auth-email-password/web/reset-password-screen.tsx +15 -18
- package/src/auth-email-password/web/session.tsx +11 -6
- package/src/auth-email-password/web/signup-complete-screen.tsx +13 -15
- package/src/auth-email-password/web/signup-screen.tsx +8 -10
- package/src/auth-email-password/web/use-shell-user.ts +5 -2
- package/src/auth-email-password/web/user-menu.tsx +3 -1
- package/src/auth-email-password/web/verify-email-screen.tsx +10 -14
- package/src/auth-foundation/__tests__/feature.test.ts +46 -0
- package/src/auth-foundation/__tests__/session-store.test.ts +77 -0
- package/src/auth-foundation/__tests__/tenant-providers.test.ts +160 -0
- package/src/auth-foundation/__tests__/token-verifier.test.ts +150 -0
- package/src/auth-foundation/boot-checks.ts +150 -0
- package/src/auth-foundation/feature.ts +157 -0
- package/src/auth-foundation/index.ts +37 -0
- package/src/auth-foundation/resolve-anonymous-access.ts +62 -0
- package/src/auth-foundation/types.ts +170 -0
- package/src/auth-mfa/__tests__/base32.test.ts +28 -0
- package/src/auth-mfa/__tests__/disable-and-regenerate.integration.test.ts +265 -0
- package/src/auth-mfa/__tests__/enable-confirm-preauth.integration.test.ts +321 -0
- package/src/auth-mfa/__tests__/enable-flow.integration.test.ts +322 -0
- package/src/auth-mfa/__tests__/enable-start-preauth.integration.test.ts +237 -0
- package/src/auth-mfa/__tests__/errors-i18n-parity.test.ts +39 -0
- package/src/auth-mfa/__tests__/mfa-preauth-setup-token.test.ts +113 -0
- package/src/auth-mfa/__tests__/no-redis.integration.test.ts +209 -0
- package/src/auth-mfa/__tests__/pii-subject-encryption.integration.test.ts +139 -0
- package/src/auth-mfa/__tests__/reencrypt-job.integration.test.ts +247 -0
- package/src/auth-mfa/__tests__/session-auto-revoke.integration.test.ts +169 -0
- package/src/auth-mfa/__tests__/totp.test.ts +131 -0
- package/src/auth-mfa/__tests__/verify.integration.test.ts +319 -0
- package/src/auth-mfa/base32.ts +51 -0
- package/src/auth-mfa/config.ts +26 -0
- package/src/auth-mfa/constants.ts +45 -0
- package/src/auth-mfa/db/queries.ts +45 -0
- package/src/auth-mfa/errors.ts +66 -0
- package/src/auth-mfa/feature.ts +170 -0
- package/src/auth-mfa/handlers/disable.write.ts +67 -0
- package/src/auth-mfa/handlers/enable-confirm-preauth.write.ts +200 -0
- package/src/auth-mfa/handlers/enable-confirm.write.ts +106 -0
- package/src/auth-mfa/handlers/enable-start-preauth.write.ts +87 -0
- package/src/auth-mfa/handlers/enable-start.write.ts +66 -0
- package/src/auth-mfa/handlers/reencrypt.job.ts +234 -0
- package/src/auth-mfa/handlers/regenerate-recovery.write.ts +77 -0
- package/src/auth-mfa/handlers/status.query.ts +23 -0
- package/src/auth-mfa/handlers/verify.write.ts +179 -0
- package/src/auth-mfa/i18n.ts +12 -0
- package/src/auth-mfa/index.ts +19 -0
- package/src/auth-mfa/mfa-challenge-token.ts +90 -0
- package/src/auth-mfa/mfa-preauth-setup-token.ts +86 -0
- package/src/auth-mfa/mfa-setup-token.ts +96 -0
- package/src/auth-mfa/mfa-status-checker.ts +84 -0
- package/src/auth-mfa/mfa-verify-attempts.ts +90 -0
- package/src/auth-mfa/otpauth-uri.ts +21 -0
- package/src/auth-mfa/recovery-codes.ts +54 -0
- package/src/auth-mfa/schema/user-mfa.ts +60 -0
- package/src/auth-mfa/testing.ts +5 -0
- package/src/auth-mfa/totp.ts +67 -0
- package/src/auth-mfa/verify-factor.ts +58 -0
- package/src/auth-mfa/web/__tests__/mfa-client.test.ts +265 -0
- package/src/auth-mfa/web/__tests__/mfa-enable-screen.test.tsx +182 -0
- package/src/auth-mfa/web/__tests__/mfa-setup-preauth-screen.test.tsx +379 -0
- package/src/auth-mfa/web/__tests__/mfa-verify-screen.test.tsx +104 -0
- package/src/auth-mfa/web/client-plugin.ts +37 -0
- package/src/auth-mfa/web/i18n.ts +136 -0
- package/src/auth-mfa/web/index.ts +27 -0
- package/src/auth-mfa/web/mfa-client.ts +184 -0
- package/src/auth-mfa/web/mfa-disable-dialog.tsx +69 -0
- package/src/auth-mfa/web/mfa-enable-screen.tsx +228 -0
- package/src/auth-mfa/web/mfa-recovery-codes-reveal.tsx +53 -0
- package/src/auth-mfa/web/mfa-regenerate-recovery-dialog.tsx +68 -0
- package/src/auth-mfa/web/mfa-setup-preauth-screen.tsx +267 -0
- package/src/auth-mfa/web/mfa-verify-screen.tsx +117 -0
- package/src/auth-mfa/web/qrcode-browser.d.ts +12 -0
- package/src/auth-mfa-user-data/__tests__/hooks.integration.test.ts +134 -0
- package/src/auth-mfa-user-data/hooks.ts +53 -0
- package/src/auth-mfa-user-data/index.ts +21 -0
- package/src/billing-foundation/__tests__/billing-foundation.integration.test.ts +206 -2
- package/src/billing-foundation/__tests__/subscription-provider-contract.ts +93 -0
- package/src/billing-foundation/entities.ts +28 -4
- package/src/billing-foundation/events.ts +6 -2
- package/src/billing-foundation/feature.ts +9 -1
- package/src/billing-foundation/get-subscription-for-tenant.ts +16 -5
- package/src/billing-foundation/handlers/create-portal-session.write.ts +17 -1
- package/src/billing-foundation/handlers/list-subscriptions.query.ts +15 -1
- package/src/billing-foundation/handlers/process-event.write.ts +39 -3
- package/src/billing-foundation/tenant-destroy-hook.ts +46 -0
- package/src/cap-counter/__tests__/cap-list.boot.test.ts +27 -0
- package/src/cap-counter/__tests__/cap-list.security.integration.test.ts +53 -0
- package/src/cap-counter/__tests__/entity-ddl.test.ts +15 -0
- package/src/cap-counter/__tests__/with-cap-enforcement.integration.test.ts +8 -5
- package/src/cap-counter/constants.ts +2 -0
- package/src/cap-counter/enforce-cap.ts +15 -18
- package/src/cap-counter/entity.ts +3 -3
- package/src/cap-counter/feature.ts +28 -1
- package/src/cap-counter/i18n.ts +12 -0
- package/src/cap-counter/with-cap-enforcement.ts +2 -2
- package/src/channel-email/__tests__/pii-guard.test.ts +56 -0
- package/src/channel-email/email-channel.ts +2 -1
- package/src/channel-email/index.ts +1 -0
- package/src/channel-email/pii-guard.ts +39 -0
- package/src/compliance-profiles/__tests__/profile-picker.boot.test.ts +28 -0
- package/src/compliance-profiles/__tests__/profile-picker.security.integration.test.ts +91 -0
- package/src/compliance-profiles/constants.ts +15 -0
- package/src/compliance-profiles/feature.ts +22 -1
- package/src/compliance-profiles/handlers/set-profile.write.ts +2 -2
- package/src/compliance-profiles/i18n.ts +6 -0
- package/src/compliance-profiles/index.ts +6 -0
- package/src/compliance-profiles/web/client-plugin.tsx +22 -0
- package/src/compliance-profiles/web/compliance-profile-screen.tsx +152 -0
- package/src/compliance-profiles/web/i18n.ts +25 -0
- package/src/compliance-profiles/web/index.ts +6 -0
- package/src/config/__tests__/app-overrides.test.ts +11 -0
- package/src/config/__tests__/backing-secrets.integration.test.ts +22 -0
- package/src/config/__tests__/cascade.integration.test.ts +35 -0
- package/src/config/__tests__/config.integration.test.ts +71 -10
- package/src/config/__tests__/deserialize-value.test.ts +5 -8
- package/src/config/__tests__/inherited-redaction.integration.test.ts +4 -3
- package/src/config/__tests__/pii-encrypted.integration.test.ts +179 -0
- package/src/config/__tests__/reencrypt-job-concurrent-write-race.integration.test.ts +234 -0
- package/src/config/__tests__/reencrypt-job-kek-rotation.integration.test.ts +243 -0
- package/src/config/__tests__/write-helpers.test.ts +23 -0
- package/src/config/db/queries/resolver.ts +3 -3
- package/src/config/feature.ts +15 -8
- package/src/config/handlers/cascade.query.ts +2 -1
- package/src/config/handlers/reencrypt.job.ts +209 -0
- package/src/config/handlers/set.write.ts +55 -3
- package/src/config/handlers/values.query.ts +2 -1
- package/src/config/i18n.ts +9 -0
- package/src/config/index.ts +5 -4
- package/src/config/resolver.ts +75 -61
- package/src/config/table.ts +1 -1
- package/src/config/write-helpers.ts +22 -0
- package/src/crypto-shredding/__tests__/forget-subject.integration.test.ts +148 -0
- package/src/crypto-shredding/constants.ts +5 -0
- package/src/crypto-shredding/feature.ts +18 -0
- package/src/crypto-shredding/handlers/forget-subject.write.ts +91 -0
- package/src/crypto-shredding/index.ts +11 -0
- package/src/custom-fields/__tests__/audit-integration.integration.test.ts +1 -1
- package/src/custom-fields/__tests__/custom-fields.integration.test.ts +92 -53
- package/src/custom-fields/__tests__/field-access.integration.test.ts +25 -0
- package/src/custom-fields/__tests__/parse-serialized-field.test.ts +11 -3
- package/src/custom-fields/__tests__/retention.integration.test.ts +40 -0
- package/src/custom-fields/__tests__/user-data-rights.integration.test.ts +26 -79
- package/src/custom-fields/constants.ts +1 -0
- package/src/custom-fields/db/queries/user-data-rights.ts +0 -20
- package/src/custom-fields/entity.ts +1 -1
- package/src/custom-fields/events.ts +4 -3
- package/src/custom-fields/feature.ts +8 -0
- package/src/custom-fields/handlers/delete-system-field.write.ts +2 -1
- package/src/custom-fields/handlers/delete-tenant-field.write.ts +2 -1
- package/src/custom-fields/handlers/set-custom-field.write.ts +3 -44
- package/src/custom-fields/handlers/update-tenant-field.write.ts +0 -17
- package/src/custom-fields/lib/field-access.ts +8 -1
- package/src/custom-fields/lib/parse-serialized-field.ts +12 -4
- package/src/custom-fields/lib/value-schema.ts +1 -1
- package/src/custom-fields/run-retention.ts +9 -1
- package/src/custom-fields/schemas.ts +9 -9
- package/src/custom-fields/wire-for-entity.ts +110 -78
- package/src/custom-fields/wire-user-data-rights.ts +5 -54
- package/src/data-retention/__tests__/parse-override.test.ts +14 -13
- package/src/data-retention/__tests__/retention-cleanup.integration.test.ts +145 -8
- package/src/data-retention/feature.ts +3 -3
- package/src/data-retention/run-retention-cleanup.ts +102 -19
- package/src/delivery/__tests__/delivery-pii-kms.integration.test.ts +171 -0
- package/src/delivery/__tests__/delivery-screens.boot.test.ts +27 -0
- package/src/delivery/__tests__/delivery-security.integration.test.ts +106 -0
- package/src/delivery/constants.ts +13 -51
- package/src/delivery/feature.ts +29 -5
- package/src/delivery/handlers/log.query.ts +28 -7
- package/src/delivery/i18n.ts +6 -0
- package/src/delivery/index.ts +6 -1
- package/src/delivery/public-names.ts +36 -0
- package/src/delivery/tables.ts +3 -3
- package/src/delivery/web/client-plugin.tsx +20 -0
- package/src/delivery/web/delivery-log-screen.tsx +103 -0
- package/src/delivery/web/i18n.ts +25 -0
- package/src/delivery/web/index.ts +3 -0
- package/src/document-ingest-foundation/__tests__/feature.integration.test.ts +147 -0
- package/src/document-ingest-foundation/__tests__/feature.test.ts +105 -0
- package/src/document-ingest-foundation/__tests__/pages.test.ts +37 -0
- package/src/document-ingest-foundation/entity.ts +43 -0
- package/src/document-ingest-foundation/events.ts +25 -0
- package/src/document-ingest-foundation/feature.ts +126 -0
- package/src/document-ingest-foundation/index.ts +12 -0
- package/src/document-ingest-foundation/pages.ts +34 -0
- package/src/feature-toggles/__tests__/compose-tier-resolver.test.ts +304 -0
- package/src/feature-toggles/__tests__/feature-toggles.integration.test.ts +7 -6
- package/src/feature-toggles/__tests__/toggle-admin.boot.test.ts +31 -0
- package/src/feature-toggles/__tests__/toggle-admin.security.integration.test.ts +69 -0
- package/src/feature-toggles/compose-tier-resolver.ts +134 -0
- package/src/feature-toggles/constants.ts +14 -0
- package/src/feature-toggles/feature.ts +23 -3
- package/src/feature-toggles/global-feature-state-table.ts +20 -1
- package/src/feature-toggles/handlers/list.query.ts +1 -1
- package/src/feature-toggles/handlers/registered.query.ts +1 -1
- package/src/feature-toggles/i18n.ts +6 -0
- package/src/feature-toggles/index.ts +8 -0
- package/src/feature-toggles/toggle-runtime.ts +14 -0
- package/src/feature-toggles/web/client-plugin.tsx +22 -0
- package/src/feature-toggles/web/i18n.ts +29 -0
- package/src/feature-toggles/web/index.ts +6 -0
- package/src/feature-toggles/web/toggle-admin-screen.tsx +136 -0
- package/src/file-foundation/__tests__/feature.test.ts +5 -5
- package/src/file-foundation/__tests__/file-foundation.integration.test.ts +4 -3
- package/src/file-foundation/feature.ts +10 -11
- package/src/files-provider-s3/__tests__/s3-provider.integration.test.ts +27 -2
- package/src/files-provider-s3/s3-provider.ts +12 -1
- package/src/folders/__tests__/folders.integration.test.ts +3 -0
- package/src/folders/web/__tests__/folder-manager.test.tsx +43 -2
- package/src/folders/web/__tests__/tree.test.ts +8 -0
- package/src/folders/web/folder-manager.tsx +2 -3
- package/src/folders/web/i18n.ts +0 -2
- package/src/folders/web/tree.ts +13 -2
- package/src/folders-user-data/__tests__/hooks.integration.test.ts +1 -0
- package/src/folders-user-data/index.ts +4 -4
- package/src/inbound-mail-foundation/__tests__/account-state.test.ts +30 -0
- package/src/inbound-mail-foundation/__tests__/connect-routes.integration.test.ts +307 -0
- package/src/inbound-mail-foundation/__tests__/feature.test.ts +169 -0
- package/src/inbound-mail-foundation/__tests__/inbound-mail-foundation.integration.test.ts +644 -0
- package/src/inbound-mail-foundation/__tests__/inbound-mail-provider-contract.ts +111 -0
- package/src/inbound-mail-foundation/__tests__/retention.integration.test.ts +237 -0
- package/src/inbound-mail-foundation/__tests__/watch-supervisor.integration.test.ts +433 -0
- package/src/inbound-mail-foundation/aggregate-id.ts +40 -0
- package/src/inbound-mail-foundation/connect-routes.ts +230 -0
- package/src/inbound-mail-foundation/constants.ts +80 -0
- package/src/inbound-mail-foundation/db/queries/inbound-projections.ts +38 -0
- package/src/inbound-mail-foundation/entities.ts +172 -0
- package/src/inbound-mail-foundation/events.ts +147 -0
- package/src/inbound-mail-foundation/feature.ts +243 -0
- package/src/inbound-mail-foundation/handlers/account-state.ts +23 -0
- package/src/inbound-mail-foundation/handlers/connect-account.write.ts +112 -0
- package/src/inbound-mail-foundation/handlers/disconnect-account.write.ts +69 -0
- package/src/inbound-mail-foundation/handlers/ingest-message.write.ts +333 -0
- package/src/inbound-mail-foundation/handlers/list-accounts.query.ts +44 -0
- package/src/inbound-mail-foundation/handlers/list-messages.query.ts +58 -0
- package/src/inbound-mail-foundation/handlers/scope-visibility.ts +14 -0
- package/src/inbound-mail-foundation/handlers/update-account.write.ts +78 -0
- package/src/inbound-mail-foundation/index.ts +97 -0
- package/src/inbound-mail-foundation/oauth-state.ts +103 -0
- package/src/inbound-mail-foundation/projection.ts +152 -0
- package/src/inbound-mail-foundation/provider-factory.ts +53 -0
- package/src/inbound-mail-foundation/retention-sweep.ts +168 -0
- package/src/inbound-mail-foundation/tenant-destroy-hook.ts +93 -0
- package/src/inbound-mail-foundation/types.ts +250 -0
- package/src/inbound-mail-foundation/watch-supervisor.ts +482 -0
- package/src/inbound-provider-imap/__tests__/feature.test.ts +115 -0
- package/src/inbound-provider-imap/__tests__/imap-foundation.integration.test.ts +302 -0
- package/src/inbound-provider-imap/__tests__/imap-live.integration.test.ts +206 -0
- package/src/inbound-provider-imap/__tests__/plugin-mocked.test.ts +358 -0
- package/src/inbound-provider-imap/credential-document.ts +51 -0
- package/src/inbound-provider-imap/feature.ts +283 -0
- package/src/inbound-provider-imap/imap-client.ts +158 -0
- package/src/inbound-provider-imap/index.ts +17 -0
- package/src/inbound-provider-inmemory/__tests__/feature.test.ts +52 -0
- package/src/inbound-provider-inmemory/feature.ts +154 -0
- package/src/inbound-provider-inmemory/index.ts +12 -0
- package/src/jobs/__tests__/entity-ddl.test.ts +15 -0
- package/src/jobs/__tests__/job-instant.test.ts +15 -0
- package/src/jobs/__tests__/job-system-user.integration.test.ts +4 -8
- package/src/jobs/__tests__/jobs-events.integration.test.ts +37 -1
- package/src/jobs/__tests__/jobs-pii-kms.integration.test.ts +120 -0
- package/src/jobs/__tests__/jobs-screens.boot.test.ts +36 -0
- package/src/jobs/__tests__/jobs-security.integration.test.ts +108 -0
- package/src/jobs/__tests__/reindex-entity-job.integration.test.ts +169 -0
- package/src/jobs/constants.ts +8 -1
- package/src/jobs/feature.ts +52 -8
- package/src/jobs/handlers/detail.query.ts +6 -0
- package/src/jobs/handlers/list.query.ts +8 -1
- package/src/jobs/handlers/projection-rebuild.job.ts +14 -4
- package/src/jobs/handlers/reindex-entity.job.ts +49 -0
- package/src/jobs/i18n.ts +37 -0
- package/src/jobs/job-instant.ts +9 -0
- package/src/jobs/job-run-table.ts +4 -4
- package/src/jobs/web/client-plugin.tsx +22 -0
- package/src/jobs/web/i18n.ts +12 -0
- package/src/jobs/web/index.ts +4 -0
- package/src/jobs/web/job-run-detail-screen.tsx +180 -0
- package/src/jobs/web/job-runs-screen.tsx +146 -0
- package/src/ledger/__tests__/ledger.integration.test.ts +8 -3
- package/src/ledger/handlers/confirm-schedule-period.write.ts +17 -4
- package/src/ledger/recurring.ts +17 -8
- package/src/ledger/web/index.ts +3 -2
- package/src/legal-pages/__tests__/legal-pages.integration.test.ts +55 -0
- package/src/legal-pages/feature.ts +24 -31
- package/src/legal-pages/index.ts +1 -0
- package/src/mail-foundation/__tests__/feature.test.ts +5 -6
- package/src/mail-foundation/__tests__/mail-foundation.integration.test.ts +4 -3
- package/src/mail-foundation/__tests__/mail-transport-contract.ts +58 -0
- package/src/mail-foundation/feature.ts +26 -24
- package/src/mail-transport-inmemory/__tests__/feature.test.ts +23 -0
- package/src/mail-transport-smtp/__tests__/feature.test.ts +65 -0
- package/src/managed-pages/__tests__/branding-coerce.test.ts +2 -6
- package/src/managed-pages/__tests__/i18n-surface.boot.test.ts +30 -0
- package/src/managed-pages/__tests__/managed-pages.integration.test.ts +137 -0
- package/src/managed-pages/feature.ts +45 -47
- package/src/managed-pages/handlers/branding.query.ts +5 -1
- package/src/managed-pages/handlers/by-tenant-published.query.ts +52 -0
- package/src/managed-pages/i18n.ts +66 -0
- package/src/managed-pages/screens/page-screens.ts +5 -1
- package/src/managed-pages/web/client-plugin.tsx +22 -0
- package/src/managed-pages/web/i18n.ts +24 -0
- package/src/managed-pages/web/index.ts +3 -0
- package/src/page-render/__tests__/layout.test.ts +63 -0
- package/src/page-render/__tests__/markdown.test.ts +29 -0
- package/src/page-render/branding.ts +4 -3
- package/src/page-render/index.ts +1 -1
- package/src/page-render/layout.ts +18 -3
- package/src/page-render/markdown.ts +1 -9
- package/src/page-render/web.ts +13 -0
- package/src/personal-access-tokens/__tests__/feature.test.ts +42 -0
- package/src/personal-access-tokens/__tests__/pat.integration.test.ts +239 -0
- package/src/personal-access-tokens/__tests__/scopes.test.ts +42 -0
- package/src/personal-access-tokens/constants.ts +33 -0
- package/src/personal-access-tokens/feature.ts +105 -0
- package/src/personal-access-tokens/handlers/available-scopes.query.ts +21 -0
- package/src/personal-access-tokens/handlers/create.write.ts +47 -0
- package/src/personal-access-tokens/handlers/list.query.ts +50 -0
- package/src/personal-access-tokens/handlers/revoke.write.ts +37 -0
- package/src/personal-access-tokens/hash.ts +17 -0
- package/src/personal-access-tokens/i18n.ts +5 -0
- package/src/personal-access-tokens/index.ts +31 -0
- package/src/personal-access-tokens/resolver.ts +58 -0
- package/src/personal-access-tokens/roles.ts +29 -0
- package/src/personal-access-tokens/schema/api-token.ts +63 -0
- package/src/personal-access-tokens/scopes.ts +43 -0
- package/src/personal-access-tokens/web/client-plugin.tsx +29 -0
- package/src/personal-access-tokens/web/i18n.ts +69 -0
- package/src/personal-access-tokens/web/index.ts +7 -0
- package/src/personal-access-tokens/web/pat-tokens-screen.tsx +265 -0
- package/src/readiness/__tests__/readiness.integration.test.ts +4 -3
- package/src/renderer-simple/__tests__/resolve-variables.test.ts +37 -0
- package/src/renderer-simple/resolve-variables.ts +3 -1
- package/src/secrets/__tests__/rotate.integration.test.ts +115 -18
- package/src/secrets/handlers/rotate.job.ts +77 -98
- package/src/secrets/secrets-context.ts +7 -38
- package/src/secrets/table.ts +7 -8
- package/src/seo/__tests__/llms-txt.test.ts +38 -0
- package/src/seo/__tests__/robots-txt.test.ts +18 -0
- package/src/seo/__tests__/schema-builders.test.ts +57 -0
- package/src/seo/__tests__/seo.integration.test.ts +350 -0
- package/src/seo/__tests__/sitemap.test.ts +38 -0
- package/src/seo/constants.ts +60 -0
- package/src/seo/feature.ts +316 -0
- package/src/seo/handlers/seo-config.query.ts +35 -0
- package/src/seo/index.ts +19 -0
- package/src/seo/llms-txt.ts +33 -0
- package/src/seo/robots-txt.ts +13 -0
- package/src/seo/schema-builders.ts +57 -0
- package/src/seo/sitemap.ts +33 -0
- package/src/sessions/__tests__/auto-revoke-binding.test.ts +71 -0
- package/src/sessions/__tests__/cleanup.integration.test.ts +2 -1
- package/src/sessions/__tests__/password-auto-revoke.integration.test.ts +11 -7
- package/src/sessions/__tests__/rebuild-survival.integration.test.ts +18 -7
- package/src/sessions/__tests__/session-store-registration.test.ts +21 -0
- package/src/sessions/__tests__/sessions-screens.boot.test.ts +55 -0
- package/src/sessions/__tests__/sessions.integration.test.ts +272 -20
- package/src/sessions/__tests__/test-helpers.ts +16 -3
- package/src/sessions/constants.ts +5 -0
- package/src/sessions/db/queries/cleanup.ts +2 -2
- package/src/sessions/feature.ts +175 -26
- package/src/sessions/handlers/detail.query.ts +36 -0
- package/src/sessions/handlers/list.query.ts +14 -9
- package/src/sessions/handlers/mine.query.ts +13 -8
- package/src/sessions/handlers/revoke-all-for-user.write.ts +51 -12
- package/src/sessions/handlers/revoke-all-others.write.ts +19 -1
- package/src/sessions/handlers/revoke.write.ts +13 -0
- package/src/sessions/i18n.ts +23 -0
- package/src/sessions/index.ts +9 -2
- package/src/sessions/schema/user-session.ts +8 -2
- package/src/sessions/session-callbacks.ts +99 -14
- package/src/sessions/session-checker-fail-open.test.ts +77 -0
- package/src/sessions/session-revoked-event.ts +29 -0
- package/src/sessions/testing.ts +14 -1
- package/src/shared/__tests__/chunked-entity-migration.test.ts +145 -0
- package/src/shared/chunked-entity-migration.ts +89 -0
- package/src/shared/decrypt-stored-pii.ts +26 -0
- package/src/shared/encrypt-for-direct-write.ts +23 -0
- package/src/shared/entities-of.ts +17 -0
- package/src/shared/grace-period.test.ts +26 -0
- package/src/shared/grace-period.ts +20 -0
- package/src/{auth-email-password/__tests__ → shared}/identity-v3-hash.test.ts +2 -2
- package/src/shared/index.ts +16 -0
- package/src/shared/map-with-concurrency.test.ts +104 -0
- package/src/shared/map-with-concurrency.ts +38 -0
- package/src/shared/password-hashing.test.ts +35 -0
- package/src/{auth-email-password → shared}/password-hashing.ts +11 -0
- package/src/shared/system-query.ts +5 -0
- package/src/{auth-email-password → shared}/token-burn-store.ts +1 -1
- package/src/subscription-mollie/__tests__/feature.test.ts +97 -0
- package/src/subscription-mollie/__tests__/mollie-foundation.integration.test.ts +12 -1
- package/src/subscription-mollie/__tests__/verify-webhook.test.ts +21 -0
- package/src/subscription-mollie/verify-webhook.ts +1 -0
- package/src/subscription-stripe/__tests__/feature.test.ts +127 -1
- package/src/subscription-stripe/__tests__/runtime.test.ts +14 -24
- package/src/subscription-stripe/__tests__/stripe-foundation.integration.test.ts +15 -5
- package/src/subscription-stripe/__tests__/verify-webhook.test.ts +20 -0
- package/src/subscription-stripe/feature.ts +2 -0
- package/src/subscription-stripe/verify-webhook.ts +3 -2
- package/src/tags/__tests__/schemas.test.ts +34 -0
- package/src/tags/__tests__/tags.integration.test.ts +12 -1
- package/src/tags/entity.ts +6 -1
- package/src/tags/feature.ts +2 -0
- package/src/tags/i18n.ts +5 -0
- package/src/tags/schemas.ts +9 -2
- package/src/tags/web/__tests__/tag-manager.test.tsx +333 -0
- package/src/tags/web/__tests__/tag-section.test.tsx +47 -1
- package/src/tags/web/tag-manager.tsx +1 -1
- package/src/tags/web/tag-section.tsx +6 -3
- package/src/template-resolver/testing.ts +2 -1
- package/src/tenant/__tests__/members-query-kms.integration.test.ts +98 -0
- package/src/tenant/__tests__/members-screens.boot.test.ts +51 -0
- package/src/tenant/__tests__/multi-tenant.integration.test.ts +1 -1
- package/src/tenant/__tests__/tenant-security.integration.test.ts +310 -0
- package/src/tenant/__tests__/tenant.integration.test.ts +8 -4
- package/src/tenant/constants.ts +5 -0
- package/src/tenant/feature.ts +19 -0
- package/src/tenant/handlers/active-tenant-ids.query.ts +8 -2
- package/src/tenant/handlers/cancel-invitation.write.ts +2 -2
- package/src/tenant/handlers/invitations.query.ts +21 -4
- package/src/tenant/handlers/members.query.ts +41 -6
- package/src/tenant/i18n.ts +28 -0
- package/src/tenant/index.ts +7 -2
- package/src/tenant/invitation-table.ts +3 -2
- package/src/tenant/schema/tenant.ts +27 -2
- package/src/tenant/screens.ts +3 -2
- package/src/tenant/seeding.ts +136 -3
- package/src/tenant/web/client-plugin.tsx +20 -0
- package/src/tenant/web/i18n.ts +43 -0
- package/src/tenant/web/index.ts +4 -0
- package/src/tenant/web/members-screen.tsx +270 -0
- package/src/tenant-lifecycle/__tests__/stages.test.ts +22 -0
- package/src/tenant-lifecycle/__tests__/tenant-lifecycle.integration.test.ts +471 -0
- package/src/tenant-lifecycle/boot-checks.ts +45 -0
- package/src/tenant-lifecycle/constants.ts +56 -0
- package/src/tenant-lifecycle/events.ts +46 -0
- package/src/tenant-lifecycle/feature.ts +112 -0
- package/src/tenant-lifecycle/handlers/cancel-destruction.write.ts +79 -0
- package/src/tenant-lifecycle/handlers/request-destruction.write.ts +83 -0
- package/src/tenant-lifecycle/index.ts +7 -0
- package/src/tenant-lifecycle/lib/revoke-tenant-sessions.ts +16 -0
- package/src/tenant-lifecycle/lifecycle-gate.ts +65 -0
- package/src/tenant-lifecycle/run-tenant-destroy.ts +368 -0
- package/src/tenant-lifecycle/stages.ts +206 -0
- package/src/tenant-settings/__tests__/tenant-settings.integration.test.ts +115 -0
- package/src/tenant-settings/config.ts +44 -0
- package/src/tenant-settings/constants.ts +16 -0
- package/src/tenant-settings/feature.ts +49 -0
- package/src/tenant-settings/index.ts +8 -0
- package/src/tenant-settings/tenant-defaults.ts +67 -0
- package/src/text-content/web/__tests__/editor-read-only.test.tsx +33 -6
- package/src/text-content/web/__tests__/group-blocks.test.ts +28 -3
- package/src/text-content/web/client-plugin.tsx +126 -104
- package/src/tier-engine/__tests__/auto-default-tier.integration.test.ts +1 -1
- package/src/tier-engine/__tests__/resolver.integration.test.ts +1 -1
- package/src/tier-engine/__tests__/tier-engine.integration.test.ts +7 -4
- package/src/tier-engine/__tests__/trial-config-validation.test.ts +30 -0
- package/src/tier-engine/feature.ts +13 -6
- package/src/tier-engine/i18n.ts +8 -0
- package/src/tier-engine/web/tier-admin-screen.tsx +26 -19
- package/src/user/__tests__/stream-tenant-backfill.integration.test.ts +186 -0
- package/src/user/__tests__/user.integration.test.ts +26 -0
- package/src/user/constants.ts +1 -0
- package/src/user/db/queries/stream-tenant-backfill.ts +112 -0
- package/src/user/feature.ts +3 -0
- package/src/user/handlers/find-for-auth.query.ts +8 -6
- package/src/user/i18n.ts +20 -0
- package/src/user/index.ts +4 -0
- package/src/user/schema/user.ts +6 -2
- package/src/user/screens.ts +3 -15
- package/src/user/seeding.ts +8 -0
- package/src/user-data-rights/COMPLIANCE.md +21 -1
- package/src/user-data-rights/__tests__/anonymous-deletion-kms.integration.test.ts +145 -0
- package/src/user-data-rights/__tests__/anonymous-deletion.integration.test.ts +3 -0
- package/src/user-data-rights/__tests__/audit-log.integration.test.ts +67 -0
- package/src/user-data-rights/__tests__/boot-checks.test.ts +170 -0
- package/src/user-data-rights/__tests__/cross-data-matrix.integration.test.ts +4 -1
- package/src/user-data-rights/__tests__/download-by-token-resolver-trust.integration.test.ts +169 -0
- package/src/user-data-rights/__tests__/download.integration.test.ts +101 -33
- package/src/user-data-rights/__tests__/email-templates.test.ts +15 -0
- package/src/user-data-rights/__tests__/export-encrypted-fields.integration.test.ts +154 -0
- package/src/user-data-rights/__tests__/export-job-idempotency.integration.test.ts +2 -0
- package/src/user-data-rights/__tests__/export-job-list-cross-tenant.integration.test.ts +2 -0
- package/src/user-data-rights/__tests__/file-binary-forget-cleanup.integration.test.ts +4 -1
- package/src/user-data-rights/__tests__/file-binary-forget-failure.integration.test.ts +4 -1
- package/src/user-data-rights/__tests__/file-retention.integration.test.ts +4 -1
- package/src/user-data-rights/__tests__/file-storage-unification.integration.test.ts +4 -1
- package/src/user-data-rights/__tests__/forget-cleanup-hook-ordering.integration.test.ts +41 -62
- package/src/user-data-rights/__tests__/forget-hook-registry.integration.test.ts +110 -0
- package/src/user-data-rights/__tests__/inspector-screens.boot.test.ts +14 -0
- package/src/user-data-rights/__tests__/mail-default-bridge.integration.test.ts +19 -2
- package/src/user-data-rights/__tests__/read-users-rebuild-survives-lifecycle.integration.test.ts +25 -14
- package/src/user-data-rights/__tests__/request-cancel-deletion.integration.test.ts +2 -0
- package/src/user-data-rights/__tests__/request-deletion-callback.integration.test.ts +4 -1
- package/src/user-data-rights/__tests__/request-export.integration.test.ts +2 -0
- package/src/user-data-rights/__tests__/restriction-flow.integration.test.ts +172 -19
- package/src/user-data-rights/__tests__/run-export-jobs-cron-context.integration.test.ts +2 -0
- package/src/user-data-rights/__tests__/run-export-jobs.integration.test.ts +257 -26
- package/src/user-data-rights/__tests__/run-forget-cleanup.integration.test.ts +339 -5
- package/src/user-data-rights/__tests__/run-user-export.integration.test.ts +77 -1
- package/src/user-data-rights/__tests__/tenant-model-erasure.integration.test.ts +2 -0
- package/src/user-data-rights/__tests__/user-data-rights.integration.test.ts +9 -1
- package/src/user-data-rights/boot-checks.ts +70 -0
- package/src/user-data-rights/db/queries/__tests__/forget-cleanup.integration.test.ts +69 -0
- package/src/user-data-rights/db/queries/forget-cleanup.ts +9 -2
- package/src/user-data-rights/email-templates.ts +6 -6
- package/src/user-data-rights/feature.ts +162 -43
- package/src/user-data-rights/handlers/cancel-deletion.write.ts +8 -11
- package/src/user-data-rights/handlers/deletion-grace-period.ts +4 -1
- package/src/user-data-rights/handlers/download-by-job.query.ts +26 -18
- package/src/user-data-rights/handlers/download-by-token.query.ts +23 -15
- package/src/user-data-rights/handlers/lift-restriction.write.ts +44 -19
- package/src/user-data-rights/handlers/list-download-attempts.query.ts +1 -0
- package/src/user-data-rights/handlers/my-audit-log.query.ts +1 -0
- package/src/user-data-rights/handlers/request-deletion-by-email.write.ts +3 -1
- package/src/user-data-rights/handlers/restrict-account.write.ts +58 -7
- package/src/user-data-rights/handlers/run-forget-cleanup.write.ts +2 -0
- package/src/user-data-rights/i18n.ts +35 -32
- package/src/user-data-rights/lib/is-admin-actor.ts +19 -0
- package/src/user-data-rights/lib/storage-provider-resolver.ts +6 -5
- package/src/user-data-rights/lib/update-user-lifecycle.ts +8 -24
- package/src/user-data-rights/run-export-jobs.ts +55 -19
- package/src/user-data-rights/run-forget-cleanup.ts +112 -7
- package/src/user-data-rights/run-user-export.ts +70 -4
- package/src/user-data-rights/schema/download-token.ts +5 -3
- package/src/user-data-rights/schema/export-job.ts +2 -0
- package/src/user-data-rights/screens.ts +2 -1
- package/src/user-data-rights/web/__tests__/privacy-center-screen.test.tsx +1 -0
- package/src/user-data-rights/web/__tests__/public-deletion-gate.test.tsx +7 -1
- package/src/user-data-rights/web/client-plugin.tsx +6 -1
- package/src/user-data-rights/web/i18n.ts +30 -10
- package/src/user-data-rights/web/privacy-center-screen.tsx +5 -3
- package/src/user-data-rights-defaults/__tests__/bundled-entities.userdata-hooks.integration.test.ts +455 -0
- package/src/user-data-rights-defaults/__tests__/feature-mounted.test.ts +24 -0
- package/src/user-data-rights-defaults/__tests__/user-data-rights-defaults.integration.test.ts +33 -9
- package/src/user-data-rights-defaults/feature.ts +78 -1
- package/src/user-data-rights-defaults/hooks/api-token.userdata-hook.ts +37 -0
- package/src/user-data-rights-defaults/hooks/config-value.userdata-hook.ts +51 -0
- package/src/user-data-rights-defaults/hooks/delivery-attempt.userdata-hook.ts +37 -0
- package/src/user-data-rights-defaults/hooks/feature-mounted.ts +10 -0
- package/src/user-data-rights-defaults/hooks/in-app-message.userdata-hook.ts +38 -0
- package/src/user-data-rights-defaults/hooks/job-run.userdata-hook.ts +35 -0
- package/src/user-data-rights-defaults/hooks/notification-preference.userdata-hook.ts +54 -0
- package/src/user-data-rights-defaults/hooks/tenant-invitation.userdata-hook.ts +112 -0
- package/src/user-data-rights-defaults/hooks/user-session.userdata-hook.ts +42 -0
- package/src/user-data-rights-defaults/index.ts +26 -0
- package/src/user-profile/__tests__/change-email.integration.test.ts +7 -1
- package/src/user-profile/__tests__/profile-screen.test.tsx +5 -0
- package/src/user-profile/feature.ts +4 -1
- package/src/user-profile/handlers/change-email.write.ts +15 -10
- package/src/user-profile/web/profile-screen.tsx +15 -3
- package/src/auth-email-password/stream-tenant.ts +0 -31
- package/src/feature-toggles/db/queries/toggle-state.ts +0 -25
- package/src/legal-pages/security-headers.ts +0 -1
- package/src/sessions/schema/index.ts +0 -5
- package/src/tenant/schema/index.ts +0 -5
- package/src/user/schema/index.ts +0 -5
- /package/src/{auth-email-password → shared}/identity-v3-hash.ts +0 -0
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
// die Policy entscheidet pro Tenant.
|
|
17
17
|
|
|
18
18
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
|
|
19
|
+
import { authFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
|
|
19
20
|
import { asRawClient } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
20
21
|
import {
|
|
21
22
|
createEventStoreExecutor,
|
|
@@ -36,7 +37,7 @@ import { createComplianceProfilesFeature } from "../../compliance-profiles";
|
|
|
36
37
|
import { createDataRetentionFeature, tenantRetentionOverrideEntity } from "../../data-retention";
|
|
37
38
|
import { tenantRetentionOverrideTable } from "../../data-retention/schema/tenant-retention-override";
|
|
38
39
|
import { createFilesFeature } from "../../files";
|
|
39
|
-
import { createSessionsFeature } from "../../sessions";
|
|
40
|
+
import { createSessionsFeature, userSessionEntity } from "../../sessions";
|
|
40
41
|
import { createUserFeature, USER_STATUS, userEntity, userTable } from "../../user";
|
|
41
42
|
import { createUserDataRightsDefaultsFeature } from "../../user-data-rights-defaults";
|
|
42
43
|
import { createUserDataRightsFeature } from "../feature";
|
|
@@ -68,6 +69,7 @@ beforeAll(async () => {
|
|
|
68
69
|
createFilesFeature(),
|
|
69
70
|
createDataRetentionFeature(),
|
|
70
71
|
createComplianceProfilesFeature(),
|
|
72
|
+
authFoundationFeature,
|
|
71
73
|
createSessionsFeature(),
|
|
72
74
|
createUserDataRightsFeature(),
|
|
73
75
|
createUserDataRightsDefaultsFeature(),
|
|
@@ -76,6 +78,7 @@ beforeAll(async () => {
|
|
|
76
78
|
db = stack.db;
|
|
77
79
|
|
|
78
80
|
await unsafeCreateEntityTable(db, userEntity);
|
|
81
|
+
await unsafeCreateEntityTable(db, userSessionEntity);
|
|
79
82
|
await unsafeCreateEntityTable(db, tenantRetentionOverrideEntity);
|
|
80
83
|
await unsafePushTables(db, { fileRefsTable });
|
|
81
84
|
await asRawClient(db).unsafe(`
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
// assertion below go red.
|
|
12
12
|
|
|
13
13
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
|
|
14
|
+
import { authFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
|
|
14
15
|
import { asRawClient } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
15
16
|
import type { DbConnection } from "@cosmicdrift/kumiko-framework/db";
|
|
16
17
|
import { type SessionUser, SYSTEM_USER_ID } from "@cosmicdrift/kumiko-framework/engine";
|
|
@@ -40,7 +41,7 @@ import { configValuesTable } from "../../config/table";
|
|
|
40
41
|
import { createDataRetentionFeature, tenantRetentionOverrideEntity } from "../../data-retention";
|
|
41
42
|
import { fileFoundationFeature } from "../../file-foundation";
|
|
42
43
|
import { createFilesFeature } from "../../files";
|
|
43
|
-
import { createSessionsFeature } from "../../sessions";
|
|
44
|
+
import { createSessionsFeature, userSessionEntity } from "../../sessions";
|
|
44
45
|
import { createUserFeature, userEntity, userTable } from "../../user";
|
|
45
46
|
import { createUserDataRightsDefaultsFeature } from "../../user-data-rights-defaults";
|
|
46
47
|
import { createUserDataRightsFeature } from "../feature";
|
|
@@ -94,6 +95,7 @@ beforeAll(async () => {
|
|
|
94
95
|
createTestFileProviderFeature(provider, "test"),
|
|
95
96
|
createDataRetentionFeature(),
|
|
96
97
|
createComplianceProfilesFeature(),
|
|
98
|
+
authFoundationFeature,
|
|
97
99
|
createSessionsFeature(),
|
|
98
100
|
createUserDataRightsFeature(),
|
|
99
101
|
createUserDataRightsDefaultsFeature(),
|
|
@@ -117,6 +119,7 @@ beforeAll(async () => {
|
|
|
117
119
|
});
|
|
118
120
|
|
|
119
121
|
await unsafeCreateEntityTable(db, userEntity);
|
|
122
|
+
await unsafeCreateEntityTable(db, userSessionEntity);
|
|
120
123
|
await unsafeCreateEntityTable(db, tenantRetentionOverrideEntity);
|
|
121
124
|
await unsafePushTables(db, { fileRefsTable, configValuesTable });
|
|
122
125
|
await createEventsTable(db);
|
|
@@ -1,32 +1,31 @@
|
|
|
1
|
-
// DSGVO forget hook-ordering —
|
|
2
|
-
// before any host hook that
|
|
3
|
-
// of feature registration
|
|
1
|
+
// DSGVO forget hook-ordering — a redaction hook with order
|
|
2
|
+
// EXT_USER_DATA_ORDER.REDACT_BEFORE_OWNER must run before any host hook that
|
|
3
|
+
// nulls the owner column it filters on, regardless of feature registration
|
|
4
|
+
// order. (Originally proven via the custom-fields sensitive strip; that strip
|
|
5
|
+
// was removed in #972, so this test pins the generic runner guarantee with a
|
|
6
|
+
// synthetic redact hook.)
|
|
4
7
|
//
|
|
5
8
|
// Two host entities are wired with the OPPOSITE EXT_USER_DATA registration
|
|
6
|
-
// order: one registers the
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
//
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
// This drives the full runner on purpose: the existing custom-fields
|
|
14
|
-
// user-data-rights test invokes the strip hook in isolation
|
|
15
|
-
// (getExtensionUsages + direct call) and is structurally blind to ordering.
|
|
9
|
+
// order: one registers the redact hook first (the order that happened to be
|
|
10
|
+
// safe), the other registers the owner-nulling host hook first (the order
|
|
11
|
+
// that exposed the bug). Both run through the real `runForgetCleanup` with
|
|
12
|
+
// strategy=anonymize. With the order-sentinel both strip the jsonb key;
|
|
13
|
+
// without it the host-first entity would leave it behind (the redact matches
|
|
14
|
+
// 0 rows after the owner column is nulled).
|
|
16
15
|
|
|
17
16
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
|
|
17
|
+
import { authFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
|
|
18
18
|
import { asRawClient } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
19
|
-
import { buildEntityTable } from "@cosmicdrift/kumiko-framework/db";
|
|
20
19
|
import {
|
|
21
20
|
createEntity,
|
|
22
21
|
createTextField,
|
|
23
22
|
defineFeature,
|
|
24
23
|
EXT_USER_DATA,
|
|
24
|
+
EXT_USER_DATA_ORDER,
|
|
25
25
|
type UserDataDeleteHook,
|
|
26
26
|
} from "@cosmicdrift/kumiko-framework/engine";
|
|
27
27
|
import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
28
28
|
import {
|
|
29
|
-
createTestUser,
|
|
30
29
|
resetEventStore,
|
|
31
30
|
setupTestStack,
|
|
32
31
|
type TestStack,
|
|
@@ -34,10 +33,7 @@ import {
|
|
|
34
33
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
35
34
|
import { seedRow as seedProjectionRow } from "@cosmicdrift/kumiko-framework/testing";
|
|
36
35
|
import { createComplianceProfilesFeature } from "../../compliance-profiles";
|
|
37
|
-
import { fieldDefinitionEntity } from "../../custom-fields/entity";
|
|
38
|
-
import { createCustomFieldsFeature } from "../../custom-fields/feature";
|
|
39
36
|
import { customFieldsField } from "../../custom-fields/wire-for-entity";
|
|
40
|
-
import { wireCustomFieldsUserDataRightsFor } from "../../custom-fields/wire-user-data-rights";
|
|
41
37
|
import { createDataRetentionFeature, tenantRetentionOverrideEntity } from "../../data-retention";
|
|
42
38
|
import { tenantRetentionOverrideTable } from "../../data-retention/schema/tenant-retention-override";
|
|
43
39
|
import { createSessionsFeature } from "../../sessions";
|
|
@@ -70,6 +66,20 @@ function makeHostDeleteHook(tableName: string): UserDataDeleteHook {
|
|
|
70
66
|
};
|
|
71
67
|
}
|
|
72
68
|
|
|
69
|
+
// Owner-keyed jsonb redaction with the REDACT_BEFORE_OWNER order sentinel —
|
|
70
|
+
// the shape the removed custom-fields strip had, kept synthetic here.
|
|
71
|
+
function makeRedactHook(tableName: string): UserDataDeleteHook {
|
|
72
|
+
return async (ctx, strategy) => {
|
|
73
|
+
// skip: delete strategy removes rows wholesale — redaction N/A.
|
|
74
|
+
if (strategy === "delete") return;
|
|
75
|
+
await asRawClient(ctx.db).unsafe(
|
|
76
|
+
`UPDATE ${tableName} SET custom_fields = custom_fields - 'ssn'
|
|
77
|
+
WHERE inserted_by_id = $1 AND tenant_id = $2`,
|
|
78
|
+
[ctx.userId, ctx.tenantId],
|
|
79
|
+
);
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
|
|
73
83
|
interface HostSpec {
|
|
74
84
|
readonly entityName: string;
|
|
75
85
|
readonly tableName: string;
|
|
@@ -99,19 +109,16 @@ function makeEntity(tableName: string) {
|
|
|
99
109
|
|
|
100
110
|
const cfFirstEntity = makeEntity(CF_FIRST.tableName);
|
|
101
111
|
const hostFirstEntity = makeEntity(HOST_FIRST.tableName);
|
|
102
|
-
const cfFirstTable = buildEntityTable(CF_FIRST.entityName, cfFirstEntity);
|
|
103
|
-
const hostFirstTable = buildEntityTable(HOST_FIRST.entityName, hostFirstEntity);
|
|
104
112
|
|
|
105
|
-
// Registration order is the whole point: cfFirst registers the
|
|
106
|
-
// owner-nulling host hook; hostFirst registers the host hook FIRST
|
|
107
|
-
// that exposed the bug). The order-sentinel must make both correct.
|
|
113
|
+
// Registration order is the whole point: cfFirst registers the redact hook
|
|
114
|
+
// BEFORE the owner-nulling host hook; hostFirst registers the host hook FIRST
|
|
115
|
+
// (the order that exposed the bug). The order-sentinel must make both correct.
|
|
108
116
|
const cfFirstFeature = defineFeature(CF_FIRST.featureName, (r) => {
|
|
109
117
|
r.entity(CF_FIRST.entityName, cfFirstEntity);
|
|
110
|
-
r.
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
userIdColumn: "inserted_by_id",
|
|
118
|
+
r.useExtension(EXT_USER_DATA, CF_FIRST.entityName, {
|
|
119
|
+
export: async () => null,
|
|
120
|
+
delete: makeRedactHook(CF_FIRST.tableName),
|
|
121
|
+
order: EXT_USER_DATA_ORDER.REDACT_BEFORE_OWNER,
|
|
115
122
|
});
|
|
116
123
|
r.useExtension(EXT_USER_DATA, CF_FIRST.entityName, {
|
|
117
124
|
export: async () => null,
|
|
@@ -121,19 +128,17 @@ const cfFirstFeature = defineFeature(CF_FIRST.featureName, (r) => {
|
|
|
121
128
|
|
|
122
129
|
const hostFirstFeature = defineFeature(HOST_FIRST.featureName, (r) => {
|
|
123
130
|
r.entity(HOST_FIRST.entityName, hostFirstEntity);
|
|
124
|
-
r.requires("custom-fields");
|
|
125
131
|
r.useExtension(EXT_USER_DATA, HOST_FIRST.entityName, {
|
|
126
132
|
export: async () => null,
|
|
127
133
|
delete: makeHostDeleteHook(HOST_FIRST.tableName),
|
|
128
134
|
});
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
135
|
+
r.useExtension(EXT_USER_DATA, HOST_FIRST.entityName, {
|
|
136
|
+
export: async () => null,
|
|
137
|
+
delete: makeRedactHook(HOST_FIRST.tableName),
|
|
138
|
+
order: EXT_USER_DATA_ORDER.REDACT_BEFORE_OWNER,
|
|
133
139
|
});
|
|
134
140
|
});
|
|
135
141
|
|
|
136
|
-
const admin = createTestUser({ id: 1, roles: ["TenantAdmin"], tenantId: TENANT });
|
|
137
142
|
const FORGET_USER = "cccccccc-cccc-4ccc-8ccc-0000000000a1";
|
|
138
143
|
|
|
139
144
|
let stack: TestStack;
|
|
@@ -144,17 +149,16 @@ beforeAll(async () => {
|
|
|
144
149
|
stack = await setupTestStack({
|
|
145
150
|
features: [
|
|
146
151
|
createUserFeature(),
|
|
152
|
+
authFoundationFeature,
|
|
147
153
|
createSessionsFeature(),
|
|
148
154
|
createDataRetentionFeature(),
|
|
149
155
|
createComplianceProfilesFeature(),
|
|
150
|
-
createCustomFieldsFeature(),
|
|
151
156
|
createUserDataRightsFeature(),
|
|
152
157
|
cfFirstFeature,
|
|
153
158
|
hostFirstFeature,
|
|
154
159
|
],
|
|
155
160
|
});
|
|
156
161
|
await unsafeCreateEntityTable(stack.db, userEntity);
|
|
157
|
-
await unsafeCreateEntityTable(stack.db, fieldDefinitionEntity);
|
|
158
162
|
await unsafeCreateEntityTable(stack.db, tenantRetentionOverrideEntity);
|
|
159
163
|
await unsafeCreateEntityTable(stack.db, cfFirstEntity);
|
|
160
164
|
await unsafeCreateEntityTable(stack.db, hostFirstEntity);
|
|
@@ -166,21 +170,6 @@ afterAll(async () => {
|
|
|
166
170
|
await stack.cleanup();
|
|
167
171
|
});
|
|
168
172
|
|
|
169
|
-
async function defineSensitiveField(entityName: string, fieldKey: string, sensitive: boolean) {
|
|
170
|
-
await stack.http.writeOk(
|
|
171
|
-
"custom-fields:write:define-tenant-field",
|
|
172
|
-
{
|
|
173
|
-
entityName,
|
|
174
|
-
fieldKey,
|
|
175
|
-
serializedField: { type: "text", sensitive },
|
|
176
|
-
required: false,
|
|
177
|
-
searchable: false,
|
|
178
|
-
displayOrder: 0,
|
|
179
|
-
},
|
|
180
|
-
admin,
|
|
181
|
-
);
|
|
182
|
-
}
|
|
183
|
-
|
|
184
173
|
async function seedAnonymizeOverride(entityName: string) {
|
|
185
174
|
await seedProjectionRow(stack.db, tenantRetentionOverrideTable, {
|
|
186
175
|
entityName,
|
|
@@ -217,25 +206,15 @@ beforeEach(async () => {
|
|
|
217
206
|
await resetEventStore(stack);
|
|
218
207
|
await asRawClient(stack.db).unsafe(`DELETE FROM ${CF_FIRST.tableName}`);
|
|
219
208
|
await asRawClient(stack.db).unsafe(`DELETE FROM ${HOST_FIRST.tableName}`);
|
|
220
|
-
await asRawClient(stack.db).unsafe(`DELETE FROM read_custom_field_definitions`);
|
|
221
209
|
await asRawClient(stack.db).unsafe(`DELETE FROM read_tenant_retention_overrides`);
|
|
222
210
|
await asRawClient(stack.db).unsafe(`DELETE FROM read_tenant_memberships`);
|
|
223
211
|
});
|
|
224
212
|
|
|
225
213
|
describe("forget hook-ordering :: redaction runs before owner-nulling regardless of registration order", () => {
|
|
226
|
-
test("both registration orders strip the
|
|
227
|
-
// Field defs (sensitive ssn, non-sensitive safe) for both entities.
|
|
214
|
+
test("both registration orders strip the redacted jsonb key and null the owner column", async () => {
|
|
228
215
|
for (const spec of [CF_FIRST, HOST_FIRST]) {
|
|
229
|
-
await defineSensitiveField(spec.entityName, "ssn", true);
|
|
230
|
-
await defineSensitiveField(spec.entityName, "safe", false);
|
|
231
216
|
await seedAnonymizeOverride(spec.entityName);
|
|
232
217
|
}
|
|
233
|
-
// Project the field definitions. Assert the pass had no failures: a silent
|
|
234
|
-
// projection failure would leave read_custom_field_definitions empty, make
|
|
235
|
-
// loadSensitiveFieldKeys return [], and turn the strip into a no-op —
|
|
236
|
-
// verifying the test exercises the strip for the right reason.
|
|
237
|
-
const pass = await stack.eventDispatcher?.runOnce();
|
|
238
|
-
expect(pass?.failed ?? 0).toBe(0);
|
|
239
218
|
|
|
240
219
|
const cfRowId = "dddddddd-dddd-4ddd-8ddd-000000000001";
|
|
241
220
|
const hostRowId = "dddddddd-dddd-4ddd-8ddd-000000000002";
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
// A forget delete-hook receives the app registry so it can cascade custom child
|
|
2
|
+
// projections for the executor's `<entity>.forgotten` event (runProjectionsForEvent).
|
|
3
|
+
// executor.forget purges only the entity's OWN projection, and the forget pipeline
|
|
4
|
+
// is a job — not a dispatched command — so the dispatcher's post-command projection
|
|
5
|
+
// pass never fires. Without registry in the hook ctx the cascade is unreachable and
|
|
6
|
+
// child read-model rows (m:n joins, per-parent detail projections) are orphaned on
|
|
7
|
+
// live forget (a DSGVO gap). This pins that the plumbing delivers the real,
|
|
8
|
+
// functional registry instance; the end-to-end cascade is covered consumer-side.
|
|
9
|
+
|
|
10
|
+
import { afterAll, beforeAll, beforeEach, expect, test } from "bun:test";
|
|
11
|
+
import { authFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
|
|
12
|
+
import { asRawClient } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
13
|
+
import {
|
|
14
|
+
createEntity,
|
|
15
|
+
createTextField,
|
|
16
|
+
defineFeature,
|
|
17
|
+
EXT_USER_DATA,
|
|
18
|
+
type Registry,
|
|
19
|
+
type UserDataDeleteHook,
|
|
20
|
+
} from "@cosmicdrift/kumiko-framework/engine";
|
|
21
|
+
import { createEventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
22
|
+
import {
|
|
23
|
+
setupTestStack,
|
|
24
|
+
type TestStack,
|
|
25
|
+
unsafeCreateEntityTable,
|
|
26
|
+
} from "@cosmicdrift/kumiko-framework/stack";
|
|
27
|
+
import { createComplianceProfilesFeature } from "../../compliance-profiles";
|
|
28
|
+
import { createDataRetentionFeature, tenantRetentionOverrideEntity } from "../../data-retention";
|
|
29
|
+
import { createSessionsFeature } from "../../sessions";
|
|
30
|
+
import { createUserFeature, userEntity } from "../../user";
|
|
31
|
+
import { createUserDataRightsFeature } from "../feature";
|
|
32
|
+
import { runForgetCleanup } from "../run-forget-cleanup";
|
|
33
|
+
import {
|
|
34
|
+
createForgetSeeders,
|
|
35
|
+
nowInstant,
|
|
36
|
+
READ_TENANT_MEMBERSHIPS_DDL,
|
|
37
|
+
TENANT_SYSTEM,
|
|
38
|
+
} from "./forget-test-helpers";
|
|
39
|
+
|
|
40
|
+
const PROBE = "forget-registry-probe";
|
|
41
|
+
let capturedRegistry: Registry | undefined;
|
|
42
|
+
|
|
43
|
+
const captureHook: UserDataDeleteHook = async (ctx) => {
|
|
44
|
+
capturedRegistry = ctx.registry;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const probeEntity = createEntity({
|
|
48
|
+
table: `read_${PROBE.replace(/-/g, "_")}`,
|
|
49
|
+
fields: { name: createTextField({ required: true }) },
|
|
50
|
+
});
|
|
51
|
+
|
|
52
|
+
const probeFeature = defineFeature(PROBE, (r) => {
|
|
53
|
+
r.entity(PROBE, probeEntity);
|
|
54
|
+
r.useExtension(EXT_USER_DATA, PROBE, {
|
|
55
|
+
export: async () => null,
|
|
56
|
+
delete: captureHook,
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
const FORGET_USER = "cccccccc-cccc-4ccc-8ccc-0000000000b1";
|
|
61
|
+
let stack: TestStack;
|
|
62
|
+
const seed = (db: unknown) =>
|
|
63
|
+
// biome-ignore lint/suspicious/noExplicitAny: dummy writer; this seeder never writes binaries.
|
|
64
|
+
createForgetSeeders(db as any, { write: async () => {} });
|
|
65
|
+
|
|
66
|
+
beforeAll(async () => {
|
|
67
|
+
stack = await setupTestStack({
|
|
68
|
+
features: [
|
|
69
|
+
createUserFeature(),
|
|
70
|
+
authFoundationFeature,
|
|
71
|
+
createSessionsFeature(),
|
|
72
|
+
createDataRetentionFeature(),
|
|
73
|
+
createComplianceProfilesFeature(),
|
|
74
|
+
createUserDataRightsFeature(),
|
|
75
|
+
probeFeature,
|
|
76
|
+
],
|
|
77
|
+
});
|
|
78
|
+
await unsafeCreateEntityTable(stack.db, userEntity);
|
|
79
|
+
await unsafeCreateEntityTable(stack.db, tenantRetentionOverrideEntity);
|
|
80
|
+
await unsafeCreateEntityTable(stack.db, probeEntity);
|
|
81
|
+
await createEventsTable(stack.db);
|
|
82
|
+
await asRawClient(stack.db).unsafe(READ_TENANT_MEMBERSHIPS_DDL);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
afterAll(async () => {
|
|
86
|
+
await stack.cleanup();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
beforeEach(() => {
|
|
90
|
+
capturedRegistry = undefined;
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("forget delete-hook receives the app registry instance", async () => {
|
|
94
|
+
await seed(stack.db).seedForgetUser(FORGET_USER);
|
|
95
|
+
await seed(stack.db).seedMembership(FORGET_USER, TENANT_SYSTEM);
|
|
96
|
+
|
|
97
|
+
const result = await runForgetCleanup({
|
|
98
|
+
db: stack.db,
|
|
99
|
+
registry: stack.registry,
|
|
100
|
+
now: nowInstant(),
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
expect(result.errors, JSON.stringify(result.errors)).toHaveLength(0);
|
|
104
|
+
expect(result.processedUserIds).toContain(FORGET_USER);
|
|
105
|
+
// The hook ran and got the exact registry passed to runForgetCleanup — not
|
|
106
|
+
// undefined, not a stand-in — so runProjectionsForEvent(event, ctx.registry, db)
|
|
107
|
+
// reaches the real projections.
|
|
108
|
+
expect(capturedRegistry).toBe(stack.registry);
|
|
109
|
+
expect(capturedRegistry?.getProjectionsForSource(PROBE)).toBeDefined();
|
|
110
|
+
});
|
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { describe, expect, test } from "bun:test";
|
|
2
2
|
import { access, validateBoot } from "@cosmicdrift/kumiko-framework/engine";
|
|
3
|
+
import { createFilesFeature } from "@cosmicdrift/kumiko-framework/files";
|
|
4
|
+
import { authFoundationFeature } from "../../auth-foundation";
|
|
3
5
|
import { createComplianceProfilesFeature } from "../../compliance-profiles/feature";
|
|
4
6
|
import { createConfigFeature } from "../../config/feature";
|
|
5
7
|
import { createDataRetentionFeature } from "../../data-retention/feature";
|
|
8
|
+
import { createPersonalAccessTokensFeature } from "../../personal-access-tokens";
|
|
6
9
|
import { createSessionsFeature } from "../../sessions/feature";
|
|
10
|
+
import { createTenantFeature } from "../../tenant/feature";
|
|
7
11
|
import { createUserFeature } from "../../user/feature";
|
|
12
|
+
import { createUserDataRightsDefaultsFeature } from "../../user-data-rights-defaults/feature";
|
|
8
13
|
import { createUserDataRightsFeature } from "../feature";
|
|
9
14
|
|
|
10
15
|
// Read-only GDPR inspector screens live IN user-data-rights (the boot-validator
|
|
@@ -16,13 +21,22 @@ import { createUserDataRightsFeature } from "../feature";
|
|
|
16
21
|
// so an entityList binding is rebuild-safe (unlike jobs/sessions read-models).
|
|
17
22
|
|
|
18
23
|
describe("user-data-rights read-only inspector screens", () => {
|
|
24
|
+
// A realistic assembly: mounting user-data-rights without its default hooks
|
|
25
|
+
// now fails the V3 boot gate (the framework `user` entity holds PII with no
|
|
26
|
+
// erase path). Real apps mount the defaults (which hard-require `files`)
|
|
27
|
+
// alongside — so this set mirrors that.
|
|
19
28
|
const features = [
|
|
20
29
|
createConfigFeature(),
|
|
21
30
|
createUserFeature(),
|
|
31
|
+
createTenantFeature(),
|
|
32
|
+
authFoundationFeature,
|
|
33
|
+
createPersonalAccessTokensFeature({ scopes: {} }),
|
|
22
34
|
createSessionsFeature(),
|
|
23
35
|
createDataRetentionFeature(),
|
|
24
36
|
createComplianceProfilesFeature(),
|
|
37
|
+
createFilesFeature(),
|
|
25
38
|
createUserDataRightsFeature(),
|
|
39
|
+
createUserDataRightsDefaultsFeature(),
|
|
26
40
|
];
|
|
27
41
|
|
|
28
42
|
test("the assembled feature set boot-validates", () => {
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
// #624: "App mountet mail-foundation+transport → GDPR-Mails ohne Callback-Code".
|
|
11
11
|
|
|
12
12
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
|
|
13
|
+
import { authFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
|
|
13
14
|
import { asRawClient } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
14
15
|
import { fileRefsTable } from "@cosmicdrift/kumiko-framework/files";
|
|
15
16
|
import {
|
|
@@ -26,7 +27,7 @@ import { createDataRetentionFeature, tenantRetentionOverrideEntity } from "../..
|
|
|
26
27
|
import { createFilesFeature } from "../../files";
|
|
27
28
|
import { mailFoundationFeature } from "../../mail-foundation";
|
|
28
29
|
import { clearInbox, getInbox, mailTransportInMemoryFeature } from "../../mail-transport-inmemory";
|
|
29
|
-
import { createSessionsFeature } from "../../sessions";
|
|
30
|
+
import { createSessionsFeature, userSessionEntity } from "../../sessions";
|
|
30
31
|
import { createUserFeature, USER_STATUS, userEntity, userTable } from "../../user";
|
|
31
32
|
import { createUserDataRightsDefaultsFeature } from "../../user-data-rights-defaults";
|
|
32
33
|
import { createUserDataRightsFeature } from "../feature";
|
|
@@ -56,6 +57,7 @@ beforeAll(async () => {
|
|
|
56
57
|
createFilesFeature(),
|
|
57
58
|
createDataRetentionFeature(),
|
|
58
59
|
createComplianceProfilesFeature(),
|
|
60
|
+
authFoundationFeature,
|
|
59
61
|
createSessionsFeature(),
|
|
60
62
|
mailFoundationFeature,
|
|
61
63
|
mailTransportInMemoryFeature,
|
|
@@ -67,6 +69,7 @@ beforeAll(async () => {
|
|
|
67
69
|
|
|
68
70
|
await unsafePushTables(stack.db, { configValuesTable });
|
|
69
71
|
await unsafeCreateEntityTable(stack.db, userEntity);
|
|
72
|
+
await unsafeCreateEntityTable(stack.db, userSessionEntity);
|
|
70
73
|
await unsafeCreateEntityTable(stack.db, tenantRetentionOverrideEntity);
|
|
71
74
|
await asRawClient(stack.db).unsafe(`
|
|
72
75
|
CREATE TABLE IF NOT EXISTS read_tenant_memberships (
|
|
@@ -120,7 +123,21 @@ describe("C6 default mail bridge :: forget cron sends deletion-executed without
|
|
|
120
123
|
expect(job).toBeDefined();
|
|
121
124
|
|
|
122
125
|
// EXAKT der prod-Job-Kontext: configResolver gesetzt, config undefined.
|
|
123
|
-
|
|
126
|
+
// log required since #1572 persists incomplete[] via ctx.log.warn.
|
|
127
|
+
const jobCtx = {
|
|
128
|
+
db: stack.db,
|
|
129
|
+
registry: stack.registry,
|
|
130
|
+
configResolver,
|
|
131
|
+
log: {
|
|
132
|
+
info() {},
|
|
133
|
+
warn() {},
|
|
134
|
+
error() {},
|
|
135
|
+
debug() {},
|
|
136
|
+
child() {
|
|
137
|
+
return this;
|
|
138
|
+
},
|
|
139
|
+
},
|
|
140
|
+
};
|
|
124
141
|
await job?.handler({}, jobCtx as never);
|
|
125
142
|
|
|
126
143
|
// Loeschung lief autonom durch.
|
package/src/user-data-rights/__tests__/read-users-rebuild-survives-lifecycle.integration.test.ts
CHANGED
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
|
|
14
14
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
|
|
15
15
|
import { randomBytes } from "node:crypto";
|
|
16
|
+
import { authFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
|
|
16
17
|
import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
17
|
-
import { createEncryptionProvider } from "@cosmicdrift/kumiko-framework/db";
|
|
18
18
|
import {
|
|
19
19
|
createRegistry,
|
|
20
20
|
type Registry,
|
|
@@ -40,13 +40,13 @@ import {
|
|
|
40
40
|
} from "@cosmicdrift/kumiko-framework/stack";
|
|
41
41
|
import {
|
|
42
42
|
createLateBoundHolder,
|
|
43
|
+
createTestEnvelopeCipher,
|
|
43
44
|
resetTestTables,
|
|
44
45
|
updateRows,
|
|
45
46
|
} from "@cosmicdrift/kumiko-framework/testing";
|
|
46
47
|
import { getTemporal } from "@cosmicdrift/kumiko-framework/time";
|
|
47
48
|
import { AuthHandlers } from "../../auth-email-password/constants";
|
|
48
49
|
import { createAuthEmailPasswordFeature } from "../../auth-email-password/feature";
|
|
49
|
-
import { hashPassword } from "../../auth-email-password/password-hashing";
|
|
50
50
|
import {
|
|
51
51
|
createComplianceProfilesFeature,
|
|
52
52
|
tenantComplianceProfileEntity,
|
|
@@ -59,7 +59,8 @@ import { createDataRetentionFeature } from "../../data-retention";
|
|
|
59
59
|
import { createSessionsFeature } from "../../sessions";
|
|
60
60
|
import { userSessionEntity, userSessionTable } from "../../sessions/schema/user-session";
|
|
61
61
|
import { createSessionCallbacks, type SessionCallbacks } from "../../sessions/session-callbacks";
|
|
62
|
-
import { sessionCallbacksFromLateBound } from "../../sessions/testing";
|
|
62
|
+
import { sessionCallbacksFromLateBound, withMintedSession } from "../../sessions/testing";
|
|
63
|
+
import { hashPassword } from "../../shared";
|
|
63
64
|
import { createTenantFeature, tenantMembershipsTable } from "../../tenant";
|
|
64
65
|
import { tenantEntity } from "../../tenant/schema/tenant";
|
|
65
66
|
import { seedTenantMembership } from "../../tenant/seeding";
|
|
@@ -91,14 +92,15 @@ function buildFeatures() {
|
|
|
91
92
|
createDataRetentionFeature(),
|
|
92
93
|
createComplianceProfilesFeature(),
|
|
93
94
|
createAuthEmailPasswordFeature(),
|
|
95
|
+
authFoundationFeature,
|
|
94
96
|
createSessionsFeature(),
|
|
95
97
|
createUserDataRightsFeature(),
|
|
96
98
|
];
|
|
97
99
|
}
|
|
98
100
|
|
|
99
101
|
beforeAll(async () => {
|
|
100
|
-
const encryption =
|
|
101
|
-
const resolver = createConfigResolver({ encryption });
|
|
102
|
+
const encryption = createTestEnvelopeCipher(encryptionKey);
|
|
103
|
+
const resolver = createConfigResolver({ cipher: encryption });
|
|
102
104
|
const bound = sessionCallbacksFromLateBound(callbacks);
|
|
103
105
|
|
|
104
106
|
stack = await setupTestStack({
|
|
@@ -137,6 +139,12 @@ beforeEach(async () => {
|
|
|
137
139
|
]);
|
|
138
140
|
});
|
|
139
141
|
|
|
142
|
+
// Any actor hitting a write handler needs a live sid once sessionChecker
|
|
143
|
+
// is wired.
|
|
144
|
+
function mintActor(user: { id: string; tenantId: TenantId; roles: readonly string[] }) {
|
|
145
|
+
return withMintedSession((u, meta) => callbacks.get().sessionCreator(u, meta), user);
|
|
146
|
+
}
|
|
147
|
+
|
|
140
148
|
describe("#494 :: read_users-Rebuild bewahrt Lifecycle-State", () => {
|
|
141
149
|
test("Restricted-Status ueberlebt einen Projection-Rebuild (T_create != T_active)", async () => {
|
|
142
150
|
// Diskriminierende Praemisse: user.created landet auf systemAdmin.tenantId
|
|
@@ -149,7 +157,7 @@ describe("#494 :: read_users-Rebuild bewahrt Lifecycle-State", () => {
|
|
|
149
157
|
const created = await stack.http.writeOk<{ id: string }>(
|
|
150
158
|
UserHandlers.create,
|
|
151
159
|
{ email: ALICE_EMAIL, passwordHash: hash, displayName: "Alice" },
|
|
152
|
-
TestUsers.systemAdmin,
|
|
160
|
+
await mintActor(TestUsers.systemAdmin),
|
|
153
161
|
);
|
|
154
162
|
// Mitgliedschaft + Lifecycle auf einem ANDEREN, aktiven Tenant.
|
|
155
163
|
await seedTenantMembership(stack.db, {
|
|
@@ -158,7 +166,7 @@ describe("#494 :: read_users-Rebuild bewahrt Lifecycle-State", () => {
|
|
|
158
166
|
roles: ["Member"],
|
|
159
167
|
});
|
|
160
168
|
|
|
161
|
-
const aliceActive = { id: created.id, tenantId: T_ACTIVE, roles: ["Member"] };
|
|
169
|
+
const aliceActive = await mintActor({ id: created.id, tenantId: T_ACTIVE, roles: ["Member"] });
|
|
162
170
|
const restricted = await stack.http.writeOk<{ status: string }>(RESTRICT, {}, aliceActive);
|
|
163
171
|
expect(restricted.status).toBe(USER_STATUS.Restricted);
|
|
164
172
|
|
|
@@ -187,7 +195,7 @@ describe("#494 :: read_users-Rebuild bewahrt Lifecycle-State", () => {
|
|
|
187
195
|
const created = await stack.http.writeOk<{ id: string }>(
|
|
188
196
|
UserHandlers.create,
|
|
189
197
|
{ email: "grace.rebuild@example.com", passwordHash: hash, displayName: "Grace" },
|
|
190
|
-
TestUsers.systemAdmin,
|
|
198
|
+
await mintActor(TestUsers.systemAdmin),
|
|
191
199
|
);
|
|
192
200
|
|
|
193
201
|
const T = getTemporal();
|
|
@@ -218,7 +226,7 @@ describe("#494 :: read_users-Rebuild bewahrt Lifecycle-State", () => {
|
|
|
218
226
|
const created = await stack.http.writeOk<{ id: string }>(
|
|
219
227
|
UserHandlers.create,
|
|
220
228
|
{ email: "legacy.rebuild@example.com", passwordHash: hash, displayName: "Legacy" },
|
|
221
|
-
TestUsers.systemAdmin,
|
|
229
|
+
await mintActor(TestUsers.systemAdmin),
|
|
222
230
|
);
|
|
223
231
|
|
|
224
232
|
// Prae-Fix-Zustand simulieren: roher Write OHNE Event.
|
|
@@ -256,14 +264,14 @@ describe("#494 :: read_users-Rebuild bewahrt Lifecycle-State", () => {
|
|
|
256
264
|
const goodRow = await stack.http.writeOk<{ id: string }>(
|
|
257
265
|
UserHandlers.create,
|
|
258
266
|
{ email: "healthy.rebuild@example.com", passwordHash: hash, displayName: "Healthy" },
|
|
259
|
-
TestUsers.systemAdmin,
|
|
267
|
+
await mintActor(TestUsers.systemAdmin),
|
|
260
268
|
);
|
|
261
269
|
await updateRows(stack.db, userTable, { status: USER_STATUS.Restricted }, { id: goodRow.id });
|
|
262
270
|
|
|
263
271
|
const badRow = await stack.http.writeOk<{ id: string }>(
|
|
264
272
|
UserHandlers.create,
|
|
265
273
|
{ email: "corrupt.rebuild@example.com", passwordHash: hash, displayName: "Corrupt" },
|
|
266
|
-
TestUsers.systemAdmin,
|
|
274
|
+
await mintActor(TestUsers.systemAdmin),
|
|
267
275
|
);
|
|
268
276
|
await updateRows(stack.db, userTable, { status: USER_STATUS.Restricted }, { id: badRow.id });
|
|
269
277
|
// userEntity is systemStream:true (schema/user.ts) — its event stream
|
|
@@ -283,8 +291,11 @@ describe("#494 :: read_users-Rebuild bewahrt Lifecycle-State", () => {
|
|
|
283
291
|
expect(backfilled).toBeGreaterThanOrEqual(1);
|
|
284
292
|
|
|
285
293
|
// Proof the loop didn't abort at the corrupt row: rebuild the projection —
|
|
286
|
-
// goodRow got its user.updated event (survives)
|
|
287
|
-
//
|
|
294
|
+
// goodRow got its user.updated event (survives). badRow's Stream ist
|
|
295
|
+
// archiviert und replayt seit fw#832 gar nicht mehr: die Row ist nach dem
|
|
296
|
+
// Rebuild WEG (nicht bloss auf Active zurueckgewischt). Genau deshalb ist
|
|
297
|
+
// der failed-Report oben der Operator-Alarm — Heilung: restoreStream +
|
|
298
|
+
// Backfill-Re-Run, DANN rebuild.
|
|
288
299
|
await rebuildProjection(USER_PROJECTION, { db: stack.db, registry });
|
|
289
300
|
const rows = (await selectMany(stack.db, userTable, {})) as Array<{
|
|
290
301
|
id: string;
|
|
@@ -293,6 +304,6 @@ describe("#494 :: read_users-Rebuild bewahrt Lifecycle-State", () => {
|
|
|
293
304
|
const good = rows.find((r) => r.id === goodRow.id);
|
|
294
305
|
const bad = rows.find((r) => r.id === badRow.id);
|
|
295
306
|
expect(good?.status).toBe(USER_STATUS.Restricted);
|
|
296
|
-
expect(bad
|
|
307
|
+
expect(bad).toBeUndefined();
|
|
297
308
|
});
|
|
298
309
|
});
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
// hier; der Frist-Ablauf-Cleanup folgt mit S2.U5b.
|
|
11
11
|
|
|
12
12
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
|
|
13
|
+
import { authFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
|
|
13
14
|
import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
14
15
|
import { createEventsTable, eventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
15
16
|
import {
|
|
@@ -57,6 +58,7 @@ const features = [
|
|
|
57
58
|
createUserFeature(),
|
|
58
59
|
createDataRetentionFeature(),
|
|
59
60
|
createComplianceProfilesFeature(),
|
|
61
|
+
authFoundationFeature,
|
|
60
62
|
createSessionsFeature(),
|
|
61
63
|
|
|
62
64
|
createUserDataRightsFeature(),
|
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
// Properties — dieser Test verifiziert sie end-to-end.
|
|
9
9
|
|
|
10
10
|
import { afterAll, beforeAll, beforeEach, describe, expect, test } from "bun:test";
|
|
11
|
+
import { authFoundationFeature } from "@cosmicdrift/kumiko-bundled-features/auth-foundation";
|
|
11
12
|
import { selectMany } from "@cosmicdrift/kumiko-framework/bun-db";
|
|
12
13
|
import { createEventsTable, eventsTable } from "@cosmicdrift/kumiko-framework/event-store";
|
|
13
14
|
import {
|
|
@@ -24,7 +25,7 @@ import {
|
|
|
24
25
|
tenantComplianceProfileTable,
|
|
25
26
|
} from "../../compliance-profiles";
|
|
26
27
|
import { createDataRetentionFeature } from "../../data-retention";
|
|
27
|
-
import { createSessionsFeature } from "../../sessions";
|
|
28
|
+
import { createSessionsFeature, userSessionEntity } from "../../sessions";
|
|
28
29
|
import { USER_STATUS, userEntity, userTable } from "../../user";
|
|
29
30
|
import { createUserFeature } from "../../user/feature";
|
|
30
31
|
import { createUserDataRightsFeature } from "../feature";
|
|
@@ -64,12 +65,14 @@ beforeAll(async () => {
|
|
|
64
65
|
createUserFeature(),
|
|
65
66
|
createDataRetentionFeature(),
|
|
66
67
|
createComplianceProfilesFeature(),
|
|
68
|
+
authFoundationFeature,
|
|
67
69
|
createSessionsFeature(),
|
|
68
70
|
|
|
69
71
|
createUserDataRightsFeature({ sendDeletionRequestedEmail }),
|
|
70
72
|
],
|
|
71
73
|
});
|
|
72
74
|
await unsafeCreateEntityTable(stack.db, userEntity);
|
|
75
|
+
await unsafeCreateEntityTable(stack.db, userSessionEntity);
|
|
73
76
|
await unsafeCreateEntityTable(stack.db, tenantComplianceProfileEntity);
|
|
74
77
|
await createEventsTable(stack.db);
|
|
75
78
|
});
|