From 547ef5b55dc3f8e706c462a6a139565bbb44ded0 Mon Sep 17 00:00:00 2001 From: Pavel Busko Date: Tue, 11 Jan 2022 10:01:15 +0100 Subject: [PATCH] feat(cnbBuild): remove docker config after parsing (#3417) Co-authored-by: Philipp Stehle --- cmd/cnbBuild.go | 42 +++++++------------ cmd/cnbBuild_test.go | 11 +++-- pkg/cnbutils/auth.go | 37 ++++++++++++++++ pkg/cnbutils/auth_test.go | 42 +++++++++++++++++++ pkg/cnbutils/bindings/bindings_test.go | 4 +- pkg/cnbutils/buildpack_test.go | 27 ++++-------- pkg/cnbutils/env_test.go | 11 ++--- pkg/cnbutils/mock.go | 20 ++++----- pkg/cnbutils/order_test.go | 19 ++++----- pkg/cnbutils/project/descriptor_test.go | 10 ++--- .../project/metadata/metadata_test.go | 2 +- pkg/piperutils/FileUtils.go | 1 + 12 files changed, 142 insertions(+), 84 deletions(-) create mode 100644 pkg/cnbutils/auth.go create mode 100644 pkg/cnbutils/auth_test.go diff --git a/cmd/cnbBuild.go b/cmd/cnbBuild.go index a01f59295..c3addd04d 100644 --- a/cmd/cnbBuild.go +++ b/cmd/cnbBuild.go @@ -2,7 +2,6 @@ package cmd import ( "archive/zip" - "encoding/json" "fmt" "os" "path" @@ -21,7 +20,6 @@ import ( "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/piperutils" "github.com/SAP/jenkins-library/pkg/telemetry" - "github.com/docker/cli/cli/config/configfile" "github.com/pkg/errors" ignore "github.com/sabhiram/go-gitignore" ) @@ -295,36 +293,12 @@ func runCnbBuild(config *cnbBuildOptions, telemetryData *telemetry.CustomData, u } dockerConfigFile := "" - dockerConfig := &configfile.ConfigFile{} - dockerConfigJSON := []byte(`{"auths":{}}`) if len(config.DockerConfigJSON) > 0 { dockerConfigFile, err = prepareDockerConfig(config.DockerConfigJSON, utils) if err != nil { log.SetErrorCategory(log.ErrorConfiguration) return errors.Wrapf(err, "failed to rename DockerConfigJSON file '%v'", config.DockerConfigJSON) } - dockerConfigJSON, err = utils.FileRead(dockerConfigFile) - if err != nil { - log.SetErrorCategory(log.ErrorConfiguration) - return errors.Wrapf(err, "failed to read DockerConfigJSON file '%v'", config.DockerConfigJSON) - } - } - - err = json.Unmarshal(dockerConfigJSON, dockerConfig) - if err != nil { - log.SetErrorCategory(log.ErrorConfiguration) - return errors.Wrapf(err, "failed to parse DockerConfigJSON file '%v'", config.DockerConfigJSON) - } - - auth := map[string]string{} - for registry, value := range dockerConfig.AuthConfigs { - auth[registry] = fmt.Sprintf("Basic %s", value.Auth) - } - - cnbRegistryAuth, err := json.Marshal(auth) - if err != nil { - log.SetErrorCategory(log.ErrorConfiguration) - return errors.Wrap(err, "failed to marshal DockerConfigJSON") } target := "/workspace" @@ -374,6 +348,20 @@ func runCnbBuild(config *cnbBuildOptions, telemetryData *telemetry.CustomData, u } } + cnbRegistryAuth, err := cnbutils.GenerateCnbAuth(dockerConfigFile, utils) + if err != nil { + log.SetErrorCategory(log.ErrorConfiguration) + return errors.Wrap(err, "failed to generate CNB_REGISTRY_AUTH") + } + + if dockerConfigFile != "" { + err = utils.FileRemove(dockerConfigFile) + if err != nil { + log.SetErrorCategory(log.ErrorBuild) + return errors.Wrap(err, "failed to remove docker config.json file") + } + } + if len(config.ContainerRegistryURL) == 0 || len(config.ContainerImageName) == 0 || len(config.ContainerImageTag) == 0 { log.SetErrorCategory(log.ErrorConfiguration) return errors.New("containerRegistryUrl, containerImageName and containerImageTag must be present") @@ -411,7 +399,7 @@ func runCnbBuild(config *cnbBuildOptions, telemetryData *telemetry.CustomData, u log.Entry().Info("skipping certificates update") } - utils.AppendEnv([]string{fmt.Sprintf("CNB_REGISTRY_AUTH=%s", string(cnbRegistryAuth))}) + utils.AppendEnv([]string{fmt.Sprintf("CNB_REGISTRY_AUTH=%s", cnbRegistryAuth)}) utils.AppendEnv([]string{"CNB_PLATFORM_API=0.8"}) creatorArgs := []string{ diff --git a/cmd/cnbBuild_test.go b/cmd/cnbBuild_test.go index 3d73f34dd..f3ac9803e 100644 --- a/cmd/cnbBuild_test.go +++ b/cmd/cnbBuild_test.go @@ -17,7 +17,6 @@ func newCnbBuildTestsUtils() cnbutils.MockUtils { utils := cnbutils.MockUtils{ ExecMockRunner: &mock.ExecMockRunner{}, FilesMock: &mock.FilesMock{}, - DockerMock: &cnbutils.DockerMock{}, } return utils } @@ -118,6 +117,12 @@ func TestRunCnbBuild(t *testing.T) { assert.Contains(t, runner.Calls[0].Params, "/tmp/buildpacks/order.toml") assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:%s", registry, config.ContainerImageName, config.ContainerImageTag)) assert.Contains(t, runner.Calls[0].Params, fmt.Sprintf("%s/%s:latest", registry, config.ContainerImageName)) + + initialFileExists, _ := utils.FileExists("/path/to/test.json") + renamedFileExists, _ := utils.FileExists("/path/to/config.json") + + assert.False(t, initialFileExists) + assert.False(t, renamedFileExists) }) t.Run("success case (customTlsCertificates)", func(t *testing.T) { @@ -200,7 +205,7 @@ func TestRunCnbBuild(t *testing.T) { addBuilderFiles(&utils) err := runCnbBuild(&config, nil, &utils, &commonPipelineEnvironment, &piperhttp.Client{}) - assert.EqualError(t, err, "failed to parse DockerConfigJSON file '/path/to/config.json': json: cannot unmarshal string into Go struct field ConfigFile.auths of type types.AuthConfig") + assert.EqualError(t, err, "failed to generate CNB_REGISTRY_AUTH: json: cannot unmarshal string into Go struct field ConfigFile.auths of type types.AuthConfig") }) t.Run("error case: DockerConfigJSON file not there (config.json)", func(t *testing.T) { @@ -215,7 +220,7 @@ func TestRunCnbBuild(t *testing.T) { addBuilderFiles(&utils) err := runCnbBuild(&config, nil, &utils, &commonPipelineEnvironment, &piperhttp.Client{}) - assert.EqualError(t, err, "failed to read DockerConfigJSON file 'not-there/config.json': could not read 'not-there/config.json'") + assert.EqualError(t, err, "failed to generate CNB_REGISTRY_AUTH: could not read 'not-there/config.json'") }) t.Run("error case: DockerConfigJSON file not there (not config.json)", func(t *testing.T) { diff --git a/pkg/cnbutils/auth.go b/pkg/cnbutils/auth.go new file mode 100644 index 000000000..ec4a0b68d --- /dev/null +++ b/pkg/cnbutils/auth.go @@ -0,0 +1,37 @@ +package cnbutils + +import ( + "encoding/json" + "fmt" + + "github.com/docker/cli/cli/config/configfile" +) + +func GenerateCnbAuth(config string, utils BuildUtils) (string, error) { + var err error + dockerConfig := &configfile.ConfigFile{} + + if config != "" { + dockerConfigJSON, err := utils.FileRead(config) + if err != nil { + return "", err + } + + err = json.Unmarshal(dockerConfigJSON, dockerConfig) + if err != nil { + return "", err + } + } + + auth := map[string]string{} + for registry, value := range dockerConfig.AuthConfigs { + auth[registry] = fmt.Sprintf("Basic %s", value.Auth) + } + + cnbRegistryAuth, err := json.Marshal(auth) + if err != nil { + return "", err + } + + return string(cnbRegistryAuth), nil +} diff --git a/pkg/cnbutils/auth_test.go b/pkg/cnbutils/auth_test.go new file mode 100644 index 000000000..3c683cf53 --- /dev/null +++ b/pkg/cnbutils/auth_test.go @@ -0,0 +1,42 @@ +package cnbutils_test + +import ( + "testing" + + "github.com/SAP/jenkins-library/pkg/cnbutils" + "github.com/SAP/jenkins-library/pkg/mock" + "github.com/stretchr/testify/assert" +) + +func TestGenerateCnbAuth(t *testing.T) { + var mockUtils = &cnbutils.MockUtils{ + ExecMockRunner: &mock.ExecMockRunner{}, + FilesMock: &mock.FilesMock{}, + } + + t.Run("successfully generates cnb auth env variable", func(t *testing.T) { + mockUtils.AddFile("/test/valid_config.json", []byte("{\"auths\":{\"example.com\":{\"username\":\"username\",\"password\":\"password\",\"auth\":\"dXNlcm5hbWU6cGFzc3dvcmQ=\"}}}")) + auth, err := cnbutils.GenerateCnbAuth("/test/valid_config.json", mockUtils) + assert.NoError(t, err) + assert.Equal(t, "{\"example.com\":\"Basic dXNlcm5hbWU6cGFzc3dvcmQ=\"}", auth) + }) + + t.Run("successfully generates cnb auth env variable if docker config is not present", func(t *testing.T) { + auth, err := cnbutils.GenerateCnbAuth("", mockUtils) + assert.NoError(t, err) + assert.Equal(t, "{}", auth) + }) + + t.Run("fails if file not found", func(t *testing.T) { + _, err := cnbutils.GenerateCnbAuth("/not/found", mockUtils) + assert.Error(t, err) + assert.Equal(t, "could not read '/not/found'", err.Error()) + }) + + t.Run("fails if file is invalid json", func(t *testing.T) { + mockUtils.AddFile("/test/invalid_config.json", []byte("not a json")) + _, err := cnbutils.GenerateCnbAuth("/test/invalid_config.json", mockUtils) + assert.Error(t, err) + assert.Equal(t, "invalid character 'o' in literal null (expecting 'u')", err.Error()) + }) +} diff --git a/pkg/cnbutils/bindings/bindings_test.go b/pkg/cnbutils/bindings/bindings_test.go index eabd08d52..be0592fef 100644 --- a/pkg/cnbutils/bindings/bindings_test.go +++ b/pkg/cnbutils/bindings/bindings_test.go @@ -13,8 +13,8 @@ import ( ) func TestProcessBindings(t *testing.T) { - var mockUtils = func() cnbutils.MockUtils { - var utils = cnbutils.MockUtils{ + var mockUtils = func() *cnbutils.MockUtils { + var utils = &cnbutils.MockUtils{ FilesMock: &mock.FilesMock{}, } utils.AddFile("/tmp/somefile.yaml", []byte("some file content")) diff --git a/pkg/cnbutils/buildpack_test.go b/pkg/cnbutils/buildpack_test.go index f20dfea85..1493d69e2 100644 --- a/pkg/cnbutils/buildpack_test.go +++ b/pkg/cnbutils/buildpack_test.go @@ -1,35 +1,24 @@ -package cnbutils +package cnbutils_test import ( "testing" + "github.com/SAP/jenkins-library/pkg/cnbutils" "github.com/SAP/jenkins-library/pkg/mock" "github.com/stretchr/testify/assert" ) -var mockUtils = MockUtils{ - ExecMockRunner: &mock.ExecMockRunner{}, - FilesMock: &mock.FilesMock{}, - DockerMock: &DockerMock{}, -} - func TestBuildpackDownload(t *testing.T) { + var mockUtils = &cnbutils.MockUtils{ + ExecMockRunner: &mock.ExecMockRunner{}, + FilesMock: &mock.FilesMock{}, + } + t.Run("successfully downloads a buildpack", func(t *testing.T) { mockUtils.AddDir("/tmp/testtest") - _, err := DownloadBuildpacks("/test", []string{"test"}, "/test/config.json", mockUtils) + _, err := cnbutils.DownloadBuildpacks("/test", []string{"test"}, "/test/config.json", mockUtils) assert.NoError(t, err) assert.True(t, mockUtils.HasRemovedFile("/tmp/testtest")) }) } - -func TestBuildpackCopy(t *testing.T) { - t.Run("successfully downloads a buildpack", func(t *testing.T) { - - mockUtils.AddDir("/src/buildpack/0.0.1") - mockUtils.AddDir("/dst") - err := copyBuildPack("/src", "/dst", mockUtils) - - assert.NoError(t, err) - }) -} diff --git a/pkg/cnbutils/env_test.go b/pkg/cnbutils/env_test.go index 80ed2e6aa..e407d814b 100644 --- a/pkg/cnbutils/env_test.go +++ b/pkg/cnbutils/env_test.go @@ -1,16 +1,17 @@ -package cnbutils +package cnbutils_test import ( "fmt" "testing" + "github.com/SAP/jenkins-library/pkg/cnbutils" "github.com/SAP/jenkins-library/pkg/mock" "github.com/stretchr/testify/assert" ) func TestCreateEnvFiles(t *testing.T) { t.Run("successfully writes environment files", func(t *testing.T) { - mockUtils := MockUtils{ + mockUtils := &cnbutils.MockUtils{ FilesMock: &mock.FilesMock{}, } @@ -20,7 +21,7 @@ func TestCreateEnvFiles(t *testing.T) { "COMPLEX": "{\"foo\": \"bar=3\"}", } - err := CreateEnvFiles(mockUtils, "/tmp/platform", envVars) + err := cnbutils.CreateEnvFiles(mockUtils, "/tmp/platform", envVars) assert.NoError(t, err) assert.True(t, mockUtils.HasWrittenFile("/tmp/platform/env/FOO")) @@ -41,7 +42,7 @@ func TestCreateEnvFiles(t *testing.T) { }) t.Run("raises an error if unable to write to a file", func(t *testing.T) { - mockUtils := MockUtils{ + mockUtils := &cnbutils.MockUtils{ FilesMock: &mock.FilesMock{ FileWriteErrors: map[string]error{ "/tmp/platform/env/FOO": fmt.Errorf("unable to create dir"), @@ -49,7 +50,7 @@ func TestCreateEnvFiles(t *testing.T) { }, } - err := CreateEnvFiles(mockUtils, "/tmp/platform", map[string]interface{}{"FOO": "BAR"}) + err := cnbutils.CreateEnvFiles(mockUtils, "/tmp/platform", map[string]interface{}{"FOO": "BAR"}) assert.Error(t, err) assert.Equal(t, err.Error(), "unable to create dir") }) diff --git a/pkg/cnbutils/mock.go b/pkg/cnbutils/mock.go index b25c80935..2ff4f1a30 100644 --- a/pkg/cnbutils/mock.go +++ b/pkg/cnbutils/mock.go @@ -1,12 +1,13 @@ +//go:build !release // +build !release package cnbutils import ( "io" + "path/filepath" pkgutil "github.com/GoogleContainerTools/container-diff/pkg/util" - "github.com/SAP/jenkins-library/pkg/docker" "github.com/SAP/jenkins-library/pkg/mock" "github.com/SAP/jenkins-library/pkg/piperutils" v1 "github.com/google/go-containerregistry/pkg/v1" @@ -16,21 +17,13 @@ import ( type MockUtils struct { *mock.ExecMockRunner *mock.FilesMock - *DockerMock -} - -func (c *MockUtils) GetDockerClient() docker.Download { - return c.DockerMock } func (c *MockUtils) GetFileUtils() piperutils.FileUtils { return c.FilesMock } -type DockerMock struct{} - -func (d *DockerMock) DownloadImageToPath(_, filePath string) (pkgutil.Image, error) { - +func (c *MockUtils) DownloadImageToPath(bpack, filePath string) (pkgutil.Image, error) { fakeImage := fakeImage.FakeImage{} fakeImage.ConfigFileReturns(&v1.ConfigFile{ Config: v1.Config{ @@ -39,16 +32,19 @@ func (d *DockerMock) DownloadImageToPath(_, filePath string) (pkgutil.Image, err }, }, }, nil) + + c.AddDir(filepath.Join(filePath, "cnb/buildpacks", bpack)) + c.AddDir(filepath.Join(filePath, "cnb/buildpacks", bpack, "0.0.1")) img := pkgutil.Image{ Image: &fakeImage, } return img, nil } -func (d *DockerMock) GetImageSource() (string, error) { +func (c *MockUtils) GetImageSource() (string, error) { return "imageSource", nil } -func (d *DockerMock) TarImage(writer io.Writer, image pkgutil.Image) error { +func (c *MockUtils) TarImage(writer io.Writer, image pkgutil.Image) error { return nil } diff --git a/pkg/cnbutils/order_test.go b/pkg/cnbutils/order_test.go index 28b007ef2..6364075de 100644 --- a/pkg/cnbutils/order_test.go +++ b/pkg/cnbutils/order_test.go @@ -1,22 +1,22 @@ -package cnbutils +package cnbutils_test import ( "fmt" "testing" + "github.com/SAP/jenkins-library/pkg/cnbutils" "github.com/SAP/jenkins-library/pkg/mock" "github.com/stretchr/testify/assert" ) func TestOrderSave(t *testing.T) { t.Run("successfully Encode struct to toml format (multiple buildpacks)", func(t *testing.T) { - mockUtils := MockUtils{ + mockUtils := &cnbutils.MockUtils{ ExecMockRunner: &mock.ExecMockRunner{}, FilesMock: &mock.FilesMock{}, - DockerMock: &DockerMock{}, } - testBuildpacks := []BuildPackMetadata{ + testBuildpacks := []cnbutils.BuildPackMetadata{ { ID: "paketo-buildpacks/sap-machine", Version: "1.1.1", @@ -26,13 +26,13 @@ func TestOrderSave(t *testing.T) { Version: "2.2.2", }, } - testOrder := Order{ + testOrder := cnbutils.Order{ Utils: mockUtils, } - var testEntry OrderEntry + var testEntry cnbutils.OrderEntry testEntry.Group = append(testEntry.Group, testBuildpacks...) - testOrder.Order = []OrderEntry{testEntry} + testOrder.Order = []cnbutils.OrderEntry{testEntry} err := testOrder.Save("/tmp/order.toml") @@ -44,15 +44,14 @@ func TestOrderSave(t *testing.T) { }) t.Run("raises an error if unable to write the file", func(t *testing.T) { - mockUtils := MockUtils{ + mockUtils := &cnbutils.MockUtils{ ExecMockRunner: &mock.ExecMockRunner{}, FilesMock: &mock.FilesMock{}, - DockerMock: &DockerMock{}, } mockUtils.FileWriteErrors = map[string]error{ "/tmp/order.toml": fmt.Errorf("unable to write to file"), } - testOrder := Order{ + testOrder := cnbutils.Order{ Utils: mockUtils, } diff --git a/pkg/cnbutils/project/descriptor_test.go b/pkg/cnbutils/project/descriptor_test.go index 686344194..982d24e36 100644 --- a/pkg/cnbutils/project/descriptor_test.go +++ b/pkg/cnbutils/project/descriptor_test.go @@ -41,7 +41,7 @@ version = "5.9.1" [[build.buildpacks]] id = "paketo-buildpacks/nodejs" ` - utils := cnbutils.MockUtils{ + utils := &cnbutils.MockUtils{ FilesMock: &mock.FilesMock{}, } @@ -92,7 +92,7 @@ id = "test/inline" shell = "/bin/bash" inline = "date" ` - utils := cnbutils.MockUtils{ + utils := &cnbutils.MockUtils{ FilesMock: &mock.FilesMock{}, } @@ -119,7 +119,7 @@ exclude = [ ] ` - utils := cnbutils.MockUtils{ + utils := &cnbutils.MockUtils{ FilesMock: &mock.FilesMock{}, } utils.AddFile("project.toml", []byte(projectToml)) @@ -131,7 +131,7 @@ exclude = [ }) t.Run("fails with file not found", func(t *testing.T) { - utils := cnbutils.MockUtils{ + utils := &cnbutils.MockUtils{ FilesMock: &mock.FilesMock{}, } @@ -143,7 +143,7 @@ exclude = [ t.Run("fails to parse corrupted project.toml", func(t *testing.T) { projectToml := "test123" - utils := cnbutils.MockUtils{ + utils := &cnbutils.MockUtils{ FilesMock: &mock.FilesMock{}, } utils.AddFile("project.toml", []byte(projectToml)) diff --git a/pkg/cnbutils/project/metadata/metadata_test.go b/pkg/cnbutils/project/metadata/metadata_test.go index c4ace5385..8ad29415c 100644 --- a/pkg/cnbutils/project/metadata/metadata_test.go +++ b/pkg/cnbutils/project/metadata/metadata_test.go @@ -24,7 +24,7 @@ func TestWriteProjectMetadata(t *testing.T) { commit = "012548" describe = "test-commit" ` - mockUtils := cnbutils.MockUtils{ + mockUtils := &cnbutils.MockUtils{ ExecMockRunner: &mock.ExecMockRunner{}, FilesMock: &mock.FilesMock{}, } diff --git a/pkg/piperutils/FileUtils.go b/pkg/piperutils/FileUtils.go index c049be763..c186b8e19 100644 --- a/pkg/piperutils/FileUtils.go +++ b/pkg/piperutils/FileUtils.go @@ -23,6 +23,7 @@ type FileUtils interface { Copy(src, dest string) (int64, error) FileRead(path string) ([]byte, error) FileWrite(path string, content []byte, perm os.FileMode) error + FileRemove(path string) error MkdirAll(path string, perm os.FileMode) error Chmod(path string, mode os.FileMode) error Glob(pattern string) (matches []string, err error)