diff --git a/cmd/ansSendEvent.go b/cmd/ansSendEvent.go index 9376675f0a..484906a9e5 100644 --- a/cmd/ansSendEvent.go +++ b/cmd/ansSendEvent.go @@ -2,10 +2,11 @@ package cmd import ( "encoding/json" + "time" + "github.com/SAP/jenkins-library/pkg/ans" "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/telemetry" - "time" ) func ansSendEvent(config ansSendEventOptions, telemetryData *telemetry.CustomData) { diff --git a/cmd/cloudFoundryDeploy.go b/cmd/cloudFoundryDeploy.go index 4bf7cf40e2..79a4e19aa2 100644 --- a/cmd/cloudFoundryDeploy.go +++ b/cmd/cloudFoundryDeploy.go @@ -148,7 +148,7 @@ func validateAppName(appName string) error { } message = append(message, fmt.Sprintf("Please change the name to fit this requirement(s). For more details please visit %s.", docuLink)) if fail { - return fmt.Errorf(strings.Join(message, " ")) + return errors.New(strings.Join(message, " ")) } return nil } diff --git a/cmd/cnbBuild.go b/cmd/cnbBuild.go index 6ee7a5d3d1..61dc9803a6 100644 --- a/cmd/cnbBuild.go +++ b/cmd/cnbBuild.go @@ -168,18 +168,17 @@ func cleanDir(dir string, utils cnbutils.BuildUtils) error { } func extractZip(source, target string) error { - if isZip(source) { - log.Entry().Infof("Extracting archive '%s' to '%s'", source, target) - _, err := piperutils.Unzip(source, target) - if err != nil { - log.SetErrorCategory(log.ErrorBuild) - return errors.Wrapf(err, "Extracting archive '%s' to '%s' failed", source, target) - } - } else { + if !isZip(source) { log.SetErrorCategory(log.ErrorBuild) return errors.New("application path must be a directory or zip") } + log.Entry().Infof("Extracting archive '%s' to '%s'", source, target) + _, err := piperutils.Unzip(source, target) + if err != nil { + log.SetErrorCategory(log.ErrorBuild) + return errors.Wrapf(err, "Extracting archive '%s' to '%s' failed", source, target) + } return nil } @@ -537,12 +536,6 @@ func runCnbBuild(config *cnbBuildOptions, telemetry *buildpacks.Telemetry, image } } - cnbRegistryAuth, err := cnbutils.GenerateCnbAuth(config.DockerConfigJSON, utils) - if err != nil { - log.SetErrorCategory(log.ErrorConfiguration) - return errors.Wrap(err, "failed to generate CNB_REGISTRY_AUTH") - } - if len(config.CustomTLSCertificateLinks) > 0 { caCertificates := "/tmp/ca-certificates.crt" _, err := utils.Copy("/etc/ssl/certs/ca-certificates.crt", caCertificates) @@ -558,7 +551,17 @@ func runCnbBuild(config *cnbBuildOptions, telemetry *buildpacks.Telemetry, image log.Entry().Info("skipping certificates update") } - utils.AppendEnv([]string{fmt.Sprintf("CNB_REGISTRY_AUTH=%s", cnbRegistryAuth)}) + dockerKeychain, err := cnbutils.ParseDockerConfig(config.DockerConfigJSON, utils) + if err != nil { + log.SetErrorCategory(log.ErrorConfiguration) + return errors.Wrap(err, "failed to parse dockerConfigJSON") + } + cnbAuthString, err := dockerKeychain.ToCNBString() + if err != nil { + log.SetErrorCategory(log.ErrorConfiguration) + return errors.Wrap(err, "failed to generate CNB_REGISTRY_AUTH") + } + utils.AppendEnv([]string{fmt.Sprintf("CNB_REGISTRY_AUTH=%s", cnbAuthString)}) utils.AppendEnv([]string{fmt.Sprintf("CNB_PLATFORM_API=%s", platformAPIVersion)}) creatorArgs := []string{ @@ -574,6 +577,10 @@ func runCnbBuild(config *cnbBuildOptions, telemetry *buildpacks.Telemetry, image } if config.RunImage != "" { + if !dockerKeychain.AuthExistsForImage(config.RunImage) { + log.Entry().Warnf("provided dockerConfigJSON does not contain credentials for the run-image %q, anonymous auth will be used", config.RunImage) + } + creatorArgs = append(creatorArgs, "-run-image", config.RunImage) } @@ -582,6 +589,9 @@ func runCnbBuild(config *cnbBuildOptions, telemetry *buildpacks.Telemetry, image } containerImage := path.Join(targetImage.ContainerRegistry.Host, targetImage.ContainerImageName) + if !dockerKeychain.AuthExistsForImage(containerImage) { + log.Entry().Warnf("provided dockerConfigJSON does not contain credentials for the target image %q, anonymous auth will be used", containerImage) + } for _, tag := range config.AdditionalTags { target := fmt.Sprintf("%s:%s", containerImage, tag) if !piperutils.ContainsString(creatorArgs, target) { diff --git a/cmd/cnbBuild_test.go b/cmd/cnbBuild_test.go index 0fe38a8c7a..f17c022a84 100644 --- a/cmd/cnbBuild_test.go +++ b/cmd/cnbBuild_test.go @@ -504,7 +504,7 @@ func TestRunCnbBuild(t *testing.T) { addBuilderFiles(&utils) err := callCnbBuild(&config, &telemetry.CustomData{}, &utils, &cnbBuildCommonPipelineEnvironment{}, &piperhttp.Client{}) - assert.EqualError(t, err, "failed to generate CNB_REGISTRY_AUTH: json: cannot unmarshal string into Go struct field ConfigFile.auths of type types.AuthConfig") + assert.EqualError(t, err, "failed to parse dockerConfigJSON: 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) { diff --git a/cmd/contrastExecuteScan.go b/cmd/contrastExecuteScan.go index d25c652a25..4ae0b39f6e 100644 --- a/cmd/contrastExecuteScan.go +++ b/cmd/contrastExecuteScan.go @@ -10,6 +10,7 @@ import ( "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/piperutils" "github.com/SAP/jenkins-library/pkg/telemetry" + "github.com/pkg/errors" ) type contrastExecuteScanUtils interface { @@ -107,7 +108,7 @@ func runContrastExecuteScan(config *contrastExecuteScanOptions, telemetryData *t if unaudited > config.VulnerabilityThresholdTotal { msg := fmt.Sprintf("Your application %v in organization %v is not compliant. Total unaudited issues are %v which is greater than the VulnerabilityThresholdTotal count %v", config.ApplicationID, config.OrganizationID, unaudited, config.VulnerabilityThresholdTotal) - return reports, fmt.Errorf(msg) + return reports, errors.New(msg) } } } diff --git a/cmd/detectExecuteScan.go b/cmd/detectExecuteScan.go index 3b7952ff2a..e0f6a68444 100644 --- a/cmd/detectExecuteScan.go +++ b/cmd/detectExecuteScan.go @@ -845,7 +845,7 @@ func postScanChecksAndReporting(ctx context.Context, config detectExecuteScanOpt } if len(errorsOccured) > 0 { - return fmt.Errorf(strings.Join(errorsOccured, ": ")) + return errors.New(strings.Join(errorsOccured, ": ")) } return nil diff --git a/cmd/jsonApplyPatch.go b/cmd/jsonApplyPatch.go index 14196201df..a64bc3d665 100644 --- a/cmd/jsonApplyPatch.go +++ b/cmd/jsonApplyPatch.go @@ -3,10 +3,11 @@ package cmd import ( "bytes" "encoding/json" + "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/piperutils" "github.com/SAP/jenkins-library/pkg/telemetry" - "github.com/evanphx/json-patch" + jsonpatch "github.com/evanphx/json-patch" ) func jsonApplyPatch(config jsonApplyPatchOptions, telemetryData *telemetry.CustomData) { diff --git a/cmd/malwareExecuteScan.go b/cmd/malwareExecuteScan.go index 55c90a0e5d..ec76c921f2 100644 --- a/cmd/malwareExecuteScan.go +++ b/cmd/malwareExecuteScan.go @@ -3,6 +3,11 @@ package cmd import ( "encoding/json" "fmt" + "io" + "os" + "strings" + "time" + piperDocker "github.com/SAP/jenkins-library/pkg/docker" piperhttp "github.com/SAP/jenkins-library/pkg/http" "github.com/SAP/jenkins-library/pkg/log" @@ -11,10 +16,6 @@ import ( "github.com/SAP/jenkins-library/pkg/telemetry" "github.com/SAP/jenkins-library/pkg/toolrecord" "github.com/pkg/errors" - "io" - "os" - "strings" - "time" ) type malwareScanUtils interface { diff --git a/cmd/mavenExecute.go b/cmd/mavenExecute.go index 87d5fb1098..5c2f8cedd8 100644 --- a/cmd/mavenExecute.go +++ b/cmd/mavenExecute.go @@ -1,12 +1,13 @@ package cmd import ( + "os" + "github.com/SAP/jenkins-library/pkg/command" piperhttp "github.com/SAP/jenkins-library/pkg/http" "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/maven" "github.com/SAP/jenkins-library/pkg/piperutils" - "os" "github.com/SAP/jenkins-library/pkg/telemetry" ) diff --git a/cmd/mavenExecuteIntegration.go b/cmd/mavenExecuteIntegration.go index 08d385b597..b39785b6d1 100644 --- a/cmd/mavenExecuteIntegration.go +++ b/cmd/mavenExecuteIntegration.go @@ -2,13 +2,14 @@ package cmd import ( "fmt" - "github.com/SAP/jenkins-library/pkg/log" - "github.com/SAP/jenkins-library/pkg/maven" - "github.com/SAP/jenkins-library/pkg/telemetry" "path/filepath" "strconv" "strings" "unicode" + + "github.com/SAP/jenkins-library/pkg/log" + "github.com/SAP/jenkins-library/pkg/maven" + "github.com/SAP/jenkins-library/pkg/telemetry" ) func mavenExecuteIntegration(config mavenExecuteIntegrationOptions, _ *telemetry.CustomData) { diff --git a/cmd/mavenExecuteStaticCodeChecks.go b/cmd/mavenExecuteStaticCodeChecks.go index 6847312865..250293cb04 100644 --- a/cmd/mavenExecuteStaticCodeChecks.go +++ b/cmd/mavenExecuteStaticCodeChecks.go @@ -1,10 +1,11 @@ package cmd import ( + "strconv" + "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/maven" "github.com/SAP/jenkins-library/pkg/telemetry" - "strconv" ) func mavenExecuteStaticCodeChecks(config mavenExecuteStaticCodeChecksOptions, telemetryData *telemetry.CustomData) { diff --git a/cmd/nexusUpload.go b/cmd/nexusUpload.go index 517b022563..16930b9ff5 100644 --- a/cmd/nexusUpload.go +++ b/cmd/nexusUpload.go @@ -2,14 +2,15 @@ package cmd import ( "fmt" - piperhttp "github.com/SAP/jenkins-library/pkg/http" - "github.com/pkg/errors" "io" "net/http" "os" "path/filepath" "strings" + piperhttp "github.com/SAP/jenkins-library/pkg/http" + "github.com/pkg/errors" + b64 "encoding/base64" "github.com/SAP/jenkins-library/pkg/command" diff --git a/cmd/readPipelineEnv.go b/cmd/readPipelineEnv.go index 8e76ff54e0..a4c2ef8016 100644 --- a/cmd/readPipelineEnv.go +++ b/cmd/readPipelineEnv.go @@ -8,13 +8,14 @@ import ( "encoding/base64" "encoding/json" "fmt" + "io" + "os" + "path" + "github.com/SAP/jenkins-library/pkg/config" "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/piperenv" "github.com/spf13/cobra" - "io" - "os" - "path" ) // ReadPipelineEnv reads the commonPipelineEnvironment from disk and outputs it as JSON diff --git a/cmd/readPipelineEnv_test.go b/cmd/readPipelineEnv_test.go index a3b846aec1..6efcb2ff61 100644 --- a/cmd/readPipelineEnv_test.go +++ b/cmd/readPipelineEnv_test.go @@ -1,9 +1,10 @@ package cmd import ( - "github.com/stretchr/testify/assert" "strings" "testing" + + "github.com/stretchr/testify/assert" ) func TestCpeEncryption(t *testing.T) { diff --git a/cmd/terraformExecute.go b/cmd/terraformExecute.go index 2389bc4903..e85344b729 100644 --- a/cmd/terraformExecute.go +++ b/cmd/terraformExecute.go @@ -3,6 +3,7 @@ package cmd import ( "bytes" "fmt" + "github.com/SAP/jenkins-library/pkg/command" "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/piperutils" diff --git a/cmd/version.go b/cmd/version.go index 07e449007c..f42e9ef3c3 100644 --- a/cmd/version.go +++ b/cmd/version.go @@ -2,9 +2,10 @@ package cmd import ( "fmt" + "os" + "github.com/SAP/jenkins-library/pkg/log" "github.com/spf13/cobra" - "os" ) // GitCommit ... diff --git a/cmd/whitesourceExecuteScan.go b/cmd/whitesourceExecuteScan.go index 4cea97dc07..1987466d13 100644 --- a/cmd/whitesourceExecuteScan.go +++ b/cmd/whitesourceExecuteScan.go @@ -308,7 +308,7 @@ func checkAndReportScanResults(ctx context.Context, config *ScanOptions, scan *w } if len(checkErrors) > 0 { - return reportPaths, fmt.Errorf(strings.Join(checkErrors, ": ")) + return reportPaths, errors.New(strings.Join(checkErrors, ": ")) } return reportPaths, nil } @@ -674,7 +674,7 @@ func checkSecurityViolations(ctx context.Context, config *ScanOptions, scan *ws. log.Entry().Debugf("Aggregated %v alerts for scanned projects", len(allAlerts)) } - reportPaths, errors := reportGitHubIssuesAndCreateReports( + reportPaths, e := reportGitHubIssuesAndCreateReports( ctx, config, utils, @@ -686,13 +686,13 @@ func checkSecurityViolations(ctx context.Context, config *ScanOptions, scan *ws. vulnerabilitiesCount, ) - allOccurredErrors = append(allOccurredErrors, errors...) + allOccurredErrors = append(allOccurredErrors, e...) if len(allOccurredErrors) > 0 { if vulnerabilitiesCount > 0 { log.SetErrorCategory(log.ErrorCompliance) } - return reportPaths, fmt.Errorf(strings.Join(allOccurredErrors, ": ")) + return reportPaths, errors.New(strings.Join(allOccurredErrors, ": ")) } return reportPaths, nil diff --git a/cmd/writePipelineEnv.go b/cmd/writePipelineEnv.go index 25d72000d1..cbc6842c06 100644 --- a/cmd/writePipelineEnv.go +++ b/cmd/writePipelineEnv.go @@ -8,11 +8,12 @@ import ( b64 "encoding/base64" "encoding/json" "fmt" - "github.com/SAP/jenkins-library/pkg/config" "io" "os" "path/filepath" + "github.com/SAP/jenkins-library/pkg/config" + "github.com/SAP/jenkins-library/pkg/log" "github.com/SAP/jenkins-library/pkg/piperenv" "github.com/spf13/cobra" diff --git a/go.mod b/go.mod index 4706e6cdad..f4338dcf43 100644 --- a/go.mod +++ b/go.mod @@ -22,6 +22,7 @@ require ( github.com/buildpacks/lifecycle v0.18.4 github.com/cloudevents/sdk-go/v2 v2.10.1 github.com/docker/cli v24.0.6+incompatible + github.com/docker/docker v24.0.7+incompatible github.com/evanphx/json-patch v5.7.0+incompatible github.com/getsentry/sentry-go v0.26.0 github.com/ghodss/yaml v1.0.1-0.20190212211648-25d852aebe32 @@ -159,7 +160,6 @@ require ( github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect github.com/docker/distribution v2.8.3+incompatible // indirect - github.com/docker/docker v24.0.7+incompatible // indirect github.com/docker/docker-credential-helpers v0.8.0 // indirect github.com/docker/go-connections v0.4.0 // indirect github.com/docker/go-metrics v0.0.1 // indirect diff --git a/pkg/cnbutils/auth.go b/pkg/cnbutils/auth.go index 98a5b58b3b..3de6378d51 100644 --- a/pkg/cnbutils/auth.go +++ b/pkg/cnbutils/auth.go @@ -7,50 +7,76 @@ import ( "github.com/SAP/jenkins-library/pkg/log" "github.com/docker/cli/cli/config/configfile" + "github.com/docker/cli/cli/config/types" + "github.com/docker/docker/registry" ) -func GenerateCnbAuth(config string, utils BuildUtils) (string, error) { - var err error - dockerConfig := &configfile.ConfigFile{} +type DockerKeychain struct { + dockerConfig *configfile.ConfigFile +} - if config != "" { - log.Entry().Debugf("using docker config file %q", config) - dockerConfigJSON, err := utils.FileRead(config) - if err != nil { - return "", err - } +func (dk *DockerKeychain) ToCNBString() (string, error) { + if dk.dockerConfig == nil || len(dk.dockerConfig.GetAuthConfigs()) == 0 { + return "{}", nil + } - err = json.Unmarshal(dockerConfigJSON, dockerConfig) - if err != nil { - return "", err + cnbAuth := map[string]string{} + for reg, authConf := range dk.dockerConfig.GetAuthConfigs() { + registryHostname := registry.ConvertToHostname(reg) + log.Entry().Debugf("adding credentials for registry %q", registryHostname) + if authConf.RegistryToken != "" { + cnbAuth[registryHostname] = fmt.Sprintf("Bearer %s", authConf.RegistryToken) + + continue } - } - auth := map[string]string{} - for registry, value := range dockerConfig.AuthConfigs { - if value.Auth == "" && value.Username == "" && value.Password == "" { - log.Entry().Warnf("docker config.json contains empty credentials for registry %q. Either 'auth' or 'username' and 'password' have to be provided.", registry) + if authConf.Auth != "" { + cnbAuth[registryHostname] = fmt.Sprintf("Basic %s", authConf.Auth) + continue } - if value.Auth == "" { - value.Auth = encodeAuth(value.Username, value.Password) + if authConf.Username == "" && authConf.Password == "" { + log.Entry().Warnf("docker config.json contains empty credentials for registry %q. Either 'auth' or 'username' and 'password' have to be provided.", registryHostname) + + continue } - log.Entry().Debugf("Adding credentials for: registry %q", registry) - auth[registry] = fmt.Sprintf("Basic %s", value.Auth) + cnbAuth[registryHostname] = fmt.Sprintf("Basic %s", encodeAuth(authConf.Username, authConf.Password)) } - if len(auth) == 0 { - log.Entry().Warn("docker config file is empty!") - } + cnbAuthBytes, err := json.Marshal(&cnbAuth) + return string(cnbAuthBytes), err +} - cnbRegistryAuth, err := json.Marshal(auth) +func (dk *DockerKeychain) AuthExistsForImage(image string) bool { + var empty types.AuthConfig + conf, err := dk.dockerConfig.GetAuthConfig(registry.ConvertToHostname(image)) if err != nil { - return "", err + log.Entry().Errorf("failed to get auth config for the image %q, error: %s", image, err.Error()) + } + + return conf != empty +} + +func ParseDockerConfig(config string, utils BuildUtils) (*DockerKeychain, error) { + keychain := &DockerKeychain{ + dockerConfig: &configfile.ConfigFile{}, + } + if config != "" { + log.Entry().Debugf("using docker config file %q", config) + dockerConfigJSON, err := utils.FileRead(config) + if err != nil { + return nil, err + } + + err = json.Unmarshal(dockerConfigJSON, keychain.dockerConfig) + if err != nil { + return nil, err + } } - return string(cnbRegistryAuth), nil + return keychain, nil } func encodeAuth(username, password string) string { diff --git a/pkg/cnbutils/auth_test.go b/pkg/cnbutils/auth_test.go index 24ed900d03..d719664d0a 100644 --- a/pkg/cnbutils/auth_test.go +++ b/pkg/cnbutils/auth_test.go @@ -18,41 +18,61 @@ func TestGenerateCnbAuth(t *testing.T) { } t.Run("successfully generates cnb auth env variable", func(t *testing.T) { - mockUtils.AddFile("/test/valid_config.json", []byte("{\"auths\":{\"example.com\":{\"auth\":\"dXNlcm5hbWU6cGFzc3dvcmQ=\"}}}")) - auth, err := cnbutils.GenerateCnbAuth("/test/valid_config.json", mockUtils) + mockUtils.AddFile("/test/valid_config.json", []byte("{\"auths\":{\"https://example.com/\":{\"auth\":\"dXNlcm5hbWU6cGFzc3dvcmQ=\"}}}")) + auth, err := cnbutils.ParseDockerConfig("/test/valid_config.json", mockUtils) assert.NoError(t, err) - assert.Equal(t, "{\"example.com\":\"Basic dXNlcm5hbWU6cGFzc3dvcmQ=\"}", auth) + + authString, err := auth.ToCNBString() + assert.NoError(t, err) + assert.Equal(t, "{\"example.com\":\"Basic dXNlcm5hbWU6cGFzc3dvcmQ=\"}", authString) + assert.True(t, auth.AuthExistsForImage("example.com/foo/bar:123")) + assert.False(t, auth.AuthExistsForImage("docker.io/foo/bar")) }) t.Run("successfully generates cnb auth env variable from username and password", func(t *testing.T) { mockUtils.AddFile("/test/valid_config.json", []byte("{\"auths\":{\"example.com\":{\"username\":\"username\",\"password\":\"password\"}}}")) - auth, err := cnbutils.GenerateCnbAuth("/test/valid_config.json", mockUtils) + auth, err := cnbutils.ParseDockerConfig("/test/valid_config.json", mockUtils) + assert.NoError(t, err) + + authString, err := auth.ToCNBString() assert.NoError(t, err) - assert.Equal(t, "{\"example.com\":\"Basic dXNlcm5hbWU6cGFzc3dvcmQ=\"}", auth) + assert.Equal(t, "{\"example.com\":\"Basic dXNlcm5hbWU6cGFzc3dvcmQ=\"}", authString) + assert.True(t, auth.AuthExistsForImage("example.com/foo/bar:123")) + assert.False(t, auth.AuthExistsForImage("docker.io/foo/bar")) }) t.Run("skips registry with empty credentials", func(t *testing.T) { mockUtils.AddFile("/test/valid_config.json", []byte("{\"auths\":{\"example.com\":{}}}")) - auth, err := cnbutils.GenerateCnbAuth("/test/valid_config.json", mockUtils) + auth, err := cnbutils.ParseDockerConfig("/test/valid_config.json", mockUtils) assert.NoError(t, err) - assert.Equal(t, "{}", auth) + + authString, err := auth.ToCNBString() + assert.NoError(t, err) + assert.Equal(t, "{}", authString) + assert.False(t, auth.AuthExistsForImage("example.com/foo/bar:123")) + assert.False(t, auth.AuthExistsForImage("docker.io/foo/bar")) }) t.Run("successfully generates cnb auth env variable if docker config is not present", func(t *testing.T) { - auth, err := cnbutils.GenerateCnbAuth("", mockUtils) + auth, err := cnbutils.ParseDockerConfig("", mockUtils) + assert.NoError(t, err) + + authString, err := auth.ToCNBString() assert.NoError(t, err) - assert.Equal(t, "{}", auth) + assert.Equal(t, "{}", authString) + assert.False(t, auth.AuthExistsForImage("example.com/foo/bar:123")) + assert.False(t, auth.AuthExistsForImage("docker.io/foo/bar")) }) t.Run("fails if file not found", func(t *testing.T) { - _, err := cnbutils.GenerateCnbAuth("/not/found", mockUtils) + _, err := cnbutils.ParseDockerConfig("/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) + _, err := cnbutils.ParseDockerConfig("/test/invalid_config.json", mockUtils) assert.Error(t, err) assert.Equal(t, "invalid character 'o' in literal null (expecting 'u')", err.Error()) })