Skip to content

Conversation

@kantord
Copy link
Member

@kantord kantord commented Oct 24, 2025

fixes: #2317

@codecov
Copy link

codecov bot commented Oct 24, 2025

Codecov Report

❌ Patch coverage is 93.54839% with 2 lines in your changes missing coverage. Please review.
✅ Project coverage is 54.44%. Comparing base (5b8af18) to head (e6fe80b).

Files with missing lines Patch % Lines
pkg/container/docker/client.go 88.88% 1 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2318      +/-   ##
==========================================
+ Coverage   54.11%   54.44%   +0.32%     
==========================================
  Files         239      239              
  Lines       23270    23288      +18     
==========================================
+ Hits        12593    12678      +85     
+ Misses       9501     9431      -70     
- Partials     1176     1179       +3     

☔ 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.

@JAORMX
Copy link
Collaborator

JAORMX commented Oct 24, 2025

@claude please do a thorough review of this making sure we don't have any backwards compatibility issues and we don't break the existing flow.

@claude
Copy link
Contributor

claude bot commented Oct 24, 2025

Claude finished @JAORMX's task —— View job


Code Review: Host Networking Fix

I've completed a thorough review of this PR. Here's my analysis regarding backwards compatibility and potential breaking changes.

Summary

This PR fixes an issue where thv ls reports invalid URLs when host networking is used. The changes handle host networking mode differently from bridge networking by:

  1. Skipping port bindings for host networking (incompatible with Docker's host network mode)
  2. Using the MCP_PORT environment variable to determine the port when host networking is enabled
  3. Returning the correct port from DeployWorkload for host networking scenarios

Backwards Compatibility Analysis ✅

Good news: No backwards compatibility issues identified. The changes are additive and only affect the new host networking code path:

  1. Default behavior unchanged: Bridge/default networking (the standard path) continues to work exactly as before
  2. Conditional logic: All new code is gated behind permissionConfig.NetworkMode == "host" checks
  3. Fallback preservation: Non-host networking continues to use generatePortBindings() as before

Detailed Review

1. pkg/container/docker/client.go Changes

Location: DeployWorkload method (lines 259-281)

✅ What's Good:

  • Correct host networking handling: Properly skips port bindings for host mode (Docker requirement)
  • Clear error handling: Returns meaningful errors when MCP_PORT is missing or invalid
  • Informative logging: Helps debugging with clear log messages
  • Backwards compatible: Falls back to existing generatePortBindings() for non-host networking

⚠️ Concerns:

1. Missing Validation (Medium Priority)

if permissionConfig.NetworkMode == "host" {
    mcpPort, ok := envVars["MCP_PORT"]
    if !ok {
        return 0, fmt.Errorf("MCP_PORT not found in environment variables for host networking")
    }

Issue: This assumes MCP_PORT is always set by the transport layer for host networking, creating a tight coupling between transport and container layers.

Recommendation: Add defensive validation or document this contract clearly. Consider:

// For host networking, MCP_PORT must be set by the transport layer before calling DeployWorkload

2. Port Range Validation Missing

hostPort, err = strconv.Atoi(mcpPort)
if err != nil {
    return 0, fmt.Errorf("failed to parse MCP_PORT for host networking: %v", err)
}

Issue: No validation that the port is in valid range (1-65535) or not a privileged port.

Recommendation: Add validation:

hostPort, err = strconv.Atoi(mcpPort)
if err != nil {
    return 0, fmt.Errorf("failed to parse MCP_PORT for host networking: %v", err)
}
if hostPort < 1 || hostPort > 65535 {
    return 0, fmt.Errorf("invalid MCP_PORT %d: must be between 1-65535", hostPort)
}

3. Conditional Port Binding Skip (lines 1446-1453)

// Setup port bindings only for non-host networking
if permissionConfig.NetworkMode != "host" {
    if err := setupPortBindings(hostConfig, portBindings); err != nil {
        return NewContainerError(err, "", err.Error())
    }
}

Status: ✅ Correct - Docker doesn't allow port bindings with host networking

2. pkg/transport/http.go Changes

Location: Setup method (lines 179-225)

✅ What's Good:

  • Clear documentation: Comments explain why host networking is handled differently
  • Proper gating: Port bindings only configured for non-host networking
  • Enhanced logging: Added exposedPort to log output for debugging

⚠️ Concerns:

1. Network Mode Check Pattern
The code checks for host networking in two places:

isHostNetworking := permissionProfile.Network != nil && permissionProfile.Network.Mode == "host"

and later:

if !isHostNetworking {
    // Setup port bindings...
}

Issue: The pattern is inconsistent with client.go which checks permissionConfig.NetworkMode == "host". Both work, but consistency aids maintainability.

Recommendation: Consider extracting this to a helper function:

func isHostNetworkMode(profile *permissions.Profile) bool {
    return profile.Network != nil && profile.Network.Mode == "host"
}

2. Silent Port Override (line 266)

// also override the exposed port, in case we need it via ingress
t.targetPort = exposedPort

Issue: For host networking, exposedPort will be the parsed MCP_PORT value, which should already match t.targetPort. However, if they don't match, this silently overwrites without warning.

Status: ⚠️ Low risk but could hide bugs

3. Test Coverage Gaps

Current State:

  • Codecov reports 22.58% patch coverage (24 lines missing coverage)
  • Existing tests (client_deploy_test.go) don't cover host networking scenarios

Missing Test Cases:

  1. ✅ Host networking with valid MCP_PORT set
  2. ❌ Host networking with missing MCP_PORT (error path)
  3. ❌ Host networking with invalid MCP_PORT (error path)
  4. ❌ Host networking with network isolation enabled (if applicable)
  5. ❌ Transport layer setup with host networking mode

Recommendation: Add tests to client_deploy_test.go:

func TestDeployWorkload_HostNetworking_UsesMCPPort(t *testing.T) {
    // Test that host networking reads MCP_PORT correctly
}

func TestDeployWorkload_HostNetworking_MissingMCPPort_ReturnsError(t *testing.T) {
    // Test error handling when MCP_PORT is not set
}

Security Considerations

No new security concerns identified:

  • Host networking is already a privileged mode requiring explicit configuration
  • Changes don't introduce new attack vectors
  • Port validation would be a nice-to-have improvement

Architecture & Flow Concerns

Potential Issue: External Network Creation Logic

Location: client.go lines 206-216

if permissionConfig.NetworkMode == "" || permissionConfig.NetworkMode == "bridge" || permissionConfig.NetworkMode == "default" {
    externalEndpointsConfig["toolhive-external"] = &network.EndpointSettings{}
    err = c.ops.createExternalNetworks(ctx)
    if err != nil {
        return 0, fmt.Errorf("failed to create external networks: %v", err)
    }
} else {
    logger.Infof("Skipping external network creation for custom network mode: %s", permissionConfig.NetworkMode)
}

Question: When using host networking, does the container still need access to toolhive-external network? The current code skips this, which seems correct for host mode, but should be verified for edge cases.

Status: ✅ Likely correct, but worth confirming

Breaking Changes Analysis

✅ No Breaking Changes Detected

Reasoning:

  1. Additive changes only: New code paths don't modify existing behavior
  2. Existing flows preserved: Bridge/default networking unchanged
  3. API compatibility: DeployWorkload signature unchanged
  4. Return value behavior: Still returns port number (just computed differently for host mode)

Affected Workflows:

  • Bridge networking: ✅ Unchanged, continues using random port assignment
  • Default networking: ✅ Unchanged
  • Host networking: ✅ New functionality, no existing code relied on this
  • Custom network modes: ✅ Handled in existing else branch

Recommendations

Must Have:

  1. Add validation for MCP_PORT port range (1-65535)
  2. Document the contract that transport layer must set MCP_PORT for host networking

Should Have:

  1. Add test coverage for host networking scenarios (to reach acceptable coverage levels)
  2. Add integration test verifying end-to-end host networking flow

Nice to Have:

  1. Extract network mode check to helper function for consistency
  2. Add warning log if exposedPort != t.targetPort during override

Conclusion

Approval Status: ✅ Approved with minor recommendations

This PR correctly fixes the host networking URL issue without introducing backwards compatibility problems or breaking changes. The code changes are well-isolated, properly gated, and follow Docker's requirements for host networking mode.

The main improvements needed are:

  1. Additional validation (port range check)
  2. Better test coverage
  3. Documentation of cross-layer contracts

These are quality improvements rather than blockers. The core fix is sound and ready to merge after addressing the validation concern.


Job Run | Branch: fix-host-networking

1. TestDeployWorkload_HostNetworking_UsesMCPPortAndSkipsExternalNetwork
    - Verifies that when using host network mode, the function:
        - Uses the MCP_PORT environment variable as the host port (9876 in the test)
      - Skips external network creation
      - Doesn't create auxiliary containers (DNS, egress, ingress)
      - Sets the correct network mode ("host") in the permission config
      - Passes empty port bindings (no mapping needed for host mode)
  2. TestDeployWorkload_HostNetworking_ErrorsIfMCPPortMissing
    - Tests the error handling when MCP_PORT is missing from environment variables
    - Ensures the function returns an appropriate error message
  3. TestDeployWorkload_HostNetworking_ErrorsIfMCPPortInvalid
    - Tests the error handling when MCP_PORT contains an invalid value (not a number)
    - Ensures the function returns an appropriate error message

Signed-off-by: ChrisJBurns <[email protected]>
@ChrisJBurns
Copy link
Collaborator

@claude we have added some tests, can you please verify that the tests provide the right assurance for the feature they are testing

@claude
Copy link
Contributor

claude bot commented Oct 24, 2025

Claude finished @ChrisJBurns's task —— View job


Test Coverage Review

I've completed a thorough review of the newly added tests. Here's my analysis:


Summary: Excellent Test Coverage ✅

The tests provide comprehensive coverage for the host networking feature. Both test files demonstrate well-structured, thorough testing that addresses the recommendations from the previous review.


Detailed Analysis

1. client_deploy_test.go - Container Layer Tests

New Tests Added (lines 312-449):

  1. TestDeployWorkload_HostNetworking_UsesMCPPortAndSkipsExternalNetwork (lines 312-371)
  2. TestDeployWorkload_HostNetworking_ErrorsIfMCPPortMissing (lines 373-410)
  3. TestDeployWorkload_HostNetworking_ErrorsIfMCPPortInvalid (lines 412-449)

✅ What These Tests Cover:

Happy Path Testing:

  • ✅ Host port correctly extracted from MCP_PORT environment variable
  • ✅ External network creation is properly skipped for host networking
  • ✅ Auxiliary containers (DNS, egress, ingress) are not created
  • ✅ MCP container created with correct network mode ("host")
  • ✅ Port bindings remain empty for host networking
  • ✅ Environment variables correctly passed through

Error Path Testing:

  • ✅ Missing MCP_PORT returns appropriate error
  • ✅ Invalid MCP_PORT (non-numeric) returns parse error

Test Quality:

  • Uses table-driven patterns where appropriate
  • Proper use of test helpers (t.Parallel(), require, assert)
  • Clear test names following Go conventions
  • Good separation of concerns with fakeDeployOps mock

💯 Coverage Score for Container Layer:

These tests address 100% of the previous review recommendations for the client.go changes:

  • ✅ "Add test coverage for host networking scenarios" - DONE
  • ✅ "Host networking with valid MCP_PORT set" - DONE (lines 312-371)
  • ✅ "Host networking with missing MCP_PORT (error path)" - DONE (lines 373-410)
  • ✅ "Host networking with invalid MCP_PORT (error path)" - DONE (lines 412-449)

2. http_test.go - Transport Layer Tests

New Test File Added: Comprehensive test suite with 404 lines

Key Test Functions:

  1. TestHTTPTransport_Setup_HostNetworking (lines 17-241)
  2. TestHTTPTransport_Setup_HostNetworking_WithCustomHost (lines 243-325)
  3. TestHTTPTransport_Setup_UnsupportedTransportType (lines 327-366)
  4. TestHTTPTransport_Setup_RemoteURL (lines 368-404)

✅ What These Tests Cover:

Host Networking Scenarios:

  • ✅ Port bindings correctly skipped for host mode
  • ✅ Exposed ports correctly skipped for host mode
  • ✅ Environment variables (MCP_PORT, FASTMCP_PORT, MCP_HOST) set correctly
  • ✅ Works with multiple transport types (SSE, streamable HTTP)
  • ✅ Custom host IPs handled correctly

Comparison Testing (Excellent!):
The test uses a table-driven approach to verify behavior across different network modes:

  • ✅ Host networking mode (lines 30-52)
  • ✅ Bridge networking mode (lines 54-78)
  • ✅ Default networking mode (lines 80-104)
  • ✅ Empty/nil network mode (lines 106-128)
  • ✅ Host networking with streamable transport (lines 130-151)

This approach ensures no regressions in existing bridge/default networking behavior while validating the new host networking code path.

Test Quality:

  • Uses gomock for proper mocking
  • Captures and validates both DeployWorkloadOptions and environment variables
  • Parallel execution for performance
  • Custom check functions for flexible validation
  • Clear, descriptive test names

💯 Coverage Score for Transport Layer:

These tests comprehensively cover the http.go changes and provide:

  • ✅ Happy path testing for host networking
  • ✅ Regression testing for existing network modes
  • ✅ Edge case testing (custom hosts, remote URLs)
  • ✅ Error handling for unsupported transport types

Comparison Against Previous Review Recommendations

From Previous Review: "Must Have"

Recommendation Status
Add validation for MCP_PORT port range (1-65535) ⚠️ Not in tests (but see note below)
Document the contract that transport layer must set MCP_PORT ✅ Implicitly validated by tests

From Previous Review: "Should Have"

Recommendation Status
Add test coverage for host networking scenarios (to reach acceptable coverage levels) FULLY ADDRESSED
Add integration test verifying end-to-end host networking flow ⚠️ Not present (unit tests only)

From Previous Review: "Nice to Have"

Recommendation Status
Extract network mode check to helper function for consistency ❌ Not implemented
Add warning log if exposedPort != t.targetPort during override ❌ Not implemented

Missing Test Coverage Analysis

⚠️ Minor Gaps (Low Priority):

  1. Port Range Validation

    • The previous review recommended validating port range (1-65535)
    • Current State: No tests for this because the implementation doesn't validate port range
    • Assessment: This is fine - the tests accurately reflect the implementation. If port validation is added later, tests should be added at that time.
  2. Integration Tests

    • No end-to-end tests verifying the full flow from thv ls to URL display
    • Assessment: Unit tests are comprehensive enough. E2E tests would be nice-to-have but not critical.
  3. Edge Cases Not Tested:

    • Port value "0" (technically valid but unusual)
    • Very large port numbers (65535, 65536)
    • Negative port numbers
    • Assessment: Low priority - the current error handling tests (invalid/missing) cover the most likely failure modes.

Strengths of the Test Suite

1. Comprehensive Error Coverage

Both happy paths AND error paths are tested, which is excellent:

  • Missing MCP_PORT → error
  • Invalid MCP_PORT → error
  • Unsupported transport → error

2. No Regression Risk

The table-driven tests in http_test.go explicitly verify that bridge, default, and empty network modes continue to work as before. This directly addresses the "backwards compatibility" concern from the original request.

3. Mock Architecture

The fakeDeployOps pattern is clean and maintainable:

  • Tracks which methods were called
  • Allows error injection
  • Captures parameters for inspection
  • Easy to extend for future tests

4. Test Organization

  • Tests are co-located with implementation
  • Clear naming conventions
  • Parallel execution enabled
  • Proper use of test helpers

5. Real-World Scenarios

Tests cover practical scenarios:

  • Custom host IPs (not just localhost)
  • Multiple transport types
  • Remote URL handling

Verification Against Feature Requirements

Let me trace through the feature requirements from the implementation:

Feature Requirement Test Coverage
Host networking reads port from MCP_PORT env var TestDeployWorkload_HostNetworking_UsesMCPPortAndSkipsExternalNetwork (line 350)
Host networking skips port bindings TestDeployWorkload_HostNetworking_UsesMCPPortAndSkipsExternalNetwork (line 367) + http_test.go (lines 48-49)
Host networking skips external network creation TestDeployWorkload_HostNetworking_UsesMCPPortAndSkipsExternalNetwork (line 354)
Host networking skips auxiliary containers TestDeployWorkload_HostNetworking_UsesMCPPortAndSkipsExternalNetwork (lines 357-359)
Error when MCP_PORT missing TestDeployWorkload_HostNetworking_ErrorsIfMCPPortMissing (line 409)
Error when MCP_PORT invalid TestDeployWorkload_HostNetworking_ErrorsIfMCPPortInvalid (line 448)
Transport layer sets MCP_PORT correctly http_test.go (lines 38-43, validation at line 229)
Transport layer skips port bindings for host mode http_test.go (lines 48-50)
Bridge/default modes unchanged http_test.go (lines 54-128)

Result: All core feature requirements have corresponding test coverage.


Codecov Report Analysis

The PR description mentions:

Patch coverage is 93.54839% with 2 lines in your changes missing coverage

This is excellent coverage for this type of change. The 2 missing lines are likely:

  • Log statements (not critical to test)
  • Error path edge cases that are hard to trigger

Given that the tests cover:

  • All major code paths
  • Error handling
  • Different network modes
  • Different transport types

The 93.54% coverage is more than sufficient.


Final Assessment

✅ Overall Quality: Excellent

Strengths:

  1. Comprehensive coverage of happy and error paths
  2. Explicit regression testing for existing network modes
  3. Well-structured, maintainable test code
  4. Addresses all critical recommendations from previous review
  5. Good use of mocking and test isolation

Recommendation: Approve

The tests provide strong assurance that:

  • The host networking feature works correctly
  • Existing functionality is not broken
  • Error conditions are properly handled
  • The feature behaves consistently across different transport types

Minor Suggestions (Optional):

If you want to achieve even more thorough coverage, consider adding:

  1. Port Range Edge Cases (if you add validation later):
func TestDeployWorkload_HostNetworking_PortRangeValidation(t *testing.T) {
    // Test ports: 0, -1, 65535, 65536, 100000
}
  1. Integration Test (nice-to-have):
func TestEndToEnd_HostNetworking_URLReporting(t *testing.T) {
    // Start actual container with host networking
    // Run `thv ls` equivalent
    // Verify URL is correct
}

But these are not necessary - the current tests are excellent as-is.


Conclusion

The tests provide the right assurance for the feature they are testing.

The test suite is comprehensive, well-organized, and effectively validates both the new host networking functionality and the preservation of existing behavior. The 93.54% code coverage is strong, and the tests cover all critical code paths and error conditions.

I recommend merging this PR - the test coverage is production-ready.


Job Run | Branch: fix-host-networking

@ChrisJBurns ChrisJBurns marked this pull request as ready for review October 24, 2025 14:01
@ChrisJBurns ChrisJBurns marked this pull request as draft October 24, 2025 14:36
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.

Host networking lies about the MCP url

3 participants