# Authorization Web Contract Fixtures

Deterministic, synthetic fixtures for the PDF2HTML browser/API authentication, authorization, CORS, CSRF, idempotency, rate-limit, administration, malformed-input, and privacy boundary. The suite contains no customer data, PDF/ZIP bytes, credentials, live domains, signed URLs, secrets, or executable/exhaustion payloads. Bracketed values are bounded inert markers interpreted only by a harness.

## Normative basis

The fixtures follow the current product and integration contracts: canonical UUIDs (including envelope `request_id`) and millisecond UTC instants; API version `2026-08-23`; all nine canonical `/v1/auth/*` routes; acceptance body `{upload_id}`; and download route `POST /v1/conversions/{conversion_id}/download`. Every response uses the `HTTP-007` envelope. `Failure.field_errors` is a closed `Record<string,string>`, and fixed public code/message/retryability tuples include `INVALID_CREDENTIALS`. Canonical public codes replace implementation-era aliases.

Refresh success is intentionally not asserted while the approved lookup/atomic-outcome/full-family adapter is unavailable. Those cases require exact `BLOCKED` results; a missing dependency can never become an inferred pass.

## Files and authority

- `principals.json` is the closed synthetic state/policy snapshot. It includes positive objects for both customers, expired/disabled states, session-bound CSRF generations, and the complete `SEC-072` rate-operation set.
- `principals.schema.json` is its Draft 2020-12 schema.
- `cases.jsonl` contains one independent typed case per line.
- `case.schema.json` closes requests, envelopes, effects, transitions, per-event race results, sink assertions, IDs, timestamps, and hashes.
- `manifest.json` fixes count, ordering, stable ID-to-semantic-key assignments, and tombstones. Retire an ID by adding it to `tombstones`; never recycle it.
- `validate.py` performs Draft 2020-12 validation with non-vacuous `FormatChecker`, then checks manifest membership/order/count, referential integrity, event ordering/uniqueness, BLOCKED semantics, envelope discrimination, and zero-effect ownership denial.

## Harness protocol

For each line, reset to `principals.json`, set the database clock to `fixtureClock`, install typed `preconditions`, and execute `request` as `actor`. `body` is parsed JSON; `rawBody` is bounded wire text and the two are mutually exclusive. Header marker values represent parser metadata, not large or malformed byte payloads.

Compare all of `expected`:

1. exact status and event-discriminated success/error envelope;
2. exact response headers listed (unlisted security headers must follow the route contract);
3. exact effect counters and ordered state transitions;
4. state before/after digests;
5. one `eventResult` for every concurrency event, in barrier order, with exact winner/loser status, code, commit bit, and shared result identity;
6. every enumerated sink assertion.

An empty transition list and zero counter mean no mutation/call. Ownership foreign/absent pairs must have byte-identical status, envelope shape, and listed headers after deterministic request-ID normalization. No signer is invoked before authentication and ownership. Admin writes are commands requiring role, exact Origin, CSRF, idempotency, state preconditions, and exactly one append-only audit event.

## Security invariants

Cookie-authenticated mutations require literal `Origin: https://tools.press.zone`, a valid access cookie, matching ordinary double-submit values, and the stored session hash. Bearer exemption applies only after successful Bearer authentication; malformed/invalid Bearer does not fall back to a valid cookie. CORS denies absent/null/prefix/suffix/sibling/arbitrary origins before auth or mutation and never emits wildcard authorization. Allowed actual responses expose the exact credentialed CORS triple; denied responses retain `Vary: Origin` and omit ACAO/credentials.

Production cookies are exact: `__Host-pdf2html_access` (`Secure; HttpOnly; SameSite=Lax; Path=/`, no Domain, Max-Age 900 with matching Expires), `__Host-pdf2html_csrf` (same except deliberately not HttpOnly), and `__Secure-pdf2html_refresh` at `Path=/auth`. Refresh-CSRF is a family-bound synchronizer returned only in JSON and the identical typed response header, never a cookie. Clears use separate Set-Cookie fields with original attributes, Max-Age 0, and Unix-epoch Expires.

Rate cases include allow-at-limit and reject-over-limit for all twelve named operations, missing-policy readiness BLOCKED, untrusted forwarding, and normalized trusted-IP identity. Idempotency includes 16/128-byte boundaries, invalid/absent keys, actor scope, exact replay, conflicting hashes, a 20-way identical race, and a conflicting concurrent race.

Logging cases use canary references rather than secret-shaped values. A conforming harness seeds its own non-retained canaries, searches every listed sink, and stores only sanitized aggregate results. Raw canaries must not enter fixture/evidence output.

## Remote validation

Run only on a buildbox through the proven explicit direct SSH route. Install `jsonschema` remotely if absent; never locally. Invoke:

```text
python3 quality/fixtures/authz-web/validate.py
```

Retain the exact sanitized stdout/stderr and exit status. Exit `2` beginning with `BLOCKED dependency=jsonschema` is a blocked result, not a pass. No local schema validation, project build, package install, or test is authorized for this fixture task.
