Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,23 @@ implementation's version.
- Clarified that an issuer MAY require out-of-band authentication and embed deployment-specific claims
on the `token` grant, and that a server MAY return implementation-defined resource or policy errors
such as quota limits; both non-normative (SPEC sections 3 and 6).
- Defined the HTTP/JSON error body `{ error, code?, detail? }` and a status→code table, and stated that
every non-2xx is terminal while a stale-version `push` is a `200` with `conflict: true` (SPEC section
6); added `$defs/Error` to the JSON Schema.
- Reworded the conformance section (SPEC section 11) to map each requirement to the vector that actually
exists: the Ed25519 primitive anchors the challenge signature and the payload-AEAD epoch-tamper case
anchors rotation correctness; dedicated challenge/token and rotation vectors are noted as welcome
additions rather than implied to already exist.

### Repository

- Added `openapi.yaml`, an OpenAPI 3.1 description of the HTTP/JSON profile (paths, status codes, error
responses) that references the JSON Schema shapes, so the route surface is machine-readable and
stub-generatable.
- Added `vectors/index.json`, a machine-readable index of the conformance vectors (file, kind, spec
section, RFC anchors) so a harness can enumerate them without hardcoding filenames.
- Added a root `Taskfile.yml` (go-task): `task test` runs the conformance suite and every language's
example tests in one command, mirroring the CI jobs.
- Added a Go reference client and server, and upgraded the TypeScript, Python, Java, and Rust reference
clients to implement the real envelope and key-wrap crypto (previously opaque placeholders). Every
example is verified byte-for-byte against the conformance vectors.
Expand Down
10 changes: 9 additions & 1 deletion IMPLEMENTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,9 @@ data key to that member entry.
### Routes (HTTP/JSON profile)

All bodies are JSON with proto field names in `camelCase`. Routes other than the two auth routes
require `Authorization: Bearer <token>`.
require `Authorization: Bearer <token>`. The machine-readable route description, with every status code
and the error body, is [`openapi.yaml`](openapi.yaml) (OpenAPI 3.1); generate a client or server stub
from it if your stack supports it.

| Method + path | Request -> Response |
|---|---|
Expand All @@ -177,6 +179,12 @@ Note: `memberId` in the path is the base64 Ed25519 public key. Because it contai
| `404` | Repo or member not found |
| `409` | Duplicate `repoId` on create |

Every non-2xx response body is an error object: `{ "error": "<message>", "code": "<machine code>",
"detail": "<optional>" }`. `error` is human-readable (do not parse it); `code` is an optional stable
token (`unauthorized`, `forbidden`, `not_found`, `duplicate_repo`, `quota_exceeded`, `policy_denied`,
`bad_request`) you may switch on. Treat all of them as **terminal** — see the concurrency note below for
the one outcome that is *not* an error.

Optimistic concurrency: `push` returns `{ "accepted": false, "conflict": true }` with the
current version when `expectedPayloadVersion` does not match. A client must pull, re-apply, and
retry; this is not a `4xx` status code.
Expand Down
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ stack:
- **gRPC profile.** [`proto/avp.proto`](proto/avp.proto) is canonical. Field numbers and names are
stable.
- **HTTP/JSON profile.** One HTTP path per operation, JSON bodies whose field names are the proto field
names in `camelCase`, and a Bearer token in `Authorization`. See [`schema/avp.schema.json`](schema/avp.schema.json).
names in `camelCase`, and a Bearer token in `Authorization`. Message shapes are
[`schema/avp.schema.json`](schema/avp.schema.json); the full route surface (paths, status codes, error
bodies) is [`openapi.yaml`](openapi.yaml).

A browser or Node client can implement AVP with no gRPC toolchain at all.

Expand All @@ -51,9 +53,11 @@ A browser or Node client can implement AVP with no gRPC toolchain at all.
|------|----------|
| [`SPEC.md`](SPEC.md) | The normative protocol specification. |
| [`proto/avp.proto`](proto/avp.proto) | Canonical Protocol Buffers schema (gRPC profile). |
| [`schema/avp.schema.json`](schema/avp.schema.json) | JSON Schema (HTTP/JSON profile). |
| [`vectors/`](vectors/) | Conformance test vectors. |
| [`examples/`](examples/) | A worked end-to-end flow, representative message bodies, and a runnable reference server. |
| [`schema/avp.schema.json`](schema/avp.schema.json) | JSON Schema message shapes (HTTP/JSON profile). |
| [`openapi.yaml`](openapi.yaml) | OpenAPI 3.1 route description for the HTTP/JSON profile. |
| [`vectors/`](vectors/) | Conformance test vectors (indexed by [`vectors/index.json`](vectors/index.json)). |
| [`examples/`](examples/) | A worked end-to-end flow, representative message bodies, and runnable reference implementations. |
| [`Taskfile.yml`](Taskfile.yml) | One-command local runner: `task test` runs the conformance suite and every example. |
| [`CONTRIBUTING.md`](CONTRIBUTING.md) | How to help. |
| [`SECURITY.md`](SECURITY.md) | How to report a vulnerability. |
| [`llms.txt`](llms.txt) | Structured entry point for LLMs and AI agents. |
Expand Down
48 changes: 46 additions & 2 deletions SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,36 @@ failures and MUST NOT retry them as if they were a stale-version conflict. Recom
HTTP `429 Too Many Requests` / `403 Forbidden` for the JSON profile; gRPC `RESOURCE_EXHAUSTED` /
`PERMISSION_DENIED` for the gRPC profile.

