Skip to content

feat(audit): emit user-management and file-lifecycle events#62

Merged
rrrodzilla merged 1 commit into
mainfrom
feat/audit-events-user-file-mutations
May 26, 2026
Merged

feat(audit): emit user-management and file-lifecycle events#62
rrrodzilla merged 1 commit into
mainfrom
feat/audit-events-user-file-mutations

Conversation

@rrrodzilla
Copy link
Copy Markdown
Contributor

Summary

  • Adds forge.user.* events for every user-management mutation (create / delete / update / role change / active toggle) and forge.access.denied for every Cedar role-rank guard deny in routes/users.rs.
  • Adds the built-in auth.password.changed audit kind plus a forge.user.password_changed custom event (carries actor + self_service flag so admin resets and self-service rotations are distinguishable in the chain).
  • Adds forge.file.{upload_minted,uploaded,scan_complete,downloaded} for the four file-lifecycle paths in routes/files.rs. Quarantined scan outcomes get Warning severity so the chain is easy to triage during an incident.
  • One audit_user / audit_file helper per module to keep emission shape consistent and stay under clippy's too_many_arguments ceiling (FileTarget packs schema/entity/field).

Second of four PRs from the production-audit gap review. Follows #61 (last_login + auth audit events). #C and #D coming next.

Test plan

  • cargo nextest run --workspace --features schema-forge-acton/surrealdb — 1680 passed
  • cargo clippy --workspace --features schema-forge-acton/surrealdb --all-targets — clean

routes/users.rs and routes/files.rs were the largest remaining gap in the
production audit chain: user CRUD, role mutations, password changes, and
every file upload/scan/download path produced zero durable chain entries.
Tracing-only events don't satisfy NIST 800-53 AU-2 for high-sensitivity
admin operations or CUI access.

routes/users.rs:
  forge.user.created            create_user success
  forge.user.deleted            delete_user success
  forge.user.updated            update_user success (roles/display_name)
  forge.user.active_toggled     update_user success (active flag)
  forge.access.denied           every Cedar role-rank guard deny
  auth.password.changed         change_password success (built-in kind)
  forge.user.password_changed   change_password success (carries actor +
                                self-service flag — the built-in kind
                                only carries the target)

routes/files.rs:
  forge.file.upload_minted      mint_upload_url success
  forge.file.uploaded           confirm_upload success
  forge.file.scan_complete      scan_complete success (Warning severity
                                when quarantined; Notice when clean)
  forge.file.downloaded         download_file success

A small `audit_user` / `audit_file` helper centralises actor / target /
metadata shape; `FileTarget` packs the schema/entity/field triple so the
audit_file signature stays under clippy's too_many_arguments ceiling.

Second of four PRs from the production-audit gap review. Follows
#61 (auth audit events + last_login). C and D coming next.
@rrrodzilla rrrodzilla merged commit 468b976 into main May 26, 2026
1 check passed
@rrrodzilla rrrodzilla deleted the feat/audit-events-user-file-mutations branch May 26, 2026 21:08
rrrodzilla added a commit that referenced this pull request May 26, 2026
Release rolling up the production-audit gap PRs (#61, #62, #63, #64).

BREAKING (pre-1.0 minor):
  schema-forge-backend 0.11 → 0.12
    AuthStore trait gains required `record_login(username, at)` method.
    Downstream impls must add it.
  schema-forge-acton 0.30 → 0.31
    DynAuthStore trait gains required `record_login` shim.
    `access::filter_entity_fields` now returns `Vec<String>` (dropped
    field names) instead of `()`. Callers binding the return value
    must update.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant