carlos / platform Public

certsync: pin the bucket side of the settled stamp and the wildcard↔mirror wiring

Mutation probe on round 2: forcing the stamp's bucket side off survived —
an entry settled in sync that later left the bucket would never
republish, #291 by another door. Now tested. The edge.go wiring of the
wildcard manager's parent set into the mirror was also uncovered (every
backfill test set it by hand); it is now attachWildcardToMirror, one
place with its own test.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Paul Campbell pushed by paul@keymail.dev 9484feb07b44d38243ba90abd68c39684eb5e3d4 parent b44e36f
3 files changed, +63 −6
  • internal/edge/certbackfill_test.go +49 −0
  • internal/edge/certsync.go +13 −0
  • internal/edge/edge.go +1 −6
diff --git a/internal/edge/certbackfill_test.go b/internal/edge/certbackfill_test.go
index 9cb8e2f7f..30f7e6e6e 100644
--- a/internal/edge/certbackfill_test.go
+++ b/internal/edge/certbackfill_test.go
@@ -7,6 +7,7 @@ import (
"log"
"os"
"path/filepath"
+ "slices"
"strings"
"sync"
"testing"
@@ -455,3 +456,51 @@ func TestCertMirrorLoopBackfillsOnTheIssuer(t *testing.T) {
close(stop)
<-done
}
+
+// The bucket side is part of the stamp: an entry settled as in sync that
+// later leaves the bucket (a prune, a mis-delete) republishes on the next
+// pass even though the file has not moved — otherwise #291's failure mode
+// returns by a different door.
+func TestBackfillRepublishesAnEntryThatLeftTheBucket(t *testing.T) {
+ log.SetOutput(io.Discard)
+ t.Cleanup(func() { log.SetOutput(os.Stderr) })
+ s := release.NewDirStore(t.TempDir())
+ local := autocert.DirCache(t.TempDir())
+ putLocal(t, local, "a.example.com", hostCertPEM(t, "a.example.com", time.Now().Add(time.Hour)))
+ ctx := context.Background()
+ m := issuerMirror(t, s, local, true)
+ m.backfill(ctx)
+ if err := m.Refresh(ctx); err != nil {
+ t.Fatal(err)
+ }
+ m.backfill(ctx) // settles in sync
+ if err := s.Delete(ctx, certKey("a.example.com")); err != nil {
+ t.Fatal(err)
+ }
+ if err := m.Refresh(ctx); err != nil {
+ t.Fatal(err)
+ }
+ m.backfill(ctx)
+ if _, ok := bucketHas(t, s, "a.example.com"); !ok {
+ t.Fatal("an entry that left the bucket was never republished")
+ }
+}
+
+// The production wiring: the wildcard manager's parent set reaches the
+// mirror, or every wildcard PEM would silently never backfill.
+func TestAttachWildcardToMirrorWiresParentsAndWake(t *testing.T) {
+ w := &wildcardManager{parents: []string{"acct.example.com"}}
+ m := newCertMirror(release.NewDirStore(t.TempDir()), nil)
+ attachWildcardToMirror(m, w)
+ if m.wildcardParents == nil || !slices.Equal(m.wildcardParents(), []string{"acct.example.com"}) {
+ t.Fatal("wildcardParents not wired to the manager's current set")
+ }
+ if m.wake == nil {
+ t.Fatal("wake not wired")
+ }
+ attachWildcardToMirror(nil, w) // no mirror: no panic
+ attachWildcardToMirror(m, nil) // no manager: leaves the wiring alone
+ if m.wildcardParents == nil {
+ t.Fatal("a nil manager cleared the wiring")
+ }
+}
diff --git a/internal/edge/certsync.go b/internal/edge/certsync.go
index cf85421be..dcb41069a 100644
--- a/internal/edge/certsync.go
+++ b/internal/edge/certsync.go
@@ -534,6 +534,19 @@ func (e *Edge) newCertMirror(local autocert.Cache) *certMirror {
return m
}
+// attachWildcardToMirror is the mirror↔wildcard-manager wiring, in one place
+// so a test can see it: a wildcard the ISSUER minted reaches this box's
+// handshakes on the next poll rather than on the manager's 12h tick (wake),
+// and the manager's current parent set bounds which wildcard PEMs the
+// issuer's backfill may publish. Either side nil is a no-op.
+func attachWildcardToMirror(m *certMirror, w *wildcardManager) {
+ if m == nil || w == nil {
+ return
+ }
+ m.wake = w.refresh
+ m.wildcardParents = w.currentParents
+}
+
func newCertMirror(s release.Store, local autocert.Cache) *certMirror {
return &certMirror{
s: s,
diff --git a/internal/edge/edge.go b/internal/edge/edge.go
index c0fa82507..3e4e35d7a 100644
--- a/internal/edge/edge.go
+++ b/internal/edge/edge.go
@@ -2380,12 +2380,7 @@ func RunWithActivatorReady(args []string, act Activator, cache *Cache, ready fun
if w := newWildcardFromEnv(e, certCache); w != nil {
getCert = wrapGetCertificate(w, getCert)
e.OnReload(w.refresh)
- if mirror != nil {
- // A wildcard the ISSUER minted reaches this box's handshakes on the
- // next poll rather than on this manager's 12h tick.
- mirror.wake = w.refresh
- mirror.wildcardParents = w.currentParents
- }
+ attachWildcardToMirror(mirror, w)
w.refresh()
go w.run()
log.Printf("edge: wildcard certs on (static %v, apps domain %q, delegation zone %q)",