Files
PaperClipAI/packages
DottaandPaperclip 5e33090e82 feat(server): add permission-gated agent action audit API (#9735)
## Thinking Path

> - Paperclip is the open source control plane for managing AI-agent
companies.
> - Company activity logs already capture agent-attributed mutations and
responsible-user context.
> - Operators need one company-scoped feed for reviewing those actions
without issuing N+1 entity lookups.
> - Full-company audit visibility is security-sensitive and must not be
available to agents by default.
> - Existing activity-log sanitization and responsible-user attribution
should remain the source of truth.
> - This pull request adds a permission-gated, cursor-paginated agent
action audit API with bulk entity enrichment.
> - The benefit is a render-ready audit feed that preserves company
boundaries, redaction, and legacy attribution.

## Linked Issues or Issue Description

### Subsystem affected

`server/` — REST API and orchestration services, plus the shared
permission-key contract.

### Problem or motivation

Board operators cannot retrieve a unified feed of agent actions with
responsible-user attribution and entity context. Existing activity reads
lack the dedicated permission boundary, cursor pagination, filter set,
and render-ready comment/issue/document snippets needed by audit views.

### Proposed solution

Add `GET /api/companies/:companyId/audit/agent-actions`, gated by
`audit:view_agent_actions`, with stable cursor pagination,
agent/responsible-user/run/entity/action/time/actor filters, read-time
redaction, heartbeat-run fallback attribution, and bulk entity
enrichment.

### Alternatives considered

Extending the broad company activity endpoint would preserve overly
broad authorization semantics and still require UI-side N+1 fetches. A
separate audit route makes the sensitive permission boundary explicit.

### Roadmap alignment

Supports the roadmap direction toward durable audit trails and explicit
review workflows; no duplicate open pull request was found.

### Additional context

The response is designed for a board audit UI that needs to render
entries such as an agent commenting on an issue without issuing
follow-up entity requests.

## What Changed

- Added the `audit:view_agent_actions` permission key.
- Added a stable `(createdAt,id)` cursor-paginated audit query with all
requested filters.
- Added read-time responsible-user fallback through `heartbeat_runs` for
legacy rows.
- Added bulk issue, comment excerpt, and issue-document key enrichment
without N+1 queries.
- Reused activity-log sanitization and username redaction on returned
details.
- Added embedded-Postgres route tests for denial, explicit grants,
pagination, filters, enrichment, and fallback attribution.

## Verification

- `pnpm --filter @paperclipai/server typecheck`
- `pnpm exec vitest run
server/src/__tests__/agent-action-audit-routes.test.ts`

## Risks

- The endpoint exposes company-wide agent audit data, so authorization
mistakes would be high impact; the route rejects agent actors and
requires an explicit board permission except for trusted
local/instance-admin contexts.
- Entity snippets are intentionally nullable for deleted or unsupported
entity types.
- No database migration is included; the query uses indexes added with
responsible-user attribution work and falls back through the existing
run relation.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex using GPT-5.4 with tool use, repository editing, command
execution, and medium reasoning. Context window size was not exposed by
the runtime.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have searched GitHub for duplicate or related PRs and linked
them above
- [x] I have either (a) linked existing issues with `Fixes: #` / `Closes
#` / `Refs #` OR (b) described the issue in-PR following the relevant
issue template
- [x] I have not referenced internal/instance-local Paperclip issues or
links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip`
URLs)
- [x] My branch name describes the change (e.g. `docs/...`, `fix/...`)
and contains no internal Paperclip ticket id or instance-derived details
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] All Paperclip CI gates are green
- [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups
- [x] I will address all Greptile and reviewer comments before
requesting merge

---------

Co-authored-by: Paperclip <noreply@paperclip.ing>
2026-07-27 19:15:42 -05:00
..