From 032163769c238cb8737b537249c67dea3756d56b Mon Sep 17 00:00:00 2001 From: antoinetoussaint-byte <312536060+antoinetoussaint-byte@users.noreply.github.com> Date: Sun, 25 Oct 2026 16:05:10 -0400 Subject: [PATCH] fix!: the authority is asked about the operation dispatched, never the decoded path Review fixes for #75 (r1): - F1 (blocker, security) and F2: wrapRequest asked the authority about r.Method+" "+r.URL.Path, the decoded path, while the mux dispatches on the escaped one, so /pages/secret%2Fhistory ran /pages/{id} under the /pages/{id}/history row; and a subtree beside {id} matched two rows, which the authority refuses as ambiguous. mountOperations now hands wrapRequest the dispatched operation's own row, verb+" "+servedRoute(path), which the authority finds by exact name. - F4: InterfaceInfo.BasePath is deleted. The CLI prefixes every row with it while the edge forwards on /v1/ and the runtime checks routes as served, so no non-empty value matched a request. - F5: InvalidArgument/OutOfRange from the authority's Check is 400 with the authority's reason (ErrRequestInvalid), not 503 "try again". - F6: a relayed stream's first message is bounded by the method's Timeout again. - F3 is recorded in the CHANGELOG and README: closes when authority#1 merges with a merge commit and the runtime re-pins. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 33 ++++++++++ README.md | 32 +++++++--- authority.go | 20 ++++-- authority_test.go | 111 ++++++++++++++++++++++++++++------ dispatch_test.go | 107 ++++++++++++++++++++++++++++++++ enforced_test.go | 2 +- operations.go | 28 ++++----- operations_test.go | 7 ++- passthrough.go | 4 +- passthrough_authority.go | 7 ++- passthrough_authority_test.go | 17 +++++- passthrough_test.go | 2 +- request_handler_test.go | 6 +- solution.go | 14 ++++- stream.go | 24 ++++++-- typed_boundary_test.go | 4 +- 16 files changed, 349 insertions(+), 69 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b2054f2..051c5dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,38 @@ # Changelog +## Unreleased — review fixes for #75: the authority is asked about the operation dispatched (breaking) + +From the independent review of #75 (r1): + +- **The route checked is the operation dispatched (F1, security; F2).** The + authority was asked about `r.Method + " " + r.URL.Path`, the decoded path, + while the mux dispatches on the escaped one: `GET /v1/page/pages/secret%2Fhistory` + ran the `/pages/{id}` operation and was checked against the + `/pages/{id}/history` row, so a caller holding only the weaker history row + ran the page handler. The same root made a subtree `/x/` beside `/x/{id}` + (legal for the mux) a path the authority refuses as matching two routes. + `wrapRequest` now asks about the dispatched operation's own row, + `" " + servedRoute(path)`, which the authority finds by exact name. +- **`InterfaceInfo.BasePath` is deleted (F4).** The CLI prefixes every route + row with the document's base path, while the edge forwards a solution's + requests on `/v1/` and the runtime checks routes as served, so no + non-empty base path ever matched a request. A backend still setting it no + longer compiles, naming the field: drop it and carry `/v1/` in each + operation's path, as the migrated solutions do. +- **A malformed request is refused with its reason (F5).** An + `InvalidArgument` or `OutOfRange` from the authority's `Check` is answered + 400 (`invalid_argument` on a relayed call) with the authority's reason, + `ErrRequestInvalid`, never 503 "try again"; an issue refused that way is a + `WorkContextRefusal` of 400 with its reason. +- **A stream's first message is bounded again (F6).** A relayed + server-streaming call cuts off a module that accepts the stream and sends + nothing at the method's `Timeout`, as `StreamFirstAnswerWithin` did before + the authority move, instead of holding it for the whole `MaxStreamDuration`. +- **Open (F3):** `go.mod` pins the authority client and hop libraries at + commits only on the unmerged `authority/vision` branch. This closes when + authority#1 merges with a merge commit and this runtime re-pins; no runtime + release before then. + ## Unreleased — the operation checked is the operation run; every served route publishes its policy (breaking) From the independent review of 2026-10-25 (F1–F4, F10, F11): diff --git a/README.md b/README.md index 3acac18..a5e8e87 100644 --- a/README.md +++ b/README.md @@ -119,18 +119,23 @@ nothing: calling a route as a tool sends the child the authority issued it through its binding: `WorkContextPrincipals` names the person as owner and the module as current actor, and `ActorChain()` the whole chain. -- **Which routes it reaches**: the `Check` names the route, `" "` - as this module serves it, and the authority applies this module's delivered - route policy (the `"