Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 16 additions & 0 deletions api/v1/mdb/mongodb_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@ package mdb

import (
"errors"
"net/url"
"strconv"
"strings"

"k8s.io/apimachinery/pkg/runtime"
"k8s.io/apimachinery/pkg/util/validation"
"k8s.io/utils/strings/slices"
"sigs.k8s.io/controller-runtime/pkg/webhook"
"sigs.k8s.io/controller-runtime/pkg/webhook/admission"
Expand Down Expand Up @@ -51,6 +53,19 @@ func horizonsMustEqualMembers(ms MongoDbSpec) v1.ValidationResult {
return v1.ValidationSuccess()
}

func horizonDomainNamesMustBeValid(ms MongoDbSpec) v1.ValidationResult {
for _, horizon := range ms.Connectivity.ReplicaSetHorizons {
for _, address := range horizon {
URL := url.URL{Host: address}
errs := validation.IsDNS1123Subdomain(URL.Hostname())
if len(errs) > 0 {
return v1.ValidationError("Horizons must have valid domain names")
}
}
}
return v1.ValidationSuccess()
}

func deploymentsMustHaveTLSInX509Env(d DbCommonSpec) v1.ValidationResult {
authSpec := d.Security.Authentication
if authSpec == nil {
Expand Down Expand Up @@ -456,6 +471,7 @@ func (m *MongoDB) RunValidations(old *MongoDB) []v1.ValidationResult {
// Topology field
mongoDBValidators := []func(m MongoDbSpec) v1.ValidationResult{
horizonsMustEqualMembers,
horizonDomainNamesMustBeValid,
additionalMongodConfig,
replicasetMemberIsSpecified,
}
Expand Down
49 changes: 49 additions & 0 deletions api/v1/mdb/mongodb_validation_test.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package mdb

import (
"strings"
"testing"

"github.com/stretchr/testify/assert"
Expand Down Expand Up @@ -39,6 +40,54 @@ func TestMongoDB_ProcessValidations_HorizonsWithoutTLS(t *testing.T) {
assert.Equal(t, "TLS must be enabled in order to use replica set horizons", err.Error())
}

func TestMongoDB_ProcessValidations_InvalidHorizonAddress(t *testing.T) {
tests := []struct {
name string
invalidAddress string
}{
{
name: "Empty address",
invalidAddress: ":27018",
},
{
name: "Invalid characters in hostname",
invalidAddress: "my_db.com:27018",
},
{
name: "Hostname too long",
invalidAddress: strings.Repeat("a", 256) + ":27018",
},
{
name: "Label starts with hyphen",
invalidAddress: "-mydb.com:27018",
},
{
name: "Label ends with hyphen",
invalidAddress: "mydb-.com:27018",
},
{
name: "Uppercase letters in hostname",
invalidAddress: "MyDB.com:27018",
},
{
name: "Consecutive dots",
invalidAddress: "my..db.com:27018",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
replicaSetHorizons := []MongoDBHorizonConfig{
{"my-horizon": tt.invalidAddress},
}
rs := NewDefaultReplicaSetBuilder().SetSecurityTLSEnabled().SetMembers(1).Build()
rs.Spec.Connectivity = &MongoDBConnectivity{}
rs.Spec.Connectivity.ReplicaSetHorizons = replicaSetHorizons
err := rs.ProcessValidationsOnReconcile(nil)
assert.Equal(t, "Horizons must have valid domain names", err.Error())
})
}
}

func TestMongoDB_ProcessValidationsOnReconcile_X509WithoutTls(t *testing.T) {
rs := NewReplicaSetBuilder().Build()
rs.Spec.Security.Authentication = &Authentication{Enabled: true, Modes: []AuthMode{"X509"}}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
kind: fix
date: 2025-12-18
---

* Fixed a panic that occurred when the domain names for a horizon was empty. Now, if the domain names are not valid (RFC 1123), the validation will fail before reconciling.
Comment on lines +1 to +6
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@vinilage Just to make sure you are fully aware of the changes. In case customers have set an invalid domain name, the resource would now be moved to Failed phase, whereas it would be Running previously. This doesn't mean that their domain name worked, it was never validated (not even by OM or mongod).