Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
88 commits
Select commit Hold shift + click to select a range
1d3cff5
Configure private DNS using resource names and registration labels
scotwells Oct 12, 2026
2b2ea81
Validate registration selector expressions in the API schema
scotwells Oct 12, 2026
cd43bb8
Validate named DNS references without duplicating authorization
scotwells Oct 12, 2026
f8d3f0b
fix: Align DNS integration boundaries
scotwells Oct 13, 2026
2e73434
test: Align DNS API boundary coverage
scotwells Oct 13, 2026
0bebb1d
test: Scope naming fixtures to DNS contexts
scotwells Oct 13, 2026
4262209
refactor: Consolidate DNS outage behavior
scotwells Oct 13, 2026
77ed5f8
fix: Keep DNS stack tests buildable
scotwells Oct 13, 2026
4420e65
refactor: Consolidate DNS continuity behavior
scotwells Oct 13, 2026
88ec745
refactor: Simplify private DNS integration
scotwells Oct 13, 2026
623dfef
refactor: Keep DNS permissions aligned with APIs
scotwells Oct 13, 2026
fb9dd0e
fix: Keep DNS review branches buildable
scotwells Oct 13, 2026
fc91e60
fix: Align DNS validation and permission checks
scotwells Oct 13, 2026
f133fb5
docs: Describe DNS mapping validation
scotwells Oct 13, 2026
d0ad21e
fix: Render Kubernetes publisher permissions
scotwells Oct 13, 2026
e450723
docs: Describe DNS mappings and reference validation
scotwells Oct 13, 2026
d1781ff
feat: Simplify private DNS publication and access
scotwells Oct 13, 2026
cb9dfe7
fix: Preserve source lifetimes across DNS takeover
scotwells Oct 13, 2026
03db667
fix: Use authoritative DNS reads consistently
scotwells Oct 13, 2026
079c929
fix: Preserve DNS readiness during reconciliation
scotwells Oct 13, 2026
0217f8c
fix: Preserve independent DNS review builds
scotwells Oct 13, 2026
6942fc2
test: Wait for both resolver probe observations
scotwells Oct 13, 2026
47a9043
test: Acknowledge both managed zone references
scotwells Oct 13, 2026
2306f7e
test: Configure scoped NATS broker users
scotwells Oct 13, 2026
360214b
feat: Publish automatic private DNS staging builds
scotwells Oct 13, 2026
38d7dc2
test: Isolate PowerDNS fixture HTTP transports
scotwells Oct 13, 2026
53def33
fix: Include serving readiness dependencies
scotwells Oct 13, 2026
aa0e755
feat: Discover internal DNS project sources
scotwells Oct 13, 2026
df1f88d
Merge shared project discovery runtime
scotwells Oct 13, 2026
fe9f5de
Merge durable project cleanup discovery
scotwells Oct 13, 2026
c572d70
Merge source project lifetime verification
scotwells Oct 13, 2026
8a5f2ef
Merge explicit Kubernetes source fixtures
scotwells Oct 13, 2026
fd02dba
Merge branch 'fix/serving-continuity-pr243' into fix/serving-continui…
scotwells Oct 13, 2026
4ff6bb4
Merge branch 'fix/serving-continuity-pr243' into fix/serving-continui…
scotwells Oct 13, 2026
cd57b37
Merge branch 'fix/serving-continuity-pr243' into fix/serving-continui…
scotwells Oct 13, 2026
c829791
Merge branch 'fix/serving-continuity-pr243' into fix/serving-continui…
scotwells Oct 13, 2026
224aeb5
Merge branch 'fix/serving-continuity-pr243' into fix/serving-continui…
scotwells Oct 13, 2026
a052b6d
chore: Sync private DNS stack with main
scotwells Oct 14, 2026
0399e63
chore: sync CoreDNS default domain parent
scotwells Oct 14, 2026
264ec0f
chore: sync CoreDNS API reference parent
scotwells Oct 14, 2026
b125390
chore: sync validated CoreDNS domain policy
scotwells Oct 14, 2026
d7d08a9
test: qualify named references with CoreDNS
scotwells Oct 14, 2026
e06344e
chore: sync DNS serving lint corrections
scotwells Oct 14, 2026
6337eb0
Merge branch 'coredns/update-pr243-20261014' into coredns/update-pr24…
scotwells Oct 14, 2026
cfdbdfe
Merge branch 'coredns/update-pr243-20261014' into coredns/update-pr24…
scotwells Oct 15, 2026
4ec3c8c
fix: detect native dnsdist console clients
scotwells Oct 15, 2026
bb7ebc3
Merge branch 'coredns/update-pr243-20261014' into coredns/update-pr24…
scotwells Oct 15, 2026
3e48b67
Merge branch 'coredns/update-pr243-20261014' into coredns/update-pr24…
scotwells Oct 15, 2026
c59645a
Merge branch 'coredns/update-pr243-20261014' into coredns/update-pr24…
scotwells Oct 15, 2026
e406b75
Merge branch 'coredns/update-pr243-20261014' into coredns/update-pr24…
scotwells Oct 15, 2026
b7b4a75
chore: sync internal DNS with main
scotwells Oct 20, 2026
f6ee3c8
chore: merge latest parent branch
scotwells Oct 21, 2026
0172581
chore: merge qualification domain fix
scotwells Oct 21, 2026
b35b8da
chore: merge candidate qualification support
scotwells Oct 21, 2026
78900fc
chore: refresh stacked validation
scotwells Oct 21, 2026
f143429
chore: merge DNS runner preparation
scotwells Oct 21, 2026
a803325
chore: merge DNS environment preparation
scotwells Oct 21, 2026
0780a71
chore: merge qualification configuration
scotwells Oct 21, 2026
5e71b10
chore: merge DNS environment preparation
scotwells Oct 21, 2026
82edb3a
fix: scope DNS publication status to its project
scotwells Oct 21, 2026
65755a5
fix: process fleet acknowledgments concurrently
scotwells Oct 21, 2026
5135987
fix: stabilize DNS health reconciliation
scotwells Oct 22, 2026
5e0148c
feat: expose internal DNS operation metrics
scotwells Oct 22, 2026
f270661
Merge branch 'codex/dns-review-231' into codex/dns-staging-operations
scotwells Oct 22, 2026
332b243
fix: preserve DNS reference recovery boundaries
scotwells Oct 22, 2026
f0e0600
test: verify concurrent DNS health projection
scotwells Oct 22, 2026
d84be02
style: group DNS transport test imports
scotwells Oct 22, 2026
03752e5
build: include metrics test dependency
scotwells Oct 22, 2026
4bfdb35
Merge branch 'codex/dns-review-232' into codex/dns-staging-operations
scotwells Oct 22, 2026
f7b0636
Merge branch 'codex/dns-review-238' into codex/dns-staging-operations
scotwells Oct 22, 2026
816d11d
Merge remote-tracking branch 'origin/feat/internal-dns-shared-query-s…
scotwells Oct 22, 2026
a46da5f
Merge commit '7484b63' into codex/dns-staging-operations
scotwells Oct 22, 2026
1af6535
Merge commit '2cd027b' into codex/dns-staging-operations
scotwells Oct 22, 2026
7cbd2f9
Merge commit '7fe056c' into codex/dns-staging-operations
scotwells Oct 22, 2026
037fff6
test: use pinned references in compiler regression fixtures
scotwells Oct 22, 2026
2bac780
Merge commit '6111210' into codex/dns-staging-operations
scotwells Oct 22, 2026
f7c269b
Merge commit '0d0397c' into codex/dns-staging-operations
scotwells Oct 22, 2026
bb43d81
Merge commit 'cd34442' into codex/dns-staging-operations
scotwells Oct 22, 2026
d693f98
Merge commit '63c82de' into codex/dns-staging-operations
scotwells Oct 22, 2026
63d53b7
fix: refresh DNS backend transport before startup
scotwells Oct 22, 2026
186e327
fix: preserve accepted routing during DNS process upgrades
scotwells Oct 22, 2026
53b4532
Merge commit '33f92d6' into codex/dns-staging-operations
scotwells Oct 22, 2026
e0e6b61
Merge commit '6df37c5' into codex/dns-staging-operations
scotwells Oct 22, 2026
6f66e14
fix: retry concurrent DNS acknowledgement projections
scotwells Oct 22, 2026
7f454ab
chore: merge the private DNS webhook and bounds from #243
scotwells Oct 22, 2026
1b90c00
Merge branch 'fix/internal-dns-default-domain' into fix/internal-dns-…
scotwells Oct 22, 2026
798ca73
Merge branch 'fix/internal-dns-default-domain' into fix/internal-dns-…
scotwells Oct 22, 2026
8151595
Merge main into fix/internal-dns-name-references
scotwells Oct 22, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
78 changes: 78 additions & 0 deletions api/v1alpha1/internaldns_naming_validation_envtest_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
// SPDX-License-Identifier: AGPL-3.0-only

