/** * The audit event catalogue (issue #201): every action id the trail may * carry, with the severity the stdout line is stamped with. This const is * the CODE half of the published catalogue in * `docs/architecture/audit-events.md` — `audit-catalogue.test.ts` fails * whenever the two drift, so an id cannot be added, renamed, or removed * without its documentation moving in the same commit. * * Compatibility promise (the reason this exists): ids are never repurposed. * New events may be added (minor catalogue version); an id that stops being * emitted is retired in the catalogue document, its meaning frozen forever — * so an operator's SIEM rules survive our releases. */ export const AUDIT_EVENTS = { 'api.token_created': { severity: 'info' }, 'api.token_revoked': { severity: 'info' }, 'api.write': { severity: 'info' }, 'audit.pruned': { severity: 'info' }, 'auth.email_verified': { severity: 'info' }, 'auth.identity_linked': { severity: 'notice' }, 'auth.login_failed': { severity: 'warning' }, 'auth.login_succeeded': { severity: 'info' }, 'auth.password_reset': { severity: 'notice' }, 'auth.proxy_rejected': { severity: 'warning' }, 'auth.signup': { severity: 'info' }, 'backup.restore_requested': { severity: 'warning' }, 'backup.run_triggered': { severity: 'info' }, 'backup.settings_changed': { severity: 'notice' }, 'file.integrity_failed': { severity: 'critical' }, 'grant.created': { severity: 'notice' }, 'grant.deleted': { severity: 'notice' }, 'job.triggered': { severity: 'info' }, 'member.added': { severity: 'notice' }, 'member.removed': { severity: 'notice' }, 'member.role_changed': { severity: 'notice' }, 'page.classification_lowered': { severity: 'warning' }, 'page.classification_raised': { severity: 'notice' }, 'plugin.installed': { severity: 'notice' }, 'plugin.rejected': { severity: 'warning' }, 'plugin.mode_set': { severity: 'notice' }, 'plugin.pond_toggled': { severity: 'info' }, 'plugin.uninstalled': { severity: 'notice' }, 'pond.archived': { severity: 'notice' }, 'pond.purged': { severity: 'notice' }, 'quota.override_cleared': { severity: 'notice' }, 'quota.override_set': { severity: 'notice' }, 'read_trail.pruned': { severity: 'info' }, 'settings.changed': { severity: 'notice' }, 'branding.changed': { severity: 'notice' }, 'font.uploaded': { severity: 'notice' }, 'font.deleted': { severity: 'notice' }, 'setup.admin_created': { severity: 'notice' }, 'setup.completed': { severity: 'info' }, 'setup.preseeded': { severity: 'info' }, 'setup.smtp_stored': { severity: 'info' }, 'user.deleted': { severity: 'notice' }, 'user.disabled_set': { severity: 'notice' }, 'user.pseudonymized': { severity: 'notice' }, 'user.site_admin_set': { severity: 'notice' }, 'user.verification_resent': { severity: 'info' }, } as const satisfies Record; /** Severity vocabulary of the catalogue — syslog-inspired, four levels are * enough for rule routing (critical pages someone, warning feeds detection, * notice is configuration drift, info is lifecycle noise). */ export type AuditSeverity = 'info' | 'notice' | 'warning' | 'critical'; /** A catalogued action id — the ONLY thing {@link AuditService.record} * accepts, so an uncatalogued event cannot be emitted (compile-time), and * the doc fence keeps the catalogue document in step (test-time). */ export type AuditAction = keyof typeof AUDIT_EVENTS;