### Errors

In the HTTP/JSON profile, any non-`2xx` response body is an **error object**:

```json
{ "error": "<human-readable message>", "code": "<machine code>", "detail": "<optional context>" }
```

`error` is a human-readable message and is always present; clients MUST NOT parse it. `code` is an
OPTIONAL stable machine-readable token (see the table) a client MAY switch on; when absent, the client
falls back to the HTTP status. `detail` is OPTIONAL extra context. The schema is
[`schema/avp.schema.json`](schema/avp.schema.json) `#/$defs/Error`; the full route surface, including
which status each operation can return, is [`openapi.yaml`](openapi.yaml).

| Status | `code` | Meaning |
|---|---|---|
| `400` | `bad_request` | Malformed body or parameters |
| `401` | `unauthorized` | Missing/invalid token, or an expired/reused challenge nonce |
| `403` | `forbidden` | Authenticated but not a member, or an operation disallowed by policy (`policy_denied`) |
| `404` | `not_found` | Repo or member does not exist |
| `409` | `duplicate_repo` | `createRepo` with an id that already exists |
| `429` | `quota_exceeded` | A deployment resource limit was hit |

A client MUST treat every error here as **terminal** and MUST NOT retry it as if it were a
stale-version conflict. The one retryable outcome — optimistic-concurrency conflict — is **not** an
error: `push` returns HTTP `200` with `PushResponse { accepted: false, conflict: true }` and the
current version (§10). The gRPC profile carries the same outcomes as status codes
(`INVALID_ARGUMENT`, `UNAUTHENTICATED`, `PERMISSION_DENIED`, `NOT_FOUND`, `ALREADY_EXISTS`,
`RESOURCE_EXHAUSTED`).

### Profiles

- **gRPC**, [`proto/avp.proto`](proto/avp.proto) is canonical. Field numbers and names are stable.
Expand Down Expand Up @@ -267,8 +297,22 @@ A conformant server MUST uphold:
## 11. Conformance

An implementation is conformant if it satisfies every MUST above and reproduces the vectors in
[`vectors/`](vectors/) (canonical AAD/binding-message construction, challenge/sign/token, key wrap/unwrap,
and rotation). See [`vectors/README.md`](vectors/README.md).
[`vectors/`](vectors/), indexed by [`vectors/index.json`](vectors/index.json):

