package main import ( "context" "encoding/json" "hash/fnv" "strings" "sync" "testing" "github.com/novox/mesh-controller/internal/inventory" "github.com/novox/mesh-controller/internal/link" ) // The routes to root a review of ADR 0266 found (novox/hq ADR 0266 §7): an agent makes a repository of its // own — or forks one the mesh builds from — commits a module.json naming a module the mesh runs everywhere // (`sudo`, granting itself a rule without a password; `mesh-host`, the node-engine), and asks the `build` verb // for it. Its outcome was registered under that name from the agent's repository, and the next push sent it. // onTrunk is an outcome of a commit on its repository's trunk, as the build seat says it. func onTrunk(id, repository, seat, path string, manifest map[string]any) link.BuildResult { raw, _ := json.Marshal(manifest) r := link.BuildResult{ID: id, Repository: "http://forge.internal:20000/" + repository + ".git", Path: path, Ref: "main", On: "anchor", Commit: "c0ffee0123456789", Manifest: raw, Trunk: "main", OnTrunk: true, Branches: []string{"main"}} if seat != "" { r.Source = &link.SourceOnSeat{Seat: seat, Repository: repository} } return r } // keptAsked keeps a build request as the asker would: through a verb, or at the terminal. func keptAsked(t *testing.T, inv *inventory.Inventory, id, repository, path string, atTerminal bool) { t.Helper() if err := inv.RecordBuildRequest(t.Context(), inventory.BuildRequest{ID: id, Repository: repository, Seat: "git", Path: path, For: "build", AtTerminal: atTerminal}); err != nil { t.Fatal(err) } } // theCatalogue is a mesh whose sudo is built from the catalogue repository and whose node-engine from its own. // The operator at the terminal may still move a module, or add one from a new repository. // The delivery's flow is untouched: a merge's rebuild of a module from its own repository, and a merge adding // a module to a repository the catalogue builds from (novox/hq issue 300), are registered with no terminal. // Through a verb, a build of a repository the catalogue builds nothing from is not even asked: the build node // would run what the agent wrote. // asTheOperator keeps a build as asked at the controller's terminal, as the operator's first build of a module // from a repository the catalogue does not yet build from is (novox/hq ADR 0266), and hands it back. func asTheOperator(t *testing.T, inv *inventory.Inventory, b link.BuildResult) link.BuildResult { t.Helper() repository, seat := b.Repository, "" if b.Source != nil { repository, seat = b.Source.Repository, b.Source.Seat } if err := inv.RecordBuildRequest(t.Context(), inventory.BuildRequest{ID: b.ID, Repository: repository, Seat: seat, Path: b.Path, For: "build", AtTerminal: true}); err != nil { t.Fatal(err) } return b } // A rollback puts back only a build of the module's own repository: an agent's build of the module's name, // recorded and refused, at the very commit the machine ran before (a fork carries it), is never registered by // the back door of a failed gate. // theForge is what the forge says in a test, by owner/name: a repository not named here is protected as a // trunk must be, with an id of its own. var theForge sync.Map func init() { askTheForge = func(_ context.Context, owner, repo, _ string) (forgeFacts, error) { if said, ok := theForge.Load(owner + "/" + repo); ok { switch f := said.(type) { case error: return forgeFacts{}, f case forgeFacts: return f, nil } } h := fnv.New32a() _, _ = h.Write([]byte(owner + "/" + repo)) return forgeFacts{ID: int64(h.Sum32()), Guarded: true}, nil } } // A module's trunk the forge does not protect — direct pushes, no required status — or a forge that cannot say, // registers nothing through a verb: the trunk rule means nothing on a branch anyone pushes to. // A repository deleted and made again under the module's repository's name is another repository: the forge's // id, recorded at registration, tells them apart. // The terminal's mark is the operator's for the repository and path they asked: an outcome of another, under that // build's id, is not theirs. // The serving controller, and everything it starts, is never the terminal: a build asked in it reads as asked // through the mesh even when no verb and no caller is named. // The forge applies one rule to a branch: the rule named for it, else the first glob that covers it. A stronger // rule later in the list is not what guards the branch, and is not read as if it were (the confirmation review). func TestTheRuleJudgedIsTheOneTheForgeApplies(t *testing.T) { guarded := protectionRule{Rule: "*", RequiredStatuses: []string{"mesh/merge-gate"}} open := protectionRule{Rule: "main", Push: true, RequiredStatuses: []string{"mesh/merge-gate"}} if f := judgedRule([]protectionRule{guarded, open}, "main"); f.Guarded { t.Error("an exact rule letting pushes was passed over for a glob that guards") } if f := judgedRule([]protectionRule{{Rule: "ma*", RequiredStatuses: nil}, {Rule: "*", RequiredStatuses: []string{"x"}}}, "main"); f.Guarded || !strings.Contains(f.Why, "ma*") { t.Errorf("the first glob covering the branch was not the one judged: %+v", f) } if f := judgedRule([]protectionRule{{Rule: "release/*"}, {Rule: "main", RequiredStatuses: []string{"x"}}}, "main"); !f.Guarded { t.Errorf("the rule named for the branch was not judged: %+v", f) } if f := judgedRule(nil, "main"); f.Guarded { t.Error("no rule is no protection") } } // An id the forge could not give keeps the id already recorded. // **The operator's Approve of a reviewed group registers a moved module from its new repository** (novox/hq ADR 0420 §7, // issue 1025). sudo is built from the catalogue; a merge into the repository of node-engine's module, announced by // mesh-delivery with the ask it merged on, brings its build from there. Accepted with the operator's Approve of the // merged head; refused with no kept merge, a warrant for other heads, a Decline, a person who is not the operator, and // through a verb.