OXYGENHUB

Spec 0.5a: wire message encodings and TLS-termination note; remove the HTTP demo file 096f447ccda0

Author
Andy McCall @andymccall <[email protected]>
When
· 2026-09-26 18:48 UTC
Signature
✔ signed by Andy McCall
Hash
096f447ccda0e0de6f99ef44618c439508811cea06da0036383c94424c53eb01
Depends on
2a7f06b4392f 86e682c242c6 ff0af1ee299d
Depended on by
570e35310f31 1ec6fdbc6bcb d36ba2f79f95 f0a517d28237 68a924846379 6f8aeb996558 b3c5a59a875a 28fc23d7706a 2863456a0f6d 83e0677b07fe fce44ae9ad29
In bookmarks
agents-in-readme bare-hashes carried-not-removed carry-identical doctor-trust identical-sides keyless-tags main merge-remote-bookmark only-help-103 paths-for-resolutions-and-amend push-notes show-stat subrepo-pin-state switch-says
In tags
v0.1.0 v0.10.0 v0.11.0 v0.2.0 v0.3.0 v0.3.1 v0.4.0 v0.4.1 v0.4.2 v0.4.3 v0.4.4 v0.4.5 v0.4.6 v0.5.0 v0.5.1 v0.6.0 v0.7.0 v0.8.0 v0.9.0
Edits
6 atoms, 1 tree operation, 2 files

Browse the tree at this change

removed HTTP.md +0 −0
…
1 unchanged lines
modified docs/spec.md +23 −5
…
1 unchanged lines
2 2
3 3
| | |
4 4
|---|---|
5 -
| **Status** | Draft 0.5 |
5 +
| **Status** | Draft 0.5a |
6 6
| **Format version** | 1 |
7 7
| **Date** | 2026-09-26 |
8 8
| **Audience** | Implementers, security reviewers, and contributors |
…
576 unchanged lines
585 585
586 586
**Verification.** A sealed change `C` is authenticated iff a seal `S` exists such that `hash(C) ∈ S.body.hashes`, `S` carries a valid signature from key `K`, and `K` equals `C.author` or is listed in `C.author`'s identity as a delegate (§14.2). The same author-or-delegate rule applies to individual change signatures. This rule is what stops a collaborator from sealing a change whose `author` field names someone else (§3.1). A seal's signer must additionally be authorized by policy for the reference being pushed.
587 587
588 -
**Handling.** A seal is stored and transported with the changes it covers: `fetch` (§16.1) streams the seals covering every change it returns, `push` (§16.3) MUST include a seal or signature for every change, and a seal covering any reachable change is itself reachable (§21). Seals from different keys MAY overlap; a change needs at least one valid authenticator, and policy thresholds count distinct authenticating keys.
588 +
**Handling.** A seal is stored and transported with the changes it covers: `fetch` (§16.1) streams the seals covering every change it returns, `push` (§16.4) MUST include a seal or signature for every change, and a seal covering any reachable change is itself reachable (§21). Seals from different keys MAY overlap; a change needs at least one valid authenticator, and policy thresholds count distinct authenticating keys.
589 589
590 590
### 14.5 Trust policy (G2)
591 591
…
24 unchanged lines
616 616
617 617
### 15.1 HTTPS (mandatory)
618 618
619 -
Every server MUST offer HTTPS with TLS 1.3 at `https://<host>/<repo>/oxy/v1/`. Authentication is by bearer token, mutual TLS, or HTTP signature over a server-issued challenge with the client's identity key. HTTPS is required because it traverses corporate proxies, load balancers, and CDNs; it is the interoperability baseline.
619 +
Every server MUST offer HTTPS with TLS 1.3 at `https://<host>/<repo>/oxy/v1/`. Authentication is by bearer token, mutual TLS, or HTTP signature over a server-issued challenge with the client's identity key. HTTPS is required because it traverses corporate proxies, load balancers, and CDNs; it is the interoperability baseline. A reference server MAY speak plain HTTP behind a TLS-terminating proxy; it MUST NOT be exposed without TLS except on a loopback or otherwise trusted network. Reads MAY be open; a push MUST be authenticated when any credential is configured.
620 620
621 621
### 15.2 Noise (optional)
622 622
…
37 unchanged lines
660 660
661 661
The client sends the heads it has for the requested references and the heads it wants. Because dependencies form a DAG and every state is its heads' closure, the server computes `closure(want) \ closure(have)` by a reverse traversal, stopping at any hash in `have`. For very large histories a server MAY ask the client for the Merkle root of its known-hash set in 2^16-hash-prefix buckets and skip buckets whose roots match. The response is ordered so that no change precedes any of its dependencies.
662 662
663 -
### 16.3 Push validation
663 +
### 16.3 Message encodings
664 +
665 +
Every message is a deterministic CBOR map. Signatures use the encoding of §5.5; a change or attestation travels as its canonical bytes so the receiver hashes exactly what was signed.
666 +
667 +
| Message | Encoding |
668 +
|---|---|
669 +
| Signed attestation | `[attest bytes, [Signature]]` |
670 +
| `Bundle` | `{0: [[change bytes, [Signature]]], 1: [signed attestation], 2: [[type name, object bytes]]}`; changes in dependency order; objects are chunks, blobs, identities, and states only |
671 +
| `capabilities` response | `{0: [versions], 1: repo id bytes(16), 2: [feature names]}` |
672 +
| `refs` response | `{0: [{0: name, 1: state ref, 2: [heads], 3: signed attestation or null, 4: last serial or null}], 1: repo id}`; the attestation is present only when it describes the current state |
673 +
| `negotiate` request | `{0: [have], 1: [want]}`; response `{0: [hashes]}` in dependency order |
674 +
| `fetch` request | `{0: [hashes]}`; response a `Bundle` |
675 +
| `push` request | `{0: Bundle, 1: [{0: name, 1: old state, 2: new state, 3: force, 4: signed attestation or null}]}`; response `{0: [{0: name, 1: ok, 2: reason}]}` |
676 +
677 +
The HTTP content type is `application/oxy-cbor`. The `objects` and `checkpoint` endpoints of §16.1 are not yet specified in this form.
678 +
679 +
### 16.4 Push validation
664 680
665 681
On push, the server MUST, in order: verify that every change has a valid signature or seal from a key embedded in policy and satisfies the author-or-delegate rule (§14.4), verify the attestation for each reference, check that `old_state` matches its current state (compare-and-swap), check policy rules for the reference including `allow_conflicts`, check that every dependency of every change is either included or already stored, and only then update references atomically. A failure rejects the whole push.
666 682
…
135 unchanged lines
802 818
803 819
---
804 820
805 -
*Changelog.* Draft 0.5 (2026-09-26): bookmarks and tags point at a `state` object naming the heads, so attestations, views, and references carry one ObjectRef per bookmark however many heads it has; repository format 2 records this, and format-1 repositories migrate on open.
821 +
*Changelog.* Draft 0.5a (2026-09-26): §15.1 allows a reference server behind TLS termination and requires authenticated pushes when credentials exist; §16.3 defines the CBOR message encodings (push validation moves to §16.4).
822 +
823 +
Draft 0.5 (2026-09-26): bookmarks and tags point at a `state` object naming the heads, so attestations, views, and references carry one ObjectRef per bookmark however many heads it has; repository format 2 records this, and format-1 repositories migrate on open.
806 824
807 825
Draft 0.4b (2026-09-26): §5.5 records the encoding conventions for variants, references, views, signatures, and secret key files; §13.1 adds the signature directory.
808 826
…
7 unchanged lines