Files
sentryagent-idp/openspec/specs/audit-log/spec.md
SentryAgent.ai Developer 61ea975c79 docs: bedroom developer documentation — complete docs/developers/ set
Adds the full bedroom-developer-docs OpenSpec change implementation:

- docs/developers/README.md — index page
- docs/developers/quick-start.md — bootstrap to working token in 7 steps
- docs/developers/concepts.md — AgentIdP, AGNTCY, lifecycle, OAuth 2.0, free tier
- docs/developers/guides/README.md — guide index
- docs/developers/guides/register-an-agent.md — all fields, validation, common errors
- docs/developers/guides/manage-credentials.md — generate, list, rotate, revoke
- docs/developers/guides/issue-and-revoke-tokens.md — OAuth 2.0 flow, introspect, revoke
- docs/developers/guides/query-audit-logs.md — filters, pagination, 90-day retention
- docs/developers/api-reference.md — all 14 endpoints, all error codes, curl examples

Also commits deferred OpenSpec housekeeping from previous session:
- Archives phase-1-mvp-implementation change to openspec/changes/archive/
- Adds bedroom-developer-docs change artifacts (30/30 tasks complete)
- Syncs 4 delta specs to openspec/specs/

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-28 14:13:03 +00:00

5.0 KiB

ADDED Requirements

Requirement: Audit events are written internally for all significant actions

The system SHALL automatically create an immutable AuditEvent record for each of the following actions: agent.created, agent.updated, agent.decommissioned, agent.suspended, agent.reactivated, token.issued, token.revoked, token.introspected, credential.generated, credential.rotated, credential.revoked, auth.failed. No API endpoint SHALL allow external creation, modification, or deletion of audit records.

Scenario: Audit event created on agent registration

  • WHEN a new agent is successfully registered via POST /agents
  • THEN an AuditEvent with action: agent.created, outcome: success, and metadata containing agentType and owner is persisted

Scenario: Audit event created on failed authentication

  • WHEN a POST /token request fails due to invalid credentials
  • THEN an AuditEvent with action: auth.failed, outcome: failure, and metadata containing reason and clientId is persisted

Scenario: Audit event created on token issuance

  • WHEN a token is successfully issued via POST /token
  • THEN an AuditEvent with action: token.issued, outcome: success, and metadata containing scope and expiresAt is persisted

Requirement: Query the audit log with pagination and filtering

The system SHALL return a paginated list of audit events ordered by timestamp descending. The caller SHALL hold a valid Bearer token with audit:read scope. Filtering SHALL support agentId, action, outcome, fromDate, and toDate — all optional, combined with logical AND.

Scenario: Successful audit log query

  • WHEN a GET request to /audit is received with a valid Bearer token with audit:read scope
  • THEN the system returns 200 OK with a PaginatedAuditEventsResponse containing data, total, page, and limit

Scenario: Filter by agentId

  • WHEN a GET request to /audit?agentId={uuid} is received
  • THEN only events where agentId equals the provided UUID are returned

Scenario: Filter by action

  • WHEN a GET request to /audit?action=token.issued is received
  • THEN only events with action: token.issued are returned

Scenario: Filter by date range

  • WHEN a GET request to /audit?fromDate=2026-03-01T00:00:00.000Z&toDate=2026-03-28T23:59:59.999Z is received
  • THEN only events with timestamp within the specified range are returned

Scenario: fromDate after toDate rejected

  • WHEN a GET request to /audit is received with fromDate that is chronologically after toDate
  • THEN the system returns 400 Bad Request with code: VALIDATION_ERROR and details.reason explaining the invalid date range

Scenario: Insufficient scope rejected

  • WHEN a GET request to /audit is received with a valid Bearer token that does not have audit:read scope
  • THEN the system returns 403 Forbidden with code: INSUFFICIENT_SCOPE

Requirement: Retrieve a single audit event by ID

The system SHALL return a single immutable AuditEvent by its eventId. The caller SHALL hold a valid Bearer token with audit:read scope.

Scenario: Audit event found

  • WHEN a GET request to /audit/{eventId} is received with a valid Bearer token with audit:read scope and a UUID that exists in the audit log
  • THEN the system returns 200 OK with the full AuditEvent object

Scenario: Audit event not found

  • WHEN a GET request to /audit/{eventId} is received with a UUID that does not exist in the audit log
  • THEN the system returns 404 Not Found with code: AUDIT_EVENT_NOT_FOUND

Requirement: Free-tier 90-day audit log retention

On the free tier, the system SHALL only return audit events from the last 90 days. Events older than 90 days SHALL be treated as not accessible (return empty results for queries, 404 for direct lookups). The system SHALL return a 400 error with code: RETENTION_WINDOW_EXCEEDED if a fromDate query parameter falls outside the 90-day retention window.

Scenario: Query outside retention window rejected

  • WHEN a GET request to /audit is received with fromDate more than 90 days before today
  • THEN the system returns 400 Bad Request with code: RETENTION_WINDOW_EXCEEDED and details.retentionDays: 90

Scenario: Direct lookup of expired event returns 404

  • WHEN a GET request to /audit/{eventId} is received for an event with a timestamp older than 90 days
  • THEN the system returns 404 Not Found with code: AUDIT_EVENT_NOT_FOUND

Requirement: Rate limiting on audit endpoints

The system SHALL enforce a rate limit of 100 requests per minute per authenticated client on all audit endpoints.

Scenario: Rate limit exceeded on audit endpoint

  • WHEN a client sends more than 100 requests to any audit endpoint within a 60-second window
  • THEN the system returns 429 Too Many Requests with X-RateLimit-Limit, X-RateLimit-Remaining: 0, and X-RateLimit-Reset headers