Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

🎃 Export the audit log as CSV or JSON from /logs

Đang mở
#998 0 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
22/100
Loại issue
Tính năng
Độ rõ ràng
Đặc tả rõ ràng
Mức độ hoạt động
Sôi nổi
Công nghệ
typescript

Hướng nghiên cứu

Start with getRecentInvocations and orgScope() in packages/backend/src/audit/audit.service.ts, and the list endpoint in audit.controller.ts, to see how the where filters are built today. Then look at the admin-only guard pattern in site-settings.controller.ts. Done means the export endpoint streams batches under the row cap, returns 403 for non-admins and for a missing organizationId, and the audit specs and Playwright test pass.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

enhancement hacktoberfest help wanted

Part of the October Challenge #997.

Why

Admins regularly need the tool-call history outside the product: for a security review, to attach to a support ticket, to load into a spreadsheet or a SIEM, or to keep it beyond the retention window. Today the Audit Log page (/logs) shows 50 rows per page and offers no download. The only way out is paging through GET /api/audit/invocations by hand. GitHub's audit log, Auth0 and Grafana all offer CSV and JSON export of the filtered view.

What already exists: the page filters by status, tool/connector search, connector and MCP server (logs/page.tsx:116-134), and the API supports the same filters plus limit/offset (audit.controller.ts:13-37). There is no date filter and no export. The header button passed to AppShell as exportButton (logs/page.tsx:183-207) is only a Refresh button with a misleading variable name. docs/api-reference.md:226-253 documents toolName, from and to filters that the API does not have, and a stats response (last24h, last7d, total) that does not match getStats() (invocations24h, errors24h, invocations7d, totalInvocations).

Self-hosted vs Cloud

  • Self-hosted: enabled in Community and Business. No ee/ code. There is no retention job on self-hosted, so an export can cover the whole history of the organization.
  • Cloud (DEPLOYMENT_MODE=cloud): enabled. Rows older than INVOCATION_RETENTION_DAYS (default 90) are deleted and payloads older than INVOCATION_PAYLOAD_RETENTION_DAYS (default 14) are cut to an excerpt (ee/cloud/kg-cron.service.ts:372, :407), so an export only contains what is still stored. Say so in a tooltip next to the button. Do not change anything under ee/. The export must be streamed in batches: an organization can have hundreds of thousands of rows, and loading them in one query would put the shared backend's heap at risk.
  • Who can use it: org ADMIN only (@Roles('ADMIN') with RolesGuard, the pattern on site-settings.controller.ts:111-112). Other roles keep reading /logs as today but get no bulk download. Rows are always scoped to the caller's organization. If the JWT carries no organizationId, return 403: orgScope() returns {} (no filter) for a missing org (audit.service.ts:297-300), and an export must never fall back to all rows.

What to build

  1. Shared filter builder: move the where construction out of getRecentInvocations (audit.service.ts:302-345) into one helper used by the list and the export, and add from / to on createdAt (ISO date or datetime; from inclusive, to exclusive). The list endpoint gets from/to too.
  2. Endpoint: GET /api/audit/invocations/export?format=csv|json with the list filters (status, search, connectorId, mcpServerId, toolId, from, to) plus payloads=true|false (default false). Headers: Content-Type: text/csv; charset=utf-8 or application/json, and Content-Disposition: attachment; filename="anythingmcp-audit-<from>-<to>.<ext>".
  3. Streaming: read in batches of 1,000 with a keyset cursor on (createdAt desc, id desc) and write each batch to the response (@Res()), never collecting all rows in memory. Cap one export at AUDIT_EXPORT_MAX_ROWS (default 100,000). When the cap is reached, end the file cleanly and add a final marker (a last CSV comment line or a truncated: true field) so the UI can say "narrow the date range". For JSON, write an array incrementally or NDJSON; pick one and document it.
  4. Columns (same names in CSV and JSON): createdAt (ISO 8601 UTC), status, tool, connector, connectorType, mcpServer, userEmail, authMethod and apiKeyName (both parsed from clientInfo), durationMs, repeatCount, error; with payloads=true also input and output (JSON strings in CSV). Keep repeatCount: one stored row can stand for many identical failures (audit.service.ts:12-18).
  5. CSV safety: RFC 4180 quoting (quotes, commas, newlines), UTF-8 with BOM so Excel shows umlauts correctly, and formula-injection protection: prefix a cell that starts with =, +, -, @, tab or carriage return with '. Tool arguments and upstream errors are user- and vendor-controlled text.
  6. UI: on /logs, rename exportButton to what it is and add an "Export" menu next to Refresh (CSV, JSON, and an "Include input and output" option), shown to admins only (useAuth().user.role). Add a From / To date range to the toolbar (logs/page.tsx:210-267) that drives both the list and the export. request() in lib/api.ts:27-57 always parses JSON, so add a separate client helper that uses fetch + blob() and an object URL, like handleExportAll on the Connectors page (connectors/page.tsx:139-160).

