Say a machine waiting for its push as waiting, not uncomposable (hq issue 275)
Between assign and push a module's own secrets are not made yet; D1 composed without making them and raised an urgent 'nothing can be sent' that the next push resolved silently. D1 now composes as the push would (Foreseeing): a secret the push makes gets a stand-in and is named, one the push is refused on is refused with the push's words. Waiting is said only past 30 minutes, as a warning. D3 and D13 expect a holder only once its machine was sent it and reported or had ten minutes to.
This commit is contained in:
@@ -87,6 +87,12 @@ type Rendering struct {
|
||||
// Needed is each module's own secrets, sealed to this node, keyed by module and then by the
|
||||
// name the module gave it.
|
||||
Needed map[string]map[string]string
|
||||
// Foreseen is each own secret not made yet that the next send WILL make, keyed like Needed: a
|
||||
// composition asked ahead of the send (the self-check's D1) composes it with ForeseenSealed in
|
||||
// its place and lists it in Composed.Foreseen, rather than failing for a value only a send
|
||||
// makes. Nil on every composition that is sent, and on every other question, which then refuse
|
||||
// a secret not made with a *NotMadeError.
|
||||
Foreseen map[string]map[string]bool
|
||||
|
||||
// Mesh is every node's address on the private network, which is what a rule saying "from the
|
||||
// mesh" resolves to. Passed in for the same reason grants are: who else is on the network is
|
||||
@@ -275,6 +281,25 @@ type Composed struct {
|
||||
// compose. Its held things are kept and its containers untouched — the machine is told so —
|
||||
// and it is told everything else.
|
||||
LeftOut map[string]string
|
||||
// Foreseen is every own secret composed with ForeseenSealed in its place (Rendering.Foreseen),
|
||||
// as `module/name`, sorted: what the next send will make. Never set on a declaration that is
|
||||
// sent — a placeholder in a sealed file is a credential the process cannot read.
|
||||
Foreseen []string
|
||||
}
|
||||
|
||||
// ForeseenSealed is what stands for an own secret a send will make, in a composition asked ahead of
|
||||
// the send. Not a sealed value: nothing composed with it may be sent.
|
||||
const ForeseenSealed = "foreseen: made by the next send"
|
||||
|
||||
// NotMadeError is a module's own secret the composition was given no value for (novox/hq issue 275):
|
||||
// typed, so that a caller can tell "a send would make this, and none has yet" from a composition that
|
||||
// fails for any other reason without reading the words.
|
||||
type NotMadeError struct {
|
||||
Module, Name string
|
||||
}
|
||||
|
||||
func (e *NotMadeError) Error() string {
|
||||
return fmt.Sprintf("%s needs a secret called %q and none was made for it", e.Module, e.Name)
|
||||
}
|
||||
|
||||
// LeftOut is which of this machine's modules a declaration composed with these settings leaves
|
||||
@@ -295,10 +320,12 @@ func (r Resolution) Compose(with Rendering) (Composed, error) {
|
||||
owner := map[string]string{}
|
||||
received := map[string]map[string][]Contribution{}
|
||||
leftOut := map[string]string{}
|
||||
resources, err := r.compose(with, owner, received, leftOut)
|
||||
var foreseen []string
|
||||
resources, err := r.compose(with, owner, received, leftOut, &foreseen)
|
||||
if err != nil {
|
||||
return Composed{}, err
|
||||
}
|
||||
sort.Strings(foreseen)
|
||||
if with.BusMembership != "" {
|
||||
// The machine's own, not any module's: how it reaches the mesh from now on. Sealed like a
|
||||
// secret and placed where the host looks for exactly this (design 28, task 5.2).
|
||||
@@ -307,7 +334,8 @@ func (r Resolution) Compose(with Rendering) (Composed, error) {
|
||||
"sealed": with.BusMembership, "mode": "0600",
|
||||
})
|
||||
}
|
||||
return Composed{Resources: resources, Owner: owner, Received: received, LeftOut: leftOut}, nil
|
||||
return Composed{Resources: resources, Owner: owner, Received: received, LeftOut: leftOut,
|
||||
Foreseen: foreseen}, nil
|
||||
}
|
||||
|
||||
// BusMembershipID names the resource carrying a machine's membership for the new bus, and
|
||||
@@ -317,7 +345,8 @@ func BusMembershipID() string { return "bus-membership" }
|
||||
const BusMembershipPath = "/var/lib/mesh/membership-next.json"
|
||||
|
||||
func (r Resolution) compose(with Rendering, owner map[string]string,
|
||||
received map[string]map[string][]Contribution, leftOut map[string]string) ([]map[string]any, error) {
|
||||
received map[string]map[string][]Contribution, leftOut map[string]string,
|
||||
foreseen *[]string) ([]map[string]any, error) {
|
||||
// **A setting is judged where it is stored, and an impossible one costs a module, not a
|
||||
// machine** (novox/hq ADR 0163, rule 6). A definition that moved under a stored setting makes
|
||||
// this module uncomposable; it is left out of the declaration — its held things kept, its
|
||||
@@ -534,12 +563,17 @@ func (r Resolution) compose(with Rendering, owner map[string]string,
|
||||
}
|
||||
for _, name := range sortedKeys(m.OwnSecrets) {
|
||||
sealed := with.Needed[m.Module][name]
|
||||
if sealed == "" && with.Foreseen[m.Module][name] {
|
||||
// Not made, and the next send makes it: composed with a stand-in so that whatever
|
||||
// else this composition would refuse is still found (novox/hq issue 275).
|
||||
sealed = ForeseenSealed
|
||||
*foreseen = append(*foreseen, m.Module+"/"+name)
|
||||
}
|
||||
if sealed == "" {
|
||||
// Declared and not made. Refused rather than skipped: a module whose own
|
||||
// credential is silently absent starts, fails to authenticate, and the reason is
|
||||
// three layers away from the machine reporting it.
|
||||
return nil, fmt.Errorf(
|
||||
"%s needs a secret called %q and none was made for it", m.Module, name)
|
||||
return nil, &NotMadeError{Module: m.Module, Name: name}
|
||||
}
|
||||
// The runtime's credential belongs to the account the runtime runs as (novox/hq ADR 0175,
|
||||
// to-be 38 WP3): its process is composed `user: <account>` where the node has one, and a
|
||||
|
||||
Reference in New Issue
Block a user