The control plane declares, and hears back
`declare` sends a node a signed declaration; `serve` now also consumes reports. Signed over the exact bytes published, which is what the node verifies. Anything re-encoding in between would sign one thing and check another, and a difference in key order alone would have a node refuse a declaration that was genuinely the mesh's. Sent to the node's queue directly rather than through the exchange: a declaration is for one node, and routing by name through a shared exchange means a binding per node that nothing removes when a node is retired. Enrolment now issues the node its own broker password, replacing the token's secret, and tells it the broker address, the fingerprint and the signing key -- so a node can reconnect after a restart without a person and a new token, which is what makes disconnection ordinary rather than a crisis. A report is a statement, not a write. What a node says it applied is its own account of its own machine, kept as a copy for recovery rather than as a source.
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
package link
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestTheWireFormatIsExactlyTheseFieldNames(t *testing.T) {
|
||||
// The contract with the host, which defines these separately because it requires nothing
|
||||
// present and does not import this. A matching test lives there; rename a field on either
|
||||
// side and both fail, rather than the mismatch surfacing on a real machine.
|
||||
for _, c := range []struct {
|
||||
value any
|
||||
expect []string
|
||||
}{
|
||||
{Signed{Declaration: []byte("{}"), Signature: []byte("x")}, []string{"declaration", "signature"}},
|
||||
{Report{Node: "n", Applied: []string{"a"}, Failed: map[string]string{"k": "v"}, Refused: "r"},
|
||||
[]string{"node", "applied", "failed", "refused"}},
|
||||
{EnrolRequest{Node: "n", Secret: "s", PublicKey: []byte("k")},
|
||||
[]string{"node", "secret", "public_key"}},
|
||||
} {
|
||||
raw, err := json.Marshal(c.value)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
var fields map[string]any
|
||||
if err := json.Unmarshal(raw, &fields); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
for _, want := range c.expect {
|
||||
if _, ok := fields[want]; !ok {
|
||||
t.Errorf("%T has no %q field; the host reads that name", c.value, want)
|
||||
}
|
||||
}
|
||||
if len(fields) != len(c.expect) {
|
||||
t.Errorf("%T has %d fields, expected %d: %v", c.value, len(fields), len(c.expect), fields)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user