Skip to content

Support publishing additional container ports in thv run#3892

Open
Sanskarzz wants to merge 8 commits intostacklok:mainfrom
Sanskarzz:addports
Open

Support publishing additional container ports in thv run#3892
Sanskarzz wants to merge 8 commits intostacklok:mainfrom
Sanskarzz:addports

Conversation

@Sanskarzz
Copy link
Contributor

Fix: #3812

Summary

This PR adds support for the --publish / -p flag to the thv run command, enabling users to expose arbitrary container ports to the host, similar to docker run -p. It also fixes a bug in the Docker runtime client where explicitly requested host ports were being overwritten by random ports.

Key Changes

  • Added --publish flag to thv run.
  • Implemented networking.ParsePortSpec for robust port specification parsing.
  • Updated runtime.Setup to handle multiple port bindings efficiently.
  • Fixed pkg/container/docker/client.go to respect existing HostPort assignments in generatePortBindings.
  • Added unit tests for port parsing logic.

Signed-off-by: Sanskarzz <sanskar.gur@gmail.com>
@github-actions github-actions bot added the size/S Small PR: 100-299 lines changed label Feb 19, 2026
Signed-off-by: Sanskarzz <sanskar.gur@gmail.com>
@github-actions github-actions bot added size/S Small PR: 100-299 lines changed and removed size/S Small PR: 100-299 lines changed labels Feb 19, 2026
@codecov
Copy link

codecov bot commented Feb 19, 2026

Codecov Report

❌ Patch coverage is 44.44444% with 30 lines in your changes missing coverage. Please review.
✅ Project coverage is 68.59%. Comparing base (0791876) to head (bab7735).

Files with missing lines Patch % Lines
pkg/runtime/setup.go 0.00% 15 Missing ⚠️
pkg/networking/port.go 71.42% 3 Missing and 3 partials ⚠️
pkg/container/docker/client.go 61.53% 2 Missing and 3 partials ⚠️
pkg/runner/config_builder.go 0.00% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #3892      +/-   ##
==========================================
- Coverage   68.62%   68.59%   -0.04%     
==========================================
  Files         445      445              
  Lines       45374    45421      +47     
==========================================
+ Hits        31140    31156      +16     
- Misses      11827    11854      +27     
- Partials     2407     2411       +4     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@github-actions github-actions bot added size/S Small PR: 100-299 lines changed and removed size/S Small PR: 100-299 lines changed labels Feb 19, 2026
Signed-off-by: Sanskarzz <sanskar.gur@gmail.com>
@github-actions github-actions bot added size/S Small PR: 100-299 lines changed and removed size/S Small PR: 100-299 lines changed labels Feb 19, 2026
Copy link
Contributor

@jerm-dro jerm-dro left a comment

Choose a reason for hiding this comment

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

Mostly LGTM to me. Can you manually verify this fixes the user's reported issue by running this locally? A series of screenshots or video will do.

Comment on lines +131 to +153
if tt.wantError {
if err == nil {
t.Errorf("ParsePortSpec(%s) expected error but got nil", tt.portSpec)
}
return
}

if err != nil {
t.Errorf("ParsePortSpec(%s) unexpected error: %v", tt.portSpec, err)
return
}

if tt.expectedHostPort != "" && hostPort != tt.expectedHostPort {
t.Errorf("ParsePortSpec(%s) hostPort = %s, want %s", tt.portSpec, hostPort, tt.expectedHostPort)
}

if tt.expectedHostPort == "" && hostPort == "" {
t.Errorf("ParsePortSpec(%s) hostPort is empty, want random port", tt.portSpec)
}

if containerPort != tt.expectedContainer {
t.Errorf("ParsePortSpec(%s) containerPort = %d, want %d", tt.portSpec, containerPort, tt.expectedContainer)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: can you rewrite these assertions to use the require package (e.g.require.Equal or require.True)?

This will make the tests less nested and easier to read.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I have rewritten the nested if statements into cleaner require assertions in pkg/networking/port_test.go as requested.

Comment on lines +1640 to +1654
hostPortStr := bindings[0].HostPort
if hostPortStr == "" || hostPortStr == "0" {
hostPort = networking.FindAvailable()
if hostPort == 0 {
return nil, 0, fmt.Errorf("could not find an available port")
}
bindings[0].HostPort = fmt.Sprintf("%d", hostPort)
portBindings[key] = bindings
} else {
var err error
hostPort, err = strconv.Atoi(hostPortStr)
if err != nil {
return nil, 0, fmt.Errorf("failed to convert host port %s to int: %w", hostPortStr, err)
}
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Is this the fix for:

It also fixes a bug in the Docker runtime client where explicitly requested host ports were being overwritten by random ports.

?

If so, can you find a way to add a regression test and some unit tests here? The generatePortBindings function seems like it should be amenable to unit testing without any refactoring.

Copy link
Contributor Author

@Sanskarzz Sanskarzz Mar 8, 2026

Choose a reason for hiding this comment

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

Added two new regression tests for generatePortBindings to client_helpers_test.go:

  • TestGeneratePortBindings_NonAuxiliaryKeepsExplicitHostPort: ensures explicit host ports (e.g., "9090") are kept instead of replaced with a random port.
  • TestGeneratePortBindings_NonAuxiliaryAssignsRandomPortForZero: ensures passing "0" correctly assigns a random available port.

Sanskarzz and others added 2 commits March 8, 2026 19:44
Signed-off-by: Sanskarzz <sanskar.gur@gmail.com>
@github-actions github-actions bot added size/S Small PR: 100-299 lines changed and removed size/S Small PR: 100-299 lines changed labels Mar 8, 2026
Signed-off-by: Sanskarzz <sanskar.gur@gmail.com>
@github-actions github-actions bot removed the size/S Small PR: 100-299 lines changed label Mar 8, 2026
@github-actions github-actions bot added the size/S Small PR: 100-299 lines changed label Mar 8, 2026
Signed-off-by: Sanskarzz <sanskar.gur@gmail.com>
@github-actions github-actions bot added size/S Small PR: 100-299 lines changed and removed size/S Small PR: 100-299 lines changed labels Mar 9, 2026
@Sanskarzz
Copy link
Contributor Author

Mostly LGTM to me. Can you manually verify this fixes the user's reported issue by running this locally? A series of screenshots or a video will do.

It looks like I need to create one or two MCP servers that are exposed on multiple ports. One of them is ghcr.io/manykarim/rf-mcp:latest, which was mentioned in the discussion. I have tested it earlier, but I’ll run it again locally and share screenshots shortly.

@jerm-dro, if you have a similar MCP server in your inventory that exposes multiple ports, could you please share it?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size/S Small PR: 100-299 lines changed

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support publishing additional container ports in thv run

2 participants