carlos / platform Public

settings-1 final fixes: ratchet tests through the production builders

The host replay and require-flag tests run the pass with fastPassOpts'
own options; the edge tests configure static serving through
enableStaticFromEnv and present a replayed legacy pointer, and a fresh
box under CARLOS_REQUIRE_POINTER_DIGEST, to the handler (Astra r1 #6).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 17356c7c1e384e09a0d7d8ea0184e1192f829520 parent 1a4d99f
2 files changed, +277 −1
  • internal/edge/staticdigest_test.go +161 −0
  • internal/host/pointerdigests_test.go +116 −1
diff --git a/internal/edge/staticdigest_test.go b/internal/edge/staticdigest_test.go
index a6ad3708a..095a689e8 100644
--- a/internal/edge/staticdigest_test.go
+++ b/internal/edge/staticdigest_test.go
@@ -2,11 +2,14 @@ package edge
import (
"context"
+ "crypto/ed25519"
"io"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
+ "slices"
+ "strings"
"testing"
"github.com/carlosframework/platform/internal/registry"
@@ -134,3 +137,161 @@ func TestStaticWithoutDigestsServesAsBefore(t *testing.T) {
t.Fatalf("legacy site = %q %q", b, v)
}
}
+
+// prodStaticEdge is an Edge whose static serving is configured the way the
+// edge process configures it, through enableStaticFromEnv: the store and key
+// from the environment, and the ratchet built there from dataDir and
+// CARLOS_OPT_DIR (Astra r1 #6). The pointer cache is off, so every request
+// re-reads the pointer.
+type prodStaticEdge struct {
+ store release.Store
+ priv ed25519.PrivateKey
+ data string
+ srv *httptest.Server
+}
+
+func newProdStaticEdge(t *testing.T, require bool, seed func(release.Store, ed25519.PrivateKey)) *prodStaticEdge {
+ t.Helper()
+ storeDir := filepath.Join(t.TempDir(), "store")
+ store := release.NewDirStore(storeDir)
+ seedB64, pubB64, err := release.GenerateKey()
+ if err != nil {
+ t.Fatal(err)
+ }
+ priv, err := release.ParseSigningKey(seedB64, "test")
+ if err != nil {
+ t.Fatal(err)
+ }
+ seed(store, priv)
+ t.Setenv("CARLOS_RELEASE_PUBKEY", pubB64)
+ t.Setenv("CARLOS_DEPLOYMENT_BUCKET", "")
+ t.Setenv("CARLOS_DEPLOYMENT_DIR", storeDir)
+ t.Setenv("CARLOS_OPT_DIR", t.TempDir())
+ flag := ""
+ if require {
+ flag = "1"
+ }
+ t.Setenv(release.RequirePointerDigestEnv, flag)
+ reg := openReg(t)
+ if err := reg.Upsert(registry.Route{Host: "site.example.com", Kind: "static", App: "site", Channel: "canary/x", Status: "ready"}); err != nil {
+ t.Fatal(err)
+ }
+ e, err := New(reg, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ data := t.TempDir()
+ if err := enableStaticFromEnv(e, data); err != nil {
+ t.Fatal(err)
+ }
+ e.SetStaticRecheck(0)
+ if err := e.Reload(); err != nil {
+ t.Fatal(err)
+ }
+ srv := httptest.NewServer(e)
+ t.Cleanup(srv.Close)
+ return &prodStaticEdge{store: store, priv: priv, data: data, srv: srv}
+}
+
+func (p *prodStaticEdge) get(t *testing.T) (int, string, string) {
+ t.Helper()
+ req, err := http.NewRequest("GET", p.srv.URL+"/", nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ req.Host = "site.example.com"
+ res, err := http.DefaultClient.Do(req)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer res.Body.Close()
+ b, _ := io.ReadAll(res.Body)
+ return res.StatusCode, string(b), res.Header.Get("X-Carlos-Version")
+}
+
+// extracted lists the site trees under the edge's static cache.
+func (p *prodStaticEdge) extracted(t *testing.T) []string {
+ t.Helper()
+ entries, err := os.ReadDir(filepath.Join(p.data, "static", release.OpsAccount, "site"))
+ if err != nil && !os.IsNotExist(err) {
+ t.Fatal(err)
+ }
+ var out []string
+ for _, e := range entries {
+ if e.IsDir() && !strings.HasPrefix(e.Name(), ".") {
+ out = append(out, e.Name())
+ }
+ }
+ return out
+}
+
+func (p *prodStaticEdge) promote(t *testing.T, v, page string) {
+ t.Helper()
+ shipSite(t, p.store, "site", v, map[string]string{"index.html": page})
+ if err := release.Promote(context.Background(), p.store, p.priv, release.OpsAccount, "site", "canary/x", v); err != nil {
+ t.Fatal(err)
+ }
+}
+
+// Astra r1 #6: the static handler, configured as production configures it,
+// refuses a replayed legacy pointer once it has served a pointer with
+// digests. The saved v1 pointer comes back with v1's name reshipped under
+// other bytes; the edge keeps serving v2 and extracts nothing new. The
+// control is the same legacy pointer served on first sight.
+func TestEdgeStaticRefusesAReplayedLegacyPointer(t *testing.T) {
+ p := newProdStaticEdge(t, false, func(release.Store, ed25519.PrivateKey) {})
+ ctx := context.Background()
+ p.promote(t, "v1", "home v1") // no marker: a legacy pointer
+ key := release.ChannelKey(release.OpsAccount, "site", "canary/x")
+ saved, _, err := p.store.Get(ctx, key)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if code, b, v := p.get(t); code != http.StatusOK || b != "home v1" || v != "v1" {
+ t.Fatalf("control: the legacy pointer on first sight = %d %q %q", code, b, v)
+ }
+ if err := release.WriteDigestMarker(ctx, p.store, release.RootSigner(p.priv), release.OpsAccount, "test"); err != nil {
+ t.Fatal(err)
+ }
+ p.promote(t, "v2", "home v2") // with digests: the edge marks the channel
+ if code, b, v := p.get(t); code != http.StatusOK || b != "home v2" || v != "v2" {
+ t.Fatalf("the digest pointer = %d %q %q", code, b, v)
+ }
+ before := p.extracted(t)
+ if err := release.DeleteVersion(ctx, p.store, release.OpsAccount, "site", "v1"); err != nil {
+ t.Fatal(err)
+ }
+ shipSite(t, p.store, "site", "v1", map[string]string{"index.html": "planted"})
+ _, etag, _ := p.store.Get(ctx, key)
+ if _, err := p.store.Put(ctx, key, saved, etag); err != nil {
+ t.Fatal(err)
+ }
+ if code, b, v := p.get(t); code != http.StatusOK || b != "home v2" || v != "v2" {
+ t.Fatalf("after the replay = %d %q %q; want v2 still served", code, b, v)
+ }
+ if after := p.extracted(t); !slices.Equal(before, after) {
+ t.Fatalf("the replay extracted a tree: before %v, after %v", before, after)
+ }
+}
+
+// CARLOS_REQUIRE_POINTER_DIGEST through the edge's own ratchet construction:
+// a fresh box with the flag on refuses a legacy pointer for a channel it has
+// never seen, so nothing is extracted or served; with the flag off (the
+// control) the same pointer serves.
+func TestEdgeStaticRequireFlagOnAFreshBox(t *testing.T) {
+ for _, on := range []bool{false, true} {
+ p := newProdStaticEdge(t, on, func(s release.Store, priv ed25519.PrivateKey) {
+ shipSite(t, s, "site", "v1", map[string]string{"index.html": "home v1"})
+ if err := release.Promote(context.Background(), s, priv, release.OpsAccount, "site", "canary/x", "v1"); err != nil {
+ t.Fatal(err)
+ }
+ })
+ code, b, _ := p.get(t)
+ switch {
+ case on && (code == http.StatusOK || len(p.extracted(t)) != 0):
+ t.Fatalf("flag on: a fresh box served a legacy pointer: %d %q, extracted %v", code, b, p.extracted(t))
+ case !on && (code != http.StatusOK || b != "home v1"):
+ t.Fatalf("control, flag off: %d %q, want home v1", code, b)
+ }
+ }
+}
diff --git a/internal/host/pointerdigests_test.go b/internal/host/pointerdigests_test.go
index bfbcc562f..8d3f27e44 100644
--- a/internal/host/pointerdigests_test.go
+++ b/internal/host/pointerdigests_test.go
@@ -57,7 +57,7 @@ func TestOneRatchetPerProcessSurvivesAFailedPersist(t *testing.T) {
}
off := func(string) string { return "" }
pass := func() {
- opts := []release.PassOption{release.WithDigestRatchet(pointerRatchet(false, opt, data, off))} // as fastPassOpts builds it, every pass
+ opts := []release.PassOption{release.WithDigestRatchet(pointerRatchet(false, opt, data, off))} // the ratchet fastPassOpts arms, looked up fresh each pass
if err := release.PassFilter(ctx, reg, store, pub, opt, nil, nil, opts...); err != nil {
t.Fatal(err)
}
@@ -98,3 +98,118 @@ func TestPointerRatchetSharesMarksBetweenRootAndTheAgent(t *testing.T) {
t.Fatalf("the flag was not read: %v", err)
}
}
+
+// fastPassBox is a box whose fast sweep is built by fastPassOpts, the
+// production builder: CARLOS_OPT_DIR points release.OptDir() at a temp dir,
+// and route a.example.com follows bab/km on canary/x.
+type fastPassBox struct {
+ store release.Store
+ priv []byte
+ opt string
+ data string
+ reg *registry.Registry
+ pub []byte
+}
+
+func newFastPassBox(t *testing.T) *fastPassBox {
+ t.Helper()
+ b := &fastPassBox{store: release.NewDirStore(t.TempDir()), opt: t.TempDir(), data: t.TempDir()}
+ t.Setenv("CARLOS_OPT_DIR", b.opt)
+ seed, pubB64, _ := release.GenerateKey()
+ priv, _ := release.ParseSigningKey(seed, "t")
+ pub, _ := release.ParsePublicKey(pubB64, "t")
+ b.priv, b.pub = priv, pub
+ reg, err := registry.Open(filepath.Join(t.TempDir(), "r.db"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := reg.Upsert(registry.Route{Host: "a.example.com", Kind: "instance", App: "km", Account: "bab", Channel: "canary/x"}); err != nil {
+ t.Fatal(err)
+ }
+ b.reg = reg
+ return b
+}
+
+func (b *fastPassBox) ship(t *testing.T, v string) {
+ t.Helper()
+ m := release.Manifest{Schema: 1, App: "km", Version: v, Kind: "binary",
+ Artifacts: map[string]release.Artifact{runtimePlatform(): {}}}
+ if err := release.Ship(context.Background(), b.store, "bab", m, map[string][]byte{runtimePlatform(): []byte(v)}); err != nil {
+ t.Fatal(err)
+ }
+}
+
+func (b *fastPassBox) promote(t *testing.T, v string) {
+ t.Helper()
+ if err := release.Promote(context.Background(), b.store, b.priv, "bab", "km", "canary/x", v); err != nil {
+ t.Fatal(err)
+ }
+}
+
+// pass runs one fast sweep with fastPassOpts' options, exactly as the agent
+// builds them each tick.
+func (b *fastPassBox) pass(t *testing.T) string {
+ t.Helper()
+ opts := fastPassOpts(b.data, func(string, string, error) {}, nil, nil)
+ if err := release.PassFilter(context.Background(), b.reg, b.store, b.pub, b.opt, nil, nil, opts...); err != nil {
+ t.Fatal(err)
+ }
+ v, _ := release.LiveVersion(b.opt, "a.example.com")
+ return v
+}
+
+// Astra r1 #6: the ratchet armed by the production builder. A pointer with
+// digests is adopted and marks the channel; replaying the saved legacy
+// pointer is then refused, and the box keeps serving the digest build.
+// Removing WithDigestRatchet from fastPassOpts fails this test.
+func TestFastPassOptsRefuseAReplayedLegacyPointer(t *testing.T) {
+ b := newFastPassBox(t)
+ ctx := context.Background()
+ b.ship(t, "v1")
+ b.promote(t, "v1") // legacy: no marker yet
+ legacy, _, err := b.store.Get(ctx, release.ChannelKey("bab", "km", "canary/x"))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if v := b.pass(t); v != "v1" {
+ t.Fatalf("control: the legacy pointer on a fresh box installed %q, want v1", v)
+ }
+ if err := release.WriteDigestMarker(ctx, b.store, release.RootSigner(b.priv), "bab", "t"); err != nil {
+ t.Fatal(err)
+ }
+ b.ship(t, "v2")
+ b.promote(t, "v2") // with digests
+ if v := b.pass(t); v != "v2" {
+ t.Fatalf("the digest pointer installed %q, want v2", v)
+ }
+ _, etag, _ := b.store.Get(ctx, release.ChannelKey("bab", "km", "canary/x"))
+ if _, err := b.store.Put(ctx, release.ChannelKey("bab", "km", "canary/x"), legacy, etag); err != nil {
+ t.Fatal(err)
+ }
+ if v := b.pass(t); v != "v2" {
+ t.Fatalf("fastPassOpts let a replayed legacy pointer install %q", v)
+ }
+}
+
+// CARLOS_REQUIRE_POINTER_DIGEST through the production builder: a fresh box
+// with the flag on refuses a legacy pointer for a channel it has never seen,
+// and with the flag off (the control) it installs it.
+func TestFastPassOptsHonourTheRequireFlagOnAFreshBox(t *testing.T) {
+ for _, on := range []bool{false, true} {
+ b := newFastPassBox(t)
+ if on {
+ t.Setenv(release.RequirePointerDigestEnv, "1")
+ } else {
+ t.Setenv(release.RequirePointerDigestEnv, "")
+ }
+ b.ship(t, "v1")
+ b.promote(t, "v1")
+ got := b.pass(t)
+ switch {
+ case on && got != "":
+ t.Fatalf("flag on: a fresh box installed the legacy pointer's %q", got)
+ case !on && got != "v1":
+ t.Fatalf("control, flag off: installed %q, want v1", got)
+ }
+ }
+}