@wildo-ai/saas-models 1.1.1 → 1.1.2
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/dist/esm/applications/applications-context.schemas.d.ts +2 -0
- package/dist/esm/applications/applications-context.schemas.d.ts.map +1 -1
- package/dist/esm/billing/billing-account.shared.resources-config.schemas.d.ts +1 -1
- package/dist/esm/billing/billing-account.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/billing/billing-account.shared.resources-config.schemas.js +36 -0
- package/dist/esm/billing/billing-account.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/billing/billing-account.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/billing-account.shared.schemas.js +8 -1
- package/dist/esm/billing/billing-account.shared.schemas.js.map +1 -1
- package/dist/esm/billing/billing-types.shared.schemas.d.ts +2 -2
- package/dist/esm/billing/credit-pool.shared.resources-config.schemas.d.ts +1 -1
- package/dist/esm/billing/credit-pool.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/billing/credit-pool.shared.resources-config.schemas.js +39 -0
- package/dist/esm/billing/credit-pool.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/billing/credit-pool.shared.schemas.d.ts +6 -6
- package/dist/esm/billing/credit-pool.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/credit-pool.shared.schemas.js +8 -4
- package/dist/esm/billing/credit-pool.shared.schemas.js.map +1 -1
- package/dist/esm/billing/invoice-ref.shared.resources-config.schemas.d.ts +1 -1
- package/dist/esm/billing/invoice-ref.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/billing/invoice-ref.shared.resources-config.schemas.js +35 -0
- package/dist/esm/billing/invoice-ref.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/billing/invoice-ref.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/invoice-ref.shared.schemas.js +8 -3
- package/dist/esm/billing/invoice-ref.shared.schemas.js.map +1 -1
- package/dist/esm/billing/subscription.shared.resources-config.schemas.d.ts +1 -1
- package/dist/esm/billing/subscription.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/billing/subscription.shared.resources-config.schemas.js +39 -0
- package/dist/esm/billing/subscription.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/billing/subscription.shared.schemas.d.ts +4 -4
- package/dist/esm/billing/subscription.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/subscription.shared.schemas.js +6 -2
- package/dist/esm/billing/subscription.shared.schemas.js.map +1 -1
- package/dist/esm/billing/usage-record.shared.resources-config.schemas.d.ts +1 -1
- package/dist/esm/billing/usage-record.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/billing/usage-record.shared.resources-config.schemas.js +39 -0
- package/dist/esm/billing/usage-record.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/billing/usage-record.shared.schemas.d.ts +4 -4
- package/dist/esm/billing/usage-record.shared.schemas.d.ts.map +1 -1
- package/dist/esm/billing/usage-record.shared.schemas.js +7 -3
- package/dist/esm/billing/usage-record.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/audit-trails/audit-logs.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/audit-logs.shared.resources-config.schemas.js +35 -2
- package/dist/esm/compliance/audit-trails/audit-logs.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/compliance/audit-trails/auditable-events.shared.schema.d.ts +61 -0
- package/dist/esm/compliance/audit-trails/auditable-events.shared.schema.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/auditable-events.shared.schema.js +58 -0
- package/dist/esm/compliance/audit-trails/auditable-events.shared.schema.js.map +1 -1
- package/dist/esm/compliance/audit-trails/security-audit-event-envelope.shared.schema.d.ts.map +1 -1
- package/dist/esm/compliance/audit-trails/security-audit-event-envelope.shared.schema.js +14 -0
- package/dist/esm/compliance/audit-trails/security-audit-event-envelope.shared.schema.js.map +1 -1
- package/dist/esm/compliance/privacy/impersonalization-scrub.shared.utils.d.ts +49 -0
- package/dist/esm/compliance/privacy/impersonalization-scrub.shared.utils.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/impersonalization-scrub.shared.utils.js +124 -1
- package/dist/esm/compliance/privacy/impersonalization-scrub.shared.utils.js.map +1 -1
- package/dist/esm/compliance/privacy/impersonalization.shared.schemas.d.ts +11 -3
- package/dist/esm/compliance/privacy/impersonalization.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/impersonalization.shared.schemas.js +11 -3
- package/dist/esm/compliance/privacy/impersonalization.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/operating-jurisdictions.shared.schemas.d.ts +93 -0
- package/dist/esm/compliance/privacy/operating-jurisdictions.shared.schemas.d.ts.map +1 -0
- package/dist/esm/compliance/privacy/operating-jurisdictions.shared.schemas.js +116 -0
- package/dist/esm/compliance/privacy/operating-jurisdictions.shared.schemas.js.map +1 -0
- package/dist/esm/compliance/privacy/operator-compliance-identity.shared.schemas.d.ts +67 -12
- package/dist/esm/compliance/privacy/operator-compliance-identity.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/operator-compliance-identity.shared.schemas.js +95 -8
- package/dist/esm/compliance/privacy/operator-compliance-identity.shared.schemas.js.map +1 -1
- package/dist/esm/compliance/privacy/redaction.shared.schemas.d.ts +21 -1
- package/dist/esm/compliance/privacy/redaction.shared.schemas.d.ts.map +1 -1
- package/dist/esm/compliance/privacy/redaction.shared.schemas.js +20 -0
- package/dist/esm/compliance/privacy/redaction.shared.schemas.js.map +1 -1
- package/dist/esm/config/app-configuration-shared.shared.schemas.d.ts +2 -0
- package/dist/esm/config/app-configuration-shared.shared.schemas.d.ts.map +1 -1
- package/dist/esm/config/app-configuration-shared.shared.schemas.js +29 -0
- package/dist/esm/config/app-configuration-shared.shared.schemas.js.map +1 -1
- package/dist/esm/config/frontend/navigation.shared.schemas.d.ts +33 -0
- package/dist/esm/config/frontend/navigation.shared.schemas.d.ts.map +1 -1
- package/dist/esm/config/frontend/navigation.shared.schemas.js +32 -0
- package/dist/esm/config/frontend/navigation.shared.schemas.js.map +1 -1
- package/dist/esm/errors/errors.custom-message-ref.shared.definitions.d.ts +12 -1
- package/dist/esm/errors/errors.custom-message-ref.shared.definitions.d.ts.map +1 -1
- package/dist/esm/errors/errors.custom-message-ref.shared.definitions.js +12 -1
- package/dist/esm/errors/errors.custom-message-ref.shared.definitions.js.map +1 -1
- package/dist/esm/external-data/external-data-pipeline.shared.schemas.d.ts +13 -0
- package/dist/esm/external-data/external-data-pipeline.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-data/external-data-pipeline.shared.schemas.js.map +1 -1
- package/dist/esm/external-providers/engine-capabilities.shared.schemas.d.ts +6 -6
- package/dist/esm/external-providers/engine-capabilities.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/engine-capabilities.shared.schemas.js +26 -6
- package/dist/esm/external-providers/engine-capabilities.shared.schemas.js.map +1 -1
- package/dist/esm/external-providers/engine-capability-resolution-mode.shared.d.ts.map +1 -1
- package/dist/esm/external-providers/engine-capability-resolution-mode.shared.js +0 -2
- package/dist/esm/external-providers/engine-capability-resolution-mode.shared.js.map +1 -1
- package/dist/esm/external-providers/frontend-bootstrap.shared.schemas.d.ts +1 -0
- package/dist/esm/external-providers/frontend-bootstrap.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/provider-capability.shared.schemas.d.ts +4 -3
- package/dist/esm/external-providers/provider-capability.shared.schemas.d.ts.map +1 -1
- package/dist/esm/external-providers/provider-capability.shared.schemas.js +4 -3
- package/dist/esm/external-providers/provider-capability.shared.schemas.js.map +1 -1
- package/dist/esm/features/user-features.shared.resources-config.schemas.d.ts +1 -1
- package/dist/esm/features/user-features.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/features/user-features.shared.resources-config.schemas.js +48 -0
- package/dist/esm/features/user-features.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/files/file-upload-grant.shared.schemas.d.ts +144 -0
- package/dist/esm/files/file-upload-grant.shared.schemas.d.ts.map +1 -0
- package/dist/esm/files/file-upload-grant.shared.schemas.js +136 -0
- package/dist/esm/files/file-upload-grant.shared.schemas.js.map +1 -0
- package/dist/esm/files/files.shared.schemas.d.ts +45 -4
- package/dist/esm/files/files.shared.schemas.d.ts.map +1 -1
- package/dist/esm/files/files.shared.schemas.js +48 -4
- package/dist/esm/files/files.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/a2a-push-delivery-log.shared.resources-config.schemas.d.ts +1 -1
- package/dist/esm/flows-actors/a2a-push-delivery-log.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/a2a-push-delivery-log.shared.resources-config.schemas.js +33 -0
- package/dist/esm/flows-actors/a2a-push-delivery-log.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/flows-actors/a2a-push-delivery-log.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/a2a-push-delivery-log.shared.schemas.js +6 -2
- package/dist/esm/flows-actors/a2a-push-delivery-log.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/a2a-token-budget-state.shared.resources-config.schemas.d.ts +1 -1
- package/dist/esm/flows-actors/a2a-token-budget-state.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/a2a-token-budget-state.shared.resources-config.schemas.js +53 -0
- package/dist/esm/flows-actors/a2a-token-budget-state.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/flows-actors/flows-actors-execution.shared.resources-config.schemas.d.ts +1 -1
- package/dist/esm/flows-actors/flows-actors-execution.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/flows-actors-execution.shared.resources-config.schemas.js +43 -0
- package/dist/esm/flows-actors/flows-actors-execution.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/flows-actors/flows-actors-execution.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/flows-actors-execution.shared.schemas.js +8 -3
- package/dist/esm/flows-actors/flows-actors-execution.shared.schemas.js.map +1 -1
- package/dist/esm/flows-actors/flows-actors-task.shared.resources-config.schemas.d.ts +1 -1
- package/dist/esm/flows-actors/flows-actors-task.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/flows-actors-task.shared.resources-config.schemas.js +41 -0
- package/dist/esm/flows-actors/flows-actors-task.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/flows-actors/flows-actors-task.shared.schemas.d.ts +0 -7
- package/dist/esm/flows-actors/flows-actors-task.shared.schemas.d.ts.map +1 -1
- package/dist/esm/flows-actors/flows-actors-task.shared.schemas.js +23 -13
- package/dist/esm/flows-actors/flows-actors-task.shared.schemas.js.map +1 -1
- package/dist/esm/guidance/guidance-state.shared.resources-config.schemas.d.ts +1 -1
- package/dist/esm/guidance/guidance-state.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/guidance/guidance-state.shared.resources-config.schemas.js +51 -0
- package/dist/esm/guidance/guidance-state.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/guidance/guidance-state.shared.schemas.d.ts.map +1 -1
- package/dist/esm/guidance/guidance-state.shared.schemas.js +8 -2
- package/dist/esm/guidance/guidance-state.shared.schemas.js.map +1 -1
- package/dist/esm/guidance/lifecycle-state.shared.resources-config.schemas.d.ts +1 -1
- package/dist/esm/guidance/lifecycle-state.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/guidance/lifecycle-state.shared.resources-config.schemas.js +51 -0
- package/dist/esm/guidance/lifecycle-state.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/guidance/lifecycle-state.shared.schemas.d.ts.map +1 -1
- package/dist/esm/guidance/lifecycle-state.shared.schemas.js +28 -3
- package/dist/esm/guidance/lifecycle-state.shared.schemas.js.map +1 -1
- package/dist/esm/guidance/progression-state.shared.resources-config.schemas.d.ts +1 -1
- package/dist/esm/guidance/progression-state.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/guidance/progression-state.shared.resources-config.schemas.js +51 -0
- package/dist/esm/guidance/progression-state.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/guidance/progression-state.shared.schemas.d.ts.map +1 -1
- package/dist/esm/guidance/progression-state.shared.schemas.js +18 -4
- package/dist/esm/guidance/progression-state.shared.schemas.js.map +1 -1
- package/dist/esm/http-api-binding/http-api-binding.shared.schemas.d.ts +37 -3
- package/dist/esm/http-api-binding/http-api-binding.shared.schemas.d.ts.map +1 -1
- package/dist/esm/http-api-binding/http-api-binding.shared.schemas.js +29 -3
- package/dist/esm/http-api-binding/http-api-binding.shared.schemas.js.map +1 -1
- package/dist/esm/index.d.ts +6 -0
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/index.js +6 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/notifications/m2m/m2m-webhook-delivery-contract.shared.d.ts +70 -0
- package/dist/esm/notifications/m2m/m2m-webhook-delivery-contract.shared.d.ts.map +1 -0
- package/dist/esm/notifications/m2m/m2m-webhook-delivery-contract.shared.js +71 -0
- package/dist/esm/notifications/m2m/m2m-webhook-delivery-contract.shared.js.map +1 -0
- package/dist/esm/notifications/notification-badges.shared.resources-config.schemas.d.ts +1 -1
- package/dist/esm/notifications/notification-badges.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/notifications/notification-badges.shared.resources-config.schemas.js +36 -0
- package/dist/esm/notifications/notification-badges.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/organizations/organization-members.shared.resources-config.schemas.d.ts +1 -1
- package/dist/esm/organizations/organization-members.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/organization-members.shared.resources-config.schemas.js +44 -0
- package/dist/esm/organizations/organization-members.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/organizations/organization-members.shared.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/organization-members.shared.schemas.js +15 -4
- package/dist/esm/organizations/organization-members.shared.schemas.js.map +1 -1
- package/dist/esm/organizations/organizations.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/organizations/organizations.shared.resources-config.schemas.js +18 -10
- package/dist/esm/organizations/organizations.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/queue/jobs.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/queue/jobs.shared.resources-config.schemas.js +17 -0
- package/dist/esm/queue/jobs.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/requests/websocket.shared.schemas.d.ts +59 -0
- package/dist/esm/requests/websocket.shared.schemas.d.ts.map +1 -1
- package/dist/esm/requests/websocket.shared.schemas.js +103 -0
- package/dist/esm/requests/websocket.shared.schemas.js.map +1 -1
- package/dist/esm/resources/collection-query-parameters.shared.d.ts +22 -0
- package/dist/esm/resources/collection-query-parameters.shared.d.ts.map +1 -0
- package/dist/esm/resources/collection-query-parameters.shared.js +22 -0
- package/dist/esm/resources/collection-query-parameters.shared.js.map +1 -0
- package/dist/esm/resources/resources-config.shared.factory.d.ts.map +1 -1
- package/dist/esm/resources/resources-config.shared.factory.js +86 -13
- package/dist/esm/resources/resources-config.shared.factory.js.map +1 -1
- package/dist/esm/resources/resources-config.shared.schemas.d.ts +162 -41
- package/dist/esm/resources/resources-config.shared.schemas.d.ts.map +1 -1
- package/dist/esm/resources/resources-config.shared.schemas.js +109 -20
- package/dist/esm/resources/resources-config.shared.schemas.js.map +1 -1
- package/dist/esm/resources/utils/resources-config-operations.dtos-builder.utils.d.ts.map +1 -1
- package/dist/esm/resources/utils/resources-config-operations.dtos-builder.utils.js +21 -6
- package/dist/esm/resources/utils/resources-config-operations.dtos-builder.utils.js.map +1 -1
- package/dist/esm/security/authentications/authentication.shared.schemas.d.ts +57 -0
- package/dist/esm/security/authentications/authentication.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/authentication.shared.schemas.js +64 -0
- package/dist/esm/security/authentications/authentication.shared.schemas.js.map +1 -1
- package/dist/esm/security/authentications/consumable-token.shared.schemas.d.ts +17 -1
- package/dist/esm/security/authentications/consumable-token.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/authentications/consumable-token.shared.schemas.js +16 -0
- package/dist/esm/security/authentications/consumable-token.shared.schemas.js.map +1 -1
- package/dist/esm/security/authentications/mfa-backup-code-contract.shared.d.ts +28 -0
- package/dist/esm/security/authentications/mfa-backup-code-contract.shared.d.ts.map +1 -0
- package/dist/esm/security/authentications/mfa-backup-code-contract.shared.js +28 -0
- package/dist/esm/security/authentications/mfa-backup-code-contract.shared.js.map +1 -0
- package/dist/esm/security/authentications/siem/siem-delivery-reliability-contract.shared.d.ts +21 -0
- package/dist/esm/security/authentications/siem/siem-delivery-reliability-contract.shared.d.ts.map +1 -0
- package/dist/esm/security/authentications/siem/siem-delivery-reliability-contract.shared.js +21 -0
- package/dist/esm/security/authentications/siem/siem-delivery-reliability-contract.shared.js.map +1 -0
- package/dist/esm/security/authorizations/platform-access-grants.shared.resources-config.schemas.d.ts +1 -1
- package/dist/esm/security/authorizations/platform-access-grants.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/security/authorizations/platform-access-grants.shared.resources-config.schemas.js +43 -0
- package/dist/esm/security/authorizations/platform-access-grants.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/security/authorizations/platform-access-grants.shared.schemas.d.ts +0 -8
- package/dist/esm/security/authorizations/platform-access-grants.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/authorizations/platform-access-grants.shared.schemas.js +13 -4
- package/dist/esm/security/authorizations/platform-access-grants.shared.schemas.js.map +1 -1
- package/dist/esm/security/authorizations/roles.shared.schemas.d.ts +16 -1
- package/dist/esm/security/authorizations/roles.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/authorizations/roles.shared.schemas.js +16 -1
- package/dist/esm/security/authorizations/roles.shared.schemas.js.map +1 -1
- package/dist/esm/security/authorizations/roles.shared.utils.d.ts +54 -0
- package/dist/esm/security/authorizations/roles.shared.utils.d.ts.map +1 -1
- package/dist/esm/security/authorizations/roles.shared.utils.js +59 -0
- package/dist/esm/security/authorizations/roles.shared.utils.js.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-clients.shared.schemas.d.ts +61 -0
- package/dist/esm/security/oauth-clients/oauth-clients.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-clients.shared.schemas.js +13 -1
- package/dist/esm/security/oauth-clients/oauth-clients.shared.schemas.js.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-consent-grants.shared.resources-config.schemas.d.ts +1 -1
- package/dist/esm/security/oauth-clients/oauth-consent-grants.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-consent-grants.shared.resources-config.schemas.js +35 -0
- package/dist/esm/security/oauth-clients/oauth-consent-grants.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-consent-grants.shared.schemas.d.ts.map +1 -1
- package/dist/esm/security/oauth-clients/oauth-consent-grants.shared.schemas.js +7 -1
- package/dist/esm/security/oauth-clients/oauth-consent-grants.shared.schemas.js.map +1 -1
- package/dist/esm/users/inbound-contacts.shared.resources-config.schemas.d.ts +1 -1
- package/dist/esm/users/inbound-contacts.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/users/inbound-contacts.shared.resources-config.schemas.js +34 -0
- package/dist/esm/users/inbound-contacts.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/users/inbound-contacts.shared.schemas.d.ts.map +1 -1
- package/dist/esm/users/inbound-contacts.shared.schemas.js +7 -4
- package/dist/esm/users/inbound-contacts.shared.schemas.js.map +1 -1
- package/dist/esm/users/user-credentials.shared.resources-config.schemas.d.ts +1 -1
- package/dist/esm/users/user-credentials.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/users/user-credentials.shared.resources-config.schemas.js +37 -0
- package/dist/esm/users/user-credentials.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/users/user-credentials.shared.schemas.d.ts.map +1 -1
- package/dist/esm/users/user-credentials.shared.schemas.js +17 -2
- package/dist/esm/users/user-credentials.shared.schemas.js.map +1 -1
- package/dist/esm/users/user-identity-links.shared.resources-config.schemas.d.ts +1 -1
- package/dist/esm/users/user-identity-links.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/users/user-identity-links.shared.resources-config.schemas.js +36 -0
- package/dist/esm/users/user-identity-links.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/users/user-identity-links.shared.schemas.d.ts.map +1 -1
- package/dist/esm/users/user-identity-links.shared.schemas.js +15 -5
- package/dist/esm/users/user-identity-links.shared.schemas.js.map +1 -1
- package/dist/esm/users/user-preferences.shared.resources-config.schemas.d.ts +1 -1
- package/dist/esm/users/user-preferences.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/users/user-preferences.shared.resources-config.schemas.js +53 -0
- package/dist/esm/users/user-preferences.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/users/user-profiles.shared.resources-config.schemas.d.ts +1 -1
- package/dist/esm/users/user-profiles.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/users/user-profiles.shared.resources-config.schemas.js +62 -0
- package/dist/esm/users/user-profiles.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/users/user-self-preferences.shared.resources-config.schemas.d.ts +1 -1
- package/dist/esm/users/user-self-preferences.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/users/user-self-preferences.shared.resources-config.schemas.js +53 -0
- package/dist/esm/users/user-self-preferences.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/users/user-self-profiles.shared.resources-config.schemas.d.ts +1 -1
- package/dist/esm/users/user-self-profiles.shared.resources-config.schemas.d.ts.map +1 -1
- package/dist/esm/users/user-self-profiles.shared.resources-config.schemas.js +62 -0
- package/dist/esm/users/user-self-profiles.shared.resources-config.schemas.js.map +1 -1
- package/dist/esm/users/users.shared.schemas.d.ts +19 -0
- package/dist/esm/users/users.shared.schemas.d.ts.map +1 -1
- package/dist/esm/users/users.shared.schemas.js +41 -16
- package/dist/esm/users/users.shared.schemas.js.map +1 -1
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +5 -6
- package/dist/esm/.builder.pid +0 -9
package/dist/esm/compliance/audit-trails/security-audit-event-envelope.shared.schema.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security-audit-event-envelope.shared.schema.d.ts","sourceRoot":"","sources":["../../../../../src/compliance/audit-trails/security-audit-event-envelope.shared.schema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAElH,sDAAsD;AACtD,oBAAY,iBAAiB;IAC3B,OAAO,YAAY;IACnB,OAAO,YAAY;CACpB;AAED;;oEAEoE;AAEpE,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuD3C,CAAC;AAEH,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gCAAgC,CAAC,CAAC;AAE1F;;;;;oEAKoE;AAEpE,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,QAAQ,EAAE,kBAAkB,CAAC;CAC9B;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,8BAA8B,EAAE,MAAM,CAAC,sBAAsB,EAAE,wBAAwB,
|
|
1
|
+
{"version":3,"file":"security-audit-event-envelope.shared.schema.d.ts","sourceRoot":"","sources":["../../../../../src/compliance/audit-trails/security-audit-event-envelope.shared.schema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,sBAAsB,EAAE,MAAM,kCAAkC,CAAC;AAElH,sDAAsD;AACtD,oBAAY,iBAAiB;IAC3B,OAAO,YAAY;IACnB,OAAO,YAAY;CACpB;AAED;;oEAEoE;AAEpE,eAAO,MAAM,gCAAgC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuD3C,CAAC;AAEH,MAAM,MAAM,0BAA0B,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,gCAAgC,CAAC,CAAC;AAE1F;;;;;oEAKoE;AAEpE,MAAM,WAAW,wBAAwB;IACvC,QAAQ,EAAE,kBAAkB,CAAC;IAC7B,QAAQ,EAAE,kBAAkB,CAAC;CAC9B;AAED;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,8BAA8B,EAAE,MAAM,CAAC,sBAAsB,EAAE,wBAAwB,CAiVnG,CAAC;AAIF;;;;;;GAMG;AACH,wBAAgB,2BAA2B,CAAC,SAAS,EAAE,MAAM,GAAG,wBAAwB,CAEvF"}
|
|
@@ -97,6 +97,13 @@ export const AUDIT_EVENT_CLASSIFICATION_MAP = {
|
|
|
97
97
|
[CoreAuditableEventType.USER_MFA_ENABLED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },
|
|
98
98
|
[CoreAuditableEventType.USER_MFA_DISABLED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },
|
|
99
99
|
[CoreAuditableEventType.USER_SESSION_EXPIRED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },
|
|
100
|
+
/*
|
|
101
|
+
* WARNING, not INFO, and the asymmetry with USER_SESSION_EXPIRED above is the point. An expiry is
|
|
102
|
+
* routine. An eviction means a live chain was displaced — which is either a user on more devices
|
|
103
|
+
* than the cap allows, or the cap doing the job it exists for and pushing a stolen chain out. A
|
|
104
|
+
* reviewer needs to see the second, and INFO is the level nobody reads.
|
|
105
|
+
*/
|
|
106
|
+
[CoreAuditableEventType.USER_SESSION_EVICTED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },
|
|
100
107
|
// SSO Authentication Events
|
|
101
108
|
[CoreAuditableEventType.USER_SSO_LOGIN]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },
|
|
102
109
|
[CoreAuditableEventType.USER_SSO_LOGIN_FAILED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },
|
|
@@ -256,6 +263,13 @@ export const AUDIT_EVENT_CLASSIFICATION_MAP = {
|
|
|
256
263
|
[CoreAuditableEventType.USER_TOTP_DISABLED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },
|
|
257
264
|
[CoreAuditableEventType.USER_IDENTITY_LINK_REMOVED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },
|
|
258
265
|
// One-Off Session Events (W7.3b)
|
|
266
|
+
// A file upload grant delegates ONE upload under the minter's authority to whoever holds the link —
|
|
267
|
+
// an AUTHORIZATION artefact, not an authentication one (nobody logs in with it). Issued is INFO like
|
|
268
|
+
// every other token mint here; revoked is WARNING for the same reason the one-off revoke below is: an
|
|
269
|
+
// administrative credential termination is what a reviewer wants to see.
|
|
270
|
+
[CoreAuditableEventType.FILE_UPLOAD_GRANT_ISSUED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.INFO },
|
|
271
|
+
[CoreAuditableEventType.FILE_UPLOAD_GRANT_REDEEMED]: { category: AuditEventCategory.DATA_ACCESS, severity: AuditEventSeverity.INFO },
|
|
272
|
+
[CoreAuditableEventType.FILE_UPLOAD_GRANT_REVOKED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },
|
|
259
273
|
[CoreAuditableEventType.ONE_OFF_TOKEN_CREATED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },
|
|
260
274
|
[CoreAuditableEventType.ONE_OFF_TOKEN_EXCHANGED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },
|
|
261
275
|
// Revocation is an ADMINISTRATIVE credential-termination — a super-admin cancels an un-exchanged
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"security-audit-event-envelope.shared.schema.js","sourceRoot":"","sources":["../../../../../src/compliance/audit-trails/security-audit-event-envelope.shared.schema.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Security Audit Event Envelope — the structured JSON payload sent to customer SIEM.\n * \n * This is the canonical format for events exported via the org-level SIEM export pipeline.\n * Different from platform observability (which ships to Axiom/Datadog for platform ops).\n * Org SIEM export ships per-org security events to the customer's own SIEM.\n */\n\nimport { z } from 'zod';\nimport { AuditEventCategory, AuditEventSeverity, CoreAuditableEventType } from './auditable-events.shared.schema';\n\n/** Outcome for SIEM envelope — success or failure. */\nexport enum AuditEventOutcome {\n SUCCESS = 'success',\n FAILURE = 'failure',\n}\n\n/** ──────────────────────────────────────────────────────────────\n * Security Audit Event Envelope Schema\n * ────────────────────────────────────────────────────────────── */\n\nexport const SecurityAuditEventEnvelopeSchema = z.object({\n // Standard fields (always present)\n eventId: z.string(),\n eventType: z.string(),\n eventCategory: z.enum(AuditEventCategory),\n severity: z.enum(AuditEventSeverity),\n timestamp: z.string(),\n /** Request-correlation id (groups every event of one request; matches the app's logs/errors). */\n correlationId: z.string().optional(),\n /**\n * Client-install id — groups an actor's events across sessions and logins, the correlation NIST\n * SP 800-53 AU-6(3) asks for at review time. Present ONLY for applications that opted into\n * `compliance.clientInstanceIdScope`; absent (never null-filled) for every other application, so a\n * SIEM rule keying on it simply never matches rather than seeing an empty field.\n */\n clientInstanceId: z.string().optional(),\n /**\n * Which frontend SURFACE the request came from (app / website / docs). Carried for the same reason as\n * the two ids above: an external reviewer correlating in the SIEM needs the same origin axes the audit\n * row has, and shipping two of the three origin signals was an asymmetry with no rationale behind it.\n * Absent for non-HTTP (job / cron / internal) events.\n */\n frontendServiceName: z.string().optional(),\n\n // Context\n organizationId: z.string(),\n organizationName: z.string().optional(),\n applicationId: z.string().optional(),\n applicationName: z.string().optional(),\n userId: z.string().optional(),\n userEmail: z.string().optional(),\n\n // Source\n sourceService: z.string(),\n sourceVersion: z.string(),\n sourceEnvironment: z.string(),\n\n // Auth-specific context (when applicable)\n authMethod: z.string().optional(),\n authSource: z.string().optional(),\n providerRef: z.string().optional(),\n connectionType: z.string().optional(),\n ipAddress: z.string().optional(),\n userAgent: z.string().optional(),\n geoLocation: z.object({\n country: z.string().optional(),\n city: z.string().optional(),\n }).optional(),\n\n // Event-specific data\n eventData: z.record(z.string(), z.any()),\n\n // Outcome\n outcome: z.enum(AuditEventOutcome),\n outcomeReason: z.string().optional(),\n});\n\nexport type SecurityAuditEventEnvelope = z.infer<typeof SecurityAuditEventEnvelopeSchema>;\n\n/** ──────────────────────────────────────────────────────────────\n * Event Classification Map\n * \n * Maps each CoreAuditableEventType to its category and severity.\n * Used by the dispatcher to classify events for SIEM filtering.\n * ────────────────────────────────────────────────────────────── */\n\nexport interface AuditEventClassification {\n category: AuditEventCategory;\n severity: AuditEventSeverity;\n}\n\n/**\n * Every core auditable event's SIEM category and severity.\n *\n * **Total over `CoreAuditableEventType` on purpose.** It was `Record<string, …>`, which let two\n * emitted event types — `SYSTEM_CONTEXT_READ` and `SYSTEM_CONTEXT_WRITE` — carry no entry at all\n * while the lookup's own JSDoc claimed \"all CoreAuditableEventType values are mapped\". They silently\n * took the fallback below, and because the fallback is one value, the WRITE inherited the READ's\n * classification: the two events exist separately precisely because \"a MUTATION under an ACL bypass is\n * more sensitive than a read\", and the classification erased that. A new core event type is now a\n * compile error rather than a silent `DATA_ACCESS`/`INFO`.\n *\n * The lookup still tolerates unknown strings, because applications may define their own event types —\n * the fallback covers THOSE, which is what it was for.\n */\nexport const AUDIT_EVENT_CLASSIFICATION_MAP: Record<CoreAuditableEventType, AuditEventClassification> = {\n // Authentication Events\n [CoreAuditableEventType.USER_LOGIN]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_LOGOUT]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_LOGIN_FAILED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.USER_ACCOUNT_LOCKED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.CRITICAL },\n [CoreAuditableEventType.MACHINE_AUTH_SUCCESS]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.MACHINE_AUTH_FAILED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n // Machine RESOURCE-ACCESS (token-USE): an authorized, expected per-request access to an A2A/MCP\n // surface — DATA_ACCESS/INFO, mirroring FIELD_ACCESS. The security signal is the volume/pattern a\n // SIEM derives from this stream, not any single row.\n [CoreAuditableEventType.MACHINE_ACCESS]: { category: AuditEventCategory.DATA_ACCESS, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_PASSWORD_CHANGED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.USER_MFA_ENABLED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.USER_MFA_DISABLED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.USER_SESSION_EXPIRED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n\n // SSO Authentication Events\n [CoreAuditableEventType.USER_SSO_LOGIN]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_SSO_LOGIN_FAILED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.USER_SSO_ENFORCEMENT_BLOCKED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.CRITICAL },\n [CoreAuditableEventType.USER_TOKEN_REFRESHED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n\n // Emergency Access Events\n [CoreAuditableEventType.EMERGENCY_ACCESS_USED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.CRITICAL },\n\n // User Lifecycle Events\n [CoreAuditableEventType.USER_CREATED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_UPDATED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_DELETED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.INFO },\n\n // Application-Role Administration — AUTHORIZATION (not USER_LIFECYCLE): the event is an\n // access-control decision, and an org SIEM filtering on the authorization category must see\n // application-role grants alongside `ORGANIZATION_MEMBER_ROLE_CHANGED`. Same WARNING severity as\n // that event for the same reason — a privilege change is never routine INFO traffic.\n [CoreAuditableEventType.USER_APP_ROLES_CHANGED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },\n\n // The application has NO usable super-administrator. CRITICAL rather than WARNING: unlike a role\n // change (a decision someone made, which an auditor reviews), this is a state nobody can undo from\n // inside the product — every recovery door is gated on the very role that is missing. AUTHORIZATION\n // because it is the absence of an authorization principal, not a user-lifecycle transition.\n [CoreAuditableEventType.APPLICATION_SUPER_ADMIN_FLOOR_BREACHED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.CRITICAL },\n [CoreAuditableEventType.ORGANIZATION_OWNER_FLOOR_BREACHED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.CRITICAL },\n\n // Organization Lifecycle Events\n [CoreAuditableEventType.ORGANIZATION_CREATED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.ORGANIZATION_UPDATED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.ORGANIZATION_DELETED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.ORGANIZATION_DELETION_REQUESTED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.ORGANIZATION_RESTORED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.ORGANIZATION_SUSPENDED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.ORGANIZATION_ACTIVATED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n // WARNING rather than INFO: the event covers BOTH directions, and the restricting direction\n // (suspend / deactivate) is what an access review is looking for. Grading the pair by its\n // less-serious half would bury suspensions among routine noise; the payload carries\n // `previousStatus` → `newStatus`, so a consumer that wants only lifts can still filter.\n // `USER_LIFECYCLE`, not `AUTHORIZATION`: the event records what CHANGED (a subject's lifecycle\n // status) rather than its consequence. Every subject it covers — a user row, a membership row —\n // is a person's participation in the product, and grading it by consequence would scatter it\n // among role grants that answer a different question.\n [CoreAuditableEventType.RESOURCE_STATUS_TRANSITION_PERFORMED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.WARNING },\n\n // Organization Member Events\n [CoreAuditableEventType.ORGANIZATION_MEMBER_INVITED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.ORGANIZATION_MEMBER_JOINED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.ORGANIZATION_MEMBER_UPDATED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.ORGANIZATION_MEMBER_ROLE_CHANGED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.ORGANIZATION_MEMBER_STATUS_CHANGED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.ORGANIZATION_MEMBER_REMOVED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.WARNING },\n\n // Organization Config Events\n [CoreAuditableEventType.ORGANIZATION_NOTIFICATIONS_UPDATED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.ORGANIZATION_PREFERENCES_UPDATED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.ORGANIZATION_PROFILE_UPDATED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.ORGANIZATION_UNIT_UPDATED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n\n // Per-unit role assignment — AUTHORIZATION (not ORG_MANAGEMENT, unlike its ORGANIZATION_UNIT_UPDATED\n // neighbour): the unit's own record-keeping confers nothing, whereas `OrganizationUnitMember.role`\n // is read back into `initiatorRoles` as a unit-narrowed grant. Narrower blast radius than\n // ORGANIZATION_MEMBER_ROLE_CHANGED, but the same KIND of decision, so it carries the same category\n // and severity — an org SIEM filtering on authorization must see both.\n [CoreAuditableEventType.ORGANIZATION_UNIT_MEMBER_ROLE_CHANGED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },\n\n // Revocation of a unit assignment. AUTHORIZATION deliberately, where the ORGANIZATION_MEMBER_REMOVED\n // above is ORG_MANAGEMENT: removing a MEMBER is a directory action whose authority loss is a\n // side effect, whereas an assignment row exists ONLY to confer a role — deleting it IS the\n // revocation. Same category and severity as the grant it closes, so an authorization-filtered\n // trail never shows unit privileges granted and never removed.\n [CoreAuditableEventType.ORGANIZATION_UNIT_MEMBER_REMOVED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },\n\n // Organization Security Management Events\n [CoreAuditableEventType.ORGANIZATION_SSO_CONFIGURATION_CHANGED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.ORGANIZATION_SIEM_EXPORT_CONFIGURED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n\n // Application Security Configuration Events\n // WARNING mirrors the SSO-configuration-changed sibling: a change to the authentication assurance\n // posture (MFA / password / lockout) is more than record-keeping (INFO) yet is not an active\n // breach (ERROR). Category ORG_MANAGEMENT keeps it in the same security-configuration cluster a\n // reviewer already queries for SSO/SIEM/SCIM configuration changes.\n [CoreAuditableEventType.APPLICATION_AUTH_POLICY_CHANGED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.WARNING },\n\n // Outbound M2M Webhook Events\n // WARNING rather than INFO, and the choice is externally grounded rather than taste — it was\n // challenged on the reasonable objection that every LEGITIMATE connectivity test then emits a\n // warning-level row.\n //\n // NIST SP 800-53 does not settle it directly: AU-6 treats what counts as \"inappropriate or\n // unusual activity\" as an explicit ORGANIZATION-DEFINED assignment and prescribes no INFO /\n // WARNING / CRITICAL vocabulary at all, so no NIST rule is broken in either direction. What NIST\n // does settle is the REMEDY for noise: AU-6(1) automated review integration, AU-6(3) correlation\n // across repositories, and supplemental guidance letting organizations tune review \"frequency,\n // scope, and/or depth\". Volume is answered by correlating and tuning REVIEW — never by demoting\n // the record itself, which would destroy the signal rather than manage it.\n //\n // OWASP's Logging Vocabulary Cheat Sheet is the concrete industry answer and puts this at WARN:\n // successful, authorized ADMINISTRATIVE operations sit at WARN (`user_created`, `user_updated`,\n // `sys_startup` / `sys_shutdown` / `sys_restart`), while INFO is reserved for routine end-user\n // activity (`authn_login_success`, `session_created`, a user's own `authn_password_change`). The\n // rationale is that administrative operations are high-risk and abuse-prone regardless of whether\n // any single instance succeeded. `testEndpoint` is precisely that shape — admin-gated, and it\n // makes the SYSTEM open an outbound connection to an operator-supplied URL — so it belongs beside\n // the `sys_*` state changes, not beside a user login. (OWASP likewise grades\n // `excess_rate_limit_exceeded` at WARN, which is this operation's own refusal mode.)\n //\n // The load-bearing property: a burst of probes across many hosts is the shape of egress\n // reconnaissance, and that pattern is only visible if the individual rows are not filtered out by\n // default. If a deployment finds the volume genuinely noisy, tune the SIEM's review per AU-6 —\n // do not silently downgrade this to INFO.\n [CoreAuditableEventType.WEBHOOK_ENDPOINT_TEST_DISPATCHED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.WARNING },\n\n // SCIM Directory Provisioning Events\n [CoreAuditableEventType.SCIM_TOKEN_CREATED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.SCIM_TOKEN_REVOKED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.SCIM_USER_PROVISIONED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.SCIM_USER_UPDATED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.SCIM_USER_DEACTIVATED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.WARNING },\n\n // Password Reset Events (H5)\n [CoreAuditableEventType.USER_PASSWORD_RESET_REQUESTED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_PASSWORD_RESET_COMPLETED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n // CRITICAL, one step above the self-service arms: an administrator reaching into another\n // account's credentials is the shape of both a legitimate incident response AND an insider\n // takeover, so it must page rather than merely accumulate.\n [CoreAuditableEventType.USER_PASSWORD_RESET_FORCED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.CRITICAL },\n\n // Registration & Verification Events (H5)\n [CoreAuditableEventType.USER_REGISTERED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_EMAIL_VERIFIED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_VERIFICATION_EMAIL_RESENT]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.INFO },\n\n // MFA Lifecycle Events (H5)\n [CoreAuditableEventType.USER_MFA_SETUP_STARTED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_MFA_SETUP_COMPLETED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.USER_MFA_EMAIL_OTP_SENT]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n\n // WebAuthn/Passkey Events (Phase G1)\n [CoreAuditableEventType.USER_PASSKEY_REGISTERED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.USER_PASSKEY_AUTHENTICATION_SUCCESS]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_PASSKEY_AUTHENTICATION_FAILURE]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.USER_PASSKEY_REMOVED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n\n // Magic Link Events (Phase G2)\n [CoreAuditableEventType.USER_MAGIC_LINK_SENT]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_MAGIC_LINK_VERIFIED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_MAGIC_LINK_FAILED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n\n // SMS OTP Events (Phase G2)\n [CoreAuditableEventType.USER_SMS_OTP_SENT]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_SMS_OTP_VERIFIED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_SMS_OTP_FAILED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n\n // Phone Verification Events (Phase G2)\n [CoreAuditableEventType.USER_PHONE_VERIFIED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_PHONE_VERIFICATION_FAILED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.WARNING },\n\n // OAuth2 Provider Restriction Events (Phase G3)\n [CoreAuditableEventType.OAUTH2_PROVIDER_BLOCKED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },\n\n // SCIM Extended Events\n [CoreAuditableEventType.SCIM_TOKEN_GENERATED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.SCIM_TOKEN_ROTATED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.SCIM_PROVISIONING_CONFIG_UPDATED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.SCIM_PROVISIONING_FAILED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.CRITICAL },\n\n // SAML Authentication Events (AUTH-2, D19.4)\n [CoreAuditableEventType.SAML_LOGIN_INITIATED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.SAML_LOGIN_SUCCESS]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.SAML_LOGIN_FAILED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.SAML_ASSERTION_REPLAY_DETECTED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.CRITICAL },\n [CoreAuditableEventType.SAML_CERT_EXPIRING]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.SAML_SLO_INITIATED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.SAML_SLO_COMPLETED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.SAML_METADATA_PARSED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.SAML_EMAIL_CHANGED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.WARNING },\n\n // Method Management Events (#13f)\n [CoreAuditableEventType.USER_PASSWORD_SET]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.USER_TOTP_DISABLED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.USER_IDENTITY_LINK_REMOVED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n\n // One-Off Session Events (W7.3b)\n [CoreAuditableEventType.ONE_OFF_TOKEN_CREATED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.ONE_OFF_TOKEN_EXCHANGED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n // Revocation is an ADMINISTRATIVE credential-termination — a super-admin cancels an un-exchanged\n // one-off/impersonation token. Per OWASP's Logging Vocabulary, administrative operations are WARNING\n // even when successful and authorized: a SOC wants one-off-token revocations visible (incident\n // response, or an abuse burst of cancellations). CREATED/EXCHANGED stay INFO (routine mint/use); the\n // revoke is the operator intervention, which is the higher-signal row.\n [CoreAuditableEventType.ONE_OFF_TOKEN_REVOKED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n\n // Cross-Frontend Handoff Events (cross-app-jwt-propagation Step 2)\n // Issuance is a credential-minting action (re-issues fresh JWT pair AND a single-use\n // AUTH_CODE_EXCHANGE token bound to the user). WARNING severity matches other\n // cross-session credential events (USER_PASSWORD_RESET_COMPLETED, USER_PASSKEY_REGISTERED)\n // so SOC dashboards flag unusual handoff issuance bursts (e.g. token-issuance abuse).\n [CoreAuditableEventType.USER_CROSS_FRONTEND_HANDOFF_ISSUED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n\n // Field Access Events\n [CoreAuditableEventType.FIELD_ACCESS]: { category: AuditEventCategory.DATA_ACCESS, severity: AuditEventSeverity.INFO },\n\n // Resource-Operation Events — a HIGH/CRITICAL operation took effect on a resource.\n // AUTHORIZATION rather than DATA_ACCESS: this event exists to evidence that a privileged ACTION\n // was exercised (role/status/credential/tenant mutations), not that data was read — FIELD_ACCESS\n // owns the disclosure axis. WARNING rather than INFO because every emission is by construction a\n // HIGH or CRITICAL verb (or an explicit opt-in), so an INFO floor would hide the whole family\n // beneath the routine-read noise on a SOC dashboard; and not CRITICAL because these are\n // AUTHORIZED administrative actions, so reserving CRITICAL for anomalies (binding violations,\n // token-reuse) keeps that level meaningful.\n [CoreAuditableEventType.RESOURCE_OPERATION_PERFORMED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },\n\n // The REFUSAL twin. AUTHORIZATION for the same reason as the success row — it IS an access-control\n // decision, just the negative one.\n //\n // WARNING, and deliberately NOT graded by the refused operation's `riskLevel`: severity is a pure\n // function of event type for every other member of this map, AND the SIEM dispatcher re-derives it\n // from the event type independently (`_passesEventFilter`), so a per-row severity would have to be\n // threaded through two authorities and would still leave this the only type whose severity is not\n // a property of its kind. Danger grading rides the row's `riskLevel` field, which is already the\n // framework's canonical danger axis; burst grading rides `eventData.occurrenceCount`.\n //\n // WARNING also matches the AUTHENTICATION twins (USER_LOGIN_FAILED, MACHINE_AUTH_FAILED): a single\n // refusal is a fail-closed control working correctly, not an incident. CRITICAL stays reserved for\n // anomalies — and the anomaly here is the PATTERN (many refusals), which a SOC rule builds from\n // `occurrenceCount` rather than from one row's severity.\n //\n // assurance-control: WILDO.ACCESS.AUTHORIZATION_DECISION_AUDIT\n [CoreAuditableEventType.RESOURCE_OPERATION_DENIED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },\n // WARNING, not CRITICAL, and the choice is deliberate. A platform operator reaching into a tenant\n // is SANCTIONED here (see the event's schema JSDoc) — most support work is exactly this — so\n // CRITICAL would cry wolf on routine activity and train reviewers to filter the category out. The\n // signal worth escalating on is the `admissionDeclared: false` subset, which a SIEM rule can select\n // precisely because the field is on the payload.\n [CoreAuditableEventType.CROSS_TENANT_ADMINISTRATIVE_ACCESS]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },\n // INFO, unlike the WARNING sibling above: an application-wide directory read is the sanctioned,\n // ordinary use of a surface built for it, and grading it WARNING would bury the genuine crossings.\n // The subset worth escalating is selected on `returnedCount` — an operator paging 40,000 rows is an\n // export — which is why that field is on the payload rather than inferred from the row count.\n [CoreAuditableEventType.PLATFORM_DIRECTORY_ACCESS]: { category: AuditEventCategory.DATA_ACCESS, severity: AuditEventSeverity.INFO },\n // WARNING for the same reason as its sibling above: requesting and deciding elevations is routine\n // operator traffic, and CRITICAL here would train reviewers to filter the category out. The subset\n // worth escalating is `autoApprovalReason: TENANT_CANNOT_APPROVE`, which a SIEM rule selects on and\n // which the emitter additionally carries at a higher `riskLevel`.\n [CoreAuditableEventType.PLATFORM_ACCESS_GRANT_LIFECYCLE]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },\n\n // Retained-Data (Impersonalization) Access Events\n // A privileged, human-attributed see-through read over RETAINED (impersonalized) records. WARNING —\n // elevated vs a normal FIELD_ACCESS/INFO read because it reveals data the retention boundary hides,\n // so SOC dashboards surface it; but an AUTHORIZED compliance action, not an anomaly ⇒ not CRITICAL.\n [CoreAuditableEventType.RETAINED_DATA_ACCESS]: { category: AuditEventCategory.DATA_ACCESS, severity: AuditEventSeverity.WARNING },\n // The single most sensitive disclosure the framework performs — everything held about one person,\n // handed out. Same DATA_ACCESS / WARNING classification as a retained-data see-through: authorized\n // and expected, but always worth a reviewer's eye.\n [CoreAuditableEventType.SUBJECT_DATA_EXPORT]: { category: AuditEventCategory.DATA_ACCESS, severity: AuditEventSeverity.WARNING },\n // INFO, with the page-vs-whole-table distinction carried by the per-emission `riskLevel` (LOW/HIGH)\n // rather than by severity — see AuditableEvent_CollectionDataExport_EventDataSchema. A routine page\n // download raised to WARNING would train reviewers to skim the channel it shares with real signals.\n [CoreAuditableEventType.COLLECTION_DATA_EXPORT]: { category: AuditEventCategory.DATA_ACCESS, severity: AuditEventSeverity.INFO },\n // Routine, authorized read-through of an EXTERNAL system's rows — the value is the queryable\n // trail (who/which provider/which entity/how much), not an alarm. WARNING would put every\n // ordinary external read beside see-through privileged access and train reviewers to skim.\n [CoreAuditableEventType.HTTP_API_READ_THROUGH_ACCESS]: { category: AuditEventCategory.DATA_ACCESS, severity: AuditEventSeverity.INFO },\n // The sanctioned mechanics of a data-protection request (D6 stance 6b) — routine, not an alarm.\n [CoreAuditableEventType.HTTP_API_EXTERNAL_ERASURE]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.INFO },\n // A deliberate, per-request erasure hole (D6 stance 6c) — the record is the control, so it must\n // surface in every severity-filtered view an operator actually reads.\n [CoreAuditableEventType.HTTP_API_NON_ERASURE_ACKNOWLEDGED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.CRITICAL },\n\n // OAuth2 / OIDC Provider Events (Wildo AS the authorization server). Delegated-authority grants +\n // consent decisions are AUTHORIZATION; token lifecycle (refresh/revoke) is AUTHENTICATION. Severity:\n // a third party gaining/holding user-acting access is WARNING (notable, SOC-dashboard-worthy, but an\n // authorized/consented action ⇒ not CRITICAL); a cross-user binding violation or refresh-token theft\n // is CRITICAL; a denial/routine refresh/revoke is INFO.\n [CoreAuditableEventType.OAUTH_DELEGATED_TOKEN_ISSUED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.OAUTH_CONSENT_GRANTED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.OAUTH_CONSENT_DENIED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.OAUTH_CONSENT_GRANT_PERSISTED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },\n // WARNING, not INFO: an unauthenticated party created a durable identity. Individually routine\n // when the feature is enabled, but the SHAPE an operator must be able to alert on is a spike —\n // which only reads as a spike if each one is above the noise floor.\n // AUTHENTICATION/WARNING: a refused client identity is an authentication-front event, and the\n // SSRF variant is an attack rather than a misconfiguration. WARNING keeps a spike visible without\n // making an ordinary allow-list miss look like an incident.\n [CoreAuditableEventType.OAUTH_CIMD_CLIENT_REFUSED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.OAUTH_DYNAMIC_CLIENT_REGISTERED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.OAUTH_TOKEN_REFRESHED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.OAUTH_TOKEN_REVOKED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.OAUTH_RP_INITIATED_LOGOUT]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.OAUTH_CODE_EXCHANGE_FAILED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.OAUTH_CONSENT_BINDING_VIOLATION]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.CRITICAL },\n [CoreAuditableEventType.USER_REFRESH_TOKEN_REUSE_DETECTED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.CRITICAL },\n\n // System-context (ACL-bypass) trail. Both were UNMAPPED until 2026-08-11 and took the fallback.\n // The READ keeps exactly what the fallback gave it — its declaration already documented\n // `DATA_ACCESS`/`INFO` as intended (\"an expected, authorized internal read — not an anomaly\"), so\n // this only stops that intent depending on a default nobody had noticed it was relying on.\n [CoreAuditableEventType.SYSTEM_CONTEXT_READ]: { category: AuditEventCategory.DATA_ACCESS, severity: AuditEventSeverity.INFO },\n // The WRITE is raised to WARNING, following `RETAINED_DATA_ACCESS` — the other privileged-access\n // event in this file — which reasons that an authorized-but-elevated access is WARNING and not\n // CRITICAL because it is expected rather than anomalous. Category deliberately UNCHANGED: moving it\n // to AUTHORIZATION would drop it for every tenant whose export filters on categories, which is a\n // worse failure than an under-graded severity. This is the classification the event's own\n // declaration asks for and had never received.\n [CoreAuditableEventType.SYSTEM_CONTEXT_WRITE]: { category: AuditEventCategory.DATA_ACCESS, severity: AuditEventSeverity.WARNING },\n};\n\nconst DEFAULT_AUDIT_EVENT_CLASSIFICATION: AuditEventClassification = { category: AuditEventCategory.DATA_ACCESS, severity: AuditEventSeverity.INFO };\n\n/**\n * Look up the classification for an audit event type.\n *\n * Every `CoreAuditableEventType` is mapped — enforced by the map's type, not by this comment, which\n * asserted exactly that while two event types went unmapped for months. The fallback exists for\n * APPLICATION-defined event types, which are ordinary strings the engine cannot enumerate.\n */\nexport function getAuditEventClassification(eventType: string): AuditEventClassification {\n return AUDIT_EVENT_CLASSIFICATION_MAP[eventType as CoreAuditableEventType] ?? DEFAULT_AUDIT_EVENT_CLASSIFICATION;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"security-audit-event-envelope.shared.schema.js","sourceRoot":"","sources":["../../../../../src/compliance/audit-trails/security-audit-event-envelope.shared.schema.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Security Audit Event Envelope — the structured JSON payload sent to customer SIEM.\n * \n * This is the canonical format for events exported via the org-level SIEM export pipeline.\n * Different from platform observability (which ships to Axiom/Datadog for platform ops).\n * Org SIEM export ships per-org security events to the customer's own SIEM.\n */\n\nimport { z } from 'zod';\nimport { AuditEventCategory, AuditEventSeverity, CoreAuditableEventType } from './auditable-events.shared.schema';\n\n/** Outcome for SIEM envelope — success or failure. */\nexport enum AuditEventOutcome {\n SUCCESS = 'success',\n FAILURE = 'failure',\n}\n\n/** ──────────────────────────────────────────────────────────────\n * Security Audit Event Envelope Schema\n * ────────────────────────────────────────────────────────────── */\n\nexport const SecurityAuditEventEnvelopeSchema = z.object({\n // Standard fields (always present)\n eventId: z.string(),\n eventType: z.string(),\n eventCategory: z.enum(AuditEventCategory),\n severity: z.enum(AuditEventSeverity),\n timestamp: z.string(),\n /** Request-correlation id (groups every event of one request; matches the app's logs/errors). */\n correlationId: z.string().optional(),\n /**\n * Client-install id — groups an actor's events across sessions and logins, the correlation NIST\n * SP 800-53 AU-6(3) asks for at review time. Present ONLY for applications that opted into\n * `compliance.clientInstanceIdScope`; absent (never null-filled) for every other application, so a\n * SIEM rule keying on it simply never matches rather than seeing an empty field.\n */\n clientInstanceId: z.string().optional(),\n /**\n * Which frontend SURFACE the request came from (app / website / docs). Carried for the same reason as\n * the two ids above: an external reviewer correlating in the SIEM needs the same origin axes the audit\n * row has, and shipping two of the three origin signals was an asymmetry with no rationale behind it.\n * Absent for non-HTTP (job / cron / internal) events.\n */\n frontendServiceName: z.string().optional(),\n\n // Context\n organizationId: z.string(),\n organizationName: z.string().optional(),\n applicationId: z.string().optional(),\n applicationName: z.string().optional(),\n userId: z.string().optional(),\n userEmail: z.string().optional(),\n\n // Source\n sourceService: z.string(),\n sourceVersion: z.string(),\n sourceEnvironment: z.string(),\n\n // Auth-specific context (when applicable)\n authMethod: z.string().optional(),\n authSource: z.string().optional(),\n providerRef: z.string().optional(),\n connectionType: z.string().optional(),\n ipAddress: z.string().optional(),\n userAgent: z.string().optional(),\n geoLocation: z.object({\n country: z.string().optional(),\n city: z.string().optional(),\n }).optional(),\n\n // Event-specific data\n eventData: z.record(z.string(), z.any()),\n\n // Outcome\n outcome: z.enum(AuditEventOutcome),\n outcomeReason: z.string().optional(),\n});\n\nexport type SecurityAuditEventEnvelope = z.infer<typeof SecurityAuditEventEnvelopeSchema>;\n\n/** ──────────────────────────────────────────────────────────────\n * Event Classification Map\n * \n * Maps each CoreAuditableEventType to its category and severity.\n * Used by the dispatcher to classify events for SIEM filtering.\n * ────────────────────────────────────────────────────────────── */\n\nexport interface AuditEventClassification {\n category: AuditEventCategory;\n severity: AuditEventSeverity;\n}\n\n/**\n * Every core auditable event's SIEM category and severity.\n *\n * **Total over `CoreAuditableEventType` on purpose.** It was `Record<string, …>`, which let two\n * emitted event types — `SYSTEM_CONTEXT_READ` and `SYSTEM_CONTEXT_WRITE` — carry no entry at all\n * while the lookup's own JSDoc claimed \"all CoreAuditableEventType values are mapped\". They silently\n * took the fallback below, and because the fallback is one value, the WRITE inherited the READ's\n * classification: the two events exist separately precisely because \"a MUTATION under an ACL bypass is\n * more sensitive than a read\", and the classification erased that. A new core event type is now a\n * compile error rather than a silent `DATA_ACCESS`/`INFO`.\n *\n * The lookup still tolerates unknown strings, because applications may define their own event types —\n * the fallback covers THOSE, which is what it was for.\n */\nexport const AUDIT_EVENT_CLASSIFICATION_MAP: Record<CoreAuditableEventType, AuditEventClassification> = {\n // Authentication Events\n [CoreAuditableEventType.USER_LOGIN]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_LOGOUT]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_LOGIN_FAILED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.USER_ACCOUNT_LOCKED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.CRITICAL },\n [CoreAuditableEventType.MACHINE_AUTH_SUCCESS]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.MACHINE_AUTH_FAILED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n // Machine RESOURCE-ACCESS (token-USE): an authorized, expected per-request access to an A2A/MCP\n // surface — DATA_ACCESS/INFO, mirroring FIELD_ACCESS. The security signal is the volume/pattern a\n // SIEM derives from this stream, not any single row.\n [CoreAuditableEventType.MACHINE_ACCESS]: { category: AuditEventCategory.DATA_ACCESS, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_PASSWORD_CHANGED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.USER_MFA_ENABLED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.USER_MFA_DISABLED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.USER_SESSION_EXPIRED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n /*\n * WARNING, not INFO, and the asymmetry with USER_SESSION_EXPIRED above is the point. An expiry is\n * routine. An eviction means a live chain was displaced — which is either a user on more devices\n * than the cap allows, or the cap doing the job it exists for and pushing a stolen chain out. A\n * reviewer needs to see the second, and INFO is the level nobody reads.\n */\n [CoreAuditableEventType.USER_SESSION_EVICTED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n\n // SSO Authentication Events\n [CoreAuditableEventType.USER_SSO_LOGIN]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_SSO_LOGIN_FAILED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.USER_SSO_ENFORCEMENT_BLOCKED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.CRITICAL },\n [CoreAuditableEventType.USER_TOKEN_REFRESHED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n\n // Emergency Access Events\n [CoreAuditableEventType.EMERGENCY_ACCESS_USED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.CRITICAL },\n\n // User Lifecycle Events\n [CoreAuditableEventType.USER_CREATED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_UPDATED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_DELETED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.INFO },\n\n // Application-Role Administration — AUTHORIZATION (not USER_LIFECYCLE): the event is an\n // access-control decision, and an org SIEM filtering on the authorization category must see\n // application-role grants alongside `ORGANIZATION_MEMBER_ROLE_CHANGED`. Same WARNING severity as\n // that event for the same reason — a privilege change is never routine INFO traffic.\n [CoreAuditableEventType.USER_APP_ROLES_CHANGED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },\n\n // The application has NO usable super-administrator. CRITICAL rather than WARNING: unlike a role\n // change (a decision someone made, which an auditor reviews), this is a state nobody can undo from\n // inside the product — every recovery door is gated on the very role that is missing. AUTHORIZATION\n // because it is the absence of an authorization principal, not a user-lifecycle transition.\n [CoreAuditableEventType.APPLICATION_SUPER_ADMIN_FLOOR_BREACHED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.CRITICAL },\n [CoreAuditableEventType.ORGANIZATION_OWNER_FLOOR_BREACHED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.CRITICAL },\n\n // Organization Lifecycle Events\n [CoreAuditableEventType.ORGANIZATION_CREATED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.ORGANIZATION_UPDATED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.ORGANIZATION_DELETED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.ORGANIZATION_DELETION_REQUESTED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.ORGANIZATION_RESTORED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.ORGANIZATION_SUSPENDED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.ORGANIZATION_ACTIVATED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n // WARNING rather than INFO: the event covers BOTH directions, and the restricting direction\n // (suspend / deactivate) is what an access review is looking for. Grading the pair by its\n // less-serious half would bury suspensions among routine noise; the payload carries\n // `previousStatus` → `newStatus`, so a consumer that wants only lifts can still filter.\n // `USER_LIFECYCLE`, not `AUTHORIZATION`: the event records what CHANGED (a subject's lifecycle\n // status) rather than its consequence. Every subject it covers — a user row, a membership row —\n // is a person's participation in the product, and grading it by consequence would scatter it\n // among role grants that answer a different question.\n [CoreAuditableEventType.RESOURCE_STATUS_TRANSITION_PERFORMED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.WARNING },\n\n // Organization Member Events\n [CoreAuditableEventType.ORGANIZATION_MEMBER_INVITED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.ORGANIZATION_MEMBER_JOINED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.ORGANIZATION_MEMBER_UPDATED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.ORGANIZATION_MEMBER_ROLE_CHANGED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.ORGANIZATION_MEMBER_STATUS_CHANGED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.ORGANIZATION_MEMBER_REMOVED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.WARNING },\n\n // Organization Config Events\n [CoreAuditableEventType.ORGANIZATION_NOTIFICATIONS_UPDATED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.ORGANIZATION_PREFERENCES_UPDATED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.ORGANIZATION_PROFILE_UPDATED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.ORGANIZATION_UNIT_UPDATED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n\n // Per-unit role assignment — AUTHORIZATION (not ORG_MANAGEMENT, unlike its ORGANIZATION_UNIT_UPDATED\n // neighbour): the unit's own record-keeping confers nothing, whereas `OrganizationUnitMember.role`\n // is read back into `initiatorRoles` as a unit-narrowed grant. Narrower blast radius than\n // ORGANIZATION_MEMBER_ROLE_CHANGED, but the same KIND of decision, so it carries the same category\n // and severity — an org SIEM filtering on authorization must see both.\n [CoreAuditableEventType.ORGANIZATION_UNIT_MEMBER_ROLE_CHANGED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },\n\n // Revocation of a unit assignment. AUTHORIZATION deliberately, where the ORGANIZATION_MEMBER_REMOVED\n // above is ORG_MANAGEMENT: removing a MEMBER is a directory action whose authority loss is a\n // side effect, whereas an assignment row exists ONLY to confer a role — deleting it IS the\n // revocation. Same category and severity as the grant it closes, so an authorization-filtered\n // trail never shows unit privileges granted and never removed.\n [CoreAuditableEventType.ORGANIZATION_UNIT_MEMBER_REMOVED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },\n\n // Organization Security Management Events\n [CoreAuditableEventType.ORGANIZATION_SSO_CONFIGURATION_CHANGED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.ORGANIZATION_SIEM_EXPORT_CONFIGURED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n\n // Application Security Configuration Events\n // WARNING mirrors the SSO-configuration-changed sibling: a change to the authentication assurance\n // posture (MFA / password / lockout) is more than record-keeping (INFO) yet is not an active\n // breach (ERROR). Category ORG_MANAGEMENT keeps it in the same security-configuration cluster a\n // reviewer already queries for SSO/SIEM/SCIM configuration changes.\n [CoreAuditableEventType.APPLICATION_AUTH_POLICY_CHANGED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.WARNING },\n\n // Outbound M2M Webhook Events\n // WARNING rather than INFO, and the choice is externally grounded rather than taste — it was\n // challenged on the reasonable objection that every LEGITIMATE connectivity test then emits a\n // warning-level row.\n //\n // NIST SP 800-53 does not settle it directly: AU-6 treats what counts as \"inappropriate or\n // unusual activity\" as an explicit ORGANIZATION-DEFINED assignment and prescribes no INFO /\n // WARNING / CRITICAL vocabulary at all, so no NIST rule is broken in either direction. What NIST\n // does settle is the REMEDY for noise: AU-6(1) automated review integration, AU-6(3) correlation\n // across repositories, and supplemental guidance letting organizations tune review \"frequency,\n // scope, and/or depth\". Volume is answered by correlating and tuning REVIEW — never by demoting\n // the record itself, which would destroy the signal rather than manage it.\n //\n // OWASP's Logging Vocabulary Cheat Sheet is the concrete industry answer and puts this at WARN:\n // successful, authorized ADMINISTRATIVE operations sit at WARN (`user_created`, `user_updated`,\n // `sys_startup` / `sys_shutdown` / `sys_restart`), while INFO is reserved for routine end-user\n // activity (`authn_login_success`, `session_created`, a user's own `authn_password_change`). The\n // rationale is that administrative operations are high-risk and abuse-prone regardless of whether\n // any single instance succeeded. `testEndpoint` is precisely that shape — admin-gated, and it\n // makes the SYSTEM open an outbound connection to an operator-supplied URL — so it belongs beside\n // the `sys_*` state changes, not beside a user login. (OWASP likewise grades\n // `excess_rate_limit_exceeded` at WARN, which is this operation's own refusal mode.)\n //\n // The load-bearing property: a burst of probes across many hosts is the shape of egress\n // reconnaissance, and that pattern is only visible if the individual rows are not filtered out by\n // default. If a deployment finds the volume genuinely noisy, tune the SIEM's review per AU-6 —\n // do not silently downgrade this to INFO.\n [CoreAuditableEventType.WEBHOOK_ENDPOINT_TEST_DISPATCHED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.WARNING },\n\n // SCIM Directory Provisioning Events\n [CoreAuditableEventType.SCIM_TOKEN_CREATED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.SCIM_TOKEN_REVOKED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.SCIM_USER_PROVISIONED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.SCIM_USER_UPDATED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.SCIM_USER_DEACTIVATED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.WARNING },\n\n // Password Reset Events (H5)\n [CoreAuditableEventType.USER_PASSWORD_RESET_REQUESTED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_PASSWORD_RESET_COMPLETED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n // CRITICAL, one step above the self-service arms: an administrator reaching into another\n // account's credentials is the shape of both a legitimate incident response AND an insider\n // takeover, so it must page rather than merely accumulate.\n [CoreAuditableEventType.USER_PASSWORD_RESET_FORCED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.CRITICAL },\n\n // Registration & Verification Events (H5)\n [CoreAuditableEventType.USER_REGISTERED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_EMAIL_VERIFIED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_VERIFICATION_EMAIL_RESENT]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.INFO },\n\n // MFA Lifecycle Events (H5)\n [CoreAuditableEventType.USER_MFA_SETUP_STARTED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_MFA_SETUP_COMPLETED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.USER_MFA_EMAIL_OTP_SENT]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n\n // WebAuthn/Passkey Events (Phase G1)\n [CoreAuditableEventType.USER_PASSKEY_REGISTERED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.USER_PASSKEY_AUTHENTICATION_SUCCESS]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_PASSKEY_AUTHENTICATION_FAILURE]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.USER_PASSKEY_REMOVED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n\n // Magic Link Events (Phase G2)\n [CoreAuditableEventType.USER_MAGIC_LINK_SENT]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_MAGIC_LINK_VERIFIED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_MAGIC_LINK_FAILED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n\n // SMS OTP Events (Phase G2)\n [CoreAuditableEventType.USER_SMS_OTP_SENT]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_SMS_OTP_VERIFIED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_SMS_OTP_FAILED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n\n // Phone Verification Events (Phase G2)\n [CoreAuditableEventType.USER_PHONE_VERIFIED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.USER_PHONE_VERIFICATION_FAILED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.WARNING },\n\n // OAuth2 Provider Restriction Events (Phase G3)\n [CoreAuditableEventType.OAUTH2_PROVIDER_BLOCKED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },\n\n // SCIM Extended Events\n [CoreAuditableEventType.SCIM_TOKEN_GENERATED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.SCIM_TOKEN_ROTATED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.SCIM_PROVISIONING_CONFIG_UPDATED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.SCIM_PROVISIONING_FAILED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.CRITICAL },\n\n // SAML Authentication Events (AUTH-2, D19.4)\n [CoreAuditableEventType.SAML_LOGIN_INITIATED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.SAML_LOGIN_SUCCESS]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.SAML_LOGIN_FAILED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.SAML_ASSERTION_REPLAY_DETECTED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.CRITICAL },\n [CoreAuditableEventType.SAML_CERT_EXPIRING]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.SAML_SLO_INITIATED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.SAML_SLO_COMPLETED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.SAML_METADATA_PARSED]: { category: AuditEventCategory.ORG_MANAGEMENT, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.SAML_EMAIL_CHANGED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.WARNING },\n\n // Method Management Events (#13f)\n [CoreAuditableEventType.USER_PASSWORD_SET]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.USER_TOTP_DISABLED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.USER_IDENTITY_LINK_REMOVED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n\n // One-Off Session Events (W7.3b)\n // A file upload grant delegates ONE upload under the minter's authority to whoever holds the link —\n // an AUTHORIZATION artefact, not an authentication one (nobody logs in with it). Issued is INFO like\n // every other token mint here; revoked is WARNING for the same reason the one-off revoke below is: an\n // administrative credential termination is what a reviewer wants to see.\n [CoreAuditableEventType.FILE_UPLOAD_GRANT_ISSUED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.FILE_UPLOAD_GRANT_REDEEMED]: { category: AuditEventCategory.DATA_ACCESS, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.FILE_UPLOAD_GRANT_REVOKED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.ONE_OFF_TOKEN_CREATED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.ONE_OFF_TOKEN_EXCHANGED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n // Revocation is an ADMINISTRATIVE credential-termination — a super-admin cancels an un-exchanged\n // one-off/impersonation token. Per OWASP's Logging Vocabulary, administrative operations are WARNING\n // even when successful and authorized: a SOC wants one-off-token revocations visible (incident\n // response, or an abuse burst of cancellations). CREATED/EXCHANGED stay INFO (routine mint/use); the\n // revoke is the operator intervention, which is the higher-signal row.\n [CoreAuditableEventType.ONE_OFF_TOKEN_REVOKED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n\n // Cross-Frontend Handoff Events (cross-app-jwt-propagation Step 2)\n // Issuance is a credential-minting action (re-issues fresh JWT pair AND a single-use\n // AUTH_CODE_EXCHANGE token bound to the user). WARNING severity matches other\n // cross-session credential events (USER_PASSWORD_RESET_COMPLETED, USER_PASSKEY_REGISTERED)\n // so SOC dashboards flag unusual handoff issuance bursts (e.g. token-issuance abuse).\n [CoreAuditableEventType.USER_CROSS_FRONTEND_HANDOFF_ISSUED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n\n // Field Access Events\n [CoreAuditableEventType.FIELD_ACCESS]: { category: AuditEventCategory.DATA_ACCESS, severity: AuditEventSeverity.INFO },\n\n // Resource-Operation Events — a HIGH/CRITICAL operation took effect on a resource.\n // AUTHORIZATION rather than DATA_ACCESS: this event exists to evidence that a privileged ACTION\n // was exercised (role/status/credential/tenant mutations), not that data was read — FIELD_ACCESS\n // owns the disclosure axis. WARNING rather than INFO because every emission is by construction a\n // HIGH or CRITICAL verb (or an explicit opt-in), so an INFO floor would hide the whole family\n // beneath the routine-read noise on a SOC dashboard; and not CRITICAL because these are\n // AUTHORIZED administrative actions, so reserving CRITICAL for anomalies (binding violations,\n // token-reuse) keeps that level meaningful.\n [CoreAuditableEventType.RESOURCE_OPERATION_PERFORMED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },\n\n // The REFUSAL twin. AUTHORIZATION for the same reason as the success row — it IS an access-control\n // decision, just the negative one.\n //\n // WARNING, and deliberately NOT graded by the refused operation's `riskLevel`: severity is a pure\n // function of event type for every other member of this map, AND the SIEM dispatcher re-derives it\n // from the event type independently (`_passesEventFilter`), so a per-row severity would have to be\n // threaded through two authorities and would still leave this the only type whose severity is not\n // a property of its kind. Danger grading rides the row's `riskLevel` field, which is already the\n // framework's canonical danger axis; burst grading rides `eventData.occurrenceCount`.\n //\n // WARNING also matches the AUTHENTICATION twins (USER_LOGIN_FAILED, MACHINE_AUTH_FAILED): a single\n // refusal is a fail-closed control working correctly, not an incident. CRITICAL stays reserved for\n // anomalies — and the anomaly here is the PATTERN (many refusals), which a SOC rule builds from\n // `occurrenceCount` rather than from one row's severity.\n //\n // assurance-control: WILDO.ACCESS.AUTHORIZATION_DECISION_AUDIT\n [CoreAuditableEventType.RESOURCE_OPERATION_DENIED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },\n // WARNING, not CRITICAL, and the choice is deliberate. A platform operator reaching into a tenant\n // is SANCTIONED here (see the event's schema JSDoc) — most support work is exactly this — so\n // CRITICAL would cry wolf on routine activity and train reviewers to filter the category out. The\n // signal worth escalating on is the `admissionDeclared: false` subset, which a SIEM rule can select\n // precisely because the field is on the payload.\n [CoreAuditableEventType.CROSS_TENANT_ADMINISTRATIVE_ACCESS]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },\n // INFO, unlike the WARNING sibling above: an application-wide directory read is the sanctioned,\n // ordinary use of a surface built for it, and grading it WARNING would bury the genuine crossings.\n // The subset worth escalating is selected on `returnedCount` — an operator paging 40,000 rows is an\n // export — which is why that field is on the payload rather than inferred from the row count.\n [CoreAuditableEventType.PLATFORM_DIRECTORY_ACCESS]: { category: AuditEventCategory.DATA_ACCESS, severity: AuditEventSeverity.INFO },\n // WARNING for the same reason as its sibling above: requesting and deciding elevations is routine\n // operator traffic, and CRITICAL here would train reviewers to filter the category out. The subset\n // worth escalating is `autoApprovalReason: TENANT_CANNOT_APPROVE`, which a SIEM rule selects on and\n // which the emitter additionally carries at a higher `riskLevel`.\n [CoreAuditableEventType.PLATFORM_ACCESS_GRANT_LIFECYCLE]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },\n\n // Retained-Data (Impersonalization) Access Events\n // A privileged, human-attributed see-through read over RETAINED (impersonalized) records. WARNING —\n // elevated vs a normal FIELD_ACCESS/INFO read because it reveals data the retention boundary hides,\n // so SOC dashboards surface it; but an AUTHORIZED compliance action, not an anomaly ⇒ not CRITICAL.\n [CoreAuditableEventType.RETAINED_DATA_ACCESS]: { category: AuditEventCategory.DATA_ACCESS, severity: AuditEventSeverity.WARNING },\n // The single most sensitive disclosure the framework performs — everything held about one person,\n // handed out. Same DATA_ACCESS / WARNING classification as a retained-data see-through: authorized\n // and expected, but always worth a reviewer's eye.\n [CoreAuditableEventType.SUBJECT_DATA_EXPORT]: { category: AuditEventCategory.DATA_ACCESS, severity: AuditEventSeverity.WARNING },\n // INFO, with the page-vs-whole-table distinction carried by the per-emission `riskLevel` (LOW/HIGH)\n // rather than by severity — see AuditableEvent_CollectionDataExport_EventDataSchema. A routine page\n // download raised to WARNING would train reviewers to skim the channel it shares with real signals.\n [CoreAuditableEventType.COLLECTION_DATA_EXPORT]: { category: AuditEventCategory.DATA_ACCESS, severity: AuditEventSeverity.INFO },\n // Routine, authorized read-through of an EXTERNAL system's rows — the value is the queryable\n // trail (who/which provider/which entity/how much), not an alarm. WARNING would put every\n // ordinary external read beside see-through privileged access and train reviewers to skim.\n [CoreAuditableEventType.HTTP_API_READ_THROUGH_ACCESS]: { category: AuditEventCategory.DATA_ACCESS, severity: AuditEventSeverity.INFO },\n // The sanctioned mechanics of a data-protection request (D6 stance 6b) — routine, not an alarm.\n [CoreAuditableEventType.HTTP_API_EXTERNAL_ERASURE]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.INFO },\n // A deliberate, per-request erasure hole (D6 stance 6c) — the record is the control, so it must\n // surface in every severity-filtered view an operator actually reads.\n [CoreAuditableEventType.HTTP_API_NON_ERASURE_ACKNOWLEDGED]: { category: AuditEventCategory.USER_LIFECYCLE, severity: AuditEventSeverity.CRITICAL },\n\n // OAuth2 / OIDC Provider Events (Wildo AS the authorization server). Delegated-authority grants +\n // consent decisions are AUTHORIZATION; token lifecycle (refresh/revoke) is AUTHENTICATION. Severity:\n // a third party gaining/holding user-acting access is WARNING (notable, SOC-dashboard-worthy, but an\n // authorized/consented action ⇒ not CRITICAL); a cross-user binding violation or refresh-token theft\n // is CRITICAL; a denial/routine refresh/revoke is INFO.\n [CoreAuditableEventType.OAUTH_DELEGATED_TOKEN_ISSUED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.OAUTH_CONSENT_GRANTED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.OAUTH_CONSENT_DENIED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.OAUTH_CONSENT_GRANT_PERSISTED]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.WARNING },\n // WARNING, not INFO: an unauthenticated party created a durable identity. Individually routine\n // when the feature is enabled, but the SHAPE an operator must be able to alert on is a spike —\n // which only reads as a spike if each one is above the noise floor.\n // AUTHENTICATION/WARNING: a refused client identity is an authentication-front event, and the\n // SSRF variant is an attack rather than a misconfiguration. WARNING keeps a spike visible without\n // making an ordinary allow-list miss look like an incident.\n [CoreAuditableEventType.OAUTH_CIMD_CLIENT_REFUSED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.OAUTH_DYNAMIC_CLIENT_REGISTERED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.OAUTH_TOKEN_REFRESHED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.OAUTH_TOKEN_REVOKED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.OAUTH_RP_INITIATED_LOGOUT]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.INFO },\n [CoreAuditableEventType.OAUTH_CODE_EXCHANGE_FAILED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.WARNING },\n [CoreAuditableEventType.OAUTH_CONSENT_BINDING_VIOLATION]: { category: AuditEventCategory.AUTHORIZATION, severity: AuditEventSeverity.CRITICAL },\n [CoreAuditableEventType.USER_REFRESH_TOKEN_REUSE_DETECTED]: { category: AuditEventCategory.AUTHENTICATION, severity: AuditEventSeverity.CRITICAL },\n\n // System-context (ACL-bypass) trail. Both were UNMAPPED until 2026-08-11 and took the fallback.\n // The READ keeps exactly what the fallback gave it — its declaration already documented\n // `DATA_ACCESS`/`INFO` as intended (\"an expected, authorized internal read — not an anomaly\"), so\n // this only stops that intent depending on a default nobody had noticed it was relying on.\n [CoreAuditableEventType.SYSTEM_CONTEXT_READ]: { category: AuditEventCategory.DATA_ACCESS, severity: AuditEventSeverity.INFO },\n // The WRITE is raised to WARNING, following `RETAINED_DATA_ACCESS` — the other privileged-access\n // event in this file — which reasons that an authorized-but-elevated access is WARNING and not\n // CRITICAL because it is expected rather than anomalous. Category deliberately UNCHANGED: moving it\n // to AUTHORIZATION would drop it for every tenant whose export filters on categories, which is a\n // worse failure than an under-graded severity. This is the classification the event's own\n // declaration asks for and had never received.\n [CoreAuditableEventType.SYSTEM_CONTEXT_WRITE]: { category: AuditEventCategory.DATA_ACCESS, severity: AuditEventSeverity.WARNING },\n};\n\nconst DEFAULT_AUDIT_EVENT_CLASSIFICATION: AuditEventClassification = { category: AuditEventCategory.DATA_ACCESS, severity: AuditEventSeverity.INFO };\n\n/**\n * Look up the classification for an audit event type.\n *\n * Every `CoreAuditableEventType` is mapped — enforced by the map's type, not by this comment, which\n * asserted exactly that while two event types went unmapped for months. The fallback exists for\n * APPLICATION-defined event types, which are ordinary strings the engine cannot enumerate.\n */\nexport function getAuditEventClassification(eventType: string): AuditEventClassification {\n return AUDIT_EVENT_CLASSIFICATION_MAP[eventType as CoreAuditableEventType] ?? DEFAULT_AUDIT_EVENT_CLASSIFICATION;\n}\n"]}
|
|
@@ -28,7 +28,56 @@ export declare function resolveImpersonalizeMaskValue(fieldSchema: z.ZodTypeAny)
|
|
|
28
28
|
* `.impersonalizeWith('remove')` IS severable — this is how "erase the subject's link, keep the scoped
|
|
29
29
|
* record" is expressed.
|
|
30
30
|
*/
|
|
31
|
+
/**
|
|
32
|
+
* The value a `RESET` field becomes: its OWN schema default.
|
|
33
|
+
*
|
|
34
|
+
* Resolved by asking the schema, never by an authored constant. `parse(undefined)` is exactly the
|
|
35
|
+
* question "what is this field when nobody has set it", answered by Zod's own semantics — so the
|
|
36
|
+
* default lives in ONE place and a later change to it moves the scrub with it. An authored copy would
|
|
37
|
+
* drift, and a scrub writing a stale default is a row that looks reset and is not.
|
|
38
|
+
*
|
|
39
|
+
* Refuses a field with NO default rather than inventing one. `RESET` on such a field is an authoring
|
|
40
|
+
* error — `undefined` would either fail the re-parse or leave the value untouched depending on the
|
|
41
|
+
* writer, and both are worse than a loud refusal at config time. REMOVE is what that field wants.
|
|
42
|
+
*
|
|
43
|
+
* The result must still SATISFY the schema, which is the whole failure this treatment exists to
|
|
44
|
+
* prevent: a patch writing a value the schema rejects surfaces as a read error long after the erasure
|
|
45
|
+
* reported success. `parse` gives that for free — a default that does not validate cannot be returned.
|
|
46
|
+
*/
|
|
47
|
+
export declare function resolveImpersonalizeResetValue(fieldSchema: z.ZodTypeAny, fieldName: string): unknown;
|
|
31
48
|
export declare function isImpersonalizeNeverScrubFloorField(fieldName: string): boolean;
|
|
49
|
+
/**
|
|
50
|
+
* The fields whose declarations say this resource holds personal data — the evidence against a
|
|
51
|
+
* `RETAIN_ONLY` claim.
|
|
52
|
+
*
|
|
53
|
+
* ## Why this exists
|
|
54
|
+
*
|
|
55
|
+
* `RETAIN_ONLY` asserts a resource holds NO personal data of its own, and the factory could check that
|
|
56
|
+
* in only one direction: it refuses the mode when a field carries an impersonalize TREATMENT. It could
|
|
57
|
+
* not see personal data that nobody had given a treatment to. So the cheap answer for most resources
|
|
58
|
+
* was also the one that failed silently when wrong — a governed document stating that erasure leaves
|
|
59
|
+
* nothing behind, about rows holding a person's data. The opposite mode never had this hole:
|
|
60
|
+
* `RETAIN_AND_IMPERSONALIZE` is refused when nothing would be scrubbed.
|
|
61
|
+
*
|
|
62
|
+
* `.dataCategories()` is the declaration this reads, so the check catches a CONTRADICTION — a resource
|
|
63
|
+
* that says both "this field is personal data" and "this resource holds none". It cannot catch an
|
|
64
|
+
* OMISSION, where nothing was ever classified; that is a coverage question and belongs to the category
|
|
65
|
+
* inventory, not here. Saying so matters: a clean result is not a proof that a resource holds nothing.
|
|
66
|
+
*
|
|
67
|
+
* ## Read the RESOLVED shape, never the source text
|
|
68
|
+
*
|
|
69
|
+
* `getMergedObjectOrUnionShape` is used deliberately, for the same reason the scrub builder below uses
|
|
70
|
+
* it. A text-shaped read of a named schema misses both shapes that occur here in practice: a schema
|
|
71
|
+
* that `.extend()`s a base carries its categories on the BASE, and one file commonly declares several
|
|
72
|
+
* schemas so a range scan closes on a nested object. A census built that way reported `users` as
|
|
73
|
+
* holding no personal data, while `users.email` carries `CONTACT_DETAILS` — understating personal data,
|
|
74
|
+
* which is the dangerous direction for a check whose whole job is to refuse a false negative claim.
|
|
75
|
+
*
|
|
76
|
+
* The never-scrub floor is excluded on the same terms as the scrub patch: a scope FK or
|
|
77
|
+
* `createdByUserId` links a row to a person without being personal data the row holds, and every mode
|
|
78
|
+
* preserves it — so its presence is no evidence against `RETAIN_ONLY`.
|
|
79
|
+
*/
|
|
80
|
+
export declare function collectDeclaredPersonalDataFields(mainSchema: z.ZodTypeAny): readonly string[];
|
|
32
81
|
/**
|
|
33
82
|
* Synthesize the field-scrub `$set` patch for an impersonalize-in-place write, from a resource's
|
|
34
83
|
* per-field `.impersonalizeWith()` treatments. Returns ONLY the scrubbed FIELDS — the impersonalize
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"impersonalization-scrub.shared.utils.d.ts","sourceRoot":"","sources":["../../../../../src/compliance/privacy/impersonalization-scrub.shared.utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,qDAAa,CAAC;AAEtD;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAAC,WAAW,EAAE,CAAC,CAAC,UAAU,GAAG,MAAM,CAE/E;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,mCAAmC,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAM9E;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,4BAA4B,CAAC,UAAU,EAAE,CAAC,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,
|
|
1
|
+
{"version":3,"file":"impersonalization-scrub.shared.utils.d.ts","sourceRoot":"","sources":["../../../../../src/compliance/privacy/impersonalization-scrub.shared.utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAKxB;;;;;;GAMG;AACH,eAAO,MAAM,2BAA2B,qDAAa,CAAC;AAEtD;;;;;;;;GAQG;AACH,wBAAgB,6BAA6B,CAAC,WAAW,EAAE,CAAC,CAAC,UAAU,GAAG,MAAM,CAE/E;AAED;;;;;;;;;;GAUG;AACH;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,8BAA8B,CAAC,WAAW,EAAE,CAAC,CAAC,UAAU,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAoEpG;AAED,wBAAgB,mCAAmC,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAM9E;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,wBAAgB,iCAAiC,CAAC,UAAU,EAAE,CAAC,CAAC,UAAU,GAAG,SAAS,MAAM,EAAE,CAS7F;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,4BAA4B,CAAC,UAAU,EAAE,CAAC,CAAC,UAAU,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CA8C9F"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { getImpersonalizeMaskValue, getImpersonalizeTreatment, getMergedObjectOrUnionShape } from '@wildo-ai/zod-decorators';
|
|
1
|
+
import { getDataCategories, getImpersonalizeMaskValue, getImpersonalizeTreatment, getMergedObjectOrUnionShape } from '@wildo-ai/zod-decorators';
|
|
2
2
|
import { RedactionType } from './redaction.shared.schemas.js';
|
|
3
3
|
import { FIELD_IDENTIFIER_TO_PRIMARY_SCOPE, ResourcePrimaryScope } from '../../resources/resources.shared.schemas.js';
|
|
4
4
|
/**
|
|
@@ -32,6 +32,83 @@ export function resolveImpersonalizeMaskValue(fieldSchema) {
|
|
|
32
32
|
* `.impersonalizeWith('remove')` IS severable — this is how "erase the subject's link, keep the scoped
|
|
33
33
|
* record" is expressed.
|
|
34
34
|
*/
|
|
35
|
+
/**
|
|
36
|
+
* The value a `RESET` field becomes: its OWN schema default.
|
|
37
|
+
*
|
|
38
|
+
* Resolved by asking the schema, never by an authored constant. `parse(undefined)` is exactly the
|
|
39
|
+
* question "what is this field when nobody has set it", answered by Zod's own semantics — so the
|
|
40
|
+
* default lives in ONE place and a later change to it moves the scrub with it. An authored copy would
|
|
41
|
+
* drift, and a scrub writing a stale default is a row that looks reset and is not.
|
|
42
|
+
*
|
|
43
|
+
* Refuses a field with NO default rather than inventing one. `RESET` on such a field is an authoring
|
|
44
|
+
* error — `undefined` would either fail the re-parse or leave the value untouched depending on the
|
|
45
|
+
* writer, and both are worse than a loud refusal at config time. REMOVE is what that field wants.
|
|
46
|
+
*
|
|
47
|
+
* The result must still SATISFY the schema, which is the whole failure this treatment exists to
|
|
48
|
+
* prevent: a patch writing a value the schema rejects surfaces as a read error long after the erasure
|
|
49
|
+
* reported success. `parse` gives that for free — a default that does not validate cannot be returned.
|
|
50
|
+
*/
|
|
51
|
+
export function resolveImpersonalizeResetValue(fieldSchema, fieldName) {
|
|
52
|
+
const parsed = fieldSchema.safeParse(undefined);
|
|
53
|
+
if (!parsed.success) {
|
|
54
|
+
throw new Error(`[impersonalize] RESET treatment on '${fieldName}' requires the field to declare a .default(), and it does not. ` +
|
|
55
|
+
`RESET means "return this field to what it is when nobody has set it", which has no answer here. ` +
|
|
56
|
+
`Use REMOVE for a field that may be absent, or add the default the treatment is asking for.`);
|
|
57
|
+
}
|
|
58
|
+
/*
|
|
59
|
+
* A CLOCK-READ default is refused, and this is the sharp edge of the whole treatment.
|
|
60
|
+
*
|
|
61
|
+
* `.default(() => new Date())` means "compute a fresh value at write time". Applied to
|
|
62
|
+
* `lastActiveAt` — a real field, declared USAGE personal data — RESET wrote the ERASURE's own
|
|
63
|
+
* timestamp, recording an erased person as last active at the moment they were erased. Measured
|
|
64
|
+
* before this guard: the value landed within a millisecond of `now`. That is worse than leaving the
|
|
65
|
+
* field alone. It does not fail to remove information, it FABRICATES it, and the fabricated value is
|
|
66
|
+
* exactly the kind a reader would trust.
|
|
67
|
+
*
|
|
68
|
+
* ## Why this is a heuristic, and why the obvious checks do not work
|
|
69
|
+
*
|
|
70
|
+
* Zod 4 exposes `defaultValue` as a GETTER returning the resolved value, so a literal and a thunk are
|
|
71
|
+
* statically indistinguishable — measured, both report `typeof object`. And resolving twice does not
|
|
72
|
+
* separate them either: two `new Date()` reads microseconds apart stringify identically, so a
|
|
73
|
+
* difference-based check silently passes the exact case it exists for. That version was written,
|
|
74
|
+
* tested, and failed to fire.
|
|
75
|
+
*
|
|
76
|
+
* What IS distinguishable is the value's relationship to the clock. A default resolving to a Date
|
|
77
|
+
* near `now` can only have come from reading the clock — whether from a thunk, or from a literal
|
|
78
|
+
* `.default(new Date())` evaluated at module load, which is equally wrong and equally invisible.
|
|
79
|
+
*
|
|
80
|
+
* A deliberate sentinel is never "recently". `new Date(0)` is 1970; an explicit epoch or a fixed
|
|
81
|
+
* historical date is years away. So the bound below admits every deliberate choice and refuses every
|
|
82
|
+
* clock read, and it is stated as a bound rather than pretending to be exact.
|
|
83
|
+
*/
|
|
84
|
+
/*
|
|
85
|
+
* `.optional()` PARSES `undefined` successfully, so the check above passes it and the resolver would
|
|
86
|
+
* return `undefined` — which is not a scrub. The patch would `$set` an undefined, which either
|
|
87
|
+
* no-ops or is rejected downstream by the canonicalizer, and either way the personal data survives
|
|
88
|
+
* an erasure that reported success.
|
|
89
|
+
*
|
|
90
|
+
* The distinction the two checks draw together: "has no default at all" and "is optional so its
|
|
91
|
+
* default IS undefined" are different authoring mistakes, and both mean RESET has no value to write.
|
|
92
|
+
* REMOVE is what an optional field wants — it writes an explicit null, which is a scrub.
|
|
93
|
+
*/
|
|
94
|
+
if (parsed.data === undefined) {
|
|
95
|
+
throw new Error(`[impersonalize] RESET treatment on '${fieldName}' resolves to \`undefined\` — the field is optional rather ` +
|
|
96
|
+
`than defaulted, so "what it is when nobody has set it" is nothing at all. Writing that is not a scrub: the ` +
|
|
97
|
+
`patch would set undefined and the personal data would survive. Use REMOVE, which writes an explicit null, ` +
|
|
98
|
+
`or give the field the .default() RESET is asking for.`);
|
|
99
|
+
}
|
|
100
|
+
const RESET_CLOCK_READ_WINDOW_MS = 24 * 60 * 60 * 1000;
|
|
101
|
+
if (parsed.data instanceof Date && Math.abs(Date.now() - parsed.data.getTime()) < RESET_CLOCK_READ_WINDOW_MS) {
|
|
102
|
+
throw new Error(`[impersonalize] RESET treatment on '${fieldName}' resolves to a timestamp within a day of NOW, which means ` +
|
|
103
|
+
`the default reads the clock (typically \`.default(() => new Date())\`, or a literal \`new Date()\` evaluated ` +
|
|
104
|
+
`at module load). Erasure would then write a value generated BY the erasure — a field like 'lastActiveAt' ` +
|
|
105
|
+
`would record the erased person as active at the moment they were erased, fabricating information rather ` +
|
|
106
|
+
`than removing it. Give the field a STATIC neutral default such as new Date(0), which asserts "no recorded ` +
|
|
107
|
+
`value", or make it nullable and use REMOVE, which asserts "unknown". Those are different claims about an ` +
|
|
108
|
+
`erased person, so choose deliberately.`);
|
|
109
|
+
}
|
|
110
|
+
return parsed.data;
|
|
111
|
+
}
|
|
35
112
|
export function isImpersonalizeNeverScrubFloorField(fieldName) {
|
|
36
113
|
if (fieldName === 'createdByUserId')
|
|
37
114
|
return true;
|
|
@@ -40,6 +117,49 @@ export function isImpersonalizeNeverScrubFloorField(fieldName) {
|
|
|
40
117
|
|| scope === ResourcePrimaryScope.APPLICATION;
|
|
41
118
|
// USER_SELF / ANONYMOUS (person-link) fall through → severable per D1.
|
|
42
119
|
}
|
|
120
|
+
/**
|
|
121
|
+
* The fields whose declarations say this resource holds personal data — the evidence against a
|
|
122
|
+
* `RETAIN_ONLY` claim.
|
|
123
|
+
*
|
|
124
|
+
* ## Why this exists
|
|
125
|
+
*
|
|
126
|
+
* `RETAIN_ONLY` asserts a resource holds NO personal data of its own, and the factory could check that
|
|
127
|
+
* in only one direction: it refuses the mode when a field carries an impersonalize TREATMENT. It could
|
|
128
|
+
* not see personal data that nobody had given a treatment to. So the cheap answer for most resources
|
|
129
|
+
* was also the one that failed silently when wrong — a governed document stating that erasure leaves
|
|
130
|
+
* nothing behind, about rows holding a person's data. The opposite mode never had this hole:
|
|
131
|
+
* `RETAIN_AND_IMPERSONALIZE` is refused when nothing would be scrubbed.
|
|
132
|
+
*
|
|
133
|
+
* `.dataCategories()` is the declaration this reads, so the check catches a CONTRADICTION — a resource
|
|
134
|
+
* that says both "this field is personal data" and "this resource holds none". It cannot catch an
|
|
135
|
+
* OMISSION, where nothing was ever classified; that is a coverage question and belongs to the category
|
|
136
|
+
* inventory, not here. Saying so matters: a clean result is not a proof that a resource holds nothing.
|
|
137
|
+
*
|
|
138
|
+
* ## Read the RESOLVED shape, never the source text
|
|
139
|
+
*
|
|
140
|
+
* `getMergedObjectOrUnionShape` is used deliberately, for the same reason the scrub builder below uses
|
|
141
|
+
* it. A text-shaped read of a named schema misses both shapes that occur here in practice: a schema
|
|
142
|
+
* that `.extend()`s a base carries its categories on the BASE, and one file commonly declares several
|
|
143
|
+
* schemas so a range scan closes on a nested object. A census built that way reported `users` as
|
|
144
|
+
* holding no personal data, while `users.email` carries `CONTACT_DETAILS` — understating personal data,
|
|
145
|
+
* which is the dangerous direction for a check whose whole job is to refuse a false negative claim.
|
|
146
|
+
*
|
|
147
|
+
* The never-scrub floor is excluded on the same terms as the scrub patch: a scope FK or
|
|
148
|
+
* `createdByUserId` links a row to a person without being personal data the row holds, and every mode
|
|
149
|
+
* preserves it — so its presence is no evidence against `RETAIN_ONLY`.
|
|
150
|
+
*/
|
|
151
|
+
export function collectDeclaredPersonalDataFields(mainSchema) {
|
|
152
|
+
const shape = getMergedObjectOrUnionShape(mainSchema);
|
|
153
|
+
const declared = [];
|
|
154
|
+
for (const [fieldName, fieldSchema] of Object.entries(shape)) {
|
|
155
|
+
if (isImpersonalizeNeverScrubFloorField(fieldName))
|
|
156
|
+
continue;
|
|
157
|
+
const categories = getDataCategories(fieldSchema);
|
|
158
|
+
if (categories !== undefined && categories.length > 0)
|
|
159
|
+
declared.push(fieldName);
|
|
160
|
+
}
|
|
161
|
+
return declared;
|
|
162
|
+
}
|
|
43
163
|
/**
|
|
44
164
|
* Synthesize the field-scrub `$set` patch for an impersonalize-in-place write, from a resource's
|
|
45
165
|
* per-field `.impersonalizeWith()` treatments. Returns ONLY the scrubbed FIELDS — the impersonalize
|
|
@@ -81,6 +201,9 @@ export function buildImpersonalizeScrubPatch(mainSchema) {
|
|
|
81
201
|
case RedactionType.MASK:
|
|
82
202
|
patch[fieldName] = resolveImpersonalizeMaskValue(fieldSchema);
|
|
83
203
|
break;
|
|
204
|
+
case RedactionType.RESET:
|
|
205
|
+
patch[fieldName] = resolveImpersonalizeResetValue(fieldSchema, fieldName);
|
|
206
|
+
break;
|
|
84
207
|
case RedactionType.HASH:
|
|
85
208
|
throw new Error(`[impersonalize] HASH treatment on '${fieldName}' is value-dependent and not supported in v1 ` +
|
|
86
209
|
`(a static $set cannot hash per-row) — use REMOVE/MASK/KEEP, or add the per-doc/pipeline scrub path.`);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"impersonalization-scrub.shared.utils.js","sourceRoot":"","sources":["../../../../../src/compliance/privacy/impersonalization-scrub.shared.utils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,yBAAyB,EAAE,2BAA2B,EAAE,MAAM,0BAA0B,CAAC;AAC7H,OAAO,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAC3D,OAAO,EAAE,iCAAiC,EAAE,oBAAoB,EAAE,MAAM,0CAA0C,CAAC;AAEnH;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,2BAA2B,GAAG,UAAU,CAAC;AAEtD;;;;;;;;GAQG;AACH,MAAM,UAAU,6BAA6B,CAAC,WAAyB;IACrE,OAAO,yBAAyB,CAAC,WAAW,CAAC,IAAI,2BAA2B,CAAC;AAC/E,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,mCAAmC,CAAC,SAAiB;IACnE,IAAI,SAAS,KAAK,iBAAiB;QAAE,OAAO,IAAI,CAAC;IACjD,MAAM,KAAK,GAAG,iCAAiC,CAAC,SAAS,CAAC,CAAC;IAC3D,OAAO,KAAK,KAAK,oBAAoB,CAAC,aAAa;WAC5C,KAAK,KAAK,oBAAoB,CAAC,WAAW,CAAC;IAClD,uEAAuE;AACzE,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,4BAA4B,CAAC,UAAwB;IACnE,kGAAkG;IAClG,oGAAoG;IACpG,mGAAmG;IACnG,kGAAkG;IAClG,cAAc;IACd,MAAM,KAAK,GAAG,2BAA2B,CAAC,UAAU,CAAC,CAAC;IACtD,MAAM,KAAK,GAA4B,EAAE,CAAC;IAE1C,KAAK,MAAM,CAAC,SAAS,EAAE,WAAW,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7D,MAAM,SAAS,GAAG,yBAAyB,CAAC,WAA2B,CAAC,CAAC;QACzE,IAAI,SAAS,KAAK,SAAS;YAAE,SAAS,CAAC,wDAAwD;QAE/F,0FAA0F;QAC1F,IAAI,mCAAmC,CAAC,SAAS,CAAC;YAAE,SAAS;QAE7D,QAAQ,SAA0B,EAAE,CAAC;YACnC,KAAK,aAAa,CAAC,IAAI;gBACrB,SAAS,CAAC,uBAAuB;YACnC,KAAK,aAAa,CAAC,MAAM;gBACvB,KAAK,CAAC,SAAS,CAAC,GAAG,IAAI,CAAC;gBACxB,MAAM;YACR,KAAK,aAAa,CAAC,IAAI;gBACrB,KAAK,CAAC,SAAS,CAAC,GAAG,6BAA6B,CAAC,WAA2B,CAAC,CAAC;gBAC9E,MAAM;YACR,KAAK,aAAa,CAAC,IAAI;gBACrB,MAAM,IAAI,KAAK,CACb,sCAAsC,SAAS,+CAA+C;oBAC9F,qGAAqG,CACtG,CAAC;YACJ,KAAK,aAAa,CAAC,OAAO;gBACxB,MAAM,IAAI,KAAK,CACb,yCAAyC,SAAS,oDAAoD;oBACtG,gGAAgG,CACjG,CAAC;YACJ;gBACE,+FAA+F;gBAC/F,yFAAyF;gBACzF,MAAM,IAAI,KAAK,CAAC,wDAAwD,SAAS,SAAS,SAAS,IAAI,CAAC,CAAC;QAC7G,CAAC;IACH,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC","sourcesContent":["import { z } from 'zod';\nimport { getImpersonalizeMaskValue, getImpersonalizeTreatment, getMergedObjectOrUnionShape } from '@wildo-ai/zod-decorators';\nimport { RedactionType } from './redaction.shared.schemas';\nimport { FIELD_IDENTIFIER_TO_PRIMARY_SCOPE, ResourcePrimaryScope } from '../../resources/resources.shared.schemas';\n\n/**\n * The DEFAULT mask applied for `RedactionType.MASK`.\n *\n * It is an UNCONSTRAINED string, so a field whose schema constrains its shape — `z.email()`,\n * `z.uuid()`, `.min(n)` — cannot hold it. Such a field declares its own value via\n * `.impersonalizeWith(MASK, { maskValue })`; see {@link resolveImpersonalizeMaskValue}.\n */\nexport const IMPERSONALIZE_MASK_CONSTANT = '••••••••';\n\n/**\n * The value a `MASK` treatment actually writes for one field: the field's own override when it\n * declares one, the framework constant otherwise.\n *\n * ONE authority, deliberately. The boot guard `safeParse`s exactly this value against the field's\n * schema and the scrub writer `$set`s exactly this value — so a guard that passes at boot cannot be\n * followed by a write the update DTO rejects inside the erasure transaction. Splitting the two\n * would reintroduce precisely the failure mode the boot guard exists to eliminate.\n */\nexport function resolveImpersonalizeMaskValue(fieldSchema: z.ZodTypeAny): string {\n return getImpersonalizeMaskValue(fieldSchema) ?? IMPERSONALIZE_MASK_CONSTANT;\n}\n\n/**\n * The impersonalization NEVER-SCRUB FLOOR: the org/app SCOPE FKs + `createdByUserId`. Nulling these\n * would orphan the retained row from its tenant (a cross-tenant / security regression) or lose its\n * audit provenance, so they stay protected even if an author accidentally puts a treatment on them.\n *\n * The PERSON-LINK (`userId` / `anonymousUserId` — the USER_SELF / ANONYMOUS scopes) is DELIBERATELY NOT\n * floor-protected: D1 allows SEVERING the person-link while keeping org/app scope (the mirror, opposite\n * direction, of the anon→user transposition). So a `userId` that carries an explicit\n * `.impersonalizeWith('remove')` IS severable — this is how \"erase the subject's link, keep the scoped\n * record\" is expressed.\n */\nexport function isImpersonalizeNeverScrubFloorField(fieldName: string): boolean {\n if (fieldName === 'createdByUserId') return true;\n const scope = FIELD_IDENTIFIER_TO_PRIMARY_SCOPE[fieldName];\n return scope === ResourcePrimaryScope.ORGANIZATIONS\n || scope === ResourcePrimaryScope.APPLICATION;\n // USER_SELF / ANONYMOUS (person-link) fall through → severable per D1.\n}\n\n/**\n * Synthesize the field-scrub `$set` patch for an impersonalize-in-place write, from a resource's\n * per-field `.impersonalizeWith()` treatments. Returns ONLY the scrubbed FIELDS — the impersonalize\n * writer appends the `retentionStatus` / `impersonalizedAt` markers.\n *\n * M4 is the FIRST + ONLY exhaustive consumer of `RedactionType` (zero appliers existed before), so the\n * `default` arm is load-bearing: it keeps the enum ADDITIVELY safe — a future member (e.g. a reserved\n * `TOKENIZE`) fails LOUD here rather than being silently skipped.\n *\n * v1 scope: KEEP / REMOVE / MASK are expressible in a single STATIC `$set` (batch `updateManyAsSystem`).\n * A per-field `maskValue` stays inside that scope — it changes WHICH constant a field is set to, not\n * that the write is one static `$set` shared by every row in the batch.\n * - `HASH` is value-dependent (each row hashes its own value) → NOT expressible in a static `$set`; it\n * THROWS in v1 (add a per-doc / aggregation-pipeline scrub path later — additive).\n * - `ENCRYPT` is reversible → forbidden for impersonalization (D6: v1 impersonalization is IRREVERSIBLE);\n * `ENCRYPT` remains a flow-actors-only redaction option.\n */\nexport function buildImpersonalizeScrubPatch(mainSchema: z.ZodTypeAny): Record<string, unknown> {\n // UNION-AWARE on purpose. `getZodObjectShape` returns `{}` for a discriminated union, which would\n // make the scrub a SILENT NO-OP the day polymorphic resources become retention-governed (rows would\n // flip to RETAINED with every personal field intact). This mirrors the union-aware shape read used\n // by `deriveTrustedSystemWritePreservedFields`, so the two never disagree about what a resource's\n // fields are.\n const shape = getMergedObjectOrUnionShape(mainSchema);\n const patch: Record<string, unknown> = {};\n\n for (const [fieldName, fieldSchema] of Object.entries(shape)) {\n const treatment = getImpersonalizeTreatment(fieldSchema as z.ZodTypeAny);\n if (treatment === undefined) continue; // no `.impersonalizeWith()` → leave the field untouched\n\n // Never-scrub floor: even an explicit treatment cannot null a scope FK / createdByUserId.\n if (isImpersonalizeNeverScrubFloorField(fieldName)) continue;\n\n switch (treatment as RedactionType) {\n case RedactionType.KEEP:\n continue; // explicit never-scrub\n case RedactionType.REMOVE:\n patch[fieldName] = null;\n break;\n case RedactionType.MASK:\n patch[fieldName] = resolveImpersonalizeMaskValue(fieldSchema as z.ZodTypeAny);\n break;\n case RedactionType.HASH:\n throw new Error(\n `[impersonalize] HASH treatment on '${fieldName}' is value-dependent and not supported in v1 ` +\n `(a static $set cannot hash per-row) — use REMOVE/MASK/KEEP, or add the per-doc/pipeline scrub path.`,\n );\n case RedactionType.ENCRYPT:\n throw new Error(\n `[impersonalize] ENCRYPT treatment on '${fieldName}' is reversible — forbidden for impersonalization ` +\n `(D6: v1 impersonalization is irreversible). ENCRYPT stays a flow-actors-only redaction option.`,\n );\n default:\n // Exhaustive guard: an unknown / future RedactionType member MUST fail LOUD, never be silently\n // skipped — this is exactly what keeps RedactionType additively safe (deep-review B-F2).\n throw new Error(`[impersonalize] unsupported impersonalize treatment '${treatment}' on '${fieldName}'.`);\n }\n }\n\n return patch;\n}\n"]}
|
|
1
|
+
{"version":3,"file":"impersonalization-scrub.shared.utils.js","sourceRoot":"","sources":["../../../../../src/compliance/privacy/impersonalization-scrub.shared.utils.ts"],"names":[],"mappings":"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","sourcesContent":["import { z } from 'zod';\nimport { getDataCategories, getImpersonalizeMaskValue, getImpersonalizeTreatment, getMergedObjectOrUnionShape } from '@wildo-ai/zod-decorators';\nimport { RedactionType } from './redaction.shared.schemas';\nimport { FIELD_IDENTIFIER_TO_PRIMARY_SCOPE, ResourcePrimaryScope } from '../../resources/resources.shared.schemas';\n\n/**\n * The DEFAULT mask applied for `RedactionType.MASK`.\n *\n * It is an UNCONSTRAINED string, so a field whose schema constrains its shape — `z.email()`,\n * `z.uuid()`, `.min(n)` — cannot hold it. Such a field declares its own value via\n * `.impersonalizeWith(MASK, { maskValue })`; see {@link resolveImpersonalizeMaskValue}.\n */\nexport const IMPERSONALIZE_MASK_CONSTANT = '••••••••';\n\n/**\n * The value a `MASK` treatment actually writes for one field: the field's own override when it\n * declares one, the framework constant otherwise.\n *\n * ONE authority, deliberately. The boot guard `safeParse`s exactly this value against the field's\n * schema and the scrub writer `$set`s exactly this value — so a guard that passes at boot cannot be\n * followed by a write the update DTO rejects inside the erasure transaction. Splitting the two\n * would reintroduce precisely the failure mode the boot guard exists to eliminate.\n */\nexport function resolveImpersonalizeMaskValue(fieldSchema: z.ZodTypeAny): string {\n return getImpersonalizeMaskValue(fieldSchema) ?? IMPERSONALIZE_MASK_CONSTANT;\n}\n\n/**\n * The impersonalization NEVER-SCRUB FLOOR: the org/app SCOPE FKs + `createdByUserId`. Nulling these\n * would orphan the retained row from its tenant (a cross-tenant / security regression) or lose its\n * audit provenance, so they stay protected even if an author accidentally puts a treatment on them.\n *\n * The PERSON-LINK (`userId` / `anonymousUserId` — the USER_SELF / ANONYMOUS scopes) is DELIBERATELY NOT\n * floor-protected: D1 allows SEVERING the person-link while keeping org/app scope (the mirror, opposite\n * direction, of the anon→user transposition). So a `userId` that carries an explicit\n * `.impersonalizeWith('remove')` IS severable — this is how \"erase the subject's link, keep the scoped\n * record\" is expressed.\n */\n/**\n * The value a `RESET` field becomes: its OWN schema default.\n *\n * Resolved by asking the schema, never by an authored constant. `parse(undefined)` is exactly the\n * question \"what is this field when nobody has set it\", answered by Zod's own semantics — so the\n * default lives in ONE place and a later change to it moves the scrub with it. An authored copy would\n * drift, and a scrub writing a stale default is a row that looks reset and is not.\n *\n * Refuses a field with NO default rather than inventing one. `RESET` on such a field is an authoring\n * error — `undefined` would either fail the re-parse or leave the value untouched depending on the\n * writer, and both are worse than a loud refusal at config time. REMOVE is what that field wants.\n *\n * The result must still SATISFY the schema, which is the whole failure this treatment exists to\n * prevent: a patch writing a value the schema rejects surfaces as a read error long after the erasure\n * reported success. `parse` gives that for free — a default that does not validate cannot be returned.\n */\nexport function resolveImpersonalizeResetValue(fieldSchema: z.ZodTypeAny, fieldName: string): unknown {\n const parsed = fieldSchema.safeParse(undefined);\n if (!parsed.success) {\n throw new Error(\n `[impersonalize] RESET treatment on '${fieldName}' requires the field to declare a .default(), and it does not. ` +\n `RESET means \"return this field to what it is when nobody has set it\", which has no answer here. ` +\n `Use REMOVE for a field that may be absent, or add the default the treatment is asking for.`,\n );\n }\n\n /*\n * A CLOCK-READ default is refused, and this is the sharp edge of the whole treatment.\n *\n * `.default(() => new Date())` means \"compute a fresh value at write time\". Applied to\n * `lastActiveAt` — a real field, declared USAGE personal data — RESET wrote the ERASURE's own\n * timestamp, recording an erased person as last active at the moment they were erased. Measured\n * before this guard: the value landed within a millisecond of `now`. That is worse than leaving the\n * field alone. It does not fail to remove information, it FABRICATES it, and the fabricated value is\n * exactly the kind a reader would trust.\n *\n * ## Why this is a heuristic, and why the obvious checks do not work\n *\n * Zod 4 exposes `defaultValue` as a GETTER returning the resolved value, so a literal and a thunk are\n * statically indistinguishable — measured, both report `typeof object`. And resolving twice does not\n * separate them either: two `new Date()` reads microseconds apart stringify identically, so a\n * difference-based check silently passes the exact case it exists for. That version was written,\n * tested, and failed to fire.\n *\n * What IS distinguishable is the value's relationship to the clock. A default resolving to a Date\n * near `now` can only have come from reading the clock — whether from a thunk, or from a literal\n * `.default(new Date())` evaluated at module load, which is equally wrong and equally invisible.\n *\n * A deliberate sentinel is never \"recently\". `new Date(0)` is 1970; an explicit epoch or a fixed\n * historical date is years away. So the bound below admits every deliberate choice and refuses every\n * clock read, and it is stated as a bound rather than pretending to be exact.\n */\n /*\n * `.optional()` PARSES `undefined` successfully, so the check above passes it and the resolver would\n * return `undefined` — which is not a scrub. The patch would `$set` an undefined, which either\n * no-ops or is rejected downstream by the canonicalizer, and either way the personal data survives\n * an erasure that reported success.\n *\n * The distinction the two checks draw together: \"has no default at all\" and \"is optional so its\n * default IS undefined\" are different authoring mistakes, and both mean RESET has no value to write.\n * REMOVE is what an optional field wants — it writes an explicit null, which is a scrub.\n */\n if (parsed.data === undefined) {\n throw new Error(\n `[impersonalize] RESET treatment on '${fieldName}' resolves to \\`undefined\\` — the field is optional rather ` +\n `than defaulted, so \"what it is when nobody has set it\" is nothing at all. Writing that is not a scrub: the ` +\n `patch would set undefined and the personal data would survive. Use REMOVE, which writes an explicit null, ` +\n `or give the field the .default() RESET is asking for.`,\n );\n }\n\n const RESET_CLOCK_READ_WINDOW_MS = 24 * 60 * 60 * 1000;\n if (parsed.data instanceof Date && Math.abs(Date.now() - parsed.data.getTime()) < RESET_CLOCK_READ_WINDOW_MS) {\n throw new Error(\n `[impersonalize] RESET treatment on '${fieldName}' resolves to a timestamp within a day of NOW, which means ` +\n `the default reads the clock (typically \\`.default(() => new Date())\\`, or a literal \\`new Date()\\` evaluated ` +\n `at module load). Erasure would then write a value generated BY the erasure — a field like 'lastActiveAt' ` +\n `would record the erased person as active at the moment they were erased, fabricating information rather ` +\n `than removing it. Give the field a STATIC neutral default such as new Date(0), which asserts \"no recorded ` +\n `value\", or make it nullable and use REMOVE, which asserts \"unknown\". Those are different claims about an ` +\n `erased person, so choose deliberately.`,\n );\n }\n return parsed.data;\n}\n\nexport function isImpersonalizeNeverScrubFloorField(fieldName: string): boolean {\n if (fieldName === 'createdByUserId') return true;\n const scope = FIELD_IDENTIFIER_TO_PRIMARY_SCOPE[fieldName];\n return scope === ResourcePrimaryScope.ORGANIZATIONS\n || scope === ResourcePrimaryScope.APPLICATION;\n // USER_SELF / ANONYMOUS (person-link) fall through → severable per D1.\n}\n\n/**\n * The fields whose declarations say this resource holds personal data — the evidence against a\n * `RETAIN_ONLY` claim.\n *\n * ## Why this exists\n *\n * `RETAIN_ONLY` asserts a resource holds NO personal data of its own, and the factory could check that\n * in only one direction: it refuses the mode when a field carries an impersonalize TREATMENT. It could\n * not see personal data that nobody had given a treatment to. So the cheap answer for most resources\n * was also the one that failed silently when wrong — a governed document stating that erasure leaves\n * nothing behind, about rows holding a person's data. The opposite mode never had this hole:\n * `RETAIN_AND_IMPERSONALIZE` is refused when nothing would be scrubbed.\n *\n * `.dataCategories()` is the declaration this reads, so the check catches a CONTRADICTION — a resource\n * that says both \"this field is personal data\" and \"this resource holds none\". It cannot catch an\n * OMISSION, where nothing was ever classified; that is a coverage question and belongs to the category\n * inventory, not here. Saying so matters: a clean result is not a proof that a resource holds nothing.\n *\n * ## Read the RESOLVED shape, never the source text\n *\n * `getMergedObjectOrUnionShape` is used deliberately, for the same reason the scrub builder below uses\n * it. A text-shaped read of a named schema misses both shapes that occur here in practice: a schema\n * that `.extend()`s a base carries its categories on the BASE, and one file commonly declares several\n * schemas so a range scan closes on a nested object. A census built that way reported `users` as\n * holding no personal data, while `users.email` carries `CONTACT_DETAILS` — understating personal data,\n * which is the dangerous direction for a check whose whole job is to refuse a false negative claim.\n *\n * The never-scrub floor is excluded on the same terms as the scrub patch: a scope FK or\n * `createdByUserId` links a row to a person without being personal data the row holds, and every mode\n * preserves it — so its presence is no evidence against `RETAIN_ONLY`.\n */\nexport function collectDeclaredPersonalDataFields(mainSchema: z.ZodTypeAny): readonly string[] {\n const shape = getMergedObjectOrUnionShape(mainSchema);\n const declared: string[] = [];\n for (const [fieldName, fieldSchema] of Object.entries(shape)) {\n if (isImpersonalizeNeverScrubFloorField(fieldName)) continue;\n const categories = getDataCategories(fieldSchema as z.ZodTypeAny);\n if (categories !== undefined && categories.length > 0) declared.push(fieldName);\n }\n return declared;\n}\n\n/**\n * Synthesize the field-scrub `$set` patch for an impersonalize-in-place write, from a resource's\n * per-field `.impersonalizeWith()` treatments. Returns ONLY the scrubbed FIELDS — the impersonalize\n * writer appends the `retentionStatus` / `impersonalizedAt` markers.\n *\n * M4 is the FIRST + ONLY exhaustive consumer of `RedactionType` (zero appliers existed before), so the\n * `default` arm is load-bearing: it keeps the enum ADDITIVELY safe — a future member (e.g. a reserved\n * `TOKENIZE`) fails LOUD here rather than being silently skipped.\n *\n * v1 scope: KEEP / REMOVE / MASK are expressible in a single STATIC `$set` (batch `updateManyAsSystem`).\n * A per-field `maskValue` stays inside that scope — it changes WHICH constant a field is set to, not\n * that the write is one static `$set` shared by every row in the batch.\n * - `HASH` is value-dependent (each row hashes its own value) → NOT expressible in a static `$set`; it\n * THROWS in v1 (add a per-doc / aggregation-pipeline scrub path later — additive).\n * - `ENCRYPT` is reversible → forbidden for impersonalization (D6: v1 impersonalization is IRREVERSIBLE);\n * `ENCRYPT` remains a flow-actors-only redaction option.\n */\nexport function buildImpersonalizeScrubPatch(mainSchema: z.ZodTypeAny): Record<string, unknown> {\n // UNION-AWARE on purpose. `getZodObjectShape` returns `{}` for a discriminated union, which would\n // make the scrub a SILENT NO-OP the day polymorphic resources become retention-governed (rows would\n // flip to RETAINED with every personal field intact). This mirrors the union-aware shape read used\n // by `deriveTrustedSystemWritePreservedFields`, so the two never disagree about what a resource's\n // fields are.\n const shape = getMergedObjectOrUnionShape(mainSchema);\n const patch: Record<string, unknown> = {};\n\n for (const [fieldName, fieldSchema] of Object.entries(shape)) {\n const treatment = getImpersonalizeTreatment(fieldSchema as z.ZodTypeAny);\n if (treatment === undefined) continue; // no `.impersonalizeWith()` → leave the field untouched\n\n // Never-scrub floor: even an explicit treatment cannot null a scope FK / createdByUserId.\n if (isImpersonalizeNeverScrubFloorField(fieldName)) continue;\n\n switch (treatment as RedactionType) {\n case RedactionType.KEEP:\n continue; // explicit never-scrub\n case RedactionType.REMOVE:\n patch[fieldName] = null;\n break;\n case RedactionType.MASK:\n patch[fieldName] = resolveImpersonalizeMaskValue(fieldSchema as z.ZodTypeAny);\n break;\n case RedactionType.RESET:\n patch[fieldName] = resolveImpersonalizeResetValue(fieldSchema as z.ZodTypeAny, fieldName);\n break;\n case RedactionType.HASH:\n throw new Error(\n `[impersonalize] HASH treatment on '${fieldName}' is value-dependent and not supported in v1 ` +\n `(a static $set cannot hash per-row) — use REMOVE/MASK/KEEP, or add the per-doc/pipeline scrub path.`,\n );\n case RedactionType.ENCRYPT:\n throw new Error(\n `[impersonalize] ENCRYPT treatment on '${fieldName}' is reversible — forbidden for impersonalization ` +\n `(D6: v1 impersonalization is irreversible). ENCRYPT stays a flow-actors-only redaction option.`,\n );\n default:\n // Exhaustive guard: an unknown / future RedactionType member MUST fail LOUD, never be silently\n // skipped — this is exactly what keeps RedactionType additively safe (deep-review B-F2).\n throw new Error(`[impersonalize] unsupported impersonalize treatment '${treatment}' on '${fieldName}'.`);\n }\n }\n\n return patch;\n}\n"]}
|
|
@@ -28,9 +28,17 @@ export declare enum RetentionStatus {
|
|
|
28
28
|
ACTIVE = "active",
|
|
29
29
|
/**
|
|
30
30
|
* Impersonalized-and-retained — personal fields scrubbed in place, the row kept for a
|
|
31
|
-
* retention obligation
|
|
32
|
-
*
|
|
33
|
-
*
|
|
31
|
+
* retention obligation: hidden and immutable to normal callers, readable only via the audited
|
|
32
|
+
* `seeRetained` see-through path, disposable only by a privileged system op.
|
|
33
|
+
*
|
|
34
|
+
* ENFORCED, not intended. This said "enforcement wired in a later phase" long after the phase
|
|
35
|
+
* landed, which is worth correcting rather than deleting: a reader deciding whether to trust the
|
|
36
|
+
* marker would have concluded the row was still visible. The rule has one semantic authority —
|
|
37
|
+
* `compliance/privacy/retention-hide-predicate.backend` — consumed by both persistence adapters,
|
|
38
|
+
* the aggregation/charts surface and RAG retrieval, and a guard test fails the suite if any site
|
|
39
|
+
* hand-writes the predicate again. That single-authority shape exists because the duplicated
|
|
40
|
+
* version produced two recovered defects: retained rows still counted in every chart, and the
|
|
41
|
+
* Mongo/Postgres compilers silently disagreed about which rows a NULL marker selected.
|
|
34
42
|
*/
|
|
35
43
|
RETAINED = "retained"
|
|
36
44
|
}
|