package link import ( "encoding/json" "slices" "sort" "sync" "time" "git.novox.be/novox/mesh-sdk/go/catalogue" "git.novox.be/novox/mesh-sdk/go/delivery" ) // The node's record (novox/hq ADR 0555 §3, issue 1126): what the machine observes of itself, written in its own have key // `.node` (delivery.HaveNode.Record) with its facts, so every node and the parts that compose read it from the bus // and hear its change as the key's. Each value is the one the controller took from this node's enrolment and reports // until now (its profile's present capabilities and networks, its outward links, its health statement's contract, and // the public halves of the keys it enrolled with), read here from the same sources, never from the controller. // RecordKeys are the public halves the node holds and the certificate the mesh issued for its internal name, as read // from its state directory at the time of a pass: the certificate arrives after enrolment, a rekey changes the tunnel key. type RecordKeys struct { TunnelKey string SealingKey string ServingKey string Certificate string // Authority is the mesh's own certificate as this machine last applied it (public). Authority string // Trusts is what this machine trusts a mesh signature from now (delivery.Trusts, ADR 0550 §2). Trusts []string // Stated is the capabilities its tool runner states of the calls it answers (CapabilitiesKey), which the record says // beside the machine's own: a module whose manifest asks for one is held off a machine whose runner does not state it. Stated []string } // manifestReads is what this engine reads of a manifest (novox/hq ADR 0614 §4): the reader capabilities of the mesh-sdk it // is built with, stated in its record so the assigner moves a want only to an engine that reads its manifest. Computed // once: it is the build's, and never changes while it runs. var manifestReads = sync.OnceValue(catalogue.ManifestReads) // readsStatedAt is when this engine computed what it reads: its start (the verb manifest-reads, ADR 0618 §3). var readsStatedAt = time.Now().UTC() // recordOf is the node's record from one facts report and its keys; nil for a report that carries no profile (one that // says nothing of the machine, such as a rekey), so the record last written stands. func recordOf(node string, r Report, keys RecordKeys) *delivery.NodeRecord { if r.Profile == nil { return nil } var p struct { Capabilities []struct { Name string `json:"name"` Present bool `json:"present"` } `json:"capabilities"` Machine *struct { Networks []catalogue.AttachedNetwork `json:"networks"` } `json:"machine"` } raw, err := json.Marshal(r.Profile) if err != nil || json.Unmarshal(raw, &p) != nil { return nil } rec := &delivery.NodeRecord{V: delivery.Version, Node: node, TunnelKey: keys.TunnelKey, SealingKey: keys.SealingKey, ServingKey: keys.ServingKey, Certificate: keys.Certificate, Authority: keys.Authority, Trusts: keys.Trusts, ManifestReads: manifestReads()} for _, c := range p.Capabilities { if c.Present && c.Name != "" { rec.Capabilities = append(rec.Capabilities, c.Name) } } for _, c := range keys.Stated { if c != "" && !slices.Contains(rec.Capabilities, c) { rec.Capabilities = append(rec.Capabilities, c) } } sort.Strings(rec.Capabilities) if p.Machine != nil { rec.NetworksSaid = true rec.Networks = p.Machine.Networks } if len(r.Outward) > 0 { rec.OutwardLinks = append([]string(nil), r.Outward...) } if r.Health != nil { rec.Contract = r.Health.Contract } return rec }