Skip to content

Fix/485 port qualified host matching - #495

Open
AromalBiju1 wants to merge 4 commits into
onecli:mainfrom
AromalBiju1:fix/485-port-qualified-host-matching
Open

Fix/485 port qualified host matching#495
AromalBiju1 wants to merge 4 commits into
onecli:mainfrom
AromalBiju1:fix/485-port-qualified-host-matching

Conversation

@AromalBiju1

Copy link
Copy Markdown

I have read the CONTRIBUTING.md file.

YES

What kind of change does this PR introduce?

Bug fix.

What is the current behavior?

Fixes #485.

Generic secrets can be created with a port-qualified hostPattern (e.g.
example.internal:3000), but the gateway strips the port from the request
authority before resolving credentials. host_matches only ever sees the
bare hostname, so a port-qualified pattern can never match — the secret is
silently unusable and requests get credential not found ... status=401.

What is the new behavior?

  • The port-inclusive authority is now passed into connect::resolve at both
    the CONNECT and plain-HTTP proxy paths, instead of the port-stripped
    hostname.
  • host_matches splits both the request host and the pattern into
    host/port. A pattern with a port (example.internal:3000) now requires
    an exact port match. A bare-hostname pattern (example.internal) still
    matches any port, so existing behavior is unchanged.

Verified locally by creating a generic secret with hostPattern: example.internal:3000, granting it to an agent, and sending a request
through the proxy:

  • Before: injection_count=0 — secret never matched.
  • After: injection_count=1 — secret injected correctly.

Added two unit tests covering both cases. Full connect:: suite passes
(35/35), cargo build and pnpm check pass clean.

Additional context

Didn't change the secret-creation validation to reject malformed
hostname:port patterns (mentioned as a "nice to have" in the issue) —
happy to add that in a follow-up if wanted.

Previously the port was stripped from the request authority before
credential resolution, so a secret's hostPattern like
example.internal:3000 could never match. host_matches now compares
ports when the pattern specifies one, and falls back to matching any
port for bare-hostname patterns, preserving existing behavior.

Fixes onecli#485
Copilot AI lite review requested due to automatic review settings August 16, 2026 13:24

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

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@chiptoe-svg

Copy link
Copy Markdown

Thanks for taking this on — the approach matches what we found when filing #485, and passing the port-inclusive authority at both resolve sites covers our real-world case (plain-HTTP MCP servers on one host across several ports).

A few notes from a close read:

  1. The hunk that adds the new tests also drops the #[test] attribute from the existing host_exact_match — it silently stops running.
  2. Worth confirming mitm.rs's in-tunnel re-resolution also sees the ported authority, or CONNECT-path port-qualified secrets would match at CONNECT but not inject.
  3. Two documentable edges: host:80 won't match http://host/… (implicit port ≠ explicit pattern), and an unbracketed IPv6 pattern like ::1 mis-splits in split_host_port.

Happy to test the branch against our live setup — seven port-qualified plain-HTTP servers behind one hostname, which is the scenario from the issue.

@AromalBiju1

Copy link
Copy Markdown
Author

Thanks for the detailed review - all three are spot-on!

Fixed the dropped #[test] on host_exact_match. Got caught by the cargo fmt diff, sorry!
And yeah, the problem you noted regarding mitm.rs - the re-resolution in the tunnel still stripped the port prior to resolving from cache, so it would match a CONNECT path secret but never re-inject it per each request. Fixed it with the same pattern, preserving the port till the resolution stage.
Good edge cases - host:80 vs implicit-port URLs, and also the unbracketed IPv6 patterns. Going to leave those out of scope for now and just document as such, but let me know if you'd prefer me to solve them here.

Going to push an updated commit soon. Your real-world testing on that seven-ports-one-hostname case would be very helpful!

- host_exact_match lost its #[test] attribute in the earlier fmt diff;
  restored it (was silently not running).
- mitm.rs's per-request rule re-resolution inside the MITM tunnel was
  still stripping the port before calling resolve_from_cache, so a
  port-qualified secret would match at CONNECT time but fail to
  re-inject on subsequent requests. Fixed with the same approach as
  the CONNECT/plain-HTTP paths.
- Documented two known edge cases in split_host_port per review
  feedback: implicit default ports aren't normalized against explicit
  :80/:443 patterns, and unbracketed IPv6 literals aren't handled.
@github-actions

github-actions Bot commented Aug 28, 2026

Copy link
Copy Markdown

All contributors have signed the CLA ✍️ ✅
Posted by the CLA Assistant Lite bot.

@AromalBiju1

Copy link
Copy Markdown
Author

I have read the CLA Document and I hereby sign the CLA

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.

Generic secret hostPattern accepts ports but gateway strips them before matching

3 participants