Skip to content

feat: surface in-memory audit log entries#27

Merged
tianzhou merged 3 commits into
mainfrom
feat/in-memory-audit-log
Jun 25, 2026
Merged

feat: surface in-memory audit log entries#27
tianzhou merged 3 commits into
mainfrom
feat/in-memory-audit-log

Conversation

@tianzhou

@tianzhou tianzhou commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Store emitted audit events in memory and expose connection-scoped entries through a new QueryService RPC
  • Render /audit-log entries for admins with newest-first polling
  • Add optional [general.audit].retention_days config, example TOML, docs, and focused tests

Notes

  • Default retention is indefinite until server restart, matching the requested behavior
  • Auth login/logout events are not shown on the current connection-scoped page because they have no connection id
  • Generated src/gen files are ignored in this repo; pnpm gen regenerates them from proto/query.proto

Tests

  • pnpm test tests/audit.test.ts
  • pnpm build

Copilot AI review requested due to automatic review settings June 25, 2026 12:08
@vercel

vercel Bot commented Jun 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
pgconsole Ready Ready Preview, Comment Jun 25, 2026 3:49pm

@greptile-apps

greptile-apps Bot commented Jun 25, 2026

Copy link
Copy Markdown

Greptile Summary

This PR adds an in-memory audit event store to pgconsole and surfaces it through a new GetAuditLogEntries gRPC endpoint, polled every 5 seconds by a new /audit-log admin page that renders SQL execution and data export entries newest-first per connection.

  • Server: A module-level auditEvents[] array accumulates all emitted events; pruneRetainedEvents trims by timestamp when retention_days is configured; listAuditEvents filters to connection-scoped entries and reverses before limiting.
  • Client: useAuditLogEntries polls with a 5-second interval, gated behind an hasAdmin check; AuditLog.tsx renders a table with time, actor, action, status, row count, duration, and SQL columns.
  • Config: Optional [audit] retention_days TOML setting is parsed and validated; indefinite retention is the documented default.

Confidence Score: 4/5

Safe to merge; the auth gate, config validation, and test coverage are solid. The main area to watch is unbounded memory growth when retention_days is not configured.

The feature is well-structured and the admin permission check is in place. The primary concern is that listAuditEvents does a full O(n) filter-and-reverse over the entire event store on every 5-second poll, and without retention_days the store grows indefinitely — including auth events that are never exposed in the UI. Neither issue causes incorrect behavior today, but they could become operational problems on long-running, high-traffic instances.

server/lib/audit.ts — the listAuditEvents scan strategy and the absence of a hard entry-count ceiling when retention_days is unset.

Important Files Changed

Filename Overview
server/lib/audit.ts Adds in-memory audit event store with pruning support; the listAuditEvents helper allocates a full reversed copy of all matching events before slicing to the limit, and contains a redundant .slice() before .reverse()
server/services/query-service.ts Adds getAuditLogEntries RPC; correctly gates on admin permission and caps the limit at 500; fallback values for DataExportEvent fields (success → true, durationMs → 0) are consistent with the type definition
src/pages/AuditLog.tsx Renders audit entries in a table with 5-second polling; permission gating and loading/error states are well-handled
server/lib/config.ts Adds [audit] TOML section with retention_days; validation (positive integer) is correct; getAuditRetentionDays accessor is clean
src/hooks/useQuery.ts Adds useAuditLogEntries hook with 5-second refetch interval and enabled guard; straightforward addition
tests/audit.test.ts New test file covering config parsing, retention validation, connection-scoped filtering, and limit application; uses clearAuditEventsForTest in beforeEach to avoid state leaks
proto/query.proto Adds GetAuditLogEntries RPC and AuditLogEntry message with all necessary fields; field numbering is sequential and non-conflicting

Sequence Diagram

%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
    participant Browser as Admin Browser
    participant AuditLogPage as AuditLog.tsx
    participant Hook as useAuditLogEntries
    participant RPC as QueryService.getAuditLogEntries
    participant Store as auditEvents[]
    participant Config as getAuditRetentionDays

    Browser->>AuditLogPage: Navigate to /audit-log
    AuditLogPage->>Hook: "enabled = hasAdmin && connections.length > 0"
    loop Every 5 seconds
        Hook->>RPC: "GetAuditLogEntries(connectionId, limit=100)"
        RPC->>RPC: requirePermission(user, connectionId, 'admin')
        RPC->>Store: listAuditEvents(connectionId, limit)
        Store->>Config: getAuditRetentionDays()
        Config-->>Store: retentionDays (or undefined)
        Store->>Store: pruneRetainedEvents()
        Store->>Store: filter + reverse + slice(0, limit)
        Store-->>RPC: AuditEvent[]
        RPC-->>Hook: GetAuditLogEntriesResponse
        Hook-->>AuditLogPage: entries[]
        AuditLogPage-->>Browser: Render table (newest first)
    end

    Note over Store: auditEvents[] grows on every auditSQL() / auditExport() call
