package inventory import ( "strings" "testing" "github.com/novox/mesh-controller/internal/broker" "github.com/novox/mesh-controller/internal/catalogue" ) // Reading the bus's user list out of the mesh's records, against a real store. // // What each of these is about is a user that would be **missing or wrong in a way nothing reports**: // the server reads whatever file it is given, and a module whose user is absent fails on its first // publish with an authorisation error that says nothing about a missing assignment. func theSeatDeclarer() catalogue.Manifest { return catalogue.Manifest{ Module: "telegram", Version: "1", DefinesSeats: []catalogue.SeatDeclaration{{ Name: "telegram-sender", Accepts: []string{"send"}, Emits: []string{"delivered"}, }}, Claims: []catalogue.Claim{{Name: "telegram-sender", Scope: catalogue.ScopeMesh}}, } } // A module assigned to a machine becomes a user with the authority its manifest declared — and the // protocol of a seat declared by a *different* module, which is the whole reason a seat exists. // A machine holding a live token gets an enrolment user; one whose token is spent or expired does // not. **An enrolment user outliving its token is a right to join that nobody issued.** // A module assigned and absent from the catalogue is refused rather than composed with no authority. // // **The catalogue refuses to forget an assigned module, so this is the second line and not the // first** — and it earns its place there: relying on another package's invariant is how a rule ends // up enforced by nothing. Checked against the derivation directly, because the situation cannot be // reached through the store. func TestAnAssignmentWithNoManifestDerivesNoAuthority(t *testing.T) { // What BusRecords would have produced had it composed a ghost: a module with nothing declared. users, err := broker.Users(broker.Records{ Nodes: []string{"one"}, Assigned: map[string][]broker.Declared{"one": {{Module: "ghost"}}}, }) if err != nil { t.Fatal(err) } perms, err := broker.PermissionsFor(users[len(users)-1]) if err != nil { t.Fatal(err) } // Its inbox and its ack subject, and nothing it could say. That is a module which starts, // connects, and is refused by the server on its first publish — an authorisation error that // says nothing about a missing manifest, which is why BusRecords names it instead. for _, p := range perms.Publish { if strings.HasPrefix(p, "mesh.mod.ghost.event.") { t.Fatalf("a module with no manifest was granted %s", p) } } } func granted(all []string, one string) bool { for _, s := range all { if s == one { return true } } return false } // **A token is an account on the bus, or it is a string nothing accepts** (novox/hq 04-ISSUES/146). // // The composed list names an enrolment user for every machine with a live token, and nothing minted // a credential for it — so the composer left it out as a user with no password, and every enrolment // since the mesh moved to this bus was refused by the server before the mesh heard of it. Nothing // caught it because nothing had enrolled since. // // The password cannot be minted, because it is the token's own secret: the machine will present // exactly that string. So this checks the two halves that make the account usable — that a row // exists under the name the composer asks for, and that the secret handed out is what that row // accepts. // The module holding mesh-broker is the bus, and its user is the bus's own: granted the snapshot API // for the night's backup and nothing else, whatever tools it declares (novox/hq ADR 0235). Another // module on the same machine is granted none of it. // The bar's holder reads the state the modules beside it offer in its blocks (novox/hq ADR 0255), // without naming them: granted on the machine where both are, and nowhere else. // A module running the machine's provisioner client gives that machine a client account of its own, apart from the // module's and the tool runner's (novox/hq ADR 0349 clause 11, design 57 P3); one with nowhere to read the account // gives none.