From dce80a851c94da1d71050d59b0032c6e19eed99d Mon Sep 17 00:00:00 2001 From: Santosh Date: Mon, 24 Jun 2024 14:37:11 +0530 Subject: [PATCH] Fix failing push/pull commands in CI Signed-off-by: Santosh --- README.md | 4 ---- cmd/artifact_pull.go | 4 ++-- cmd/artifact_push.go | 29 +++++++++++++++------- pkg/oci/ociClient.go | 57 ++++++++++++++++++++++++++++---------------- 4 files changed, 59 insertions(+), 35 deletions(-) diff --git a/README.md b/README.md index 0e1cde0a..5c8c87ac 100644 --- a/README.md +++ b/README.md @@ -390,10 +390,6 @@ Genval offers comprehensive management capabilities for the configuration files To bolster supply chain security workflows, Genval enables users to sign the artifacts after storing them in the registry. Similarly, when pulling any artifact, Genval provides functionality to verify the signatures of the artifacts. This feature leverages **Sigstore's Cosign keyless mode** of signing and verifying artifacts. However, users can also utilize their own private and public keys for signing and verifying the artifacts respectively. -To facilitate authentication with container registries, Genval initially looks for the `~/.docker/config.json` file in the user's -`$HOME` directory. If this file is found, Genval utilizes it for authentication with the registry. However, if the file is not present, -users must set the `ARTIFACT_REGISTRY_USERNAME` and `ARTIFACT_REGISTRY_PASSWORD` environment variables to authenticate with the container registry. - #### Building, pushing, and signing generated and/or verified config files and OCI artifacts The following command demonstrates building and pushing the OCI artifact (genval:test) to GitHub Container Registry (ghcr.io) while signing the artifact with Cosign in Keyless mode: diff --git a/cmd/artifact_pull.go b/cmd/artifact_pull.go index 86120aad..fc2d20a9 100644 --- a/cmd/artifact_pull.go +++ b/cmd/artifact_pull.go @@ -106,8 +106,8 @@ func runPullArtifactCmd(cmd *cobra.Command, args []string) error { defer spin.Stop() if err := oci.PullArtifact(context.Background(), pullArgs.creds, pullArgs.dest, pullArgs.path); err != nil { - color.Red("Error pulling artifact from remote : %v", err) - return err + fe := color.RedString("Error pulling artifact from remote: %v", err) + return fmt.Errorf(fe) } spin.Stop() color.Green("Artifact from %s pulled and stored in :%s", pullArgs.dest, pullArgs.path) diff --git a/cmd/artifact_push.go b/cmd/artifact_push.go index 87d59419..3d5336a7 100644 --- a/cmd/artifact_push.go +++ b/cmd/artifact_push.go @@ -1,11 +1,13 @@ package cmd import ( + "context" "fmt" "os" "path/filepath" "time" + "github.com/fatih/color" "github.com/google/go-containerregistry/pkg/authn" "github.com/google/go-containerregistry/pkg/compression" "github.com/google/go-containerregistry/pkg/crane" @@ -155,21 +157,31 @@ func runPushCmd(cmd *cobra.Command, args []string) error { if err != nil { log.Errorf("appending content to artifact failed: %v", err) } + spin := utils.StartSpinner("pushing artifact") defer spin.Stop() + + var opts []crane.Option auth, err := oci.GetCreds(pushArgs.creds) if err != nil { - return fmt.Errorf("error getting credentials: %v", err) + return err } - opts, err := oci.GenerateCraneOptions(ref, auth, []string{ref.Context().Scope(transport.PushScope)}) - if err != nil { - log.Errorf("Error creating options required for push: %v", err) + + if pushArgs.creds == "" || auth == nil { + auth, err = authn.DefaultKeychain.Resolve(ref.Context()) + if err != nil { + return err + } } + opts = append(opts, crane.WithAuth(auth)) - if pushArgs.creds == "" { - opts = append(opts, crane.WithAuthFromKeychain(authn.DefaultKeychain)) + + topts, err := oci.GenerateCraneOptions(context.Background(), ref.Context().Registry, auth, []string{ref.Context().Scope(transport.PushScope)}) + if err != nil { + return fmt.Errorf("error creating transport for push operation: %v", err) } + opts = append(opts, topts) if err := crane.Push(img, ref.String(), opts...); err != nil { log.Fatalf("Error pushing artifact: %v", err) } @@ -188,7 +200,8 @@ func runPushCmd(cmd *cobra.Command, args []string) error { } } - log.Infof("✔ Artifact pushed successfully to: %v\n,Artifact Digest: %v\n", source, digest) - log.Infof("Digest URL: %v\n", digestURL) + log.Infof(color.GreenString("✔ Artifact pushed successfully to: %v", pushArgs.dest)) + log.Infof(color.GreenString("✔ Digest: %v", digest)) + log.Infof(color.GreenString("✔ Digest URL: %v\n", digestURL)) return nil } diff --git a/pkg/oci/ociClient.go b/pkg/oci/ociClient.go index ecdb0967..17672984 100644 --- a/pkg/oci/ociClient.go +++ b/pkg/oci/ociClient.go @@ -52,18 +52,26 @@ func CheckTagAndPullArchive(url, tool, creds string, archivePath *os.File) error ociref := parts[0] desiredTag := parts[1] + var opts []crane.Option auth, err := GetCreds(creds) if err != nil { - return fmt.Errorf("error getting credentials: %v", err) + return fmt.Errorf("error fetching credentials: %v", err) } - opts, err := GenerateCraneOptions(ref, auth, []string{ref.Context().Scope(transport.PullScope)}) - if err != nil { - log.Errorf("Error reading credentials: %v", err) + + if creds == "" || auth == nil { + auth, err = authn.DefaultKeychain.Resolve(ref.Context()) + if err != nil { + return fmt.Errorf("error fetching default keychain: %v", err) + } } + opts = append(opts, crane.WithAuth(auth)) - if creds == "" { - opts = append(opts, crane.WithAuthFromKeychain(authn.DefaultKeychain)) + + topts, err := GenerateCraneOptions(context.Background(), ref.Context().Registry, auth, []string{ref.Context().Scope(transport.PullScope)}) + if err != nil { + return fmt.Errorf("error creating transport for pull: %v", err) } + opts = append(opts, topts) tags, err := crane.ListTags(ociref, opts...) if err != nil { @@ -204,18 +212,26 @@ func PullArtifact(ctx context.Context, creds, dest, path string) error { url := parts[0] desiredTag := parts[1] + var opts []crane.Option auth, err := GetCreds(creds) if err != nil { - return fmt.Errorf("error getting credentials: %v", err) + return fmt.Errorf("error fetching credentials: %v", err) } - opts, err := GenerateCraneOptions(ref, auth, []string{ref.Context().Scope(transport.PullScope)}) - if err != nil { - return fmt.Errorf("error getting credentials: %v", err) + + if creds == "" || auth == nil { + auth, err = authn.DefaultKeychain.Resolve(ref.Context()) + if err != nil { + return fmt.Errorf("error fetching default keychain: %v", err) + } } + opts = append(opts, crane.WithAuth(auth)) - if creds == "" { - opts = append(opts, crane.WithAuthFromKeychain(authn.DefaultKeychain)) + + topts, err := GenerateCraneOptions(context.Background(), ref.Context().Registry, auth, []string{ref.Context().Scope(transport.PullScope)}) + if err != nil { + return fmt.Errorf("error creating transport for pull:%v", err) } + opts = append(opts, topts) tags, err := crane.ListTags(url, opts...) if err != nil { @@ -297,11 +313,11 @@ func GetCreds(creds string) (authn.Authenticator, error) { } // Most parts of GenerateCraneOptions and its related funcs are copied from https://github.com/google/go-containerregistry/blob/1b4e4078a545f2b6f96766a064b45ee77cdbefdd/pkg/v1/remote/options.go#L128 -func GenerateCraneOptions(ref name.Reference, auth authn.Authenticator, scopes []string) ([]crane.Option, error) { - opts := []crane.Option{} +// GenerateCraneOptions generates an crane options object to perform remote operations +func GenerateCraneOptions(ctx context.Context, ref name.Registry, auth authn.Authenticator, scopes []string) (crane.Option, error) { var retryTransport http.RoundTripper - userAgent := fmt.Sprintf("intelops/genval/%s (%s; %s)", version.GetVersionInfo().GitVersion, runtime.GOOS, runtime.GOARCH) + userAgent := fmt.Sprintf("genval/%s (%s; %s)", version.GetVersionInfo().GitVersion, runtime.GOOS, runtime.GOARCH) retryTransport = remote.DefaultTransport.(*http.Transport).Clone() if logs.Enabled(logs.Debug) { retryTransport = transport.NewLogger(retryTransport) @@ -319,13 +335,12 @@ func GenerateCraneOptions(ref name.Reference, auth authn.Authenticator, scopes [ })) retryTransport = transport.NewUserAgent(retryTransport, userAgent) - // t, err := transport.NewWithContext(ref.Context().Registry, auth, retryTransport, scopes) - // if err != nil { - // return nil, err - // } - opts = append(opts, crane.WithTransport(retryTransport)) + t, err := transport.NewWithContext(ctx, ref, auth, retryTransport, scopes) + if err != nil { + return nil, err + } - return opts, nil + return crane.WithTransport(t), nil } var defaultRetryPredicate = func(err error) bool {