7e42380dcd36a40101fa0222384c7f1711749f0d
3
Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
97448194ac |
Seats are a closed set, a seat's holder answers for what it delivers, and a build source may live on the git seat
Implements novox/hq ADR 0110 and 0111. The seat set lives in internal/catalogue/seats.go: fourteen seats, each with a scope, what occupying it delivers, and the record that made it one. A test asserts the count and a decision per entry, so changing the set means finding the argument, as the host's vocabulary test does. The first set is every seat already claimed — including the-private-network, which the network module claims from a manifest composed in this repository's code, not from any module.json — plus npm-package-registry (ADR 0109) and git (ADR 0111). A test parses every catalogue manifest and this repository's own and fails on any refused claim, so closing the set refuses nothing in use. ParseManifest now refuses a claim on a seat the mesh does not define, a seat claimed at another scope, and a delivering seat claimed by a module that does not provide what it delivers. A malformed claim is refused once, for being malformed. Resolution: among several providers of a mesh provision, a pin still wins; then the holder of the seat that delivers it; then the only provider; otherwise refused as before. ADR 0009's "never guessed" holds — the seat is the choice made once, mesh-wide, rather than a pin per consumer node. A provider now carries the module it came from, because a provider is a (node, module) pair and the pair is what tells a holder from a neighbour on the same machine. The planner's second pass is now given the first pass's holdings. Without them, a node consuming a seat-delivered provision was refused there, and a refused node's own claims dropped out of what the mesh holds — letting a second holder of one of its seats pass unrefused. `seats [--json]` lists every seat, what it delivers, and each holder, derived from assignments every time and never stored. Unheld seats are listed. A stored claim outside the set — possible for a manifest registered before the set closed, since stored manifests are not re-validated — is shown rather than hidden. `build --self <owner>/<repo>` builds from a repository on the git seat's holder. The clone URL is composed at build time from the holder's node and what it serves for git; the recorded source is the path and the seat (migration 0032), never an address, so a moved forge changes nothing recorded. Nobody holding the seat refuses self-hosted builds and says so; external URLs are unchanged. An address passed with --self is refused rather than recorded as a path. Replaces three foundation tests that defended the builder's carried package binding. The catalogue removed that binding when the builder began requiring the registry through a real grant, so the tests were already failing on main; they now assert the builder requires what the npm seat delivers and carries no copy of its own, and that the forge holds the npm and git seats. Verified: go vet clean; the whole suite passes against a throwaway Postgres (make postgres), the new inventory tests included; gofmt clean apart from cmd/mesh-builder/stdout_test.go, which fails on main too. |
||
|
|
e11e1374bd |
route-proxy: a priority is an ordering, not a port
Found reviewing my own change before merging it, and it was load-bearing rather than cosmetic. Priority was read with asPort, which caps at 65535. A rule declared above that silently became priority 0 and stopped shadowing the route it exists to shadow. The one real rule this has to reproduce is declared at 100000 — so path scoping and refusal would both have shipped looking complete, passing their tests, and doing nothing on the only case that motivated them. A priority is an ordering and has no range. asWhole takes any whole number the mesh wrote and rejects a non-integral one, which was not meant as a priority. Also: a host may now be routed on some paths and not others, which made the 404 dishonest — it said "no route for this name" while listing that very name as served, a contradiction an operator has to disbelieve the proxy to get past. An uncovered path now says so, and a name that is genuinely not served still lists what is. Two regression tests, both through the proxy rather than against the parser, because the parser was where the bug looked fine. |
||
|
|
008ce39ec0 |
route-proxy: a route carries the policy applied to a request
Implements novox/hq ADR 0108, closing issue 116. The proxy's request path was a host lookup and a forward, so it applied nothing — while the ingress it replaces relies on four things it had none of. Path scoping came first because it is a prerequisite, not a sibling. The table mapped a host to one target, so a host could not be routed two ways, and the refusal this issue turns on matches a path on a host already routed to a workload. No amount of authentication or source filtering would have made it expressible. The table is now host to an ordered list of rules, matched on path prefix. The order is total, not just by priority. Sorting on priority alone leaves rules that share one in whatever order the map produced, so the same declaration would serve differently between restarts — a fault that works, and works differently each time, which is the hardest kind to believe when reported. Within a priority the longer path wins, which is also the intuitive reading. auth names a secret and never holds one. A declaration carrying a credential is refused whole rather than served unprotected, so the option ADR 0108 rejected cannot return by accident. A secret that cannot be read makes the route refuse and say so, rather than serve the workload unprotected — a gate that cannot check is not a gate that opens, and the alternative turns a missing file into a silently public admin surface. Authentication costs one bcrypt comparison on every path including an unknown user, so an unknown user is not measurably faster than a known one with a wrong password. That difference is a way to enumerate a route's users from outside it. Redirects keep the request's own path and query, or canonicalising one name onto another would land every deep link on the front page and raise no error doing it. Eleven tests, four of them for the capabilities and two for the failure modes that rot quietly: the credential-in-a-declaration refusal, and the unreadable secret failing closed. Nothing else breaks if those stop working, so nothing else would report it. No new dependency: bcrypt comes from the x/crypto module already required. |