- the **deterministic constructions** — the AAD layout (`aad.json`) and the canonical key-binding
message (`key-binding-message.json`);
- the **RFC-anchored primitives** — HKDF-SHA256 (`hkdf.json`), X25519 (`x25519.json`), and Ed25519
sign/verify (`ed25519.json`). The Ed25519 vector anchors the signature used by the challenge→token
flow (§3): signing the raw nonce bytes is exactly this primitive;
- the **envelope compositions** — payload AEAD (`payload-aead.json`) and the key wrap/unwrap
(`key-wrap.json`). The payload-AEAD case includes the epoch-tamper assertion (decryption fails when
the AAD's `keyEpoch` changes), which is the cryptographic core of rotation correctness (§10): a
stale-epoch envelope cannot authenticate.

See [`vectors/README.md`](vectors/README.md). Dedicated end-to-end vectors for the challenge→token
exchange and the multi-step `removeMember` rotation are a welcome addition (see
[`CONTRIBUTING.md`](CONTRIBUTING.md)); today those paths are covered by the primitives above plus the
cross-language wire interop in [`examples/`](examples/).

## 12. Security considerations and open items

Expand Down
78 changes: 78 additions & 0 deletions Taskfile.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
# One-command local runner for the AVP reference examples and conformance suite.
#
# Uses go-task (https://taskfile.dev): `task --list`. Each target mirrors the matching
# .github/workflows/examples-*.yml job, so "green locally" means "green in CI". Each language
# is independent — run only the toolchains you have installed.
#
# Requirements per target: conformance/typescript -> Bun; go -> Go; python -> Python 3;
# rust -> Cargo; java -> a JDK. `task test` runs every target and needs them all.
version: "3"

tasks:
default:
desc: List available tasks.
cmds:
- task --list
silent: true

test:
desc: Run the conformance suite and every language's example tests.
cmds:
- task: conformance
- task: go
- task: typescript
- task: python
- task: rust
- task: java

conformance:
desc: Reproduce every vector in vectors/ with the Node conformance runner.
dir: examples/conformance
cmds:
- bun install --frozen-lockfile
- bun run typecheck
- bun run test

go:
desc: Vet, test, and build the Go client and server.
dir: examples/go
cmds:
- go vet ./...
- go test ./...
- go build ./...

typescript:
desc: Typecheck and test the TypeScript client and server.
cmds:
- for: { var: PROJECTS }
cmd: cd examples/typescript/{{.ITEM}} && bun install --frozen-lockfile && bun run typecheck && (grep -q '"test"' package.json && bun run test || echo "no test script in {{.ITEM}}")
vars:
PROJECTS: client server

python:
desc: Byte-compile and unit-test the Python client and server.
cmds:
- cd examples/python/server && pip install -r requirements.txt && python -m py_compile server.py test_server.py && python -m unittest test_server.py
- cd examples/python/client && pip install -r requirements.txt && python -m py_compile client.py crypto.py && python -m unittest test_crypto.py

rust:
desc: Build and test the Rust client and server.
cmds:
- cd examples/rust/server && cargo test
- cd examples/rust/client && cargo test

java:
desc: Compile and run the Java server smoke test and client crypto vectors.
cmds:
- cd examples/java/server && javac Server.java SmokeTest.java && java SmokeTest
- cd examples/java/client && javac Crypto.java CryptoVectors.java Client.java && java CryptoVectors

interop:
desc: Cross-language wire interop (informational — runs in CI).
cmds:
- |
echo "The cross-language interop matrix (each lang's client -> Go server, Go client ->"
echo "each lang's server) runs in .github/workflows/examples-interop.yml. Reproducing the"
echo "full matrix locally needs all five toolchains plus port-readiness polling; the"
echo "workflow is the reference. Per-language correctness is covered by 'task test'."
silent: true
4 changes: 3 additions & 1 deletion examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ server, and the Go reference client runs against each language's server. Go and
are the fullest worked references for the cryptographic core.

Conformance tooling lives in [`conformance/`](conformance/) (it checks the repo's
[`../vectors/`](../vectors/)). More languages are welcome; see
[`../vectors/`](../vectors/)). From the repo root, [`task test`](../Taskfile.yml) (go-task) runs the
conformance suite and every language's example tests in one command; per-language targets
(`task go`, `task rust`, …) run just one toolchain. More languages are welcome; see
[`../CONTRIBUTING.md`](../CONTRIBUTING.md).

## The cast
Expand Down
4 changes: 3 additions & 1 deletion llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ Notes for implementers: field names are normative; do not rename or renumber the

- [Specification (SPEC.md)](https://raw.githubusercontent.com/trqlmao/avp/main/SPEC.md): The normative protocol: identity and authentication, the cryptographic envelope, payload and provenance, the transport surface, federation, anti-MITM key binding, invariants, conformance, and security considerations.
- [Protobuf schema (avp.proto)](https://raw.githubusercontent.com/trqlmao/avp/main/proto/avp.proto): Canonical gRPC schema with stable field numbers and names.
- [JSON Schema (avp.schema.json)](https://raw.githubusercontent.com/trqlmao/avp/main/schema/avp.schema.json): Message shapes for the HTTP/JSON transport profile.
- [JSON Schema (avp.schema.json)](https://raw.githubusercontent.com/trqlmao/avp/main/schema/avp.schema.json): Message shapes for the HTTP/JSON transport profile, including the error body (`$defs/Error`).
- [OpenAPI (openapi.yaml)](https://raw.githubusercontent.com/trqlmao/avp/main/openapi.yaml): OpenAPI 3.1 route description of the HTTP/JSON profile — paths, methods, status codes, and error responses, referencing the JSON Schema shapes.

## Examples

Expand All @@ -23,6 +24,7 @@ Notes for implementers: field names are normative; do not rename or renumber the

## Conformance vectors

- [Vectors index (index.json)](https://raw.githubusercontent.com/trqlmao/avp/main/vectors/index.json): Machine-readable index of every vector file — kind, spec section, and RFC anchors — for a harness to enumerate.
- [Vectors overview](https://raw.githubusercontent.com/trqlmao/avp/main/vectors/README.md): How the vectors are organized and which are deterministic versus generated.
- [AAD vectors](https://raw.githubusercontent.com/trqlmao/avp/main/vectors/aad.json): Deterministic additional-authenticated-data construction (SPEC section 4).
- [Key-binding message vectors](https://raw.githubusercontent.com/trqlmao/avp/main/vectors/key-binding-message.json): Deterministic canonical key-binding message (SPEC section 9).
Expand Down
Loading
Loading