Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Read access token to use it in authentication. #12123

Merged
merged 6 commits into from
Oct 16, 2024
Merged
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
13 changes: 13 additions & 0 deletions cmd/image-syncer/image_syncer_suite_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package main

import (
"testing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

func TestImageSyncer(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "ImageSyncer Suite")
}
63 changes: 43 additions & 20 deletions cmd/image-syncer/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,13 +184,7 @@ func SyncImage(ctx context.Context, src, dest string, dryRun bool, auth authn.Au
}

// SyncImages is a main syncing function that takes care of copying images.
func SyncImages(ctx context.Context, cfg *Config, images *imagesync.SyncDef, authCfg []byte) error {
var auth authn.Authenticator
if cfg.TargetKeyFile != "" {
auth = &authn.Basic{Username: "_json_key", Password: string(authCfg)}
} else {
auth = &authn.Bearer{Token: string(authCfg)}
}
func SyncImages(ctx context.Context, cfg *Config, images *imagesync.SyncDef, auth authn.Authenticator) error {
for _, img := range images.Images {
target, err := getTarget(img.Source, cfg.TargetRepoPrefix, img.Tag)
imageType := "Index"
Expand Down Expand Up @@ -224,6 +218,40 @@ func SyncImages(ctx context.Context, cfg *Config, images *imagesync.SyncDef, aut
return nil
}

// newAuthenticator creates a new authenticator based on the provided configuration
// An authenticator is used to authenticate to the target repository.
func (cfg *Config) newAuthenticator() (authn.Authenticator, error) {
log.Debug("started creating new authenticator")
var (
auth authn.Authenticator
authCfg []byte
err error
)

if cfg.TargetKeyFile != "" {
log.WithField("targetKeyFile", cfg.TargetKeyFile).Debug("target key file path provided, reading the file")

authCfg, err = os.ReadFile(cfg.TargetKeyFile)
if err != nil {
return nil, fmt.Errorf("could not open target auth key JSON file, error: %w", err)
}
log.Debug("target key file read successfully, creating basic authenticator")

auth = &authn.Basic{Username: "_json_key", Password: string(authCfg)}
log.WithField("username", "_json_key").Debug("basic authenticator created successfully")

return auth, nil
}
if cfg.AccessToken != "" {
log.Debug("access token provided, creating bearer authenticator")
auth = &authn.Bearer{Token: cfg.AccessToken}

return auth, nil
}

return nil, fmt.Errorf("no target auth key file or access token provided")
}

func main() {
log.Out = os.Stdout
var cfg Config
Expand All @@ -234,7 +262,6 @@ func main() {
Long: `image-syncer copies docker images. It compares checksum between source and target and protects target images against overriding`,
//nolint:revive
Run: func(cmd *cobra.Command, args []string) {
var authCfg []byte
logLevel := logrus.InfoLevel
if cfg.Debug {
logLevel = logrus.DebugLevel
Expand All @@ -248,26 +275,22 @@ func main() {
if err != nil {
log.WithError(err).Fatal("Could not parse images file")
}
if cfg.TargetKeyFile != "" {
authCfg, err = os.ReadFile(cfg.TargetKeyFile)
if err != nil {
log.WithError(err).Fatal("Could not open target auth key JSON")
}
log.Info("Parsed images file")

auth, err := cfg.newAuthenticator()
if err != nil {
log.WithError(err).Fatal("Failed to create authenticator")
}
log.Info("Created authenticator for target repository")

if cfg.DryRun {
log.Info("Dry-Run enabled. Program will not make any changes to the target repository.")
}

// This error looks like some leftover.
if err != nil {
log.WithError(err).Fatal("Failed to create signer instance")
}
if err := SyncImages(ctx, &cfg, imagesFile, authCfg); err != nil {
if err := SyncImages(ctx, &cfg, imagesFile, auth); err != nil {
log.WithError(err).Fatal("Failed to sync images")
} else {
log.Info("All images synced successfully")
}
log.Info("All images synced successfully")
},
}

Expand Down
55 changes: 55 additions & 0 deletions cmd/image-syncer/main_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package main

import (
"github.com/google/go-containerregistry/pkg/authn"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

var _ = Describe("newAuthenticator", func() {
var cfg Config

BeforeEach(func() {
cfg = Config{}
})

Context("when TargetKeyFile is provided", func() {
It("should create a basic authenticator", func() {
cfg.TargetKeyFile = "./test-fixtures/keyfile.json"
auth, err := cfg.newAuthenticator()
Expect(err).NotTo(HaveOccurred())
Expect(auth).To(Equal(&authn.Basic{
Username: "_json_key",
Password: "test_content",
}))
})

It("should return an error if the key file cannot be read", func() {
cfg.TargetKeyFile = "./test-fixtures/invalid_keyfile.json"
auth, err := cfg.newAuthenticator()
Expect(err).To(HaveOccurred())
Expect(auth).To(BeNil())
})
})

Context("when AccessToken is provided", func() {
It("should create a bearer authenticator", func() {
cfg.AccessToken = "valid-access-token"
auth, err := cfg.newAuthenticator()
Expect(err).NotTo(HaveOccurred())
Expect(auth).To(Equal(&authn.Bearer{
Token: "valid-access-token",
}))
})
})

Context("when neither TargetKeyFile nor AccessToken is provided", func() {
It("should return an error", func() {
cfg.TargetKeyFile = ""
cfg.AccessToken = ""
auth, err := cfg.newAuthenticator()
Expect(err).To(HaveOccurred())
Expect(auth).To(BeNil())
})
})
})
1 change: 1 addition & 0 deletions cmd/image-syncer/test-fixtures/keyfile.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
test_content
6 changes: 0 additions & 6 deletions cmd/image-syncer/util_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,11 @@ package main

import (
"os"
"testing"

. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

func TestMainSuite(t *testing.T) {
RegisterFailHandler(Fail)
RunSpecs(t, "Main Suite")
}

var _ = Describe("getTarget", func() {
tests := []struct {
source string
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ require (
github.com/jamiealquiza/envy v1.1.0
github.com/jinzhu/copier v0.4.0
github.com/microsoft/azure-devops-go-api/azuredevops/v7 v7.1.0
github.com/onsi/ginkgo/v2 v2.20.2
github.com/onsi/ginkgo/v2 v2.20.1
github.com/onsi/gomega v1.34.2
github.com/pkg/errors v0.9.1
github.com/sirupsen/logrus v1.9.3
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -548,8 +548,8 @@ github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.11.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4=
github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag=
github.com/onsi/ginkgo/v2 v2.20.1 h1:YlVIbqct+ZmnEph770q9Q7NVAz4wwIiVNahee6JyUzo=
github.com/onsi/ginkgo/v2 v2.20.1/go.mod h1:lG9ey2Z29hR41WMVthyJBGUBcBhGOtoPF2VFMvBXFCI=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.7.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY=
github.com/onsi/gomega v1.34.2 h1:pNCwDkzrsv7MS9kpaQvVb1aVLahQXyJ/Tv5oAZMI3i8=
Expand Down
Loading