fix(publish): accept short-form port mappings (fixes docker#13672)

Signed-off-by: Ijtihed Kilani <ijtihedk@gmail.com>
This commit is contained in:
Ijtihed Kilani 2026-06-17 20:45:26 +03:00
parent 0afb4c8c4c
commit 523c51c435
2 changed files with 117 additions and 2 deletions

View file

@ -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
}

View file

@ -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)
}