package host import ( "context" "encoding/json" "errors" "os" "github.com/carlosframework/platform/internal/moves" "github.com/carlosframework/platform/internal/rootparticipation" ) type rootFloorHealthy struct { Identity rootFloorIdentity Binary rootFloorBinary } // Only a successful root health gate supplies this observation. A signed file // alone proves identity, not that the box ever accepted it as healthy. func (f rootMovesFloors) acceptHealthy(ctx context.Context, b rootFloorBinary) error { if !b.supports(nil) { return errRootFloorHistory } unlock, err := f.private.Lock(ctx, "floor.lock") if err != nil { return err } defer unlock() old, err := f.healthy() if err != nil { return err } if old != nil { if at, _ := moves.ReleaseAtOrAbove(old.Version, b.Version); at { b = *old } } raw, _ := json.Marshal(rootFloorHealthy{Identity: f.identity, Binary: b}) if err := f.private.Write("healthy.json", raw); err != nil { return err } bound, err := f.localBound() if err != nil { return err } // A healthy observation never acknowledges a bound the observed build cannot meet. if !b.supports(bound) { return nil } generation := uint64(1) if r, err := f.record(rootFloorAccepted); err == nil { generation = r.Generation + 1 } r := rootFloorRecord{Schema: 1, Identity: f.identity, Generation: generation, Floor: bound, NeverArmed: bound == nil, Provenance: rootFloorReconstruction{Identity: f.identity, Source: "root health gate", Digest: b.Digest, Floor: bound, NeverArmed: bound == nil}} return f.persist(r, bound, true) } func (f rootMovesFloors) healthy() (*rootFloorBinary, error) { raw, err := f.private.Read("healthy.json") if errors.Is(err, os.ErrNotExist) { return nil, nil } if err != nil { return nil, err } var h rootFloorHealthy if rootparticipation.Decode(raw, &h) != nil || h.Identity != f.identity || !h.Binary.supports(nil) { return nil, nil } return &h.Binary, nil } func (f rootMovesFloors) capLegacy(legacy []*moves.Floor) ([]*moves.Floor, error) { h, err := f.healthy() if err != nil || h == nil { return nil, err } out := make([]*moves.Floor, 0, len(legacy)) for _, fl := range legacy { if !validRootFloor(fl) { continue } c := *fl if c.Min > h.Protocol { c.Min = h.Protocol } if at, _ := moves.ReleaseAtOrAbove(c.MinRelease, h.Version); at { c.MinRelease = h.Version } if validRootFloor(&c) { out = append(out, &c) } } return out, nil } func (a *systemApplier) acceptRootFloorHealthy(ctx context.Context) error { id, required, err := a.rootMoves.read() if err != nil || !required { return err } b, err := readRootFloorBinary(a.optDir, systemBinaryPath(a.optDir)) if err != nil { return err } f, err := openRootMovesFloors(a.optDir, id, true) if err != nil { return err } defer f.close() if err := f.acceptHealthy(ctx, b); err != nil { return err } bound, err := readRootSeedsBound(a.optDir, id) if err != nil || bound == nil { return err } seeds, err := openRootProtocolFloors(rootSeedsFloorDir(a.optDir), id, true) if err != nil { return err } defer seeds.close() return seeds.acceptHealthy(ctx, b.forSeeds()) }