From 98f5d34610a096228e9037ad80dd72d512b8ffe7 Mon Sep 17 00:00:00 2001 From: jochen Date: Thu, 10 Sep 2026 00:22:06 +0200 Subject: [PATCH] route-proxy: an empty ACME_CA_BUNDLE means the system trust store MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Piece A of ADR 0056 (selectable issuer). A provider that serves an empty root — public-acme, whose root already ships in the OS trust store — leaves route-proxy's CA bundle file existing but empty, because the mesh writes it unconditionally from ${bound:acme-ca:root}. Read that as "trust the system roots", the same as an unset bundle, instead of failing with "holds no certificate this can trust". A bundle that holds bytes but no parseable certificate is still refused. Claude-Session: https://claude.ai/code/session_01LrgweAeERJYBg88c5cKDzF --- examples/route-proxy/main.go | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/examples/route-proxy/main.go b/examples/route-proxy/main.go index 6ae5440..3235d18 100644 --- a/examples/route-proxy/main.go +++ b/examples/route-proxy/main.go @@ -203,13 +203,21 @@ func run() error { if err != nil { return fmt.Errorf("ACME_CA_BUNDLE names %s and it cannot be read: %w", bundle, err) } - pool := x509.NewCertPool() - if !pool.AppendCertsFromPEM(pem) { - return fmt.Errorf("%s holds no certificate this can trust", bundle) - } - client.HTTPClient = &http.Client{ - Timeout: 30 * time.Second, - Transport: &http.Transport{TLSClientConfig: &tls.Config{RootCAs: pool}}, + // An empty bundle means the issuer's root is already in the system trust store — a public + // authority whose root ships with the OS, pointed at by a provider that serves an empty + // root (novox/hq ADR 0056). The mesh always writes the bundle file, so it exists and holds + // nothing; that is the signal to fall back to the system roots, the same as if nothing had + // named a bundle at all. A file that holds bytes but no certificate is still a + // misconfiguration and is refused, because there the operator meant to trust something. + if strings.TrimSpace(string(pem)) != "" { + pool := x509.NewCertPool() + if !pool.AppendCertsFromPEM(pem) { + return fmt.Errorf("%s holds no certificate this can trust", bundle) + } + client.HTTPClient = &http.Client{ + Timeout: 30 * time.Second, + Transport: &http.Transport{TLSClientConfig: &tls.Config{RootCAs: pool}}, + } } } manager := &autocert.Manager{