package broker import ( "slices" "strings" "testing" ) // The writers table, checked (novox/hq to-be 45 §1, ADR 0227 rule 1, "how it is checked"): it is the // design's table row for row; every row that writes on the bus names its writer; a whole mesh composes // with one writer per piece of state; and a grant that would make a second writer is refused, naming // the state and whose it is. // designRows are the states of to-be 45 §1, in its order. A row added to the design is added here and // to the table; one dropped from either fails. var designRows = []string{ "a machine's declaration", "a machine's applied state and its report", "the controller lease", "plans and their tiers", "conditions", "calls and their outcomes", "the hand-act log", "the healers' acts and their brake", "stream definitions and bus permissions", "builds and their outcomes", "a merge announced", "a pull request's head announced", "a pull request's merge check", "a provider's standing", "the operator-channel's open messages", "the facts snapshot", } func TestTheWritersTableIsTheDesigns(t *testing.T) { var states []string for _, row := range WritersTable { states = append(states, row.State) if row.Writer == "" || row.KeptIn == "" || row.Others == "" { t.Errorf("%q does not say who writes it, where it is kept and what others do", row.State) } if len(row.Subjects) > 0 && row.Writes == nil { t.Errorf("%q is written on the bus and names no writer among the principals", row.State) } } if !slices.Equal(states, designRows) { t.Fatalf("the writers table is not to-be 45 §1's:\n have %q\n want %q", states, designRows) } } // A mesh of every kind of principal composes: nobody is granted a second writer's subject. func TestAWholeMeshComposesWithOneWriterPerState(t *testing.T) { builder := Seat{Name: "node-build-agent", Scope: "node", Accepts: []string{"build"}, Emits: []string{"built", "started"}} principals := []Principal{ {Kind: KindController, PasswordHash: "x"}, {Kind: KindNode, Node: "one", PasswordHash: "x"}, {Kind: KindEnrolment, Node: "two", PasswordHash: "x"}, {Kind: KindPerson, Module: "jochen", Invokes: []string{"*"}, PasswordHash: "x"}, {Kind: KindModule, Node: "one", Module: "gitea", Emits: []string{"pull.merged"}, PasswordHash: "x"}, {Kind: KindModule, Node: "one", Module: "postgres", Emits: []string{"provisioner.failing", "provisioner.recovered", "provisioner.retirement"}, PasswordHash: "x"}, {Kind: KindModule, Node: "one", Module: "build-agent", Holds: []Seat{builder}, PasswordHash: "x"}, {Kind: KindNodeTools, Node: "one", Module: RuntimeModule, PasswordHash: "x", Carries: []Declared{ {Module: "gitea", Emits: []string{"pull.merged"}}, {Module: "build-agent", Holds: []Seat{builder}}}}, } for _, p := range principals { if _, err := PermissionsFor(p); err != nil { t.Errorf("%s does not compose: %v", p.Username(), err) } } if _, err := ComposeAccounts(principals); err != nil { t.Fatalf("the mesh does not compose: %v", err) } } func TestASecondWriterIsRefusedAtComposition(t *testing.T) { for _, c := range []struct { name string p Principal publish []string state string }{ {"the controller publishing what machines say", Principal{Kind: KindController}, []string{"mesh.control.>"}, "a machine's applied state and its report"}, {"a machine publishing another's report", Principal{Kind: KindNode, Node: "one"}, []string{"mesh.control.two.report"}, "a machine's applied state and its report"}, {"a machine publishing every machine's", Principal{Kind: KindNode, Node: "one"}, []string{"mesh.control.*.>"}, "a machine's applied state and its report"}, {"a module writing the lease", Principal{Kind: KindModule, Module: "shop"}, []string{"$KV.mesh-controller_lease.>"}, "the controller lease"}, {"a module sending a declaration", Principal{Kind: KindModule, Module: "shop"}, []string{"mesh.node.one.declare"}, "a machine's declaration"}, {"a module defining a stream", Principal{Kind: KindModule, Module: "shop"}, []string{"$JS.API.>"}, "stream definitions and bus permissions"}, {"a module announcing another forge's merge", Principal{Kind: KindModule, Module: "shop"}, []string{"mesh.mod.gitea.event.pull.merged"}, "a merge announced"}, {"a module saying a build it did not do", Principal{Kind: KindModule, Module: "shop"}, []string{"mesh.seat.node-build-agent.event.built"}, "builds and their outcomes"}, } { t.Run(c.name, func(t *testing.T) { err := CheckWriters(c.p, c.publish) if err == nil { t.Fatalf("%v granted to %s was not refused", c.publish, c.p.Username()) } if !strings.Contains(err.Error(), c.state) { t.Fatalf("the refusal does not name %q: %v", c.state, err) } }) } // And the writers themselves are not refused. for _, ok := range []struct { p Principal publish []string }{ {Principal{Kind: KindNode, Node: "one"}, []string{"mesh.control.one.>"}}, {Principal{Kind: KindController}, []string{"mesh.node.>", "$JS.API.>", "$KV.mesh-controller_lease.>"}}, {Principal{Kind: KindModule, Module: "gitea"}, []string{"mesh.mod.gitea.event.pull.merged"}}, {Principal{Kind: KindModule, Module: "shop"}, []string{"$JS.API.CONSUMER.CREATE.KV_shop_carts.>"}}, } { if err := CheckWriters(ok.p, ok.publish); err != nil { t.Errorf("a writer was refused its own: %v", err) } } } func TestSubjectsOverlap(t *testing.T) { for _, c := range []struct { a, b string want bool }{ {"mesh.control.>", "mesh.control.*.report", true}, {"mesh.control.one.>", "mesh.control.*.report", true}, {"mesh.control.one.alive", "mesh.control.*.report", false}, {"mesh.control.*", "mesh.control.*.report", false}, {"$JS.API.>", "$JS.API.STREAM.CREATE.>", true}, {"$JS.API.CONSUMER.CREATE.KV_x.>", "$JS.API.STREAM.CREATE.>", false}, {"a.b", "a.b", true}, {"a.b", "a.b.c", false}, {"a.>", "a", false}, } { if got := SubjectsOverlap(c.a, c.b); got != c.want || SubjectsOverlap(c.b, c.a) != c.want { t.Errorf("%s ~ %s: %v, want %v", c.a, c.b, got, c.want) } } }