--- status: resolved opened: 2026-08-31 located-in: [mesh-control, mesh-lab] fixed-by: mesh-lab multiple-fixes — the bed, not the proxy: its backend stub never listened and its check read a subject the authority leaves empty; against both Pebble and the catalogue's step-ca the same proxy now orders, answers the challenge, is issued and serves amended-design: --- # 020 — A certificate is issued and never collected ## Symptom Against a real ACME server in the lab, the proxy orders a certificate for a name the mesh routes, the challenge is answered, the authority **issues the certificate** — and the proxy never obtains it. Every TLS handshake then fails, and the order is retried indefinitely. The client's error, once per attempt: ``` http: TLS handshake error: Post "": unsupported protocol scheme "" ``` A POST to an empty URL: the certificate's location, on an order the authority considers valid. ## What is proven, and it is most of it Read from the authority's own log rather than inferred: ``` Starting 3 validations authz … set VALID by completed challenge … POST /finalize-order/ → Order … is fully authorized. Processing finalization Issued certificate serial 3ef142939115ee88 ``` **The hard half works.** The order is created, the HTTP-01 challenge is answered *at the name being certified* on port 80 through the proxy itself, the authorisation goes valid, finalisation is accepted, and a certificate is issued. Across one run the authority issued **two** certificates and accepted finalise **three** times — the client reaches issuance every attempt and fails at the same step after it. **And the policy that guards the quota is proven too.** The second assertion in the same file passes: no certificate is ordered for a name nothing routes, so a scan cannot spend an account's rate limit. ## What is not known **Whether this happens against a real authority at all.** Everything above is against Pebble, which exists to be a test server. The failure is in the last hop between one client and one server, and may say nothing about behaviour against a public authority. ## Ruled out | | | |---|---| | the directory | fetched and complete — `newAccount`, `newNonce`, `newOrder`, `revokeCert` all present | | the authority's API certificate | covers `127.0.0.1`; the bundle is named explicitly and verification is not skipped | | a hand-written server config | suspected, and wrong. Replacing it with the server's **own** default config, changing only the challenge port, gives the identical error | | the finalize URL being empty | the authority logs finalisation being accepted | | the challenge path | the authorisation goes valid | | the server version | pinned 2.5.0 behaves exactly as `latest`, so the draft profiles extension is not it | ## Where it might be - **The order's `certificate` field is absent when the client reads it.** The client waits for the order to become valid and only then fetches, so an empty location on a valid order is the remaining shape. - ~~**A moving tag was used.**~~ **Ruled out.** `pebble:latest` advertises a draft *profiles* extension, so a pinned 2.5.0 was tried: **identical failure**. The scenario now pins it anyway, which it should have from the start. ## Why this is filed rather than pursued **The mesh-side behaviour is proven and the remainder is interop between two libraries.** Continuing would be several more twenty-minute lab runs against a server that is not the one production uses, to chase a defect that may not exist there. **What the mesh needed to show, it showed**: a name it routes gets a certificate ordered from a configured authority, and a name it does not route gets nothing. The configuration is right, the challenge path is right, and issuance happens. ## What would close it - The same scenario against a different ACME implementation — a second server, or a real staging endpoint from a machine that can reach one. **If it passes there, this is a Pebble interop detail and the issue closes with that recorded.** - Or the client's request captured on the wire, showing what the order actually contained when the location was read. ## Evidence - `mesh-lab test/integration/certificates.test.ts`, scenario `a-public-name` - One assertion passes (no certificate for an unrouted name); one fails (a routed name is never served).