Loading
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
    participant Browser as Admin Browser
    participant AuditLogPage as AuditLog.tsx
    participant Hook as useAuditLogEntries
    participant RPC as QueryService.getAuditLogEntries
    participant Store as auditEvents[]
    participant Config as getAuditRetentionDays

    Browser->>AuditLogPage: Navigate to /audit-log
    AuditLogPage->>Hook: "enabled = hasAdmin && connections.length > 0"
    loop Every 5 seconds
        Hook->>RPC: "GetAuditLogEntries(connectionId, limit=100)"
        RPC->>RPC: requirePermission(user, connectionId, 'admin')
        RPC->>Store: listAuditEvents(connectionId, limit)
        Store->>Config: getAuditRetentionDays()
        Config-->>Store: retentionDays (or undefined)
        Store->>Store: pruneRetainedEvents()
        Store->>Store: filter + reverse + slice(0, limit)
        Store-->>RPC: AuditEvent[]
        RPC-->>Hook: GetAuditLogEntriesResponse
        Hook-->>AuditLogPage: entries[]
        AuditLogPage-->>Browser: Render table (newest first)
    end

    Note over Store: auditEvents[] grows on every auditSQL() / auditExport() call
Loading

Reviews (1): Last reviewed commit: "feat: surface in-memory audit log entrie..." | Re-trigger Greptile

Comment thread server/lib/audit.ts Outdated
Comment thread server/lib/audit.ts
Comment thread server/lib/audit.ts

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Adds an in-memory audit-event buffer on the server and surfaces connection-scoped audit entries via a new QueryService RPC, then renders them on the admin-only /audit-log page with polling. This complements the existing “JSON lines to stdout” audit logging by enabling quick in-app inspection of recent activity.

Changes:

  • Persist emitted audit events in memory with optional [audit].retention_days pruning, plus a server RPC to fetch connection-scoped entries.
  • Add a React Query hook and UI table rendering for /audit-log with newest-first polling.
  • Update example config and docs; add focused Vitest coverage for config parsing and ordering/limit behavior.

Reviewed changes

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

Show a summary per file
File Description
server/lib/audit.ts Stores audit events in memory, prunes by retention, and exposes listAuditEvents.
server/services/query-service.ts Adds getAuditLogEntries handler with admin permission gating and event-to-RPC mapping.
proto/query.proto Introduces GetAuditLogEntries RPC and AuditLogEntry message.
src/hooks/useQuery.ts Adds useAuditLogEntries hook and query key for polling audit entries.
src/pages/AuditLog.tsx Renders audit entries for admins in a table with status/metadata columns.
server/lib/config.ts Adds [audit].retention_days parsing and getters.
tests/audit.test.ts Tests audit config parsing and event store ordering/limits.
pgconsole.example.toml Documents optional [audit] retention_days config.
docs/features/audit-log.mdx Documents the in-app audit log page and retention behavior.
docs/configuration/config.mdx Adds configuration reference for audit retention.

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

Comment thread server/lib/audit.ts
Comment thread server/lib/audit.ts Outdated
Comment thread proto/query.proto
Comment thread server/services/query-service.ts
@mintlify

mintlify Bot commented Jun 25, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
pgconsole 🟢 Ready View Preview Jun 25, 2026, 12:32 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 10 out of 10 changed files in this pull request and generated 3 comments.

Comment thread server/lib/audit.ts Outdated
Comment thread src/pages/AuditLog.tsx Outdated
Comment thread proto/query.proto Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 10 out of 10 changed files in this pull request and generated 3 comments.

Comment thread server/lib/audit.ts
Comment thread src/pages/AuditLog.tsx Outdated
Comment thread proto/query.proto Outdated

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 10 out of 10 changed files in this pull request and generated 3 comments.

Comment thread server/services/query-service.ts
Comment thread server/lib/audit.ts
Comment thread tests/audit.test.ts

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 10 out of 10 changed files in this pull request and generated 2 comments.

Comment thread src/pages/AuditLog.tsx Outdated
Comment thread server/lib/audit.ts
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 10 out of 10 changed files in this pull request and generated 2 comments.

Comment thread src/pages/AuditLog.tsx Outdated
Comment thread docs/features/audit-log.mdx
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

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 10 out of 10 changed files in this pull request and generated 1 comment.

Comment thread server/lib/audit.ts
@tianzhou
tianzhou merged commit ca2118c into main Jun 25, 2026
4 checks passed
@tianzhou
tianzhou deleted the feat/in-memory-audit-log branch June 29, 2026 09:04
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