The join's importers name the delivery repository's moved contracts and sdk (MV1), node-tools' tests use mesh-sdk's gate, the duplicate node-engine claim rule of the reader release gives way to G's, and the assigner names its first watched branch, never a constant. The seat holders' AnswerSeat callers are area 6's. Builds: design 47 G join 11 (merge of fix round 11) Claude-Session: https://claude.ai/code/session_01NcbgfGKaxw984XyAPfLm4h
101 lines
3.8 KiB
Go
101 lines
3.8 KiB
Go
// Package approval is the tool runner's side of mesh-sdk's approval gate (go/approval; design 47 G lead answers A-224,
|
|
// A-228): it translates what the gate reads beyond itself from the generated contracts, the gate's findings into the
|
|
// contract's findings about the runner on its machine, the catalog's entries into the gate's, and the assigner's view of
|
|
// the seats' holders into its holder function. The gate itself is mesh-sdk's; none is written here.
|
|
package approval
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"fmt"
|
|
"time"
|
|
|
|
assignerseat "git.novox.be/novox/mesh-contracts/go/seats/meshmoduleassigner"
|
|
condseat "git.novox.be/novox/mesh-contracts/health-and-repair/go/seats/meshconditions"
|
|
catalogseat "git.novox.be/novox/mesh-delivery/modules/mesh-delivery-contracts/go/seats/meshcatalog"
|
|
gate "git.novox.be/novox/mesh-sdk/go/approval"
|
|
"git.novox.be/novox/mesh-sdk/go/views"
|
|
)
|
|
|
|
// HeldWriter is the runner's held finding writer (views.HeldWriter over the contract's Finding).
|
|
type HeldWriter interface {
|
|
Write(ctx context.Context, finding condseat.Finding) error
|
|
Clear(ctx context.Context, scope, id, kind, why string) error
|
|
}
|
|
|
|
// scopeMachine is the scope of the gate's findings on the tool runner: its machine (lead answer A-154).
|
|
const scopeMachine = "machine"
|
|
|
|
// Findings is the gate's finding writer over the runner's held writer: each finding about the runner's module on node, at
|
|
// scope machine, and its pending named in the writer's `findings-stated` where the writer keeps one (design 47 G §384).
|
|
func Findings(w HeldWriter, node, runner string, now func() time.Time) gate.FindingWriter {
|
|
if w == nil {
|
|
return nil
|
|
}
|
|
if now == nil {
|
|
now = time.Now
|
|
}
|
|
return findingWriter{w: w, node: node, runner: runner, now: now}
|
|
}
|
|
|
|
type findingWriter struct {
|
|
w HeldWriter
|
|
node, runner string
|
|
now func() time.Time
|
|
}
|
|
|
|
func (f findingWriter) Raise(ctx context.Context, kind, id, summary, headline string) error {
|
|
return f.w.Write(ctx, condseat.Finding{Kind: kind, Scope: scopeMachine, ID: id, Severity: condseat.FindingSeverityWarning,
|
|
Source: "approval", Observer: f.runner, Subject: condseat.Subject{Scope: "module", ID: f.runner, Machine: f.node},
|
|
Summary: summary, Headline: headline, At: f.now().UTC()})
|
|
}
|
|
|
|
func (f findingWriter) Clear(ctx context.Context, kind, id, why string) error {
|
|
return f.w.Clear(ctx, scopeMachine, id, kind, why)
|
|
}
|
|
|
|
// pender is the held writer's pending (views.HeldWriter's Pend and Judged).
|
|
type pender interface {
|
|
Pend(views.PendingKey)
|
|
Judged(key string)
|
|
}
|
|
|
|
func (f findingWriter) Pend(kind, id string, since time.Time, bound time.Duration) {
|
|
if p, ok := f.w.(pender); ok {
|
|
p.Pend(views.PendingKey{Key: views.FindingKey(scopeMachine, id, kind), Since: since, Bound: bound.String()})
|
|
}
|
|
}
|
|
|
|
func (f findingWriter) Judged(kind, id string) {
|
|
if p, ok := f.w.(pender); ok {
|
|
p.Judged(views.FindingKey(scopeMachine, id, kind))
|
|
}
|
|
}
|
|
|
|
// Entry is a catalog entry as the gate reads its marks.
|
|
func Entry(e catalogseat.CatalogEntry) gate.Entry {
|
|
manifest, _ := json.Marshal(e.Manifest)
|
|
return gate.Entry{Module: e.Module, Fingerprint: e.Fp, Serves: e.Serves, Manifest: manifest}
|
|
}
|
|
|
|
// HoldersIn is the gate's holder function over the assigner's view of the seats' holders as the runner holds it (§19):
|
|
// view answers the view's values by key, an error while its first view is not answered; a seat is held when its key names
|
|
// a holder.
|
|
func HoldersIn(view func() (map[string][]byte, error)) func(seat string) (bool, error) {
|
|
return func(seat string) (bool, error) {
|
|
values, err := view()
|
|
if err != nil {
|
|
return false, err
|
|
}
|
|
raw, ok := values[assignerseat.SeatHoldersBySeatKey(seat)]
|
|
if !ok {
|
|
return false, nil
|
|
}
|
|
var h assignerseat.SeatHolders
|
|
if err := json.Unmarshal(raw, &h); err != nil {
|
|
return false, fmt.Errorf("the holders of %s cannot be read: %w", seat, err)
|
|
}
|
|
return len(h.Holders) > 0, nil
|
|
}
|
|
}
|