carlos / platform Public

instance policy: nothing set is byte-identical (plan 1's part)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
claude agent, operated by paul@keymail.dev 87fe7f5a2dd331fcb6ed458faada02e934846223 parent 97085bd
1 file changed, +139 −0
  • internal/provision/apppolicy_reconcile_test.go +139 −0
diff --git a/internal/provision/apppolicy_reconcile_test.go b/internal/provision/apppolicy_reconcile_test.go
index f1dc43ae0..a43c3c75a 100644
--- a/internal/provision/apppolicy_reconcile_test.go
+++ b/internal/provision/apppolicy_reconcile_test.go
@@ -3,9 +3,11 @@ package provision
import (
"context"
"crypto/ed25519"
+ "database/sql"
"errors"
"fmt"
"os"
+ "slices"
"strconv"
"strings"
"sync"
@@ -471,3 +473,140 @@ func TestReconcileHeldMintCarriesThePolicy(t *testing.T) {
}
wantCols(t, rt, "10.0.5.20", "large", fx.now.Add(apppolicy.Lifetime).Unix())
}
+
+// Nothing set is byte-identical (spec §7, plan 1's part, ruling PF-1): with
+// no policy object anywhere, reconcile mints the rows main's mint does, both
+// registry digests equal main's, a later pass writes nothing, and the policy
+// reads stay inside spec §3a's backstop allowance (one listing per backstop,
+// no GET).
+func TestNoPolicyLeavesRowsAndFingerprintsAsMain(t *testing.T) {
+ fx := newPolicyFixture(t)
+ if err := PutManifest(ctx, fx.s, fx.sqid, "blog", Manifest{Schema: 1, App: "blog", Domain: "example.com", Seed: []string{"seed"}}); err != nil {
+ t.Fatal(err)
+ }
+ blog := fx.record("blog-a.example.com")
+ blog.App = "blog"
+ recs := []Record{blog, fx.record(policyHost), fx.record("shop-b.example.com")}
+ for _, rec := range recs {
+ fx.putRecord(rec)
+ }
+ // The production shape: one cache for every pass, over a store that
+ // counts the policy listings and reads.
+ fx.cfg.Policies = NewPolicyCache(nil)
+ cs := &countingStore{DirStore: fx.s, gets: map[string]int{}}
+
+ fx.runOn(cs) // pass 1 mints, and is the cache's first backstop
+ if c := cs.take(); c.lists != 0 || c.listETags != 1 || c.totalGets() != 0 {
+ t.Fatalf("minting pass: %d LISTs, %d ETag listings, %d GETs of policy keys, want 0, 1, 0", c.lists, c.listETags, c.totalGets())
+ }
+ minted, err := fx.reg.List()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if len(minted) != len(recs) {
+ t.Fatalf("minted %d rows, want %d", len(minted), len(recs))
+ }
+ for _, rt := range minted {
+ wantCols(t, rt, "", "", 0)
+ }
+
+ // Main's mint, which carries neither column, upserted in the order this
+ // pass minted (Fingerprint hashes the rowid, and the pass walks its
+ // records in map order, on main as here).
+ byHost := map[string]Record{}
+ for _, rec := range recs {
+ byHost[rec.Host] = rec
+ }
+ mainReg := regWith(t)
+ for _, host := range mintOrder(t, fx.reg) {
+ rec := byHost[host]
+ m, err := GetManifest(ctx, fx.s, rec.Account, rec.App)
+ if err != nil {
+ t.Fatal(err)
+ }
+ rt := RouteFor(rec, "/data", seedJSON(m), false, nil)
+ // Upsert stamps CreatedAt from the wall clock when it is zero; not
+ // part of the contract under test (TestReconcileMints).
+ rt.CreatedAt = fx.row(rec.Host).CreatedAt
+ if err := mainReg.Upsert(rt); err != nil {
+ t.Fatal(err)
+ }
+ }
+ mainRows, err := mainReg.List()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !slices.Equal(minted, mainRows) {
+ t.Fatalf("minted rows differ from main's mint:\n got %+v\nwant %+v", minted, mainRows)
+ }
+ digests := func(reg *registry.Registry) (string, string) {
+ t.Helper()
+ f, err := reg.Fingerprint()
+ if err != nil {
+ t.Fatal(err)
+ }
+ s, err := reg.SnapshotFingerprint()
+ if err != nil {
+ t.Fatal(err)
+ }
+ return f, s
+ }
+ f, s := digests(fx.reg)
+ mainF, mainS := digests(mainReg)
+ if f != mainF {
+ t.Fatalf("Fingerprint = %s, main's mint %s", f, mainF)
+ }
+ if s != mainS {
+ t.Fatalf("SnapshotFingerprint = %s, main's mint %s", s, mainS)
+ }
+
+ // Pass 2, between backstops: no policy request, nothing written.
+ fx.runOn(cs)
+ if c := cs.take(); c.lists != 0 || c.listETags != 0 || c.totalGets() != 0 {
+ t.Fatalf("second pass: %d LISTs, %d ETag listings, %d GETs of policy keys, want none", c.lists, c.listETags, c.totalGets())
+ }
+ if f2, s2 := digests(fx.reg); f2 != f || s2 != s {
+ t.Fatalf("second pass moved the digests: Fingerprint %s -> %s, SnapshotFingerprint %s -> %s", f, f2, s, s2)
+ }
+
+ // The next backstop: its one listing, still nothing written.
+ fx.now = fx.now.Add(34 * time.Minute)
+ fx.runOn(cs)
+ if c := cs.take(); c.lists != 0 || c.listETags != 1 || c.totalGets() != 0 {
+ t.Fatalf("backstop pass: %d LISTs, %d ETag listings, %d GETs of policy keys, want 0, 1, 0", c.lists, c.listETags, c.totalGets())
+ }
+ if f3, s3 := digests(fx.reg); f3 != f || s3 != s {
+ t.Fatalf("backstop pass moved the digests: Fingerprint %s -> %s, SnapshotFingerprint %s -> %s", f, f3, s, s3)
+ }
+ if got := fx.changedHosts(); len(got) != 0 {
+ t.Fatalf("PolicyChanged with no policy: %v", got)
+ }
+ fx.wantState("")
+}
+
+// mintOrder is reg's hosts in rowid order: the order they were minted.
+func mintOrder(t *testing.T, reg *registry.Registry) []string {
+ t.Helper()
+ db, err := sql.Open("sqlite", reg.Path())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer db.Close()
+ rows, err := db.Query(`SELECT host FROM routes ORDER BY rowid`)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer rows.Close()
+ var hosts []string
+ for rows.Next() {
+ var h string
+ if err := rows.Scan(&h); err != nil {
+ t.Fatal(err)
+ }
+ hosts = append(hosts, h)
+ }
+ if err := rows.Err(); err != nil {
+ t.Fatal(err)
+ }
+ return hosts
+}