package v1alpha1

import (
"context"
"strings"
"testing"

apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sigs.k8s.io/controller-runtime/pkg/client"
)

func validateNamingAPISchemas(t *testing.T, cl client.Client) {
t.Helper()
ctx := context.Background()
for _, tc := range []struct {
name string
selector *DNSRegistrationSelector
allowed bool
}{
{"omitted-selector", nil, true},
{"empty-selector", &DNSRegistrationSelector{}, true},
{"in-selector", &DNSRegistrationSelector{MatchExpressions: []DNSRegistrationSelectorRequirement{{Key: "app", Operator: metav1.LabelSelectorOpIn, Values: []string{"web"}}}}, true},
{"exists-selector", &DNSRegistrationSelector{MatchExpressions: []DNSRegistrationSelectorRequirement{{Key: "app", Operator: metav1.LabelSelectorOpExists}}}, true},
{"invalid-operator", &DNSRegistrationSelector{MatchExpressions: []DNSRegistrationSelectorRequirement{{Key: "app", Operator: "Unsupported"}}}, false},
{"missing-values", &DNSRegistrationSelector{MatchExpressions: []DNSRegistrationSelectorRequirement{{Key: "app", Operator: metav1.LabelSelectorOpIn}}}, false},
{"unexpected-values", &DNSRegistrationSelector{MatchExpressions: []DNSRegistrationSelectorRequirement{{Key: "app", Operator: metav1.LabelSelectorOpExists, Values: []string{"web"}}}}, false},
{"invalid-value", &DNSRegistrationSelector{MatchExpressions: []DNSRegistrationSelectorRequirement{{Key: "app", Operator: metav1.LabelSelectorOpIn, Values: []string{"invalid value"}}}}, false},
{"long-value", &DNSRegistrationSelector{MatchExpressions: []DNSRegistrationSelectorRequirement{{Key: "app", Operator: metav1.LabelSelectorOpIn, Values: []string{strings.Repeat("x", 64)}}}}, false},
} {
t.Run(tc.name, func(t *testing.T) {
p := &DNSNamingPolicy{ObjectMeta: metav1.ObjectMeta{Name: tc.name, Namespace: "validation"}, Spec: DNSNamingPolicySpec{ResolverContextRef: DNSNameReference{Name: "context"}, AdditionalNames: []DNSAdditionalNameRule{{DNSZoneRef: DNSNameReference{Name: "zone"}, Selector: tc.selector, NamePrefix: "hosts"}}}}
err := cl.Create(ctx, p)
if tc.allowed {
if err != nil {
t.Fatal(err)
}
} else if !apierrors.IsInvalid(err) {
t.Fatalf("expected API validation rejection, got %v", err)
}
})
}
t.Run("selector-expression-limit", func(t *testing.T) {
p := &DNSNamingPolicy{ObjectMeta: metav1.ObjectMeta{Name: "expression-limit", Namespace: "validation"}, Spec: DNSNamingPolicySpec{ResolverContextRef: DNSNameReference{Name: "context"}, AdditionalNames: []DNSAdditionalNameRule{{DNSZoneRef: DNSNameReference{Name: "zone"}, NamePrefix: "hosts", Selector: &DNSRegistrationSelector{}}}}}
for range 64 {
p.Spec.AdditionalNames[0].Selector.MatchExpressions = append(p.Spec.AdditionalNames[0].Selector.MatchExpressions, DNSRegistrationSelectorRequirement{Key: "app", Operator: metav1.LabelSelectorOpExists})
}
if err := cl.Create(ctx, p); err != nil {
t.Fatal(err)
}
p.Spec.AdditionalNames[0].Selector.MatchExpressions = append(p.Spec.AdditionalNames[0].Selector.MatchExpressions, DNSRegistrationSelectorRequirement{Key: "app", Operator: metav1.LabelSelectorOpExists})
if err := cl.Update(ctx, p); !apierrors.IsInvalid(err) {
t.Fatalf("expected expression limit rejection, got %v", err)
}
})
for _, tc := range []struct {
name string
context DNSNameReference
allowed bool
}{
{"one-context", DNSNameReference{Name: "context"}, true},
{"no-consumer", DNSNameReference{}, false},
} {
t.Run(tc.name, func(t *testing.T) {
a := &DNSZoneAssociation{ObjectMeta: metav1.ObjectMeta{Name: tc.name, Namespace: "validation"}, Spec: DNSZoneAssociationSpec{DNSZoneRef: DNSNameReference{Name: "zone"}, ResolverContextRef: tc.context}}
err := cl.Create(ctx, a)
if tc.allowed {
if err != nil {
t.Fatal(err)
}
} else if !apierrors.IsInvalid(err) {
t.Fatalf("expected API validation rejection, got %v", err)
}
})
}
}
65 changes: 34 additions & 31 deletions api/v1alpha1/internaldns_project_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,26 @@ type DNSObjectReference struct {
Generation int64 `json:"generation,omitempty"`
}

