diff --git a/pkg/compose/publish.go b/pkg/compose/publish.go index 2e820cf8a5c..89b8cd4d1ab 100644 --- a/pkg/compose/publish.go +++ b/pkg/compose/publish.go @@ -38,6 +38,7 @@ import ( "github.com/opencontainers/image-spec/specs-go" v1 "github.com/opencontainers/image-spec/specs-go/v1" "github.com/sirupsen/logrus" + "go.yaml.in/yaml/v4" "github.com/docker/compose/v5/internal/desktop" "github.com/docker/compose/v5/internal/oci" @@ -724,11 +725,24 @@ func (s *composeService) checkForSensitiveData(ctx context.Context, project *typ } func composeFileAsByteReader(ctx context.Context, filePath string, project *types.Project) (io.Reader, error) { - base, err := loadUnresolvedFile(ctx, project, filePath) + model, err := loader.LoadModelWithContext(ctx, types.ConfigDetails{ + WorkingDir: project.WorkingDir, + Environment: project.Environment, + ConfigFiles: []types.ConfigFile{{Filename: filePath}}, + }, func(options *loader.Options) { + options.SkipValidation = true + options.SkipExtends = true + options.SkipConsistencyCheck = true + options.ResolvePaths = true + options.SkipInclude = true + options.SkipInterpolation = true + options.SkipResolveEnvironment = true + options.Profiles = project.Profiles + }) if err != nil { return nil, fmt.Errorf("failed to load compose file %s: %w", filePath, err) } - in, err := base.MarshalYAML() + in, err := yaml.Marshal(model) if err != nil { return nil, err } diff --git a/pkg/compose/publish_test.go b/pkg/compose/publish_test.go index 21cdfa1bed3..b076325ddd6 100644 --- a/pkg/compose/publish_test.go +++ b/pkg/compose/publish_test.go @@ -593,3 +593,104 @@ func Test_publish_decline_returns_ErrCanceled(t *testing.T) { assert.Assert(t, errors.Is(err, api.ErrCanceled), "expected api.ErrCanceled when user declines, got: %v", err) } + +func Test_composeFileAsByteReader_shortFormPorts(t *testing.T) { + dir := t.TempDir() + composePath := filepath.Join(dir, "compose.yaml") + err := os.WriteFile(composePath, []byte(`name: test +services: + whoami: + image: docker.io/traefik/whoami:v1.11 + ports: + - ${DASHBOARD_PORT:-3000}:3000 +`), 0o600) + assert.NilError(t, err) + + project, err := loader.LoadWithContext(t.Context(), types.ConfigDetails{ + WorkingDir: dir, + Environment: types.Mapping{"DASHBOARD_PORT": ""}, + ConfigFiles: []types.ConfigFile{{Filename: composePath}}, + }) + assert.NilError(t, err) + project.ComposeFiles = []string{composePath} + + reader, err := composeFileAsByteReader(t.Context(), composePath, project) + assert.NilError(t, err) + assert.Assert(t, reader != nil) +} + +func Test_composeFileAsByteReader_shortFormPortsBasic(t *testing.T) { + dir := t.TempDir() + composePath := filepath.Join(dir, "compose.yaml") + err := os.WriteFile(composePath, []byte(`name: test +services: + whoami: + image: docker.io/traefik/whoami:v1.11 + ports: + - "8080:80" +`), 0o600) + assert.NilError(t, err) + + project, err := loader.LoadWithContext(t.Context(), types.ConfigDetails{ + WorkingDir: dir, + Environment: types.Mapping{}, + ConfigFiles: []types.ConfigFile{{Filename: composePath}}, + }) + assert.NilError(t, err) + project.ComposeFiles = []string{composePath} + + reader, err := composeFileAsByteReader(t.Context(), composePath, project) + assert.NilError(t, err) + assert.Assert(t, reader != nil) +} + +func Test_composeFileAsByteReader_shortFormPortsIPBound(t *testing.T) { + dir := t.TempDir() + composePath := filepath.Join(dir, "compose.yaml") + err := os.WriteFile(composePath, []byte(`name: test +services: + whoami: + image: docker.io/traefik/whoami:v1.11 + ports: + - "127.0.0.1:8080:80" +`), 0o600) + assert.NilError(t, err) + + project, err := loader.LoadWithContext(t.Context(), types.ConfigDetails{ + WorkingDir: dir, + Environment: types.Mapping{}, + ConfigFiles: []types.ConfigFile{{Filename: composePath}}, + }) + assert.NilError(t, err) + project.ComposeFiles = []string{composePath} + + reader, err := composeFileAsByteReader(t.Context(), composePath, project) + assert.NilError(t, err) + assert.Assert(t, reader != nil) +} + +func Test_composeFileAsByteReader_longFormPorts(t *testing.T) { + dir := t.TempDir() + composePath := filepath.Join(dir, "compose.yaml") + err := os.WriteFile(composePath, []byte(`name: test +services: + whoami: + image: docker.io/traefik/whoami:v1.11 + ports: + - target: 3000 + published: "3000" +`), 0o600) + assert.NilError(t, err) + + project, err := loader.LoadWithContext(t.Context(), types.ConfigDetails{ + WorkingDir: dir, + Environment: types.Mapping{}, + ConfigFiles: []types.ConfigFile{{Filename: composePath}}, + }) + assert.NilError(t, err) + project.ComposeFiles = []string{composePath} + + reader, err := composeFileAsByteReader(t.Context(), composePath, project) + assert.NilError(t, err) + assert.Assert(t, reader != nil) +}