Repository navigation
fix(node): close three host-class gaps in the public-URL gate - #346
Conversation
is_public_http_url is the shared gate for every operator-supplied outbound URL: peer announce, webhook creation, and the boot-time peer prune. Three host forms got past it that the checks around them plainly meant to exclude. A name with no dot never matched the `.local` / `.internal` suffix rules, so `http://internal/` and `http://wpad/` were accepted and left to the resolver to complete from its search domain. The dotless rule sits on the branch where the host did not parse as an IP literal, which keeps bracketed IPv6 (also dotless) on the accepting path; the existing 6to4 and NAT64 accept cases pin that. fec0::/10 fell through the IPv6 arm because the link-local mask does not cover it: 0xfec0 & 0xffc0 is 0xfec0, not 0xfe80. RFC 3879 deprecated the range, which argues for rejecting it rather than ignoring it. Trailing root dots were stripped once, so `localhost..` reduced to `localhost.` and matched neither the equality nor the suffix check. Stripping to fixation closes that. Each of the three is covered by a test that reddens when its own production line is reverted, and the dotted forms stay as negative controls so the suffix checks remain proven.
|
No actionable comments were generated in the recent review. Walkthrough
Merge Risk:
|
| Check name | Status | Explanation |
|---|---|---|
| Title check | ✅ Passed | The title clearly identifies the node fix and the three host-class gaps in the public-URL gate. |
| Description check | ✅ Passed | The description explains the motivation, concrete behavior changes, isolated tests, verification results, scope, and related issues. |
| Docstring Coverage | ✅ Passed | Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. |
| Linked Issues check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
| Out of Scope Changes check | ✅ Passed | Check skipped because no linked issues were found for this pull request. |
Finishing Touches
-
Generate docstrings
-
- Create stacked PR
- Commit on current branch
🧪 Generate unit tests (beta)
-
- Create PR with unit tests
- Commit unit tests in branch
fix/host-gate-bare-labels
-
- Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts
ℹ️ Recent review info
-
⚙️ Run configuration
-
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: f808efc5-7455-43b3-867a-059712ea26bd
📒 Files selected for processing (1)
-
crates/gitlawb-node/src/api/peers.rs
ℹ️ Recent review info
-
⚙️ Run configuration
-
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID:
f808efc5-7455-43b3-867a-059712ea26bd
📒 Files selected for processing (1)
-
crates/gitlawb-node/src/api/peers.rs
-
|
@kevincodex1 this one is ready when you are. jatmn approved, 19/19 checks green on ceadf8b, no open threads. |
|
@kevincodex1 LGTM |
euxarist
left a comment
There was a problem hiding this comment.
All three host-class gaps verified against HEAD: the single-dot strip accepted localhost.., the mask missed fec0::/10, and dotless single-label names slipped both suffix checks. Each fix is placed correctly (truncate before suffix checks, the v6 mask math pinned by the feff::ffff test, dotless rejection on the IP branch so bracketed IPv6 stays accepted), and the deferred .localhost note is honest. Clean.
Closes #339.
is_public_http_urlis the shared host-class gate for every operator-supplied outbound URL: peer announce, webhook creation, and the boot-time peer prune. Three host forms got past it that the checks around them plainly meant to exclude.Dotless names.
.localand.internalare suffix tests, so a single label matches neither, andhttp://internal/,http://wpad/,http://metadata/were accepted and left to the resolver to complete from its search domain.POST /api/v1/peers/announceis unauthenticated and a peer row'shttp_urldrives outbound sync-notify fan-out, so the caller choosing that name need not be anyone in particular.The new rule sits on the branch where the host did not parse as an IP literal. That placement is the whole trick: a bracketed IPv6 literal is also dotless, and the existing 6to4 and NAT64 accept cases pin that it stays accepted.
fec0::/10. The IPv6 arm missed it because the link-local mask does not cover it:0xfec0 & 0xffc0is0xfec0, not0xfe80. RFC 3879 deprecated the range in 2004, which argues for rejecting it rather than ignoring it.Repeated root dots. Trailing dots were stripped once, so
localhost..reduced tolocalhost.and matched neither the equality nor the suffix check. Stripping to fixation closes it. I could not resolve that name locally, so it is a predicate gap rather than a demonstrated reachable target.Verification
Each of the three is covered by a test that goes red when its own production line is reverted, checked one at a time rather than as a batch:
rejects_dotless_single_label_hostsfec0::/10clauserejects_deprecated_site_local_v6rejects_repeated_trailing_root_dotsThe dotted forms stay in the tables as negative controls so the suffix checks remain proven, and the IPv6 accept cases guard against the dotless rule over-rejecting.
cargo test -p gitlawb-node --bin gitlawb-node --lockedis 826 passed / 0 failed, withfmtandclippy --workspace --all-targets -- -D warningsclean.Scope
Predicate only. The larger gap, that nothing validates the address a hostname actually resolves to, is #340 and needs a resolver policy on both outbound clients rather than a change here.
This touches the same span of
peers.rsas #333, so whichever lands second wants a rebase. The conflict is adjacent lines, not competing logic: #333 adds.localhostto the suffix list, this adds a dotless branch further down. Thenode.localhost..case is deliberately not asserted here, since.localhostis not a rejected suffix until #333 lands.Summary by CodeRabbit