Skip to content

feat(audit): record and display actor full name in audit logs#233

Merged
appleboy merged 3 commits into
mainfrom
feat/audit-actor-full-name
Jun 1, 2026
Merged

feat(audit): record and display actor full name in audit logs#233
appleboy merged 3 commits into
mainfrom
feat/audit-actor-full-name

Conversation

@appleboy
Copy link
Copy Markdown
Member

@appleboy appleboy commented Jun 1, 2026

Summary

Audit logs currently show only the actor's username in the Actor column. This PR records the actor's full name as an immutable snapshot at write time and surfaces it across the admin audit views, so reviewers can tell who acted and search by a person's real name. The actor now renders as username (full name) (falling back to bare username when no full name exists), the audit search matches on full name, and the CSV export gains a dedicated full-name column. Existing rows are unaffected — no backfill.

AI Authorship

  • No AI was used in this PR
  • AI was used. Details:
    • Tool / model: Claude Opus 4.8 (Claude Code)
    • AI-authored files: all files in the diff
    • Human line-by-line reviewed: yes — reviewed as a CORE change via a line-by-line code review of internal/services/audit.go, internal/models/context.go, internal/core/audit.go, and internal/store/audit_log.go, plus the handler/template/model changes. All 13 ActorUsername call sites were audited to rule out full-name misattribution.

Change classification

  • Leaf node (local impact)
  • Core code (broad impact — needs line-by-line review)

Touches the shared AuditLogEntry contract, a shared context helper, a DB schema column, and the central buildAuditLog enrichment path that every audited action flows through.

Plan reference

See plan.md in the repo — "Audit Log Actor — record & display username + full name". Both of its open questions were resolved before implementation: (1) CSV export uses a separate "Actor Full Name" column; (2) the DB lookup is decoupled so the full name is backfilled even when the username is already set.

Verification

  • Unit tests — buildAuditLog fills full name from context, from the DB-lookup fallback, and when the username is already pre-set; machine identities (client:<id>) still skip the lookup
  • Integration tests — GetAuditLogsPaginated matches a stored actor full name ("Wang Xiaoming" via search "Xiaoming") and returns nothing for a non-matching term
  • At least 3 e2e/error cases (full-name happy path, empty/system actor edge, search match + no-match)
  • Stress / soak test: N/A — no long-running or async code paths added
  • Manual verification: make generate && make build && ./bin/authgate server, log in as admin, perform an action, open /admin/audit and the dashboard, confirm the Actor column shows username (full name), search the full name, then export CSV and confirm the new column.

Verifiability check

  • Inputs and outputs documented (snapshot column mirrors the existing ActorUsername)
  • Reviewer can judge correctness from the tests + the UserDisplay helper without re-reading every line
  • Failures surface in the admin audit UI and CSV export

Risk & rollback

  • Risk: GORM AutoMigrate must add the new column — additive nullable varchar(100), supported on both SQLite and Postgres; AuditLog is already in the migration list. Misattribution risk is mitigated by reusing the existing ActorUserID-vs-context guard. Empty () rendering is prevented by UserDisplay returning a bare username when the full name is empty.
  • Rollback: revert the commit. The added column is harmless if left in place (unused by old code); there is no data migration to undo.

Reviewer guide

  • Read carefully: internal/services/audit.go — the refactored buildAuditLog enrichment (context fill + decoupled DB fallback, gated on resolvedFromContext to avoid a redundant query when the context user already supplies the actor).
  • Spot-check OK: internal/core/audit.go, internal/models/audit_log.go, internal/models/context.go, the two .templ actor cells, and the CSV export columns in internal/handlers/audit.go — all are one-line parallels of the existing ActorUsername pattern.

Note for reviewers (non-blocking, from self-review)

The decoupled DB lookup means call sites that pre-set ActorUsername but not ActorFullName (e.g. login-failure and admin user-management events) now incur one indexed GetUserByID in the async/batched audit path. Impact is low (off the request critical path, PK lookup, /login rate-limited). Happy to follow up by setting ActorFullName directly at the call sites that already hold the *User, if preferred.

🤖 Generated with Claude Code

- Add an ActorFullName snapshot column to the audit log model and entry
- Add a context helper to read the actor full name during enrichment
- Fill the full name from the context user or a single backfill lookup
- Show username with full name in the audit and dashboard actor columns
- Match the audit search against the actor full name
- Add a separate actor full name column to the CSV export
Copilot AI review requested due to automatic review settings June 1, 2026 09:58
@codecov
Copy link
Copy Markdown

codecov Bot commented Jun 1, 2026

Codecov Report

❌ Patch coverage is 93.75000% with 2 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
internal/handlers/audit.go 0.00% 2 Missing ⚠️

📢 Thoughts on this report? Let us know!

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR extends the audit logging pipeline to snapshot and surface an actor’s full name alongside the username, enabling display as username (full name), search by full name, and CSV export of the full-name field.

Changes:

  • Add ActorFullName to the shared audit entry/model contract and persist it in audit_logs.
  • Enrich audit log building to fill full name from request context or a DB fallback (skipping machine identities).
  • Update admin UI templates, search filtering, and CSV export to display/export the full name; add tests for enrichment and search.

Reviewed changes

Copilot reviewed 10 out of 10 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
internal/templates/admin_dashboard.templ Render actor as username (full name) via UserDisplay.
internal/templates/admin_audit_logs.templ Update actor rendering and search placeholder to include full name.
internal/store/audit_log.go Extend search filter to match actor_full_name.
internal/store/audit_log_test.go Add coverage for searching by actor full name.
internal/services/audit.go Enrich audit log entries with actor full name and persist it.
internal/services/audit_test.go Add test coverage for context + DB fallback full-name enrichment.
internal/models/context.go Add GetFullNameFromContext helper.
internal/models/audit_log.go Add actor_full_name column to AuditLog model.
internal/handlers/audit.go Add “Actor Full Name” column to CSV export output.
internal/core/audit.go Add ActorFullName to core.AuditLogEntry.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/services/audit.go
Comment thread internal/models/context.go Outdated
- Truncate actor username and full name to the varchar(100) audit
  columns so over-long names cannot error the INSERT on Postgres
- Add a unit test for the full name context accessor
- Cover actor name truncation in the audit log builder tests
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 11 out of 11 changed files in this pull request and generated 2 comments.

Comment thread internal/services/audit.go Outdated
Comment thread internal/models/context.go Outdated
- Clamp audit string fields only when they exceed the varchar width so
  values already within the limit are stored verbatim instead of being
  needlessly truncated with an ellipsis
- Drop the now-unused GetFullNameFromContext helper and its test; the
  audit builder reads the full name from the context user directly
Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 9 out of 9 changed files in this pull request and generated no new comments.

@appleboy appleboy merged commit 6d772b7 into main Jun 1, 2026
18 checks passed
@appleboy appleboy deleted the feat/audit-actor-full-name branch June 1, 2026 11:36
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.

2 participants