Skip to content

feat(ee): add enterprise audit logs settings page#4111

Open
waleedlatif1 wants to merge 14 commits intostagingfrom
waleedlatif1/audit-log-page
Open

feat(ee): add enterprise audit logs settings page#4111
waleedlatif1 wants to merge 14 commits intostagingfrom
waleedlatif1/audit-log-page

Conversation

@waleedlatif1
Copy link
Copy Markdown
Collaborator

@waleedlatif1 waleedlatif1 commented Apr 11, 2026

Summary

  • Add enterprise audit logs settings page with server-side search, resource type filtering, date range selection, and cursor-based pagination
  • Extract shared query logic (buildFilterConditions, buildOrgScopeCondition, queryAuditLogs) into a reusable module used by all 3 audit log API routes
  • Gate the feature behind requiresHosted + requiresEnterprise navigation flags, with all enterprise code in ee/audit-logs/

Test plan

  • Verify audit logs page appears only for enterprise users
  • Test server-side search across action, actor email/name, resource name, description
  • Test resource type and date range filters
  • Test cursor-based pagination (load more button)
  • Verify existing v1 and admin audit log API routes still work correctly after refactor
  • Verify expandable row details show resource, actor, description, and metadata

…arch

Add a new audit logs page under enterprise settings that displays all
actions captured via recordAudit. Includes server-side search, resource
type filtering, date range selection, and cursor-based pagination.

- Add internal API route (app/api/audit-logs) with session auth
- Extract shared query logic (buildFilterConditions, buildOrgScopeCondition,
  queryAuditLogs) into app/api/v1/audit-logs/query.ts
- Refactor v1 and admin audit log routes to use shared query module
- Add React Query hook with useInfiniteQuery and cursor pagination
- Add audit logs UI with debounced search, combobox filters, expandable rows
- Gate behind requiresHosted + requiresEnterprise navigation flags
- Place all enterprise audit log code in ee/audit-logs/

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@vercel
Copy link
Copy Markdown

vercel bot commented Apr 11, 2026

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

1 Skipped Deployment
Project Deployment Actions Updated (UTC)
docs Skipped Skipped Apr 11, 2026 8:28pm

Request Review

@cursor
Copy link
Copy Markdown

cursor bot commented Apr 11, 2026

PR Summary

Medium Risk
Adds a new enterprise-facing audit log UI and a new /api/audit-logs endpoint, plus refactors audit-log querying across v1/admin routes; moderate risk due to new pagination/filtering logic and many changes to audit event payloads.

Overview
Adds an Enterprise Audit Logs settings section (hosted + enterprise gated) with a new client UI that supports server-side search, resource-type filtering, date-range filtering, expandable row details, and cursor-based “load more” pagination.

Introduces a new /api/audit-logs route and extracts shared audit-log query utilities into app/api/v1/audit-logs/query.ts (filters, org scoping, cursor pagination), then updates the existing v1 and admin audit-log endpoints to use the shared implementation.

Broadly enriches recordAudit calls across many APIs (credentials, schedules, workspaces, invitations, webhooks, knowledge, templates, MCP, etc.) with more consistent resourceId/resourceName, new audit actions/resource types (CREDENTIAL_*, schedule create/delete, invitation resent, env deleted, password reset requested, workspace updated), and more detailed metadata fields; AuditAction/AuditResourceType constants are moved to lib/audit/types.ts and re-exported from lib/audit/log.ts.

Reviewed by Cursor Bugbot for commit 231df15. Configure here.

@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Apr 11, 2026

Greptile Summary

This PR adds an enterprise audit logs settings page with server-side search, resource-type filtering, date-range selection, and cursor-based pagination, and extracts shared query logic (buildFilterConditions, buildOrgScopeCondition, queryAuditLogs) into a reusable module consumed by all three audit-log API routes. Previous P1 findings (empty inArray crash, debounce no-op on mount) were addressed in the follow-up commit.

Confidence Score: 5/5

Safe to merge — all previously raised P1 concerns are resolved and the only remaining finding is a P2 UX suggestion.

Both P1 issues from prior review rounds (empty-array inArray crash, debounce no-op) were fixed. The refactoring of shared query logic is clean and preserves all existing filter parameters on the admin and v1 routes. The sole remaining finding is the missing error state in the UI component, which is a non-blocking P2 improvement.

apps/sim/ee/audit-logs/components/audit-logs.tsx — add error branch in the list renderer.

Important Files Changed

Filename Overview
apps/sim/app/api/v1/audit-logs/query.ts New shared query module — buildFilterConditions, buildOrgScopeCondition (with empty-array guard), queryAuditLogs, and cursor helpers are all correct; reused cleanly by all three audit-log routes.
apps/sim/app/api/audit-logs/route.ts New session-auth BFF endpoint; validates dates, delegates scope/filter/pagination to the shared query module, and returns formatted entries — consistent with other internal session routes.
apps/sim/app/api/v1/admin/audit-logs/route.ts Refactored to use buildFilterConditions; all previously supported query params (action, resourceType, resourceId, workspaceId, actorId, actorEmail, dates) are preserved — no regressions.
apps/sim/ee/audit-logs/hooks/audit-logs.ts Correctly wired infinite query with signal forwarding, staleTime, and keepPreviousData; doesn't expose isError to consumers, causing misleading empty state on API failures.
apps/sim/ee/audit-logs/components/audit-logs.tsx Full audit-log UI with debounced search, resource-type/date-range filters, and cursor pagination; missing error state means API failures silently show "No audit logs found".

