93 lines
3.3 KiB
Go
93 lines
3.3 KiB
Go
//go:build integration
|
|
|
|
package main
|
|
|
|
import (
|
|
"strings"
|
|
"testing"
|
|
|
|
"github.com/novox/mesh-controller/internal/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)
|
|
}
|
|
}
|