| index 4925d6918..73c607fe5 100644 |
| --- a/internal/edge/wildcard_test.go |
| +++ b/internal/edge/wildcard_test.go |
| @@ -73,7 +73,7 @@ func TestParentsFor(t *testing.T) { |
| func TestCertForMatchesExactlyOneLabel(t *testing.T) { |
| w := newWildcardManager([]string{"go.tito.io"}, "oncarlos.com", |
| func() []string { return []string{"kass.abs.oncarlos.com"} }, |
| - autocert.DirCache(t.TempDir()), nil) |
| + nil, "", autocert.DirCache(t.TempDir()), nil) |
| w.refresh() |
| cert, _ := selfSignedWildcard(t, "abs.oncarlos.com", time.Now().Add(60*24*time.Hour)) |
| w.mu.Lock() |
| @@ -124,7 +124,7 @@ func TestWildcardPEMRoundTripAndRenewDecision(t *testing.T) { |
| t.Fatal("parseWildcardPEM(junk): want error") |
| } |
| |
| - w := newWildcardManager(nil, "oncarlos.com", func() []string { return nil }, autocert.DirCache(t.TempDir()), nil) |
| + w := newWildcardManager(nil, "oncarlos.com", func() []string { return nil }, nil, "", autocert.DirCache(t.TempDir()), nil) |
| if !w.needsObtain("abs.oncarlos.com", time.Now()) { |
| t.Fatal("no cert loaded: needsObtain should be true") |
| } |
| @@ -152,7 +152,7 @@ func TestLoadCachedAndRefreshWake(t *testing.T) { |
| } |
| |
| w := newWildcardManager(nil, "oncarlos.com", |
| - func() []string { return []string{"kass.abs.oncarlos.com"} }, cache, nil) |
| + func() []string { return []string{"kass.abs.oncarlos.com"} }, nil, "", cache, nil) |
| if !w.loadCached(context.Background(), "abs.oncarlos.com") { |
| t.Fatal("loadCached: want true for cached parent") |
| } |
| @@ -169,7 +169,7 @@ func TestLoadCachedAndRefreshWake(t *testing.T) { |
| default: |
| } |
| w2 := newWildcardManager(nil, "oncarlos.com", |
| - func() []string { return []string{"kass.abs.oncarlos.com"} }, autocert.DirCache(t.TempDir()), nil) |
| + func() []string { return []string{"kass.abs.oncarlos.com"} }, nil, "", autocert.DirCache(t.TempDir()), nil) |
| w2.refresh() |
| select { |
| case <-w2.wake: |
| @@ -190,7 +190,7 @@ func TestLoadCachedRejectsWrongCoverage(t *testing.T) { |
| if err := cache.Put(context.Background(), wildcardPEMKey("abs.oncarlos.com"), rawWrongParent); err != nil { |
| t.Fatal(err) |
| } |
| - w := newWildcardManager(nil, "oncarlos.com", func() []string { return nil }, cache, nil) |
| + w := newWildcardManager(nil, "oncarlos.com", func() []string { return nil }, nil, "", cache, nil) |
| if w.loadCached(context.Background(), "abs.oncarlos.com") { |
| t.Fatal("loadCached: want false for cert covering the wrong parent") |
| } |
| @@ -215,7 +215,7 @@ func TestLoadCachedRejectsWrongCoverage(t *testing.T) { |
| if err := cache2.Put(context.Background(), wildcardPEMKey("abs.oncarlos.com"), rawMismatch); err != nil { |
| t.Fatal(err) |
| } |
| - w2 := newWildcardManager(nil, "oncarlos.com", func() []string { return nil }, cache2, nil) |
| + w2 := newWildcardManager(nil, "oncarlos.com", func() []string { return nil }, nil, "", cache2, nil) |
| if w2.loadCached(context.Background(), "abs.oncarlos.com") { |
| t.Fatal("loadCached: want false for key/leaf mismatch") |
| } |
| @@ -248,12 +248,12 @@ func (f *fakeDNS) present(_ context.Context, fqdn, value string) (func(context.C |
| func TestWildcardAccountKeyStableAcrossManagers(t *testing.T) { |
| dir := t.TempDir() |
| cache := autocert.DirCache(dir) |
| - w1 := newWildcardManager(nil, "oncarlos.com", func() []string { return nil }, cache, &fakeDNS{}) |
| + w1 := newWildcardManager(nil, "oncarlos.com", func() []string { return nil }, nil, "", cache, &fakeDNS{}) |
| k1, err := w1.accountKey(context.Background()) |
| if err != nil { |
| t.Fatal(err) |
| } |
| - w2 := newWildcardManager(nil, "oncarlos.com", func() []string { return nil }, cache, &fakeDNS{}) |
| + w2 := newWildcardManager(nil, "oncarlos.com", func() []string { return nil }, nil, "", cache, &fakeDNS{}) |
| k2, err := w2.accountKey(context.Background()) |
| if err != nil { |
| t.Fatal(err) |
| @@ -274,7 +274,7 @@ func (f faultyCache) Get(context.Context, string) ([]byte, error) { |
| |
| func TestAccountKeyBackendFaultDoesNotMint(t *testing.T) { |
| w := newWildcardManager(nil, "oncarlos.com", func() []string { return nil }, |
| - faultyCache{autocert.DirCache(t.TempDir())}, &fakeDNS{}) |
| + nil, "", faultyCache{autocert.DirCache(t.TempDir())}, &fakeDNS{}) |
| if _, err := w.accountKey(context.Background()); err == nil { |
| t.Fatal("backend fault: want error, got a (freshly minted) key") |
| } |
| @@ -286,7 +286,7 @@ func TestAccountKeyBackendFaultDoesNotMint(t *testing.T) { |
| // (delete) clears the entry entirely. |
| func TestPerParentBackoff(t *testing.T) { |
| w := newWildcardManager(nil, "oncarlos.com", func() []string { return nil }, |
| - autocert.DirCache(t.TempDir()), &fakeDNS{}) |
| + nil, "", autocert.DirCache(t.TempDir()), &fakeDNS{}) |
| |
| if w.backingOff("abs.oncarlos.com", time.Now()) { |
| t.Fatal("no nextAttempt recorded yet: backingOff should be false") |
| @@ -321,7 +321,7 @@ func TestPerParentBackoff(t *testing.T) { |
| func TestWrappedGetCertificateFallsThrough(t *testing.T) { |
| w := newWildcardManager(nil, "oncarlos.com", |
| func() []string { return []string{"kass.abs.oncarlos.com"} }, |
| - autocert.DirCache(t.TempDir()), &fakeDNS{}) |
| + nil, "", autocert.DirCache(t.TempDir()), &fakeDNS{}) |
| w.refresh() |
| cert, _ := selfSignedWildcard(t, "abs.oncarlos.com", time.Now().Add(60*24*time.Hour)) |
| w.mu.Lock() |
| @@ -418,3 +418,65 @@ func TestCurrentHostsPlatformOnly(t *testing.T) { |
| t.Fatalf("currentHosts = %v, want %v", got, want) |
| } |
| } |
| + |
| +func TestDelegatedParentsJoinTheSet(t *testing.T) { |
| + w := newWildcardManager(nil, "oncarlos.com", func() []string { |
| + return []string{"app.bab.oncarlos.com"} |
| + }, func() []string { |
| + return []string{"woodstar.app"} |
| + }, "acme.oncarlos.com", autocert.DirCache(t.TempDir()), &fakeDNS{}) |
| + w.refresh() |
| + w.mu.Lock() |
| + parents := append([]string(nil), w.parents...) |
| + w.mu.Unlock() |
| + want := []string{"bab.oncarlos.com", "woodstar.app"} |
| + if !reflect.DeepEqual(parents, want) { |
| + t.Fatalf("parents = %v, want %v", parents, want) |
| + } |
| +} |
| + |
| +func TestChallengeFQDNDelegation(t *testing.T) { |
| + w := newWildcardManager(nil, "oncarlos.com", func() []string { return nil }, |
| + func() []string { return []string{"woodstar.app"} }, |
| + "acme.oncarlos.com", autocert.DirCache(t.TempDir()), &fakeDNS{}) |
| + w.refresh() |
| + // A delegated parent's TXT publishes into OUR zone, at the target |
| + // the customer's CNAME points to. |
| + if got, want := w.challengeFQDN("woodstar.app"), "_acme-challenge.woodstar.app.acme.oncarlos.com"; got != want { |
| + t.Errorf("delegated: %q, want %q", got, want) |
| + } |
| + // A platform-zone parent publishes directly, exactly as before. |
| + if got, want := w.challengeFQDN("bab.oncarlos.com"), "_acme-challenge.bab.oncarlos.com"; got != want { |
| + t.Errorf("own-zone: %q, want %q", got, want) |
| + } |
| +} |
| + |
| +func TestChallengeFQDNWithoutZoneNeverDelegates(t *testing.T) { |
| + // No delegation zone configured: even a listed delegated parent |
| + // publishes directly (misconfiguration degrades to the historical |
| + // behavior, which per-host issuance then covers — never a dead edge). |
| + w := newWildcardManager(nil, "", func() []string { return nil }, |
| + func() []string { return []string{"woodstar.app"} }, |
| + "", autocert.DirCache(t.TempDir()), &fakeDNS{}) |
| + w.refresh() |
| + if got, want := w.challengeFQDN("woodstar.app"), "_acme-challenge.woodstar.app"; got != want { |
| + t.Errorf("%q, want %q", got, want) |
| + } |
| +} |
| + |
| +func TestNilDelegatedSourceIsFine(t *testing.T) { |
| + // Every existing construction site passes nil — the zero-source |
| + // manager must behave exactly as before this feature existed. |
| + w := newWildcardManager([]string{"go.tito.io"}, "", func() []string { return nil }, |
| + nil, "acme.oncarlos.com", autocert.DirCache(t.TempDir()), &fakeDNS{}) |
| + w.refresh() |
| + w.mu.Lock() |
| + parents := append([]string(nil), w.parents...) |
| + w.mu.Unlock() |
| + if !reflect.DeepEqual(parents, []string{"go.tito.io"}) { |
| + t.Fatalf("parents = %v, want [go.tito.io]", parents) |
| + } |
| + if got, want := w.challengeFQDN("go.tito.io"), "_acme-challenge.go.tito.io"; got != want { |
| + t.Errorf("%q, want %q", got, want) |
| + } |
| +} |