diff --git a/.golangci.yaml b/.golangci.yaml index e312e398..bf449906 100644 --- a/.golangci.yaml +++ b/.golangci.yaml @@ -5,6 +5,19 @@ linters: generated: lax presets: [comments, common-false-positives, legacy, std-error-handling] rules: + # embedlit activates at language version 1.27 and rewrites every + # Kubernetes object literal in the repo, turning + # corev1.Pod{ObjectMeta: metav1.ObjectMeta{Name: "x"}} + # into + # corev1.Pod{Name: "x"} + # The flattened form hides which embedded struct a field came from, and + # mixes TypeMeta and ObjectMeta fields into one list. Keep it off here + # rather than in settings.modernize.disable, which silently ignores + # names it does not recognise. warn-unused reports this rule if it ever + # stops matching. + - linters: + - modernize + text: '^embedlit:' - linters: - errchkjson - forbidigo diff --git a/go.mod b/go.mod index 832eb347..e75daf02 100644 --- a/go.mod +++ b/go.mod @@ -1,11 +1,13 @@ // TODO(wallrj): Rename the Go module to match the repository name module github.com/jetstack/preflight -go 1.26.4 +go 1.27.1 require ( github.com/cenkalti/backoff/v5 v5.0.3 github.com/fatih/color v1.19.0 + github.com/go-logr/logr v1.4.3 + github.com/golang-jwt/jwt/v4 v4.5.2 github.com/google/uuid v1.6.0 github.com/hashicorp/go-multierror v1.1.1 github.com/jetstack/venafi-connection-lib v0.6.1-0.20260528123542-443dd7e48a1a @@ -18,10 +20,12 @@ require ( github.com/stretchr/testify v1.11.1 golang.org/x/sync v0.23.0 gopkg.in/yaml.v2 v2.4.0 + gopkg.in/yaml.v3 v3.0.1 k8s.io/api v0.36.1 k8s.io/apimachinery v0.36.1 k8s.io/client-go v0.36.1 k8s.io/component-base v0.36.1 + k8s.io/klog/v2 v2.140.0 sigs.k8s.io/controller-runtime v0.24.1 sigs.k8s.io/yaml v1.6.0 ) @@ -30,13 +34,20 @@ require ( cel.dev/expr v0.25.2 // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/aymerick/douceur v0.2.0 // indirect + github.com/beorn7/perks v1.0.1 // indirect github.com/blang/semver/v4 v4.0.0 // indirect + github.com/cespare/xxhash/v2 v2.3.0 // indirect + github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.4.1 // indirect + github.com/emicklei/go-restful/v3 v3.13.0 // indirect github.com/evanphx/json-patch/v5 v5.9.11 // indirect github.com/fsnotify/fsnotify v1.10.1 // indirect github.com/fxamacker/cbor/v2 v2.9.2 // indirect github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a // indirect github.com/go-logr/zapr v1.3.0 // indirect + github.com/go-openapi/jsonpointer v0.23.1 // indirect + github.com/go-openapi/jsonreference v0.21.6 // indirect + github.com/go-openapi/swag v0.26.0 // indirect github.com/go-openapi/swag/cmdutils v0.26.0 // indirect github.com/go-openapi/swag/conv v0.26.0 // indirect github.com/go-openapi/swag/fileutils v0.26.0 // indirect @@ -55,12 +66,22 @@ require ( github.com/google/cel-go v0.30.0 // indirect github.com/google/gnostic-models v0.7.1 // indirect github.com/gorilla/css v1.0.1 // indirect + github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/lestrrat-go/blackmagic v1.0.4 // indirect github.com/lestrrat-go/httpcc v1.0.1 // indirect github.com/lestrrat-go/httprc/v3 v3.0.5 // indirect github.com/lestrrat-go/option/v2 v2.0.0 // indirect + github.com/mattn/go-colorable v0.1.15 // indirect + github.com/mattn/go-isatty v0.0.22 // indirect + github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect + github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect + github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect + github.com/prometheus/client_model v0.6.2 // indirect + github.com/prometheus/common v0.68.1 // indirect + github.com/prometheus/procfs v0.20.1 // indirect github.com/segmentio/asm v1.2.1 // indirect github.com/sosodev/duration v1.4.0 // indirect github.com/valyala/fastjson v1.6.10 // indirect @@ -74,46 +95,22 @@ require ( golang.org/x/crypto v0.57.0 // indirect golang.org/x/exp v0.0.0-20260603202125-055de637280b // indirect golang.org/x/net v0.58.0 // indirect - gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect - google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect - gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect - k8s.io/apiextensions-apiserver v0.36.1 // indirect - k8s.io/apiserver v0.36.1 // indirect - sigs.k8s.io/randfill v1.0.0 // indirect - sigs.k8s.io/structured-merge-diff/v6 v6.4.0 // indirect -) - -require ( - github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.3.0 // indirect - github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect - github.com/emicklei/go-restful/v3 v3.13.0 // indirect - github.com/go-logr/logr v1.4.3 - github.com/go-openapi/jsonpointer v0.23.1 // indirect - github.com/go-openapi/jsonreference v0.21.6 // indirect - github.com/go-openapi/swag v0.26.0 // indirect - github.com/golang-jwt/jwt/v4 v4.5.2 - github.com/hashicorp/errwrap v1.1.0 // indirect - github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/mattn/go-colorable v0.1.15 // indirect - github.com/mattn/go-isatty v0.0.22 // indirect - github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect - github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect - github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/prometheus/client_model v0.6.2 // indirect - github.com/prometheus/common v0.68.1 // indirect - github.com/prometheus/procfs v0.20.1 // indirect golang.org/x/oauth2 v0.36.0 // indirect golang.org/x/sys v0.48.0 // indirect golang.org/x/term v0.46.0 // indirect golang.org/x/text v0.42.0 // indirect golang.org/x/time v0.15.0 // indirect + gomodules.xyz/jsonpatch/v2 v2.5.0 // indirect + google.golang.org/genproto/googleapis/api v0.0.0-20260526163538-3dc84a4a5aaa // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20260526163538-3dc84a4a5aaa // indirect google.golang.org/protobuf v1.36.12-0.20260120151049-f2248ac996af // indirect + gopkg.in/evanphx/json-patch.v4 v4.13.0 // indirect gopkg.in/inf.v0 v0.9.1 // indirect - gopkg.in/yaml.v3 v3.0.1 - k8s.io/klog/v2 v2.140.0 + k8s.io/apiextensions-apiserver v0.36.1 // indirect + k8s.io/apiserver v0.36.1 // indirect k8s.io/kube-openapi v0.0.0-20260603220949-865597e52e25 // indirect k8s.io/utils v0.0.0-20260507154919-ff6756f316d2 // indirect sigs.k8s.io/json v0.0.0-20250730193827-2d320260d730 // indirect + sigs.k8s.io/randfill v1.0.0 // indirect + sigs.k8s.io/structured-merge-diff/v6 v6.4.0 // indirect ) diff --git a/pkg/client/client_cyberark_convertdatareadings_test.go b/pkg/client/client_cyberark_convertdatareadings_test.go index de1a598b..953373e6 100644 --- a/pkg/client/client_cyberark_convertdatareadings_test.go +++ b/pkg/client/client_cyberark_convertdatareadings_test.go @@ -1,8 +1,10 @@ package client import ( + "crypto" "crypto/ecdsa" "crypto/elliptic" + "crypto/mldsa" "crypto/rand" "crypto/x509" "crypto/x509/pkix" @@ -1477,6 +1479,16 @@ func TestIsExcludableSecret(t *testing.T) { secret: newTLSSecret("tls-secret-without-client", sampleCertificateChain(t, x509.ExtKeyUsageServerAuth)), exclude: true, }, + { + name: "TLS secret with ML-DSA client cert in tls.crt", + secret: newTLSSecret("tls-secret-with-mldsa-client", sampleMLDSACertificateChain(t, x509.ExtKeyUsageClientAuth)), + exclude: false, + }, + { + name: "TLS secret with ML-DSA non-client cert in tls.crt", + secret: newTLSSecret("tls-secret-without-mldsa-client", sampleMLDSACertificateChain(t, x509.ExtKeyUsageServerAuth)), + exclude: true, + }, { name: "Non-unstructured", secret: &corev1.Pod{ @@ -1577,15 +1589,15 @@ func newOpaqueSecret(name string) *unstructured.Unstructured { } } -// sampleCertificateChain returns a PEM encoded sample certificate chain for testing purposes. -// The leaf certificate is signed by a self-signed CA certificate. -// Uses an elliptic curve key for the CA and leaf certificates for speed. -// The returned string is base64 encoded to match how TLS certificates -// are typically provided in Kubernetes secrets. -func sampleCertificateChain(t testing.TB, usages ...x509.ExtKeyUsage) string { +// certificateChain returns a PEM encoded sample certificate chain for testing +// purposes. The leaf certificate is signed by a self-signed CA certificate, +// both keyed by newKey. The returned string is base64 encoded to match how TLS +// certificates are typically provided in Kubernetes secrets. The parsed leaf is +// returned so that callers can assert they got the algorithm they asked for. +func certificateChain(t testing.TB, newKey func() (crypto.Signer, error), usages ...x509.ExtKeyUsage) (string, *x509.Certificate) { t.Helper() - caPrivKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + caPrivKey, err := newKey() require.NoError(t, err) caTemplate := x509.Certificate{ @@ -1602,7 +1614,7 @@ func sampleCertificateChain(t testing.TB, usages ...x509.ExtKeyUsage) string { IsCA: true, } - caCertDER, err := x509.CreateCertificate(rand.Reader, &caTemplate, &caTemplate, &caPrivKey.PublicKey, caPrivKey) + caCertDER, err := x509.CreateCertificate(rand.Reader, &caTemplate, &caTemplate, caPrivKey.Public(), caPrivKey) require.NoError(t, err) caCertPEM := pem.EncodeToMemory(&pem.Block{ @@ -1610,7 +1622,7 @@ func sampleCertificateChain(t testing.TB, usages ...x509.ExtKeyUsage) string { Bytes: caCertDER, }) - clientPrivKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + clientPrivKey, err := newKey() require.NoError(t, err) clientTemplate := x509.Certificate{ SerialNumber: big.NewInt(2), @@ -1624,7 +1636,7 @@ func sampleCertificateChain(t testing.TB, usages ...x509.ExtKeyUsage) string { ExtKeyUsage: usages, } - clientCertDER, err := x509.CreateCertificate(rand.Reader, &clientTemplate, &caTemplate, &clientPrivKey.PublicKey, caPrivKey) + clientCertDER, err := x509.CreateCertificate(rand.Reader, &clientTemplate, &caTemplate, clientPrivKey.Public(), caPrivKey) require.NoError(t, err) clientCertPEM := pem.EncodeToMemory(&pem.Block{ @@ -1632,5 +1644,35 @@ func sampleCertificateChain(t testing.TB, usages ...x509.ExtKeyUsage) string { Bytes: clientCertDER, }) - return base64.StdEncoding.EncodeToString(append(clientCertPEM, caCertPEM...)) + leaf, err := x509.ParseCertificate(clientCertDER) + require.NoError(t, err) + + return base64.StdEncoding.EncodeToString(append(clientCertPEM, caCertPEM...)), leaf +} + +// sampleCertificateChain is certificateChain with P-256 keys, for speed. +func sampleCertificateChain(t testing.TB, usages ...x509.ExtKeyUsage) string { + t.Helper() + + chain, leaf := certificateChain(t, func() (crypto.Signer, error) { + return ecdsa.GenerateKey(elliptic.P256(), rand.Reader) + }, usages...) + require.Equal(t, x509.ECDSA, leaf.PublicKeyAlgorithm) + + return chain +} + +// sampleMLDSACertificateChain is certificateChain with ML-DSA-65 keys. The +// crypto/mldsa import holds the Go 1.27 floor: this package will not build on +// an older toolchain. +func sampleMLDSACertificateChain(t testing.TB, usages ...x509.ExtKeyUsage) string { + t.Helper() + + chain, leaf := certificateChain(t, func() (crypto.Signer, error) { + return mldsa.GenerateKey(mldsa.MLDSA65()) + }, usages...) + require.Equal(t, x509.MLDSA, leaf.PublicKeyAlgorithm) + require.Equal(t, x509.MLDSA65, leaf.SignatureAlgorithm) + + return chain }