carlos / platform Public

Clone
git clone https://amadan.net/carlos/platform

Plain git — no account needed to clone.

Download

Download this file

1package release
2
3import (
4 "context"
5 "crypto/ed25519"
6
7 "github.com/carlosframework/platform/internal/registry"
8)
9
10// StageHeld is a held row's staging step, ensureStaged, with nothing
11// published: the version lands in the version store and live/<host> is
12// left alone. It refuses while CARLOS_HOST_CLAIM is on, and a refused write
13// is ErrStageBlocked wrapping the cause.
14//
15// It stages only a build §4.1 authorizes (settings spec rev 11 §4.3a):
16// HeldAuthorized, under pub and the box's ratchet r, answers first, and the
17// staging binds the digest it returns. A build nothing authorizes is
18// ErrHeldNotAuthorized, and nothing is downloaded.
19func StageHeld(ctx context.Context, s Store, pub ed25519.PublicKey, r *DigestRatchet, optDir string, rt registry.Route, version string) (*Manifest, error) {
20 if err := heldStageable(rt, version); err != nil {
21 return nil, err
22 }
23 return stageHeld(ctx, s, pub, r, optDir, rt, version)
24}
25
26// PublishHeld points live/<host> at a staged version, and does it inside
27// guard: guard re-checks whatever authorised the stage (for the root relay,
28// the registry hold frozen and the host claim re-read) and calls publish
29// only if that still holds, as its last step. Staging can take minutes, so
30// an authority checked only before it could be stale by now: a move aborted
31// or replaced meanwhile must never have live/<host> repointed for it. A nil
32// guard is refused: nothing is published on a request's word alone.
33//
34// Before guard it runs D3 as adoption does (admit, then bind on the staged
35// bytes), so a release the box's proof policy does not admit is
36// ErrHeldNotProven and live/<host> is untouched. A nil proof is refused.
37func PublishHeld(ctx context.Context, s Store, optDir string, rt registry.Route, version string, proof *ProofGate, guard func(publish func() error) error) error {
38 if err := heldStageable(rt, version); err != nil {
39 return err
40 }
41 if guard == nil {
42 return errHeldNoGuard
43 }
44 if proof == nil {
45 return errHeldNoProofGate
46 }
47 proof.BeginPass()
48 ptr, v, err := heldProofAdmit(ctx, s, optDir, rt, version, proof)
49 if err != nil {
50 return err
51 }
52 return publishHeld(optDir, rt, version, proof, ptr, v, guard)
53}
54
55// ServeHeldStageRequests is the root side of the held-stage relay, run by
56// `carlos adopt` after its release adoption. For each <name>.json in
57// HeldStageDir it validates every field before any filesystem effect (Host
58// equal to name and a valid host shape, valid account, app and version, a
59// non-empty op and box), asks authorize, stages, asks authorize again with
60// the publication as its then, writes the HeldStaged ack and removes the
61// request. A request that fails validation, that authorize refuses at
62// either point with ErrStaleHeldStage, that D3 refuses (proof, as
63// MaterializeHeld applies it: ErrHeldNotProven), or that §4.1 does not
64// authorize (ErrHeldNotAuthorized, or a build that does not hash to its
65// authorizing digest: ErrManifestDigest) is removed with a log line,
66// and live/<host> is never repointed for it. A request whose staging, ack or
67// publication fails any other way is kept for the next pass. With no
68// request directory it reads nothing and creates nothing.
69//
70// authorize(req, then) checks req and, if it passes, runs then (when
71// non-nil) under whatever guard keeps the check true until then returns.
72// Before staging it is called with a nil then.
73//
74// The directory is agent-owned and this runs as root, so every read, write
75// and removal goes through safefile: no symlink is followed at any
76// component, and only a regular file with one link is read.
77func ServeHeldStageRequests(ctx context.Context, s Store, pub ed25519.PublicKey, r *DigestRatchet, optDir, dataDir string, proof *ProofGate, authorize func(req HeldStageRequest, then func() error) error) error {
78 return ServeHeldStageRequestsWithPins(ctx, s, pub, r, optDir, dataDir, proof, authorize)
79}
80