Issue 116: resolved by mesh-controller PR #58

The gap is closed in the proxy: policy applies, the four capabilities exist, the table is keyed
by host and path with a total ordering, and the two failure modes that rot quietly are held by
tests — a declaration carrying a credential refused rather than served, an unreadable secret
failing closed.

Resolved rather than left open because the issue reports a gap in the proxy and that gap is
gone. But the record says plainly what it does not yet allow: an operator still cannot move the
affected routes, because that needs the mesh side — a manifest able to declare these values and
the controller minting the secret auth names. Until both exist the capability is reachable only
by writing the routes file by hand. That is the ordinary build-out of a contract this issue's
decision created, and it belongs to to-be 08 rather than here.

The open questions are marked answered and kept rather than deleted, pointing at ADR 0108 —
what was rejected and why is the half worth having, and a section still saying "the fix should
not be written before these are answered" after the fix was written reads as though nobody
looked.

One finding kept in the record: priority was read with the reader for ports, which caps at
65535, and the one real rule this reproduces is declared at 100000. It parsed to zero, so
refusal and path scoping would have shipped looking complete and doing nothing on the only case
that motivated them. A validator borrowed from a neighbouring field is a silent default.
This commit is contained in:
jochen
2026-09-25 14:25:24 +02:00
parent a11da86591
commit 367df38e6d
@@ -1,8 +1,8 @@
--- ---
status: located status: resolved
opened: 2026-09-25 opened: 2026-09-25
located-in: [mesh-controller examples/route-proxy] located-in: [mesh-controller examples/route-proxy]
fixed-by: fixed-by: mesh-controller PR #58 — the four capabilities implemented in the reference proxy; the table re-keyed by host and path with a total ordering; a declaration carrying a credential refused rather than served, and an unreadable secret failing closed
amended-design: 03-DESIGN/01-to-be/08-connectivity.md amended-design: 03-DESIGN/01-to-be/08-connectivity.md
--- ---
@@ -105,10 +105,13 @@ vulnerability. The two outcomes if it is left unfixed are both bad:
can resolve a name, while a known-exploited path loses the block that was put in front of it can resolve a name, while a known-exploited path loses the block that was put in front of it
during an incident. during an incident.
## Open questions ## Open questions — answered
These are design questions, not implementation details, and the fix should not be written before These were design questions, not implementation details, and the fix was not written before they
they are answered. were answered. All three were settled in
[ADR 0108](../../02-DECISIONS/0108-a-route-carries-the-policy-applied-to-a-request.md): policy goes
**on the route**, the set is **closed at the four**, and a declaration **names a secret and never
carries one**. Kept as asked, because what was rejected and why is the half worth having.
- **Where does request-level policy come from?** Today a contribution carries a name and a port. - **Where does request-level policy come from?** Today a contribution carries a name and a port.
Extending it to carry policy keeps the mesh as the source of truth, consistent with everything Extending it to carry policy keeps the mesh as the source of truth, consistent with everything
@@ -123,3 +126,27 @@ they are answered.
scoping and redirects are what the predecessor uses *today*. Whether route-level policy should be scoping and redirects are what the predecessor uses *today*. Whether route-level policy should be
an open middleware surface, or exactly these four and no more, is worth deciding before any of it an open middleware surface, or exactly these four and no more, is worth deciding before any of it
is written — an open surface is far harder to withdraw than to add. is written — an open surface is far harder to withdraw than to add.
## What the fix covers, and what it does not yet allow
*2026-09-25, on resolution.* The gap this issue reports is closed: the proxy applies policy, the
four capabilities exist, the table is keyed by host and path with a total ordering, and the two
failure modes that would rot quietly are held by tests — a declaration carrying a credential is
refused rather than served, and an unreadable secret makes the route refuse rather than open.
**It does not yet let an operator move the affected routes.** That needs the mesh side: a manifest
able to declare these values, and the controller minting the secret that `auth` names. Until both
exist the capability is reachable only by writing the routes file by hand, so the routes held back
on the adopted ingress stay there.
Resolved rather than left open because the issue reports a gap **in the proxy**, and that gap is
gone. The remaining work is not this fault persisting; it is the ordinary build-out of a contract
this record's decision created, and it belongs to
[to-be 08](../../03-DESIGN/01-to-be/08-connectivity.md) rather than here.
**One thing found while fixing it, worth keeping.** Priority was first read with the reader for
ports, which caps at 65535 — and the one real rule this has to reproduce is declared at 100000. It
parsed to zero, so refusal and path scoping would both have shipped looking complete, passing their
own tests, and doing nothing on the only case that motivated them. *A validator borrowed from a
neighbouring field is a silent default*, and the test that now guards it goes through the proxy,
because at the parser the value looked fine.