Skip to content

fix: correct port binding for non-default ports#112

Merged
anisaoshafi merged 6 commits intomainfrom
drg-611
Mar 16, 2026
Merged

fix: correct port binding for non-default ports#112
anisaoshafi merged 6 commits intomainfrom
drg-611

Conversation

@anisaoshafi
Copy link
Contributor

@anisaoshafi anisaoshafi commented Mar 12, 2026

When configuring a non-default port (e.g. 4567), the Docker binding was 4567:4567 instead of 4567:4566, so the health check could not reach localstack and lstk would hang.

Fix port binding for non-default ports so the emulator actually becomes ready.

@anisaoshafi anisaoshafi marked this pull request as ready for review March 12, 2026 18:10
@coderabbitai
Copy link

coderabbitai bot commented Mar 12, 2026

Caution

Review failed

The head commit changed during the review from 4b121cb to 124db39.

📝 Walkthrough

Walkthrough

Introduces a container-level port mapping and plumbing: a new ContainerPort field and ContainerPort() lookup, propagates containerPort through container start logic and Docker bindings, and adds an integration test that starts the service with a non-default host port via a generated TOML config.

Changes

Cohort / File(s) Summary
Integration Test
test/integration/start_test.go
Added TestStartCommandSucceedsWithNonDefaultPort that writes a temporary TOML config (port 4567), starts a mock license server, and runs lstk start --config to validate startup with a non-default host port.
Container config surface
internal/config/containers.go
Added exported Port field to ContainerConfig, introduced emulatorContainerPorts mapping (e.g., 4566/tcp → EmulatorAWS) and ContainerPort() (string, error) to resolve container-target port for an emulator.
Start flow / runtime model
internal/container/start.go, internal/runtime/runtime.go
Added public ContainerPort string to runtime ContainerConfig, updated container start code to retrieve containerPort via c.ContainerPort() and populate runtime.ContainerConfig.ContainerPort.
Docker runtime binding
internal/runtime/docker.go
Changed Docker Start to use the container port value (derived from config’s ContainerPort) for ExposedPorts/PortBindings while keeping HostPort bound to configured host port.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested reviewers

  • silv-io
🚥 Pre-merge checks | ✅ 2
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: correct port binding for non-default ports' accurately describes the main change: fixing port binding to support non-default ports for Docker container configuration.
Description check ✅ Passed The description clearly explains the problem (incorrect Docker binding for non-default ports causing health checks to fail) and the solution (fixing port binding), which aligns with the changeset modifications.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch drg-611
📝 Coding Plan
  • Generate coding plan for human review comments

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

Tip

You can validate your CodeRabbit configuration file in your editor.

If your editor has YAML language server, you can enable auto-completion and validation by adding # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json at the top of your CodeRabbit configuration file.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
internal/container/start.go (1)

326-332: Consider extracting the default port to a constant to avoid duplication.

The string "4566" is hardcoded here, but the same default is also defined in internal/config/config.go:setDefaults(). If the default port changes in one place but not the other, non-default port detection will silently break.

♻️ Suggested approach

Define a constant in the config package and reference it from both locations:

// In internal/config/config.go
const DefaultPort = "4566"

func setDefaults() {
    viper.SetDefault("containers", []map[string]any{
        {
            "type": "aws",
            "tag":  "latest",
            "port": DefaultPort,
        },
    })
}

