Trust Policy
A trust policy lives in the repository and says which keys may move which bookmarks. Servers enforce it on push; clients enforce it on fetch. Without one, a repository is unverified and every remote command says so.
classDiagram
class Policy {
repo: repository id
serial: only goes up
roots: keys and a threshold
rules: one per bookmark pattern
identities: embedded, so checking needs no fetch
revoked: keys
expires
}
class Rule {
pattern: e.g. main, release/*
keys
threshold
require: signed, sealed or any
allow_conflicts
}
Policy "1" *-- "many" Rule
oxy policy init # your key becomes the only root
oxy policy grant alice.identity # from her `oxy identity export`
oxy policy grant ci.identity --pattern 'release/*'
oxy policy revoke 9458b656
oxy policy show
oxy push # publishes the policy
How a push is checked
flowchart TD
P[Push arrives] --> A{Every new change signed or sealed<br/>by its author or a delegate?}
A -->|no| X[Refuse the whole push]
A -->|yes| B{Attestation signed by a key<br/>the rule for this bookmark lists?}
B -->|no| X
B -->|yes| C{Bookmark still at the old state?}
C -->|no| X
C -->|yes| D{Conflicts allowed here,<br/>or none?}
D -->|no| X
D -->|yes| OK[Move the bookmark]
Changing the policy
Every new policy must be signed by the root threshold of the policy it replaces, and have a higher serial. With more than one root required, an update you make alone becomes a proposal file for the other root holders:
sequenceDiagram
participant Ada as Ada (root)
participant Bob as Bob (root)
participant Repo as Remote
Ada->>Ada: oxy policy grant carol.identity
Note over Ada: threshold is 2: writes policy-7.proposal
Ada->>Bob: sends policy-7.proposal
Bob->>Bob: oxy policy sign policy-7.proposal
Bob->>Repo: oxy push (publishes policy 7)
Repo-->>Ada: next fetch: policy 7, checked against policy 6
A client remembers the highest policy serial each remote has shown, and refuses a remote that later shows a lower one or none. The very first policy a repository sees vouches for itself (trust on first use).