diff --git a/pkg/compose/publish.go b/pkg/compose/publish.go index e15eaec89d..30b6a6a49b 100644 --- a/pkg/compose/publish.go +++ b/pkg/compose/publish.go @@ -59,7 +59,7 @@ func (s *composeService) publish(ctx context.Context, project *types.Project, re return err } if !accept { - return nil + return api.ErrCanceled } err = s.Push(ctx, project, api.PushOptions{IgnoreFailures: true, ImageMandatory: true}) if err != nil { diff --git a/pkg/compose/publish_test.go b/pkg/compose/publish_test.go index 8f91f663e6..3b0e5a4389 100644 --- a/pkg/compose/publish_test.go +++ b/pkg/compose/publish_test.go @@ -17,6 +17,8 @@ package compose import ( + "errors" + "os" "slices" "testing" @@ -100,3 +102,64 @@ services: return !slices.Contains([]string{".Data", ".Digest", ".Size"}, path.String()) }, cmp.Ignore())) } + +func Test_preChecks_sensitive_data_detected_decline(t *testing.T) { + dir := t.TempDir() + envPath := dir + "/secrets.env" + secretData := `AWS_SECRET_ACCESS_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY"` + err := os.WriteFile(envPath, []byte(secretData), 0o600) + assert.NilError(t, err) + + project := &types.Project{ + Services: types.Services{ + "web": { + Name: "web", + Image: "nginx", + EnvFiles: []types.EnvFile{ + {Path: envPath, Required: true}, + }, + }, + }, + } + + declined := func(message string, defaultValue bool) (bool, error) { + return false, nil + } + svc := &composeService{ + prompt: declined, + } + + accept, err := svc.preChecks(t.Context(), project, api.PublishOptions{}) + assert.NilError(t, err) + assert.Equal(t, accept, false) +} + +func Test_publish_decline_returns_ErrCanceled(t *testing.T) { + project := &types.Project{ + Services: types.Services{ + "web": { + Name: "web", + Image: "nginx", + Volumes: []types.ServiceVolumeConfig{ + { + Type: types.VolumeTypeBind, + Source: "/host/path", + Target: "/container/path", + }, + }, + }, + }, + } + + declined := func(message string, defaultValue bool) (bool, error) { + return false, nil + } + svc := &composeService{ + prompt: declined, + events: &ignore{}, + } + + err := svc.publish(t.Context(), project, "docker.io/myorg/myapp:latest", api.PublishOptions{}) + assert.Assert(t, errors.Is(err, api.ErrCanceled), + "expected api.ErrCanceled when user declines, got: %v", err) +} diff --git a/pkg/e2e/publish_test.go b/pkg/e2e/publish_test.go index b5488df601..1dd83d031e 100644 --- a/pkg/e2e/publish_test.go +++ b/pkg/e2e/publish_test.go @@ -71,7 +71,7 @@ or remove sensitive data from your Compose configuration "-p", projectName, "publish", "test/test", "--dry-run") cmd.Stdin = strings.NewReader("n\n") res := icmd.RunCmd(cmd) - res.Assert(t, icmd.Expected{ExitCode: 0}) + res.Assert(t, icmd.Expected{ExitCode: 130}) out := res.Combined() assert.Assert(t, strings.Contains(out, "you are about to publish bind mounts declaration within your OCI artifact."), out) assert.Assert(t, strings.Contains(out, "e2e/fixtures/publish:/user-data"), out) @@ -111,7 +111,7 @@ or remove sensitive data from your Compose configuration "-p", projectName, "publish", "test/test", "--with-env", "--dry-run") cmd.Stdin = strings.NewReader("n\n") res := icmd.RunCmd(cmd) - res.Assert(t, icmd.Expected{ExitCode: 0}) + res.Assert(t, icmd.Expected{ExitCode: 130}) output := res.Combined() assert.Assert(t, strings.Contains(output, "you are about to publish sensitive data within your OCI artifact.\n"), output)