Sequence Diagram

sequenceDiagram
    participant UI as AuditLogs Component
    participant Hook as useAuditLogs
    participant BFF as /api/audit-logs
    participant Auth as validateEnterpriseAuditAccess
    participant Q as query.ts (shared)
    participant DB as Database

    UI->>Hook: filters object
    Hook->>BFF: GET with search/resourceType/startDate/cursor
    BFF->>Auth: check session and enterprise membership
    Auth-->>BFF: orgMemberIds
    BFF->>Q: buildOrgScopeCondition
    BFF->>Q: buildFilterConditions
    BFF->>Q: queryAuditLogs
    Q->>DB: SELECT with WHERE and ORDER BY
    DB-->>Q: rows
    Q-->>BFF: data plus nextCursor
    BFF-->>Hook: JSON response
    Hook-->>UI: pages and hasNextPage
Loading

Reviews (3): Last reviewed commit: "lint" | Re-trigger Greptile

- Fix import path: @/lib/utils → @/lib/core/utils/cn
- Guard against empty orgMemberIds array in buildOrgScopeCondition
- Skip debounce effect on mount when search is already synced

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

✅ Bugbot reviewed your changes and found no new issues!

Comment @cursor review or bugbot run to trigger another review on this PR

Reviewed by Cursor Bugbot for commit 36a1aa4. Configure here.

Use ternary instead of && chain to prevent unknown type from being
returned as ReactNode.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add PASSWORD_RESET_REQUESTED audit on forget-password with user lookup
- Add CREDENTIAL_CREATED/UPDATED/DELETED audit on credential CRUD routes
  with metadata (credentialType, providerId, updatedFields, envKey)
- Add SCHEDULE_CREATED audit on schedule creation with cron/timezone metadata
- Fix SCHEDULE_DELETED (was incorrectly using SCHEDULE_UPDATED for deletes)
- Enhance existing schedule update/disable/reactivate audit with structured
  metadata (operation, updatedFields, sourceType, previousStatus)
- Add CREDENTIAL resource type and Credential filter option to audit logs UI
- Enhance password reset completed description with user email

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Add actorName/actorEmail to all new credential and schedule audit calls
  to match the established pattern (e.g., api-keys, byok-keys, knowledge)
- Add resourceId and resourceName to forget-password audit call
- Enhance forget-password description with user email

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ype entries

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Instead of maintaining a separate hardcoded list, the filter dropdown
now derives its options directly from the AuditResourceType const object.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
- Move resource type filter options to ee/audit-logs/constants.ts
  (derived from AuditResourceType, no separate list to maintain)
- Remove export from internal cursor helpers in query.ts
- Add 5 new AuditAction entries: BYOK_KEY_UPDATED, ENVIRONMENT_DELETED,
  INVITATION_RESENT, WORKSPACE_UPDATED, ORG_INVITATION_RESENT
- Enrich ~80 recordAudit calls across the codebase with structured
  metadata (knowledge bases, connectors, documents, workspaces, members,
  invitations, workflows, deployments, templates, MCP servers, credential
  sets, organizations, permission groups, files, tables, notifications,
  copilot operations)
- Sync audit mock with all new entries

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…dit fields

Remove metadata entries that duplicate resourceName, workspaceId, or
other top-level recordAudit fields. Also remove noisy fileNames arrays
from bulk document upload audits (kept fileCount).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Extract AuditAction, AuditResourceType, and their types into
lib/audit/types.ts (client-safe, no @sim/db dependency). The
server-only recordAudit stays in log.ts and re-exports the types
for backwards compatibility. constants.ts now imports from types.ts
directly, breaking the postgres -> tls client bundle chain.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@greptile

@waleedlatif1
Copy link
Copy Markdown
Collaborator Author

@cursor review

Copy link
Copy Markdown

@cursor cursor bot left a comment

Choose a reason for hiding this comment

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

Cursor Bugbot has reviewed your changes and found 2 potential issues.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 231df15. Configure here.

metadata: {
knowledgeBaseName: accessCheck.knowledgeBase?.name,
fileCount: createdDocuments.length,
fileNames: createdDocuments.map((doc) => doc.filename),
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Removed fileNames from bulk document upload audit metadata

Low Severity

The fileNames field was removed from the audit log metadata for bulk document uploads and not replaced with an equivalent. Previously, the metadata included fileNames: createdDocuments.map((doc) => doc.filename), which provided a record of which specific files were uploaded. Now only knowledgeBaseName and fileCount are logged, losing the ability to determine which individual files were part of a bulk upload from the audit trail. This reduces audit log usefulness for enterprise compliance scenarios, which is the primary purpose of this PR.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 231df15. Configure here.

ilike(auditLog.resourceName, searchTerm),
ilike(auditLog.description, searchTerm)
)!
)
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Search input LIKE wildcards not escaped in query

Low Severity

The search parameter is embedded directly into a LIKE pattern (%${params.search}%) without escaping SQL LIKE wildcards (% and _). A user searching for a literal % or _ character will get unexpected broad matches. For example, searching for _ matches any single character, potentially returning all audit logs. While not a SQL injection risk (Drizzle parameterizes the value), it degrades search accuracy for enterprise audit log queries.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 231df15. Configure here.

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