Swaps three import paths for mesh-sdk's go/catalogue, go/overlay and go/validate (the same packages, copied from this repository at 6c2a8d62) and lets gofmt order the groups. The six swap commits compile together once the pin commit (go.mod, modules.txt) is on the branch; each alone does not, because a file on the SDK's types cannot call one still on the old package.
93 lines
3.3 KiB
Go
93 lines
3.3 KiB
Go
//go:build integration
|
|
|
|
package main
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
"github.com/novox/mesh-controller/internal/inventory"
|
|
)
|
|
|
|
// A fresh assignment is pushed before its credential exists (novox/hq issue 203): `assign` recorded
|
|
// the module, `push` sealed a random own secret where the bus credential belongs, and the process
|
|
// crash-looped until a person ran `module issue` and pushed again. Now assigning a module that speaks
|
|
// on the bus issues its credential in the same act — or, when the bus cannot be reached from here,
|
|
// says which verb to run — and a push never seals a placeholder in a credential's place.
|
|
|
|
func aTalker() catalogue.Manifest {
|
|
return catalogue.Manifest{Module: "talker", Version: "1",
|
|
OwnSecrets: catalogue.OwnSecrets{"broker": {Path: "/var/lib/mesh/talker/broker"}},
|
|
Resources: []map[string]any{
|
|
{"id": "state", "type": "directory", "path": "/var/lib/mesh/talker", "mode": "0700"},
|
|
}}
|
|
}
|
|
|
|
func TestAssigningAModuleThatSpeaksOnTheBusNamesItsCredential(t *testing.T) {
|
|
open := aMesh(t)
|
|
ctx := t.Context()
|
|
register(t, open, aTalker())
|
|
|
|
// No bus is known to this process, so the credential cannot be issued here: the assignment
|
|
// stands and says exactly what must happen before a push — never silently.
|
|
said, err := assign(ctx, open, "laptop", "talker")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if !strings.Contains(said, "module issue talker --node laptop") {
|
|
t.Fatalf("an assignment whose credential could not be issued does not name the verb:\n%s", said)
|
|
}
|
|
|
|
// And the push refuses to send it, naming the same verb, rather than sealing a placeholder.
|
|
plan, settings, err := planFor(ctx, open, "laptop")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
_, err = declarationFor(ctx, open, "laptop", plan, settings)
|
|
if err == nil {
|
|
t.Fatal("a push sealed a placeholder where talker's bus credential belongs")
|
|
}
|
|
if !strings.Contains(err.Error(), "module issue talker --node laptop") || !strings.Contains(err.Error(), "issue 203") {
|
|
t.Fatalf("the refusal does not say what to run: %v", err)
|
|
}
|
|
|
|
// Once the user is minted, the push goes on to the credential the mesh sealed, and re-assigning
|
|
// does not mint again: a credential rotates on purpose, never by habit.
|
|
if _, err := open.inventory.MintBusPassword(ctx, inventory.BusUser{
|
|
Username: "laptop.talker", Kind: inventory.BusModule, Node: "laptop", Module: "talker"}); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
hash, _, err := open.inventory.BusUserHash(ctx, "laptop.talker")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
said, err = assign(ctx, open, "laptop", "talker")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if strings.Contains(said, "module issue") {
|
|
t.Fatalf("a module with a minted credential was told to issue one:\n%s", said)
|
|
}
|
|
again, _, err := open.inventory.BusUserHash(ctx, "laptop.talker")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if again != hash {
|
|
t.Fatal("re-assigning rotated the credential")
|
|
}
|
|
}
|
|
|
|
// A module that declares no broker secret is left alone: nothing to issue, nothing said.
|
|
func TestAssigningAModuleThatDoesNotSpeakSaysNothingOfCredentials(t *testing.T) {
|
|
open := aMesh(t)
|
|
register(t, open, helloWeb())
|
|
said, err := assign(t.Context(), open, "laptop", "hello-web")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if strings.Contains(said, "credential") {
|
|
t.Fatalf("a module without a broker secret was told about credentials:\n%s", said)
|
|
}
|
|
}
|