With this commit no Go file outside vendor/ and the two packages about to go imports internal/catalogue, internal/overlay or mesh-host/validate, go.mod and vendor/modules.txt agree on mesh-sdk 14fd5cb68fd1, and the tree builds. testdata/beside/CAPTURED names the pinned SDK commit (conformance/events is unchanged since aa68b673). merge-check.sh's comment no longer names internal/catalogue as a slow package.
89 lines
3.6 KiB
Go
89 lines
3.6 KiB
Go
package ownmanifest
|
|
|
|
import (
|
|
"testing"
|
|
|
|
. "git.novox.be/novox/mesh-sdk/go/catalogue"
|
|
)
|
|
|
|
// The public issuer is the proxy's own fact (novox/hq ADR 0226), and the folding of it must not
|
|
// move the proxy's account.
|
|
//
|
|
// route-proxy keeps each ACME authority's account and certificates in a directory named after a
|
|
// digest of the directory URL and of the root bundle its `trust` container copies in
|
|
// (examples/route-proxy, forThisAuthority). Until ADR 0226 the URL was rendered from a binding to
|
|
// `public-acme`'s `acme-ca`, spelled with the port. A URL spelled any other way — even the same
|
|
// authority without `:443` — or a root bundle from another image is a new authority to the proxy:
|
|
// a new account, and every routed name ordered again, on two machines at once, against Let's
|
|
// Encrypt's rate limits. So what the module now states is held to exactly what the binding rendered.
|
|
|
|
// renderedBeforeTheFold is route-proxy's acme.env as the binding to public-acme rendered it on every
|
|
// machine running the proxy, read from the controller's plan on 2026-10-06.
|
|
const renderedBeforeTheFold = "ACME_DIRECTORY=https://acme-v02.api.letsencrypt.org:443/directory\n" +
|
|
"ACME_ROOTS=https://acme-v02.api.letsencrypt.org:443\n" +
|
|
"ACME_ROOTS_PATH=\n"
|
|
|
|
// trustImage is the image whose system bundle becomes the public root the account directory is
|
|
// named after. Moving it renames that directory.
|
|
const trustImage = "alpine@sha256:28bd5fe8b56d1bd048e5babf5b10710ebe0bae67db86916198a6eec434943f8b"
|
|
|
|
func TestRouteProxyKeepsItsPublicAccountDirectory(t *testing.T) {
|
|
m := catalogueManifest(t, "route-proxy")
|
|
for _, r := range m.Requires {
|
|
if r == "acme-ca" {
|
|
t.Fatal("route-proxy still asks for acme-ca; the public issuer is its own fact (ADR 0226)")
|
|
}
|
|
}
|
|
|
|
// As a build would leave it: each artifact a container names resolved to an image. Which image
|
|
// does not matter to the file checked here.
|
|
for _, res := range m.Resources {
|
|
if artifact, ok := res["artifact"].(string); ok {
|
|
delete(res, "artifact")
|
|
res["image"] = "registry.invalid/route-proxy/" + artifact +
|
|
"@sha256:1111111111111111111111111111111111111111111111111111111111111111"
|
|
}
|
|
}
|
|
r := Resolution{
|
|
Node: "anchor",
|
|
Modules: []Manifest{m},
|
|
Needs: []Needed{{
|
|
Name: "internal-acme-ca", From: "home", At: "home.internal", For: "route-proxy",
|
|
Serves: map[string]any{
|
|
"port": float64(9000), "path": "/acme/acme/directory", "roots": "/roots.pem",
|
|
},
|
|
}},
|
|
}
|
|
// Its own broker credential, sealed as the mesh would; what it is does not matter here.
|
|
out, err := r.Declaration(Rendering{Needed: map[string]map[string]string{
|
|
"route-proxy": {"broker": "sealed"}}})
|
|
if err != nil {
|
|
t.Fatalf("route-proxy could not be composed for a machine: %v", err)
|
|
}
|
|
env := fileNamed(out, "route-proxy.acme-env")
|
|
if env == nil {
|
|
t.Fatalf("nothing writes the public issuer's environment: %v", out)
|
|
}
|
|
if got, _ := env["content"].(string); got != renderedBeforeTheFold {
|
|
t.Fatalf("acme.env changed, which moves the proxy's account and reorders every certificate:\n"+
|
|
"got %q\nwant %q", got, renderedBeforeTheFold)
|
|
}
|
|
if fileNamed(out, "route-proxy.bound-acme-ca") != nil {
|
|
t.Error("a binding to acme-ca is still written")
|
|
}
|
|
|
|
var trust string
|
|
if m.Build != nil {
|
|
for _, a := range m.Build.Artifacts {
|
|
if a.Name == "trust" {
|
|
trust = a.From
|
|
}
|
|
}
|
|
}
|
|
if trust != trustImage {
|
|
t.Errorf("the trust image is %q, not %q: its system bundle is the public root the account "+
|
|
"directory is named after, so moving it reorders every certificate. Move it only with a "+
|
|
"plan for the account (ADR 0226)", trust, trustImage)
|
|
}
|
|
}
|