Where to look

  • packages/backend/src/audit/audit.controller.ts:13-37: list endpoint and its filters.
  • packages/backend/src/audit/audit.service.ts:297-345: orgScope() and getRecentInvocations() (the includes give tool, connector, user and server names).
  • packages/backend/prisma/schema.prisma:678-718: ToolInvocation (clientInfo is a JSON string; repeatCount).
  • packages/backend/src/auth/roles.guard.ts:11 and packages/backend/src/settings/site-settings.controller.ts:111-112: admin-only guard pattern.
  • packages/backend/src/ee/cloud/kg-cron.service.ts:372, :407: Cloud payload trim and retention (read only).
  • packages/frontend/src/app/logs/page.tsx:83-207: state, filters, fetch, header actions.
  • packages/frontend/src/lib/api.ts:753-765: audit.invocations() client.
  • packages/frontend/src/components/ui/action-menu.tsx: dropdown for the menu.
  • docs/api-reference.md:219-253: Audit section to correct and extend.

Acceptance criteria

  • Unit specs next to the service (cd packages/backend && npm test): filters and from/to build the expected where; another organization's rows never appear; CSV escaping (quotes, newlines, a cell starting with =); the row cap ends the file with the truncation marker; payloads=false omits input/output.
  • EDITOR and VIEWER get 403 from the export endpoint; a JWT without organizationId gets 403.
  • Exporting 50,000 seeded rows keeps backend memory flat (describe how you checked in the PR).
  • The CSV opens in LibreOffice or Excel with correct columns and umlauts.
  • Playwright test in packages/frontend/tests/e2e/ (stub /api/audit/invocations* like mobile.spec.ts): an admin sees the Export menu and the request carries the active filters and dates; a viewer does not see it. Run with cd packages/frontend && npm run test:e2e.
  • docs/api-reference.md: export endpoint documented, toolName example removed, from/to documented, stats response corrected.

Out of scope

  • Scheduled or emailed exports, pushing to S3 or a SIEM.
  • Exporting security events or product events.
  • Changing retention on Cloud or adding retention to self-hosted.
  • Any change under ee/.

Size

M (1–2 days)

How to claim

Comment "I'd like to work on this" and we'll assign you. Rules in #997.

Ngôn ngữ chính
TypeScript
Star
856
Fork
82
Merge trung bình
6 giờ 49 phút
Pull request đã merge (30 ngày)
152

Chuẩn bị môi trường

Dự án này không cung cấp dev container, Dockerfile hay hướng dẫn đóng góp, nên bạn cần tự thiết lập môi trường: hãy bắt đầu từ README và xem hướng dẫn đóng góp lần đầu của chúng tôi để biết các bước chung.

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của HelpCode-ai/anythingmcp

Tất cả issue của HelpCode-ai/anythingmcp

Issue tương tự

Thêm issue về TypeScript

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.