OXYGENHUB

Wire Protocol

Andy McCall edited this page · 1 revision

Wire Protocol

Clients and servers speak one protocol over HTTPS, at https://HOST/REPO/oxy/v1/. Messages are deterministic CBOR. The transport only carries bytes: integrity comes from the objects themselves, which are hashed and signed, whatever channel they cross.

Endpoints

EndpointPurpose
GET capabilitiesprotocol versions, features, the repository id
GET refsevery bookmark and tag with its state, heads and attestation, plus the current trust policy
POST negotiatewhich changes the client lacks
POST fetchthose changes, the seals covering them, and their content
POST objectsparticular objects, such as blobs a partial clone skipped
GET checkpointthe nearest checkpoint, for shallow clones
POST pushchanges, objects, seals and the signed bookmark moves

A fetch

sequenceDiagram
    participant C as Client
    participant S as Server
    C->>S: GET capabilities
    S-->>C: versions, features, repository id
    C->>S: GET refs
    S-->>C: main = state S2 (heads, attestation), policy
    C->>C: check the attestation against the policy
    C->>S: POST negotiate (have: my heads, want: S2's heads)
    S-->>C: hashes of the changes I lack, in dependency order
    C->>S: POST fetch (those hashes)
    S-->>C: bundle: changes, seals, blobs, chunks
    C->>C: hash every object, check every seal or signature
    C->>C: move origin/main to S2

Negotiation is simple because history is a set: the server walks back from the wanted heads and stops at anything the client has. Changes always arrive after the changes they depend on.

A push

sequenceDiagram
    participant C as Client
    participant S as Server
    C->>S: GET refs
    S-->>C: main = S1
    C->>C: seal unsigned changes, sign attestation main: S1 to S2
    C->>S: POST push (bundle, update main S1 to S2, attestation)
    S->>S: signatures and seals, policy, old state is still S1,<br/>every dependency present
    alt all pass
        S->>S: move main atomically
        S-->>C: ok
    else any fails
        S-->>C: refused, with the reason
    end

A push either applies entirely or not at all.

Unbound repositories

A hub can create an empty repository with no id yet. The first push gives it the pusher's id, so an existing repository keeps its identity when it moves to a hub.

Implementers: the full message encodings are in docs/protocol.md and section 16 of the spec.