A node applying what it composed refuses a composition that stands in for anything its input lacks, the bus's user list alone held out (issue 1126, ADR 0547 §2)
This commit is contained in:
@@ -2,8 +2,10 @@ package compose
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"git.novox.be/novox/mesh-sdk/go/declaration"
|
||||
"git.novox.be/novox/mesh-sdk/go/delivery"
|
||||
@@ -16,6 +18,26 @@ import (
|
||||
// (mesh-hand-compose) gets that one. Each module's Data says whether its manifest declares data. The compositions are not
|
||||
// signed and not yet by digest: the writer does both (delivery.SignComposed, Composed.ByDigest).
|
||||
func Compositions(in Input, node string, fps map[string]string, mode Mode) (out map[string]delivery.Composed, skipped []string, err error) {
|
||||
return compositions(in, node, fps, mode, false)
|
||||
}
|
||||
|
||||
// ErrStoodIn is a composition that holds a stand-in for a value the input does not carry (an own secret, a grant's
|
||||
// sealed copy, a vault box, the certificate, the bus's user list) or a port it does not give: what a send would make,
|
||||
// never what may be applied.
|
||||
var ErrStoodIn = errors.New("compose: the composition stands in for what its input does not carry")
|
||||
|
||||
// BusUsersStandIn is what a composition says it stood in for when its input carries no bus user list.
|
||||
const BusUsersStandIn = "the bus's user list"
|
||||
|
||||
// CompositionsApplied is Compositions for a node that applies what it composed itself (novox/hq ADR 0547 §2, issue
|
||||
// 1126): a declaration that stands in for anything (Declared.StoodIn, Foreseen, ForeseenPorts) is refused with
|
||||
// ErrStoodIn, naming each, so a stand-in is never applied as if it were the value; but for the bus's user list
|
||||
// (BusUsersStandIn), which the bus node holds out of every apply of a composition it made itself.
|
||||
func CompositionsApplied(in Input, node string, fps map[string]string) (map[string]delivery.Composed, []string, error) {
|
||||
return compositions(in, node, fps, Reading, true)
|
||||
}
|
||||
|
||||
func compositions(in Input, node string, fps map[string]string, mode Mode, applied bool) (out map[string]delivery.Composed, skipped []string, err error) {
|
||||
reading := in
|
||||
reading.Nodes = append([]Node(nil), in.Nodes...)
|
||||
found := false
|
||||
@@ -35,6 +57,24 @@ func Compositions(in Input, node string, fps map[string]string, mode Mode) (out
|
||||
if len(problems) > 0 {
|
||||
return nil, nil, fmt.Errorf("compose: %s's declaration is refused by the node-engine's validator: %v", node, problems)
|
||||
}
|
||||
if applied {
|
||||
var stood []string
|
||||
for _, x := range d.StoodIn {
|
||||
// The bus's user list is the bus node's own to follow, written alone and never from a composition the node
|
||||
// made itself (ADR 0547 §7, §8): its stand-in is held out of the apply, not applied.
|
||||
if x != BusUsersStandIn {
|
||||
stood = append(stood, x)
|
||||
}
|
||||
}
|
||||
stood = append(stood, d.Foreseen...)
|
||||
for _, p := range d.ForeseenPorts {
|
||||
stood = append(stood, "port "+p)
|
||||
}
|
||||
if len(stood) > 0 {
|
||||
sort.Strings(stood)
|
||||
return nil, nil, fmt.Errorf("%w on %s: %s", ErrStoodIn, node, strings.Join(stood, ", "))
|
||||
}
|
||||
}
|
||||
body, err := d.Body()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
|
||||
@@ -2,6 +2,7 @@ package compose
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"strings"
|
||||
"testing"
|
||||
|
||||
@@ -78,6 +79,16 @@ func TestAnOwnSecretHeldIsCarriedAndOneNotHeldIsForeseenOrLeftOut(t *testing.T)
|
||||
t.Errorf("a held secret with no value is not named: %v", got.Rendering.Foreseen)
|
||||
}
|
||||
unchanged(t, mk, func(in Input) { rendered(t, in, "laptop", Foreseeing) })
|
||||
|
||||
// 1126 (ADR 0547 §2): a node applying what it composed itself never applies a stand-in: a held secret with no value in the
|
||||
// Input is refused, naming it; held with its value, it composes.
|
||||
fps := map[string]string{"assistant": "src2:" + strings.Repeat("a", 64), overlay.Name: "src2:" + strings.Repeat("b", 64)}
|
||||
if _, _, err := CompositionsApplied(in, "laptop", fps); !errors.Is(err, ErrStoodIn) || !strings.Contains(err.Error(), "assistant/password") {
|
||||
t.Errorf("a stand-in was not refused for a node's own apply: %v", err)
|
||||
}
|
||||
if out, _, err := CompositionsApplied(mk(), "laptop", fps); err != nil || len(out) == 0 {
|
||||
t.Errorf("a held secret with its value is refused for a node's own apply: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// An own secret issued outside the mesh that nobody gave is never made (novox/hq issue 401, ADR 0228): nothing is composed or
|
||||
|
||||
@@ -201,14 +201,15 @@ func Input(ctx context.Context, r Reader, mesh Mesh, s Scope) (compose.Input, er
|
||||
return in, nil
|
||||
}
|
||||
|
||||
// Compose is the node's compositions over the bus (ADR 0547 §2): Input for s, then compose.Compositions in the Reading
|
||||
// mode at the fingerprints fps gives each module, as the controller composes them.
|
||||
// Compose is the node's compositions over the bus (ADR 0547 §2): Input for s, then compose.CompositionsApplied at the
|
||||
// fingerprints fps gives each module: composed in the Reading mode as the controller composes them, and refused when it
|
||||
// stands in for anything the input does not carry (compose.ErrStoodIn), since the node applies what it composed.
|
||||
func Compose(ctx context.Context, r Reader, mesh Mesh, s Scope, fps map[string]string) (map[string]delivery.Composed, []string, error) {
|
||||
in, err := Input(ctx, r, mesh, s)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
return compose.Compositions(in, s.Node, fps, compose.Reading)
|
||||
return compose.CompositionsApplied(in, s.Node, fps)
|
||||
}
|
||||
|
||||
// nodeOf is the composition's node from its record (what the machine observes) and its placement (what a person
|
||||
|
||||
@@ -113,7 +113,7 @@ func (c *composer) render(nodeName string, mode Mode) (Rendered, error) {
|
||||
r.BusUsers = c.in.BusUsers
|
||||
if r.BusUsers == "" {
|
||||
r.BusUsers = ForeseenBusUsers
|
||||
foreseen("the bus's user list")
|
||||
foreseen(BusUsersStandIn)
|
||||
}
|
||||
if len(c.in.BusMissing) > 0 {
|
||||
out.Said = append(out.Said, fmt.Sprintf("the bus's user list leaves out %d user(s) the mesh has minted no credential "+
|
||||
|
||||
Reference in New Issue
Block a user