// +kubebuilder:validation:XValidation:rule="!has(self.resolverContextRef) || ((self.resolverContextRef.name.size() == 0 && !has(self.resolverContextRef.uid) && (!has(self.resolverContextRef.generation) || self.resolverContextRef.generation == 0)) || (self.resolverContextRef.name.size() > 0 && has(self.resolverContextRef.uid) && self.resolverContextRef.uid.size() > 0))",message="a nonempty resolverContextRef must pin name and UID"
// +kubebuilder:validation:XValidation:rule="has(self.dnsZoneRef.uid) && self.dnsZoneRef.uid.size() > 0",message="dnsZoneRef must pin the zone UID"
// +kubebuilder:validation:XValidation:rule="self.resolverContextRef.name.size() > 0 && has(self.resolverContextRef.uid) && self.resolverContextRef.uid.size() > 0",message="resolverContextRef is required"
// +kubebuilder:validation:XValidation:rule="self.dnsZoneRef.name == oldSelf.dnsZoneRef.name && self.dnsZoneRef.uid == oldSelf.dnsZoneRef.uid",message="dnsZoneRef identity is immutable"
// +kubebuilder:validation:XValidation:rule="self.resolverContextRef.name == oldSelf.resolverContextRef.name && self.resolverContextRef.uid == oldSelf.resolverContextRef.uid",message="resolverContextRef identity is immutable"
// DNSNameReference selects a resource in the same project namespace.
// DNS records its resolved lifetime in controller-owned status.
type DNSNameReference struct {
// +kubebuilder:validation:MaxLength=253
Name string `json:"name"`
}

