mesh/merge-gate pass: builds build-agent, mesh-controller, route-proxy → ace, g14, novox, shanks; no bus step; every machine composes with the change as it…
mesh/repo-check pass: its merge-check.sh passed
mesh/delivery delivered
mesh/delivery-group group fix/358-judge-directories-read-only delivered: every member is delivered
Before the node-engine gives a mesh directory its mode and owner only through a walk that follows no link another account could make, the operator is to see which directories that walk would refuse on every node, the control-node included, where no tool reads a path. `node judge-directories <node>` signs the ask as a hand-over is, under its own context, and prints the engine's one line per directory; it changes nothing, so it is a seat verb an agent may call. The node is granted the subject, the controller alone its publish.
61 lines
2.4 KiB
Go
61 lines
2.4 KiB
Go
package link
|
|
|
|
import (
|
|
"context"
|
|
"crypto/ed25519"
|
|
"encoding/json"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/nats-io/nats.go"
|
|
|
|
"github.com/novox/mesh-controller/internal/broker"
|
|
"github.com/novox/mesh-controller/internal/testbus"
|
|
)
|
|
|
|
// A judgement of a machine's directories is asked of the machine on its own subject, signed under its own context
|
|
// (never a hand-over's), naming no path, and the engine's answer comes back (novox/hq issue 358). The engine holds the
|
|
// same subject and context (mesh-host internal/link, TestTheDirectoryJudgementAskKeepsItsSubjectAndContext).
|
|
func TestADirectoryJudgementIsAskedOfTheMachineSignedUnderItsOwnContext(t *testing.T) {
|
|
if broker.AskJudgeDirectoriesSubject("laptop") != "mesh.node.laptop.ask.judge-directories" ||
|
|
JudgeDirectoriesContext != "novox-mesh judge-directories v1\n" {
|
|
t.Fatalf("the subject %q, the context %q", broker.AskJudgeDirectoriesSubject("laptop"), JudgeDirectoriesContext)
|
|
}
|
|
conn, err := nats.Connect(testbus.URL(t))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(conn.Close)
|
|
signer, public := testSigner(t)
|
|
var heard HandOverAsk
|
|
engine, err := conn.Subscribe(broker.AskJudgeDirectoriesSubject("laptop"), func(msg *nats.Msg) {
|
|
var signed SignedHandOver
|
|
_ = json.Unmarshal(msg.Data, &signed)
|
|
if ed25519.Verify(public, append([]byte(HandOverContext), signed.Ask...), signed.Signature) ||
|
|
ed25519.Verify(public, append([]byte(SetuidSearchContext), signed.Ask...), signed.Signature) ||
|
|
!ed25519.Verify(public, append([]byte(JudgeDirectoriesContext), signed.Ask...), signed.Signature) {
|
|
_ = msg.Respond([]byte(`{"refused":"not signed as a judgement"}`))
|
|
return
|
|
}
|
|
_ = json.Unmarshal(signed.Ask, &heard)
|
|
body, _ := json.Marshal(HandOverAnswer{Said: "3 directories declared, asked by " + heard.By})
|
|
_ = msg.Respond(body)
|
|
})
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
t.Cleanup(func() { _ = engine.Unsubscribe() })
|
|
a, err := AskJudgeDirectories(context.Background(), conn, signer, "laptop", "jo", 5*time.Second)
|
|
if err != nil || a.Said != "3 directories declared, asked by jo" {
|
|
t.Fatalf("answered %+v, %v", a, err)
|
|
}
|
|
if heard.Node != "laptop" || heard.Path != "" || heard.Nonce == "" || heard.Expires.IsZero() {
|
|
t.Fatalf("the engine heard %+v", heard)
|
|
}
|
|
if _, err := AskJudgeDirectories(context.Background(), conn, signer, "anchor", "jo", 5*time.Second); err == nil ||
|
|
!strings.Contains(err.Error(), "nothing was judged") {
|
|
t.Fatalf("a machine with no engine listening: %v", err)
|
|
}
|
|
}
|