Compose each node's provisioning plans from the bus alone, in a Planning mode that reads no secret, so mesh-provisioner composes the plans the controller did (issue 1954 L6-P1, ADR 0570 clause 2)
This commit is contained in:
@@ -23,6 +23,10 @@ const (
|
||||
// Foreseeing composes an own secret the next send would make with a stand-in and names it foreseen, while one the send would
|
||||
// refuse (a bus credential nobody issued, a given secret under an old key) is refused here, in the same words.
|
||||
Foreseeing
|
||||
// Planning composes for a provisioning plan alone (novox/hq ADR 0570 clause 2): every own secret the Input holds none
|
||||
// for stands in, named foreseen, and nothing is refused for a value, since a plan names secrets and never carries one.
|
||||
// The seat mesh-provisioner's holder composes so, reading no secret; a rendering in this mode is never applied.
|
||||
Planning
|
||||
)
|
||||
|
||||
// ForeseenCertificate and ForeseenBusUsers stand for what the Input does not carry, in a composition asked ahead of the send.
|
||||
@@ -344,6 +348,10 @@ func (c *composer) ownSecretsFor(node Node, plan catalogue.Resolution, handing c
|
||||
continue
|
||||
}
|
||||
sealed, held := c.moduleSecretIfIssued(node, m.Module, name)
|
||||
if !held && mode == Planning {
|
||||
mark(m.Module, name)
|
||||
continue
|
||||
}
|
||||
if !held && mode == Foreseeing {
|
||||
// Asked ahead of the send: what the send would do about it, by the send's own rules. Made by it -- a stand-in,
|
||||
// named; refused by it -- refused here, the same words (novox/hq issue 275).
|
||||
|
||||
@@ -426,6 +426,48 @@ func Compose(ctx context.Context, r Reader, mesh Mesh, s Scope, fps map[string]s
|
||||
return out, skipped, held, err
|
||||
}
|
||||
|
||||
// Plans is the provisioning plan of each module handed to the provisioner on the scope's node, composed from the bus
|
||||
// alone (novox/hq ADR 0570 clause 2): the controller's handedPlans over the same input (mesh-control
|
||||
// cmd/mesh-controller/compose_sdk.go), its rendering in the Foreseeing mode with the mesh's generators. A plan names
|
||||
// templates, files, own secrets by name, items, collections and provisions, never a value, so no value is read for it:
|
||||
// the seat mesh-provisioner's holder composes every node's plans with a Reader that reads no secret.
|
||||
func Plans(ctx context.Context, r Reader, mesh Mesh, s Scope) (map[string]catalogue.Plan, error) {
|
||||
in, err := Input(ctx, r, mesh, s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return PlansOf(in, s.Node)
|
||||
}
|
||||
|
||||
// PlansOf is Plans over an input already filled, rendered in the Planning mode (compose.Planning): every own secret the
|
||||
// input holds none for stands in, so no value and no record of one is needed.
|
||||
func PlansOf(in compose.Input, node string) (map[string]catalogue.Plan, error) {
|
||||
return plansIn(in, node, compose.Planning)
|
||||
}
|
||||
|
||||
// plansIn is the controller's handedPlans in a mode: Foreseeing is the controller's own.
|
||||
func plansIn(in compose.Input, node string, mode compose.Mode) (map[string]catalogue.Plan, error) {
|
||||
resolved, err := compose.Resolve(in, node)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("frombus: the plans of %s: %w", node, err)
|
||||
}
|
||||
rendered, err := compose.Render(in, node, mode)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("frombus: the plans of %s: %w", node, err)
|
||||
}
|
||||
gens, err := compose.Generators(in)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("frombus: the plans of %s: %w", node, err)
|
||||
}
|
||||
with := rendered.Rendering
|
||||
with.Generators = gens
|
||||
composed, err := resolved.Plan.Compose(with)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("frombus: the plans of %s: %w", node, err)
|
||||
}
|
||||
return composed.Plans, nil
|
||||
}
|
||||
|
||||
// parser reads a manifest as the indexer does, against the mesh's predefined keys when given.
|
||||
func parser(mesh Mesh) func([]byte) (catalogue.Manifest, error) {
|
||||
return func(raw []byte) (catalogue.Manifest, error) {
|
||||
|
||||
@@ -694,6 +694,24 @@ func TestInput(t *testing.T) {
|
||||
wj, _ := json.MarshalIndent(fromStoreMoved, "", " ")
|
||||
t.Errorf("composed from the build differs from the controller's take-in:\n got %s\nwant %s", gj, wj)
|
||||
}
|
||||
// ADR 0570 clause 2 (issue 1954 L6-P1): the seat mesh-provisioner's plans, composed from the bus alone and with no
|
||||
// secret read (the Planning mode), are the controller's handedPlans over its own input, which holds its secrets
|
||||
// (compose_sdk.go: Resolve, Render in Foreseeing, Generators, Plan.Compose), and restic, handed, has one.
|
||||
noSecrets := movedMesh(true)
|
||||
noSecrets.own = nil
|
||||
seat, err := Plans(ctx, noSecrets, Mesh{}, Scope{Node: "n1"})
|
||||
if err != nil {
|
||||
t.Fatalf("the plans from the bus: %v", err)
|
||||
}
|
||||
controllers, err := plansIn(storeIn, "n1", compose.Foreseeing)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if _, handed := seat["restic"]; !handed || !reflect.DeepEqual(seat, controllers) {
|
||||
gj, _ := json.MarshalIndent(seat, "", " ")
|
||||
wj, _ := json.MarshalIndent(controllers, "", " ")
|
||||
t.Errorf("the seat's plans differ from the controller's:\n got %s\nwant %s", gj, wj)
|
||||
}
|
||||
|
||||
// And what a provider on another node serves from its settings (mailu's smtp domain, issue 1126: shanks refused
|
||||
// '${setting:domain} ... nothing sets "domain"'): read for that provider's served keys alone, through Served.
|
||||
|
||||
@@ -71,7 +71,7 @@ func (c *composer) render(nodeName string, mode Mode) (Rendered, error) {
|
||||
return Rendered{}, err
|
||||
}
|
||||
r.Needed = needed
|
||||
if mode == Foreseeing || len(foreseenOwn) > 0 {
|
||||
if mode == Foreseeing || mode == Planning || len(foreseenOwn) > 0 {
|
||||
r.Foreseen = foreseenOwn
|
||||
}
|
||||
var names []string
|
||||
|
||||
Reference in New Issue
Block a user