// +kubebuilder:validation:XValidation:rule="self.dnsZoneRef.name.size() > 0",message="dnsZoneRef requires a name"
// +kubebuilder:validation:XValidation:rule="self.resolverContextRef.name.size() > 0",message="resolverContextRef is required"
// +kubebuilder:validation:XValidation:rule="self.dnsZoneRef.name == oldSelf.dnsZoneRef.name",message="dnsZoneRef is immutable"
// +kubebuilder:validation:XValidation:rule="self.resolverContextRef.name == oldSelf.resolverContextRef.name",message="resolverContextRef is immutable"
type DNSZoneAssociationSpec struct {
DNSZoneRef DNSObjectReference `json:"dnsZoneRef"`
ResolverContextRef DNSObjectReference `json:"resolverContextRef"`
DNSZoneRef DNSNameReference `json:"dnsZoneRef"`
ResolverContextRef DNSNameReference `json:"resolverContextRef"`
}

type DNSZoneAssociationStatus struct {
ResolvedDNSZoneRef DNSObjectReference `json:"resolvedDNSZoneRef,omitempty"`
ResolvedResolverContextRef DNSObjectReference `json:"resolvedResolverContextRef,omitempty"`
BindingRef *DNSObjectReference `json:"bindingRef,omitempty"`
Conditions []metav1.Condition `json:"conditions,omitempty"`
ResolvedDNSZoneRef DNSNameReference `json:"resolvedDNSZoneRef,omitempty"`
ResolvedResolverContextRef DNSNameReference `json:"resolvedResolverContextRef,omitempty"`
Conditions []metav1.Condition `json:"conditions,omitempty"`
}

