From f8a383f53365481f2d5b83dcc1ae436c8fdb991e Mon Sep 17 00:00:00 2001 From: Philip Laine Date: Tue, 5 May 2026 11:12:37 +0200 Subject: [PATCH] Pin the default client image with digest (#227) This changes the default client image from latest to a pinned digest. It also enforces that the default image version tag matches the version of the Netbird dependency. This makes testing a lot easier and also ensures that we wont get untested behavior introduced if the client makes a breaking change. Signed-off-by: Philip Laine --- cmd/main.go | 7 ++++++- go.mod | 3 ++- go.sum | 2 ++ internal/version/version.go | 5 +++++ internal/version/version_test.go | 33 ++++++++++++++++++++++++++++++++ 5 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 internal/version/version.go create mode 100644 internal/version/version_test.go diff --git a/cmd/main.go b/cmd/main.go index ef5e087..dd85d51 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -48,6 +48,7 @@ import ( nbv1 "github.com/netbirdio/kubernetes-operator/api/v1" nbv1alpha1 "github.com/netbirdio/kubernetes-operator/api/v1alpha1" "github.com/netbirdio/kubernetes-operator/internal/controller" + "github.com/netbirdio/kubernetes-operator/internal/version" nbwebhookv1 "github.com/netbirdio/kubernetes-operator/internal/webhook/v1" ) @@ -84,7 +85,7 @@ func main() { ) flag.StringVar(&runtimeNamespace, "runtime-namespace", "", "Namespace the controller is running in") flag.StringVar(&managementURL, "netbird-management-url", "https://api.netbird.io", "Management service URL") - flag.StringVar(&clientImage, "netbird-client-image", "netbirdio/netbird:latest", "Image for netbird client container") + flag.StringVar(&clientImage, "netbird-client-image", "", "Image for netbird client container") flag.StringVar( &clusterName, "cluster-name", @@ -148,6 +149,10 @@ func main() { os.Exit(1) } + if clientImage == "" { + clientImage = version.ClientImage() + } + defaultLabelsMap := make(map[string]string) if defaultLabels != "" { for s := range strings.SplitSeq(defaultLabels, ",") { diff --git a/go.mod b/go.mod index c33182b..196558a 100644 --- a/go.mod +++ b/go.mod @@ -7,10 +7,12 @@ toolchain go1.26.1 require ( github.com/fluxcd/pkg/runtime v0.105.0 github.com/go-logr/logr v1.4.3 + github.com/go-openapi/testify/v2 v2.5.0 github.com/google/uuid v1.6.0 github.com/netbirdio/netbird v0.70.4 github.com/onsi/ginkgo/v2 v2.28.3 github.com/onsi/gomega v1.40.0 + golang.org/x/mod v0.35.0 k8s.io/api v0.36.0 k8s.io/apimachinery v0.36.0 k8s.io/client-go v0.36.0 @@ -79,7 +81,6 @@ require ( go.yaml.in/yaml/v2 v2.4.3 // indirect go.yaml.in/yaml/v3 v3.0.4 // indirect golang.org/x/crypto v0.50.0 // indirect - golang.org/x/mod v0.35.0 // indirect golang.org/x/net v0.53.0 // indirect golang.org/x/oauth2 v0.36.0 // indirect golang.org/x/sync v0.20.0 // indirect diff --git a/go.sum b/go.sum index 559789b..d342bd7 100644 --- a/go.sum +++ b/go.sum @@ -159,6 +159,8 @@ github.com/go-openapi/jsonreference v0.21.0 h1:Rs+Y7hSXT83Jacb7kFyjn4ijOuVGSvOdF github.com/go-openapi/jsonreference v0.21.0/go.mod h1:LmZmgsrTkVg9LG4EaHeY8cBDslNPMo06cago5JNLkm4= github.com/go-openapi/swag v0.23.1 h1:lpsStH0n2ittzTnbaSloVZLuB5+fvSY/+hnagBjSNZU= github.com/go-openapi/swag v0.23.1/go.mod h1:STZs8TbRvEQQKUA+JZNAm3EWlgaOBGpyFDqQnDHMef0= +github.com/go-openapi/testify/v2 v2.5.0 h1:UOCr63aAsMIDydZbZGqo5Ev01D4eydItRbekDuZMJLw= +github.com/go-openapi/testify/v2 v2.5.0/go.mod h1:SgsVHtfooshd0tublTtJ50FPKhujf47YRqauXXOUxfw= github.com/go-sql-driver/mysql v1.9.3 h1:U/N249h2WzJ3Ukj8SowVFjdtZKfu9vlLZxjPXV1aweo= github.com/go-sql-driver/mysql v1.9.3/go.mod h1:qn46aNg1333BRMNU69Lq93t8du/dwxI64Gl8i5p1WMU= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= diff --git a/internal/version/version.go b/internal/version/version.go new file mode 100644 index 0000000..4aa5079 --- /dev/null +++ b/internal/version/version.go @@ -0,0 +1,5 @@ +package version + +func ClientImage() string { + return "ghcr.io/netbirdio/netbird:0.70.4@sha256:3a28b9f7f32875c6a35f952ca7e9cb688b1e610365365ff55f6e790da3950f55" +} diff --git a/internal/version/version_test.go b/internal/version/version_test.go new file mode 100644 index 0000000..bd0eea8 --- /dev/null +++ b/internal/version/version_test.go @@ -0,0 +1,33 @@ +package version + +import ( + "os" + "slices" + "strings" + "testing" + + "golang.org/x/mod/modfile" + + "github.com/go-openapi/testify/v2/require" +) + +func TestClientImage(t *testing.T) { + t.Parallel() + + b, err := os.ReadFile("../../go.mod") + require.NoError(t, err) + f, err := modfile.Parse("go.mod", b, nil) + require.NoError(t, err) + idx := slices.IndexFunc(f.Require, func(r *modfile.Require) bool { + return r.Mod.Path == "github.com/netbirdio/netbird" + }) + require.GreaterT(t, idx, -1) + modVersion := strings.TrimPrefix(f.Require[idx].Mod.Version, "v") + + clientImg := ClientImage() + start := strings.Index(clientImg, ":") + 1 + end := strings.Index(clientImg, "@") + imgVersion := clientImg[start:end] + + require.EqualT(t, modVersion, imgVersion) +}