Skip to content

fix(publish): support short-form port mapping with variable interpolation - #14198

Open
Hoomanghkhani wants to merge 1 commit into
docker:mainfrom
Hoomanghkhani:fix-publish-short-form-ports
Open

fix(publish): support short-form port mapping with variable interpolation#14198
Hoomanghkhani wants to merge 1 commit into
docker:mainfrom
Hoomanghkhani:fix-publish-short-form-ports

Conversation

@Hoomanghkhani

Copy link
Copy Markdown

What I did

Fixed an issue where docker compose publish failed with:
'services[...].ports[0]' expected a map or struct, got "string"
when a service defined short-form port syntax containing variable substitutions (e.g. ${PORT:-3000}:3000).

During preChecks, loadUnresolvedFile runs with options.SkipInterpolation = true to detect uncommitted secrets and suspicious literals. Because interpolation is skipped, types.ParsePortConfig cannot parse un-interpolated port expressions into numeric ports, leaving them as raw string slices. Mapstructure subsequently failed attempting to decode strings into types.ServicePortConfig structs.

To fix this:

  1. loadUnresolvedFile now loads the model via loader.LoadModelWithContext and deletes ports from services before calling loader.Transform. Neither collectEnvCheckFindings nor checkForSensitiveData inspects ports (only environment, env_files, extends, and configs are checked).
  2. composeFileAsByteReader now reads the compose file directly from disk via os.ReadFile, guaranteeing the secret scanner examines the exact file bytes to be published without loss of comments or unnecessary decoding.
  3. Added unit tests in publish_test.go verifying loadUnresolvedFile, checkForSensitiveData, and collectEnvCheckFindings with short-form port syntax containing variable substitutions.

Related issue
Fixes #13672

@Hoomanghkhani
Hoomanghkhani requested review from a team as code owners September 8, 2026 14:00
…tion

When publishing a Compose project with short-form port syntax containing
environment variable substitutions (e.g. `${PORT:-3000}:3000`), `publish`
previously failed with:
  'services[...].ports[0]' expected a map or struct, got "string"

During `preChecks`, `loadUnresolvedFile` loads each file with
`SkipInterpolation = true` to detect raw un-interpolated literals and
secrets. Because variable interpolation is skipped, `types.ParsePortConfig`
cannot parse the non-numeric port strings into `ServicePortConfig`
definitions, leaving them as raw string slices in the canonical dictionary.
When `loader.Transform` attempts to decode this into `types.Project`,
mapstructure fails because `types.ServiceConfig.Ports` expects a slice of
structs, not strings.

Neither `collectEnvCheckFindings` nor `checkForSensitiveData` inspects
service ports (only environment, env_files, extends, and configs are
checked). Load the raw model via `loader.LoadModelWithContext` and strip
`ports` from services before calling `loader.Transform`. Additionally,
have `composeFileAsByteReader` read the raw compose file directly from
disk so all file content is preserved for secret scanning without
unnecessary decoding.

Fixes docker#13672

Signed-off-by: Hooman <hooman.ghkhani@gmail.com>
@Hoomanghkhani
Hoomanghkhani force-pushed the fix-publish-short-form-ports branch from a85b23a to f99ca7e Compare September 8, 2026 14:04
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] docker compose publish rejects short-form port mapping

1 participant