From 9ab328e83a2c3ace679127a81baa5113263a907b Mon Sep 17 00:00:00 2001 From: Jakub Warczarek Date: Wed, 18 Dec 2024 16:07:29 +0100 Subject: [PATCH] chore(refactor): Do not create temporary file when dealing with container registry credentials --- .../kongplugininstallation/controller.go | 7 ++++--- .../kongplugininstallation/image/image.go | 21 ------------------- .../image/image_test.go | 11 +++++----- go.mod | 2 ++ go.sum | 4 ++-- 5 files changed, 14 insertions(+), 31 deletions(-) diff --git a/controller/kongplugininstallation/controller.go b/controller/kongplugininstallation/controller.go index e8ee45344..2ec4dee2b 100644 --- a/controller/kongplugininstallation/controller.go +++ b/controller/kongplugininstallation/controller.go @@ -1,6 +1,7 @@ package kongplugininstallation import ( + "bytes" "context" "errors" "fmt" @@ -11,7 +12,7 @@ import ( k8serrors "k8s.io/apimachinery/pkg/api/errors" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" - "oras.land/oras-go/v2/registry/remote/credentials" + orascreds "oras.land/oras-go/v2/registry/remote/credentials" ctrl "sigs.k8s.io/controller-runtime" "sigs.k8s.io/controller-runtime/pkg/builder" "sigs.k8s.io/controller-runtime/pkg/client" @@ -99,7 +100,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu } log.Trace(logger, "managing KongPluginInstallation resource") - var credentialsStore credentials.Store + var credentialsStore orascreds.Store if kpi.Spec.ImagePullSecretRef != nil { log.Trace(logger, "getting secret for KongPluginInstallation resource") kpiNamespace := gatewayv1.Namespace(kpi.Namespace) @@ -142,7 +143,7 @@ func (r *Reconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Resu ) } var err error - credentialsStore, err = image.CredentialsStoreFromString(string(secretData)) + credentialsStore, err = orascreds.NewReadOnlyFileStore(bytes.NewReader(secretData)) if err != nil { return ctrl.Result{}, setStatusConditionFailedForKongPluginInstallation(ctx, r.Client, &kpi, fmt.Sprintf("can't parse secret: %q data: %s", secretNN, err)) } diff --git a/controller/kongplugininstallation/image/image.go b/controller/kongplugininstallation/image/image.go index 3372c1c9d..0aebaa897 100644 --- a/controller/kongplugininstallation/image/image.go +++ b/controller/kongplugininstallation/image/image.go @@ -7,7 +7,6 @@ import ( "errors" "fmt" "io" - "os" "path/filepath" "strings" "sync" @@ -118,26 +117,6 @@ func FetchPlugin(ctx context.Context, imageURL string, credentialsStore credenti return extractKongPluginFromLayer(contentOfLayerWithPlugin) } -// CredentialsStoreFromString expects content of typical configuration as a string, described -// in https://kubernetes.io/docs/tasks/configure-pod-container/pull-image-private-registry -// and returns credentials.Store. -// This is typical way how private registries are used with Docker and Kubernetes. -func CredentialsStoreFromString(s string) (credentials.Store, error) { - // TODO: Now we create temporary file, which is not great and should be changed, - // but it's the only way to use credentials.NewFileStore(...) which robustly - // parses config.json (format used by Docker and Kubernetes). - tmpFile, err := os.CreateTemp("", "credentials") - if err != nil { - return nil, fmt.Errorf("failed to create temporary file: %w", err) - } - defer os.Remove(tmpFile.Name()) - defer tmpFile.Close() - if _, err = tmpFile.WriteString(s); err != nil { - return nil, fmt.Errorf("failed to write credentials to file: %w", err) - } - return credentials.NewFileStore(tmpFile.Name()) -} - type sizeLimitBytes int64 func (sl sizeLimitBytes) int64() int64 { diff --git a/controller/kongplugininstallation/image/image_test.go b/controller/kongplugininstallation/image/image_test.go index 0d328fafb..11d412416 100644 --- a/controller/kongplugininstallation/image/image_test.go +++ b/controller/kongplugininstallation/image/image_test.go @@ -2,11 +2,12 @@ package image_test import ( "context" + "strings" "testing" "github.com/stretchr/testify/require" "oras.land/oras-go/v2/registry/remote/auth" - "oras.land/oras-go/v2/registry/remote/credentials" + orascreds "oras.land/oras-go/v2/registry/remote/credentials" "github.com/kong/gateway-operator/controller/kongplugininstallation/image" "github.com/kong/gateway-operator/test/integration" @@ -17,7 +18,7 @@ func TestCredentialsStoreFromString(t *testing.T) { name string credentials string expectedErrorMsg string - expectedCredentials func(t *testing.T, cs credentials.Store) + expectedCredentials func(t *testing.T, cs orascreds.Store) }{ { name: "invalid credentials", @@ -35,7 +36,7 @@ func TestCredentialsStoreFromString(t *testing.T) { } } }`, - expectedCredentials: func(t *testing.T, cs credentials.Store) { + expectedCredentials: func(t *testing.T, cs orascreds.Store) { t.Helper() require.NotNil(t, cs) c, err := cs.Get(context.Background(), "ghcr.io") @@ -47,7 +48,7 @@ func TestCredentialsStoreFromString(t *testing.T) { for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { - credsStore, err := image.CredentialsStoreFromString(tc.credentials) + credsStore, err := orascreds.NewReadOnlyFileStore(strings.NewReader(tc.credentials)) if tc.expectedCredentials != nil { tc.expectedCredentials(t, credsStore) } else { @@ -94,7 +95,7 @@ func TestFetchPluginContent(t *testing.T) { t.Skip("skipping - no credentials provided") } - credsStore, err := image.CredentialsStoreFromString(credentials) + credsStore, err := orascreds.NewReadOnlyFileStore(strings.NewReader(credentials)) require.NoError(t, err) plugin, err := image.FetchPlugin( diff --git a/go.mod b/go.mod index f554be0b8..b53a83feb 100644 --- a/go.mod +++ b/go.mod @@ -8,6 +8,8 @@ go 1.23.2 // This retraction is to prevent it from being used and from breaking builds of dependent projects. retract v1.2.2 +replace oras.land/oras-go/v2 => github.com/programmer04/oras-go/v2 v2.5.1-0.20241218150055-30e49616b702 + require ( github.com/Kong/sdk-konnect-go v0.1.14 github.com/Masterminds/semver v1.5.0 diff --git a/go.sum b/go.sum index ee48afe4f..141a982e7 100644 --- a/go.sum +++ b/go.sum @@ -388,6 +388,8 @@ github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRI github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pquerna/otp v1.4.0 h1:wZvl1TIVxKRThZIBiwOOHOGP/1+nZyWBil9Y2XNEDzg= github.com/pquerna/otp v1.4.0/go.mod h1:dkJfzwRKNiegxyNb54X/3fLwhCynbMspSyWKnvi1AEg= +github.com/programmer04/oras-go/v2 v2.5.1-0.20241218150055-30e49616b702 h1:FwZ4uQxKGq3pnc7rKxvByeMQc7SYkgpZ+hMNdqfssQw= +github.com/programmer04/oras-go/v2 v2.5.1-0.20241218150055-30e49616b702/go.mod h1:ecS2SG90/ztmqyrxF98+K4Uxq88AqdpZti6DP3g3FZc= github.com/prometheus/client_golang v1.20.4 h1:Tgh3Yr67PaOv/uTqloMsCEdeuFTatm5zIq5+qNN23vI= github.com/prometheus/client_golang v1.20.4/go.mod h1:PIEt8X02hGcP8JWbeHyeZ53Y/jReSnHgO035n//V5WE= github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= @@ -687,8 +689,6 @@ k8s.io/kubernetes v1.32.0 h1:4BDBWSolqPrv8GC3YfZw0CJvh5kA1TPnoX0FxDVd+qc= k8s.io/kubernetes v1.32.0/go.mod h1:tiIKO63GcdPRBHW2WiUFm3C0eoLczl3f7qi56Dm1W8I= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738 h1:M3sRQVHv7vB20Xc2ybTt7ODCeFj6JSWYFzOFnYeS6Ro= k8s.io/utils v0.0.0-20241104100929-3ea5e8cea738/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0= -oras.land/oras-go/v2 v2.5.0 h1:o8Me9kLY74Vp5uw07QXPiitjsw7qNXi8Twd+19Zf02c= -oras.land/oras-go/v2 v2.5.0/go.mod h1:z4eisnLP530vwIOUOJeBIj0aGI0L1C3d53atvCBqZHg= sigs.k8s.io/controller-runtime v0.19.3 h1:XO2GvC9OPftRst6xWCpTgBZO04S2cbp0Qqkj8bX1sPw= sigs.k8s.io/controller-runtime v0.19.3/go.mod h1:j4j87DqtsThvwTv5/Tc5NFRyyF/RF0ip4+62tbTSIUM= sigs.k8s.io/gateway-api v1.2.1 h1:fZZ/+RyRb+Y5tGkwxFKuYuSRQHu9dZtbjenblleOLHM=