Then in needsGatewayListen:

 func needsGatewayListen(port string, env []string) bool {
-    return port != "4566" && !slices.ContainsFunc(env, func(e string) bool {
+    return port != config.DefaultPort && !slices.ContainsFunc(env, func(e string) bool {
         return strings.HasPrefix(e, "GATEWAY_LISTEN=")
     })
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/container/start.go` around lines 326 - 332, Extract the hardcoded
"4566" into a shared constant (e.g. DefaultPort string) in the config package
(add const DefaultPort = "4566" in internal/config/config.go and use it inside
setDefaults()), then replace the literal "4566" in needsGatewayListen with
config.DefaultPort and add the config import in internal/container/start.go;
ensure all references to the default port use config.DefaultPort so non-default
detection remains consistent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@internal/container/start.go`:
- Around line 326-332: Extract the hardcoded "4566" into a shared constant (e.g.
DefaultPort string) in the config package (add const DefaultPort = "4566" in
internal/config/config.go and use it inside setDefaults()), then replace the
literal "4566" in needsGatewayListen with config.DefaultPort and add the config
import in internal/container/start.go; ensure all references to the default port
use config.DefaultPort so non-default detection remains consistent.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 08836855-fa8f-4c4d-8368-99ea054603a3

📥 Commits

Reviewing files that changed from the base of the PR and between 2ce11ae and ce6eef2.

📒 Files selected for processing (2)
  • internal/container/start.go
  • test/integration/start_test.go

@anisaoshafi anisaoshafi changed the title fix: pass GATEWAY_LISTEN env var for non-default ports fix: correct port binding for non-default ports Mar 12, 2026
@anisaoshafi anisaoshafi force-pushed the drg-611 branch 2 times, most recently from 7c93e09 to 4a6b0e9 Compare March 12, 2026 18:41
Copy link
Collaborator

@carole-lavillonniere carole-lavillonniere left a comment

Choose a reason for hiding this comment

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

👏

return nil
}

const emulatorContainerPort = nat.Port("4566/tcp")
Copy link
Collaborator

Choose a reason for hiding this comment

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

thought: ultimately, when we support other emulators, we will to configure it per emulator and might want to move this value to runtime.ContainerConfig, but we can do it later!

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

🧹 Nitpick comments (2)
internal/config/containers.go (1)

34-36: Avoid introducing another mutable package-level map for port resolution.

Line 34–36 adds new shared global state. Prefer resolving in ContainerPort() via switch (or immutable config injected at construction) to keep test isolation tighter.

♻️ Suggested refactor
-var emulatorContainerPorts = map[EmulatorType]string{
-	EmulatorAWS: "4566/tcp",
-}
-
 func (c *ContainerConfig) ContainerPort() (string, error) {
-	port, ok := emulatorContainerPorts[c.Type]
-	if !ok {
-		return "", fmt.Errorf("%s emulator not supported yet by lstk", c.Type)
-	}
-	return port, nil
+	switch c.Type {
+	case EmulatorAWS:
+		return "4566/tcp", nil
+	default:
+		return "", fmt.Errorf("%s emulator not supported yet by lstk", c.Type)
+	}
 }

As per coding guidelines: "Keep packages testable in isolation by avoiding package-level global variables - use constructor functions that return fresh instances and inject dependencies explicitly".

Also applies to: 91-97

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/config/containers.go` around lines 34 - 36, Remove the package-level
mutable map emulatorContainerPorts and instead resolve ports inside the
ContainerPort(...) function (or via an immutable config injected at
construction); update ContainerPort to use a switch on EmulatorType (matching
cases like EmulatorAWS) to return the appropriate port string, and delete the
global map declaration (also remove/replace any other globals at lines ~91-97)
so tests get no shared mutable state and port resolution is local to the
function or supplied config.
internal/runtime/runtime.go (1)

14-14: Keep runtime config adapter-agnostic.

Line 14 encodes Docker-style port format ("4566/tcp") in a runtime-wide struct. Consider splitting into neutral fields (e.g., ContainerPort + Protocol) so each runtime adapter formats ports as needed.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@internal/runtime/runtime.go` at line 14, The struct field ContainerPort
currently encodes a Docker-style value ("4566/tcp"); change the runtime config
to use neutral fields (e.g., ContainerPortNumber (string or int) and
ContainerPortProtocol (string)) instead of a single formatted string, update any
code paths that read/write ContainerPort to construct the adapter-specific
formatted port (for example Docker adapter should format as fmt.Sprintf("%s/%s",
ContainerPortNumber, ContainerPortProtocol)), and update parsing/validation in
functions that consume ContainerPort (referencing the ContainerPort field in
internal/runtime/runtime.go and any runtime adapter methods) so each adapter is
responsible for formatting/serializing the final port representation.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@internal/config/containers.go`:
- Around line 34-36: Remove the package-level mutable map emulatorContainerPorts
and instead resolve ports inside the ContainerPort(...) function (or via an
immutable config injected at construction); update ContainerPort to use a switch
on EmulatorType (matching cases like EmulatorAWS) to return the appropriate port
string, and delete the global map declaration (also remove/replace any other
globals at lines ~91-97) so tests get no shared mutable state and port
resolution is local to the function or supplied config.

In `@internal/runtime/runtime.go`:
- Line 14: The struct field ContainerPort currently encodes a Docker-style value
("4566/tcp"); change the runtime config to use neutral fields (e.g.,
ContainerPortNumber (string or int) and ContainerPortProtocol (string)) instead
of a single formatted string, update any code paths that read/write
ContainerPort to construct the adapter-specific formatted port (for example
Docker adapter should format as fmt.Sprintf("%s/%s", ContainerPortNumber,
ContainerPortProtocol)), and update parsing/validation in functions that consume
ContainerPort (referencing the ContainerPort field in
internal/runtime/runtime.go and any runtime adapter methods) so each adapter is
responsible for formatting/serializing the final port representation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 94c90055-933a-4689-8351-b5333507cfce

📥 Commits

Reviewing files that changed from the base of the PR and between 4a6b0e9 and db2c708.

📒 Files selected for processing (5)
  • internal/config/containers.go
  • internal/container/start.go
  • internal/runtime/docker.go
  • internal/runtime/runtime.go
  • test/integration/start_test.go
🚧 Files skipped from review as they are similar to previous changes (1)
  • test/integration/start_test.go

@anisaoshafi
Copy link
Contributor Author

@coderabbitai recheck

@anisaoshafi anisaoshafi merged commit 79fa694 into main Mar 16, 2026
7 checks passed
@anisaoshafi anisaoshafi deleted the drg-611 branch March 16, 2026 14:08
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.

3 participants