Skip to content

Default web ports from image EXPOSE - #1099

Merged
phinze merged 1 commit into
mainfrom
phinze/mir_1445-default-the-service-port-to-the-images-expose
Aug 29, 2026
Merged

Default web ports from image EXPOSE#1099
phinze merged 1 commit into
mainfrom
phinze/mir_1445-default-the-service-port-to-the-images-expose

Conversation

@phinze

@phinze phinze commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

Images already advertise their listening port through EXPOSE, but Miren ignored it and always resolved an unspecified web port to 3000. Common upstream images therefore needed duplicate port config or waited for the alternative-port fallback.

Builds now carry OCI exposed-port metadata into the resolved service config. A single TCP declaration fills an otherwise unspecified web port, while explicit port config still wins and ambiguous declarations stay conservative. Persisting the result as the ordinary scalar port keeps routing, health checks, and $PORT on the same value.

A Docker-backed smoke deploy with EXPOSE 4321 came up directly on 4321 and served through the default HTTPS route.

Closes MIR-1445

Miren ignored EXPOSE when resolving web service ports, so images that
listen somewhere other than 3000 waited for the alternative-port
fallback unless users repeated the port in app.toml.

Carry deterministic OCI exposed-port keys through BuildResult and fold a
single TCP declaration into the resolved service config. Explicit ports
still win, while multiple ports, UDP-only declarations, and custom
service images stay conservative when the right choice is ambiguous or
unavailable.

@miren-code-agent miren-code-agent Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🍪 biscuit: ✅ ready to merge — auto-review, non-blocking

This is a draft PR, so I'm judging whether it's ready to graduate to human review. It is — the implementation is solid and I'd be comfortable with it being merged after a final human sign-off.

What the change does: it threads image EXPOSE metadata through the build pipeline — from BuildResult.ExposedPorts (populated in both the stackbuild and Dockerfile paths) — and uses it to auto-populate svc.Port on the synthesized web service when exactly one TCP port is declared and nothing in app.toml already sets a port.

What I like about the implementation: The guard in defaultServicePortFromImage is conservative and correct: it skips the service if it isn't named "web", if it carries a custom Image (right call — EXPOSE metadata belongs to the app image, not a sidecar), if a scalar Port is already set, or if a Ports array is present. All four conditions are exercised by the test cases. singleExposedTCPPort is correctly strict: it rejects multiple ports (ambiguous), UDP, and out-of-range values, and it treats a bare port number (no / suffix) as TCP, matching Docker's own semantics.

The refactor in buildkit.go is clean: extracting applyImageConfig and exposedPortNames from the inline anonymous struct lets both the stackbuild path and the Dockerfile path share the same parsing, and the test TestApplyImageConfig now exercises the parsing directly. The sort in exposedPortNames makes port order deterministic, which matters because the test asserts a specific slice order (["4000/tcp", "8080/tcp"]).

One small thing worth noting: the TestBuildVersionConfigDefaultsWebPortFromImage table test uses buildVersionConfig (the full pipeline) rather than testing defaultServicePortFromImage in isolation. That's fine here — it means the test validates the real call site — but it also means each case goes through appconfig.ResolveDefaults and the full service-building path. Nothing is broken by this; I just want to flag it in case a future maintainer wonders why an isolated unit test isn't available. The coverage of the interesting cases (UDP, multiple ports, existing port wins, custom image, ports array) is thorough regardless.

No correctness issues I can find. The res != nil guard around defaultServicePortFromImage is consistent with the existing guard for WorkingDir. The draft is ready for human review.


🍪 full review note · comment /biscuit review to run biscuit again.

@coderabbitai

coderabbitai Bot commented Aug 28, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: ac741031-e2fc-449f-bd2a-f4c3d4ef0a47

📥 Commits

Reviewing files that changed from the base of the PR and between 17dd4bf and 79ba35f.

📒 Files selected for processing (4)
  • servers/build/build.go
  • servers/build/build_test.go
  • servers/build/buildkit.go
  • servers/build/buildkit_test.go

Included review availability: 4 reviews are currently available. Your included PR review attempts over the past 7 days set your current allowance at 5 reviews per hour.


📝 Walkthrough

Walkthrough

BuildKit now extracts and sorts image-exposed ports into BuildResult.ExposedPorts for Dockerfile and stack builds. Version configuration uses one valid TCP port as the default web service port when no image or port configuration exists. Existing scalar or list ports take precedence. Multiple ports, UDP ports, and invalid port values are ignored. Tests cover metadata extraction and default-port behavior.

Merge Risk: ⚪ Minimal · up to 79ba3

The change derives an unspecified web port from a single TCP port advertised by the image while preserving explicit configuration; no actionable merge-blocking risk remains beyond normal checks and review.


Comment @coderabbitai help to get the list of available commands.

@phinze
phinze marked this pull request as ready for review August 28, 2026 21:20
@phinze
phinze requested a review from a team as a code owner August 28, 2026 21:20

@evanphx evanphx left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, very nice and friendly!

@phinze
phinze merged commit 8e69822 into main Aug 29, 2026
24 checks passed
@phinze
phinze deleted the phinze/mir_1445-default-the-service-port-to-the-images-expose branch August 29, 2026 16:59
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.

2 participants