// DNSResolverContext is the DNS-owned serving and namespace boundary created by
Expand All @@ -58,8 +63,8 @@ type DNSResolverContextManagedNamespace struct {
}

type DNSResolverContextManagedNamespaceStatus struct {
DNSZoneRef DNSObjectReference `json:"dnsZoneRef,omitempty"`
Suffix string `json:"suffix,omitempty"`
DNSZoneRef DNSNameReference `json:"dnsZoneRef,omitempty"`
Suffix string `json:"suffix,omitempty"`
}

type DNSResolverContextStatus struct {
Expand Down Expand Up @@ -112,9 +117,8 @@ type DNSResolverAccessBindingSpec struct {
}

type DNSResolverAccessBindingStatus struct {
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
BindingRef *DNSObjectReference `json:"bindingRef,omitempty"`
Conditions []metav1.Condition `json:"conditions,omitempty"`
ObservedGeneration int64 `json:"observedGeneration,omitempty"`
Conditions []metav1.Condition `json:"conditions,omitempty"`
}

// +kubebuilder:object:root=true
Expand Down Expand Up @@ -153,11 +157,11 @@ type DNSZoneAssociationList struct {

const DNSRegistrationMaxTTLSeconds int32 = 30

// +kubebuilder:validation:XValidation:rule="has(self.dnsZoneRef.uid) && self.dnsZoneRef.uid.size() > 0",message="dnsZoneRef must pin the zone UID"
// +kubebuilder:validation:XValidation:rule="self.dnsZoneRef.name == oldSelf.dnsZoneRef.name && self.dnsZoneRef.uid == oldSelf.dnsZoneRef.uid",message="dnsZoneRef identity is immutable"
// +kubebuilder:validation:XValidation:rule="self.dnsZoneRef.name.size() > 0",message="dnsZoneRef requires a name"
// +kubebuilder:validation:XValidation:rule="self.dnsZoneRef.name == oldSelf.dnsZoneRef.name",message="dnsZoneRef is immutable"
// +kubebuilder:validation:XValidation:rule="self.name == oldSelf.name",message="name is immutable"
type DNSRegistrationSpec struct {
DNSZoneRef DNSObjectReference `json:"dnsZoneRef"`
DNSZoneRef DNSNameReference `json:"dnsZoneRef"`
// Name is the owner name, relative to the zone or fully qualified.
// +kubebuilder:validation:MinLength=1
// +kubebuilder:validation:MaxLength=253
Expand Down Expand Up @@ -245,25 +249,25 @@ type DNSRecordContributionList struct {
Items []DNSRecordContribution `json:"items"`
}

// +kubebuilder:validation:XValidation:rule="!has(self.resolverContextRef) || ((self.resolverContextRef.name.size() == 0 && !has(self.resolverContextRef.uid) && (!has(self.resolverContextRef.generation) || self.resolverContextRef.generation == 0)) || (self.resolverContextRef.name.size() > 0 && has(self.resolverContextRef.uid) && self.resolverContextRef.uid.size() > 0))",message="a nonempty resolverContextRef must pin name and UID"
// +kubebuilder:validation:XValidation:rule="!has(self.dnsZoneRef) || self.dnsZoneRef.name.size() == 0 || (has(self.dnsZoneRef.uid) && self.dnsZoneRef.uid.size() > 0)",message="a selected dnsZoneRef must pin the zone UID"
// +kubebuilder:validation:XValidation:rule="self.resolverContextRef.name.size() > 0 && has(self.resolverContextRef.uid) && self.resolverContextRef.uid.size() > 0",message="resolverContextRef is required"
// +kubebuilder:validation:XValidation:rule="self.resolverContextRef.name == oldSelf.resolverContextRef.name && self.resolverContextRef.uid == oldSelf.resolverContextRef.uid",message="resolverContextRef identity is immutable"
// +kubebuilder:validation:XValidation:rule="(has(self.dnsZoneRef) ? self.dnsZoneRef.name : \"\") == (has(oldSelf.dnsZoneRef) ? oldSelf.dnsZoneRef.name : \"\") && ((has(self.dnsZoneRef) && has(self.dnsZoneRef.uid)) ? self.dnsZoneRef.uid : \"\") == ((has(oldSelf.dnsZoneRef) && has(oldSelf.dnsZoneRef.uid)) ? oldSelf.dnsZoneRef.uid : \"\")",message="dnsZoneRef identity is immutable"
// +kubebuilder:validation:XValidation:rule="self.resolverContextRef.name.size() > 0",message="resolverContextRef is required"
// +kubebuilder:validation:XValidation:rule="self.resolverContextRef.name == oldSelf.resolverContextRef.name",message="resolverContextRef is immutable"
// +kubebuilder:validation:XValidation:rule="(has(self.dnsZoneRef) ? self.dnsZoneRef.name : \"\") == (has(oldSelf.dnsZoneRef) ? oldSelf.dnsZoneRef.name : \"\")",message="dnsZoneRef is immutable"
type DNSNamingPolicySpec struct {
ResolverContextRef DNSObjectReference `json:"resolverContextRef"`
ResolverContextRef DNSNameReference `json:"resolverContextRef"`
// +kubebuilder:validation:MaxItems=256
AdditionalNames []DNSAdditionalNameRule `json:"additionalNames"`
DNSZoneRef DNSObjectReference `json:"dnsZoneRef,omitempty"`
DNSZoneRef DNSNameReference `json:"dnsZoneRef,omitempty"`
// +kubebuilder:validation:MaxLength=253
ScopePrefix string `json:"scopePrefix,omitempty"`
Priority int32 `json:"priority,omitempty"`
}

// +kubebuilder:validation:XValidation:rule="has(self.dnsZoneRef.uid) && self.dnsZoneRef.uid.size() > 0",message="dnsZoneRef must pin the zone UID"
// +kubebuilder:validation:XValidation:rule="self.dnsZoneRef.name.size() > 0",message="dnsZoneRef requires a name"
type DNSAdditionalNameRule struct {
// Selector matches DNSRegistration metadata labels within this DNS context.
// An omitted or empty selector matches every registration in the context.
Selector *DNSRegistrationSelector `json:"selector,omitempty"`
DNSZoneRef DNSObjectReference `json:"dnsZoneRef"`
DNSZoneRef DNSNameReference `json:"dnsZoneRef"`
// +kubebuilder:validation:MaxLength=253
NamePrefix string `json:"namePrefix"`
}
Expand Down Expand Up @@ -304,15 +308,14 @@ func (s *DNSRegistrationSelector) AsLabelSelector() *metav1.LabelSelector {
}

type DNSNamingPolicyStatus struct {
ResolvedResolverContextRef DNSObjectReference `json:"resolvedResolverContextRef,omitempty"`
ResolvedDNSZoneRef DNSObjectReference `json:"resolvedDNSZoneRef,omitempty"`
ResolvedResolverContextRef DNSNameReference `json:"resolvedResolverContextRef,omitempty"`
ResolvedAdditionalNames []DNSResolvedAdditionalNameRule `json:"resolvedAdditionalNames,omitempty"`
Conditions []metav1.Condition `json:"conditions,omitempty"`
}

type DNSResolvedAdditionalNameRule struct {
Selector *metav1.LabelSelector `json:"selector,omitempty"`
DNSZoneRef DNSObjectReference `json:"dnsZoneRef"`
DNSZoneRef DNSNameReference `json:"dnsZoneRef"`
NamePrefix string `json:"namePrefix"`
}

Expand Down
4 changes: 2 additions & 2 deletions api/v1alpha1/internaldns_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import (

func TestDNSPoliciesSelectResolverContexts(t *testing.T) {
for name, value := range map[string]any{
"association context": DNSZoneAssociationSpec{ResolverContextRef: DNSObjectReference{Name: "ctx", UID: "ctx-uid"}},
"naming context": DNSNamingPolicySpec{ResolverContextRef: DNSObjectReference{Name: "ctx", UID: "ctx-uid"}},
"association context": DNSZoneAssociationSpec{ResolverContextRef: DNSNameReference{Name: "ctx"}},
"naming context": DNSNamingPolicySpec{ResolverContextRef: DNSNameReference{Name: "ctx"}},
} {
t.Run(name, func(t *testing.T) {
data, err := json.Marshal(value)
Expand Down
24 changes: 9 additions & 15 deletions api/v1alpha1/internaldns_validation_envtest_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ func TestPrivateDNSValidationAtAPIServer(t *testing.T) {
})
for _, ttl := range []int32{0, 31, 2147483647} {
t.Run("ttl", func(t *testing.T) {
a := &DNSRegistration{ObjectMeta: metav1.ObjectMeta{GenerateName: "registration-", Namespace: "validation"}, Spec: DNSRegistrationSpec{DNSZoneRef: DNSObjectReference{Name: "zone", UID: "zone-uid"}, Name: "web", RecordTypes: []RRType{RRTypeAAAA}, TTLSeconds: ttl}}
a := &DNSRegistration{ObjectMeta: metav1.ObjectMeta{GenerateName: "registration-", Namespace: "validation"}, Spec: DNSRegistrationSpec{DNSZoneRef: DNSNameReference{Name: "zone"}, Name: "web", RecordTypes: []RRType{RRTypeAAAA}, TTLSeconds: ttl}}
requireInvalid(t, cl.Create(ctx, a))
})
}
Expand Down Expand Up @@ -165,29 +165,27 @@ func TestPrivateDNSValidationAtAPIServer(t *testing.T) {
}
})
validateServiceDNSContracts(t, cl)
validateNamingAPISchemas(t, cl)
validateReferenceIdentity(t, cl, requireInvalid)
validateRegistrationBounds(t, cl, requireInvalid)
}

// References may advance a pinned generation, but never retarget another object.
// References select objects by name and never retarget another object.
func validateReferenceIdentity(t *testing.T, cl client.Client, requireInvalid func(*testing.T, error)) {
ctx := context.Background()
zone := DNSObjectReference{Name: "zone", UID: "zone-uid", Generation: 1}
resolverContext := DNSObjectReference{Name: "context", UID: "context-uid"}
zone := DNSNameReference{Name: "zone"}
resolverContext := DNSNameReference{Name: "context"}
t.Run("association-reference-identity", func(t *testing.T) {
for name, mutate := range map[string]func(*DNSZoneAssociation){
"zone-name": func(a *DNSZoneAssociation) { a.Spec.DNSZoneRef.Name = "other" },
"zone-uid": func(a *DNSZoneAssociation) { a.Spec.DNSZoneRef.UID = "other-uid" },
"context-name": func(a *DNSZoneAssociation) { a.Spec.ResolverContextRef.Name = "other" },
"context-uid": func(a *DNSZoneAssociation) { a.Spec.ResolverContextRef.UID = "other-uid" },
} {
a := &DNSZoneAssociation{ObjectMeta: metav1.ObjectMeta{GenerateName: "association-", Namespace: "validation"}, Spec: DNSZoneAssociationSpec{DNSZoneRef: zone, ResolverContextRef: resolverContext}}
if err := cl.Create(ctx, a); err != nil {
t.Fatal(err)
}
a.Spec.DNSZoneRef.Generation = 2
if err := cl.Update(ctx, a); err != nil {
t.Fatalf("zone generation cannot advance: %v", err)
t.Fatalf("unchanged association update rejected: %v", err)
}
mutate(a)
t.Run(name, func(t *testing.T) { requireInvalid(t, cl.Update(ctx, a)) })
Expand All @@ -196,10 +194,8 @@ func validateReferenceIdentity(t *testing.T, cl client.Client, requireInvalid fu
t.Run("naming-policy-reference-identity", func(t *testing.T) {
for name, mutate := range map[string]func(*DNSNamingPolicy){
"zone-name": func(p *DNSNamingPolicy) { p.Spec.DNSZoneRef.Name = "other" },
"zone-uid": func(p *DNSNamingPolicy) { p.Spec.DNSZoneRef.UID = "other-uid" },
"zone-cleared": func(p *DNSNamingPolicy) { p.Spec.DNSZoneRef = DNSObjectReference{} },
"zone-cleared": func(p *DNSNamingPolicy) { p.Spec.DNSZoneRef = DNSNameReference{} },
"context-name": func(p *DNSNamingPolicy) { p.Spec.ResolverContextRef.Name = "other" },
"context-uid": func(p *DNSNamingPolicy) { p.Spec.ResolverContextRef.UID = "other-uid" },
} {
p := &DNSNamingPolicy{ObjectMeta: metav1.ObjectMeta{GenerateName: "naming-", Namespace: "validation"}, Spec: DNSNamingPolicySpec{ResolverContextRef: resolverContext, DNSZoneRef: zone, AdditionalNames: []DNSAdditionalNameRule{}}}
if err := cl.Create(ctx, p); err != nil {
Expand All @@ -223,16 +219,14 @@ func validateReferenceIdentity(t *testing.T, cl client.Client, requireInvalid fu
for name, mutate := range map[string]func(*DNSRegistration){
"name": func(r *DNSRegistration) { r.Spec.Name = "api" },
"zone-name": func(r *DNSRegistration) { r.Spec.DNSZoneRef.Name = "other" },
"zone-uid": func(r *DNSRegistration) { r.Spec.DNSZoneRef.UID = "other-uid" },
} {
r := &DNSRegistration{ObjectMeta: metav1.ObjectMeta{GenerateName: "registration-", Namespace: "validation"}, Spec: DNSRegistrationSpec{DNSZoneRef: zone, Name: "web", RecordTypes: []RRType{RRTypeAAAA}, TTLSeconds: 30}}
if err := cl.Create(ctx, r); err != nil {
t.Fatal(err)
}
r.Spec.TTLSeconds = 10
r.Spec.DNSZoneRef.Generation = 2
if err := cl.Update(ctx, r); err != nil {
t.Fatalf("registration cannot change TTL or zone generation: %v", err)
t.Fatalf("registration cannot change TTL: %v", err)
}
mutate(r)
t.Run(name, func(t *testing.T) { requireInvalid(t, cl.Update(ctx, r)) })
Expand All @@ -258,7 +252,7 @@ func validateRegistrationBounds(t *testing.T, cl client.Client, requireInvalid f
"many-reserved": func(s *DNSRegistrationSpec) { s.ReservedDescendants = many(65, "r") },
} {
t.Run("registration-bounds-"+name, func(t *testing.T) {
r := &DNSRegistration{ObjectMeta: metav1.ObjectMeta{GenerateName: "bounded-", Namespace: "validation"}, Spec: DNSRegistrationSpec{DNSZoneRef: DNSObjectReference{Name: "zone", UID: "zone-uid"}, Name: "web", RecordTypes: []RRType{RRTypeA}, TTLSeconds: 30}}
r := &DNSRegistration{ObjectMeta: metav1.ObjectMeta{GenerateName: "bounded-", Namespace: "validation"}, Spec: DNSRegistrationSpec{DNSZoneRef: DNSNameReference{Name: "zone"}, Name: "web", RecordTypes: []RRType{RRTypeA}, TTLSeconds: 30}}
mutate(&r.Spec)
requireInvalid(t, cl.Create(ctx, r))
})
Expand Down
Loading
Loading