# `rho audit`

## Purpose

`rho audit` is a middleware plugin for recording what happened during Rho operations in a structured and reviewable way.

It should help with:

- traceability
- debugging
- operator review
- security review
- replay and fixture generation

It is not the source of truth for authorization or execution.
It records what other layers decided and did.

## Plugin Role

`rho audit` should be implemented as a middleware plugin, not as a top-level policy engine.

This means it can observe and record events from commands such as:

- `rho auth`
- `rho messages`
- `rho run`
- `rho agent`
- `rho middleware`

## Responsibilities

- record structured audit events
- record request and approval lifecycles
- record tool and run metadata
- record network request metadata where appropriate
- scrub sensitive values before writing artifacts
- support fixture and debugging workflows

## Network Request Scrubbing

When network requests are dumped for audit or debugging, sensitive values must be scrubbed **before** being written to disk — not after the fact. The audit middleware must never persist raw credentials, account identifiers, or session material, even temporarily.

### Mandatory scrub list

These headers must always be scrubbed:

- `authorization` — bearer tokens, JWTs, basic auth credentials
- `chatgpt-account-id` — identifies the upstream OpenAI account; leaking it in fixtures or logs allows account correlation and potential abuse
- `session_id` — session binding material
- `cookie` / `set-cookie` — may contain auth tokens or session identifiers

### Strongly recommended scrub list

- `x-api-key` — API key passed as a header
- `proxy-authorization` — proxy-level credentials
- `openai-organization` — org-level identifier if present

### Request body scrubbing

POST bodies may also contain secrets. The scrub layer should redact:

- any JSON field matching `token`, `secret`, `password`, `api_key`, `access_token`, `refresh_token`, or `session_id` (case-insensitive)
- embedded JWTs (pattern: `eyJ...`)

### Implementation rules

- header and field names must be matched **case-insensitively**
- the original value must **never** be written to disk, even in crash dumps or partial writes
- scrubbed values should use `[REDACTED]` as a deterministic placeholder
- the scrub list must be defined in one place (currently `SENSITIVE_KEY_RE` in `rho_fixture_scrub.py`) and shared by both the audit middleware and the fixture scrub tool
- new headers should be added to the regex, tests, and this document together

Example:

```yaml
headers:
  authorization: "[REDACTED]"
  chatgpt-account-id: "[REDACTED]"
  session_id: "[REDACTED]"
  cookie: "[REDACTED]"
```

### Why this matters

Audit logs and test fixtures are committed to version control and shared across developers. A single leaked bearer token or account ID in a fixture file can:

- grant unauthorized API access if the token is still valid
- enable account correlation and targeted attacks via the account ID
- violate data-handling policies if PII is embedded in session tokens

Scrub first, persist second. No exceptions.

## Suggested Events

- `identity.created`
- `identity.linked`
- `auth.paired`
- `auth.blocked`
- `message.sent`
- `message.received`
- `request.created`
- `approval.recorded`
- `run.started`
- `run.completed`
- `run.failed`
- `network.request`

## Suggested Files

```text
.rho/audit/events/<event-id>.yaml
.rho/audit/network/<request-id>.yaml
```

## Important Rules

- Audit logs should be append-oriented and tamper-evident where practical.
- Sensitive values should be scrubbed before persistence, not only before display.
- Audit should not silently expand the trust boundary by collecting secrets it does not need.
