Skip to content

feat: SQLite immutable audit triggers - #113

Merged
nfvelten merged 1 commit into
masterfrom
feat/sqlite-immutable-audit-triggers
Apr 7, 2026
Merged

feat: SQLite immutable audit triggers#113
nfvelten merged 1 commit into
masterfrom
feat/sqlite-immutable-audit-triggers

Conversation

@nfvelten

@nfvelten nfvelten commented Apr 7, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Installs two BEFORE UPDATE / BEFORE DELETE triggers on audit_log during schema initialisation in SqliteAudit::with_rotation.
  • Any modification or deletion of a committed audit row is now aborted by SQLite at the engine level — zero runtime performance cost, applies to all connections regardless of which process issues the statement.
  • The no_audit_delete trigger is skipped when rotation (max_entries / max_age_days) is configured, since rotation legitimately prunes old rows by design.
  • Existing tamper tests (verify_chain_detects_hash_mismatch, verify_chain_detects_chain_break) updated to drop triggers before mutating the DB, showing that the hash chain remains a second layer of defence even when triggers are bypassed by a privileged attacker.

Closes #99

Test plan

  • cargo fmt --check — clean
  • cargo clippy -- -D warnings — zero warnings
  • cargo test --lib — all 434 unit tests pass
  • trigger_prevents_update_on_audit_log — UPDATE rejected with "immutable" error
  • trigger_prevents_delete_on_audit_log — DELETE rejected with "immutable" error
  • max_entries_rotation_keeps_newest — rotation still works (delete trigger skipped)
  • max_age_days_rotation_purges_old — age rotation still works

🤖 Generated with Claude Code

Install BEFORE UPDATE and BEFORE DELETE triggers on audit_log during
schema init. Any modification or deletion of committed audit rows is
aborted by SQLite at the engine level with zero runtime cost.

The DELETE trigger is omitted when rotation (max_entries/max_age_days)
is active since rotation intentionally prunes old rows. Tamper tests
updated to drop triggers before mutating, demonstrating that the
hash-chain remains a second layer of defence even if triggers are bypassed.
Adds two new trigger unit tests.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@nfvelten
nfvelten merged commit 18184e0 into master Apr 7, 2026
3 checks passed
@nfvelten
nfvelten deleted the feat/sqlite-immutable-audit-triggers branch April 7, 2026 18:49
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.

feat: SQLite immutable audit triggers — database-level enforcement of audit record immutability

1 participant