Skip to content

Network Egress Check - #153

Merged
brikin01 merged 5 commits into
mainfrom
network-check
Aug 25, 2026
Merged

Network Egress Check#153
brikin01 merged 5 commits into
mainfrom
network-check

Conversation

@JoeStech

Copy link
Copy Markdown
Member
  • Added runtime egress validation for AMD64 and Arm64 release images.
  • Added blocked DNS/TCP/UDP/HTTP(S) negative controls and retained evidence.
  • Made validation failures block production publication.
  • Disabled FastMCP’s unnecessary PyPI update check.
  • Moved contributor/build/release documentation into CONTRIBUTING.md.

Copilot AI lite review requested due to automatic review settings August 21, 2026 21:37
@JoeStech
JoeStech requested a review from a team as a code owner August 21, 2026 21:37

Copilot AI 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.

Pull request overview

Adds runtime egress validation for AMD64 and Arm64 release images, disables unnecessary update checks, and consolidates contributor documentation.

Changes:

  • Adds traced network validation and negative controls.
  • Gates production publication on validation.
  • Moves build and release guidance into CONTRIBUTING.md.

Critical blockers remain: published images are not digest-bound to validated images, and container-controlled evidence files can be tampered with.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.

Show a summary per file
File Summary
README.md Links to contributor documentation.
mcp-local/tests/test_build_inputs.py Adds release-gate assertions.
mcp-local/scripts/validate-runtime-egress.py Implements runtime egress validation.
mcp-local/Dockerfile Disables FastMCP update checks.
CONTRIBUTING.md Consolidates development and release guidance.
.github/workflows/build-mcp-image.yml Runs validation before publication.
Suppressed comments (4)

.github/workflows/build-mcp-image.yml:241

  • This push: true publishes the semantic-versioned architecture tags before the runtime gate runs. If either validator fails, publish-release is skipped but the failed image remains publicly pullable as ${VERSION}-amd64 or ${VERSION}-arm64, allowing distribution of an image that did not pass the release checks. Push to a quarantine/temporary reference or defer public publication until validation succeeds, while retaining a digest-addressable image for the check.
          push: ${{ needs.validate-release.outputs.publish == 'true' }}
          load: ${{ needs.validate-release.outputs.publish != 'true' }}
          tags: ${{ env.IMAGE }}:${{ needs.validate-release.outputs.version }}-${{ matrix.tag }}

mcp-local/scripts/validate-runtime-egress.py:143

  • LD_LIBRARY_PATH is set on the whole docker run, so it is inherited by strace and every tracee. _prepare_tracer copies the runner's libc.so.6 and other libraries into /validation/lib; consequently the MCP Python process can load the runner's glibc instead of the image's pinned runtime libraries. This can make validation fail for ABI differences or, worse, validate behavior that the released image does not have. Scope the tracer library path to the tracer process and clear it for the tracee (or use an image-compatible/static tracer).
        "LD_LIBRARY_PATH=/validation/lib",

mcp-local/scripts/validate-runtime-egress.py:420

  • Checking only the set {9, 53, 80, 443} does not prove all five controls were observed: TCP/9 and UDP/9 collapse to one port, so this condition would still pass if one of those trace entries is missing. Compare (protocol, port) (and ideally the fixed destination) against all five expected controls so the “present in trace” claim is enforced per protocol.
        and {9, 53, 80, 443}.issubset(detected_ports)

mcp-local/scripts/validate-runtime-egress.py:23

  • The address regex does not match the normal strace rendering of an IPv6 sockaddr, which includes a trailing argument such as inet_pton(AF_INET6, "2001:db8::1", &sin6_addr). Those lines are therefore skipped at the address-match check, so an external IPv6 connect/sendto can leave runtime_attempts empty and bypass the advertised IPv4/IPv6 egress gate. Allow the optional trailing arguments (or parse the sockaddr structure) here.
    r'(?:inet_addr\("([^"]+)"\)|inet_pton\([^,]+, "([^"]+)"\))'

💡 Add a code-review agent skill for context-aware, tailored reviews. Learn more in the docs.

Comment thread .github/workflows/build-mcp-image.yml
Comment thread mcp-local/scripts/validate-runtime-egress.py Outdated
Comment thread .github/workflows/build-mcp-image.yml Outdated

@brikin01 brikin01 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Overall, the approach looks good to me. @JoeStech clarified that this PR is scoped to paths expected to operate offline. Intentional remote-repository and container-scanning requests are outside this gate’s scope and will be revisited, along with the documentation, once the corresponding carve-out language is finalized.

I think once the Copilot findings are addressed and the merge conflicts resolved, should be g2g

@brikin01
brikin01 merged commit 8f8fc73 into main Aug 25, 2026
17 checks passed
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