A GitHub Enterprise remote is no longer asked about on github.com, so unowned-push keeps the allow-list's refusal for it - #296
Merged
Conversation
|
Warning Review limit reachedYou've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository. Next included review available in 32 minutes. View limit detailsLimit details: You’ve used the included review currently available. Review configuration: ⚙️ Run configuration
📒 Files selected for processing (5)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
Merged
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #296 +/- ##
==========================================
+ Coverage 94.04% 94.07% +0.02%
==========================================
Files 46 46
Lines 20868 20962 +94
==========================================
+ Hits 19626 19720 +94
Misses 1242 1242 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
… unowned-push keeps the allow-list's refusal for it Forge::of_url counted any host containing "github" as GitHub, so a remote on github.acme.com reached forge_owns, whose `gh api` carries no --hostname and answered about the same-named github.com repository. An operator who administers github.com/acme/widget could push to github.acme.com/acme/widget past the allow-list. The git shim's visibility lookup read the same classifier. There is now one definition of GitHub, git::is_github_host (moved from guard::names), and Forge::of_url uses it. An enterprise host is a host no client answers for: unowned-push refuses it on the allow-list alone (exit 1, no gh call), and the shim's visibility lookup reports there was nobody to ask instead of reading github.com's answer. Closes #278
… longer makes github.com answer for a push to another host `git::host` ended a url's authority only at `/`. In `https://evil.com#@github.com/acme/widget.git` it therefore stripped `evil.com#` as userinfo and read the host as github.com, and `owner_repo` read `acme/widget` -- while git and curl connect to evil.com. A pusher who administers github.com/acme/widget had the unowned-push guard's forge question answered yes, and the off-list push to evil.com passed. The authority now ends at the first `/`, `?` or `#`, as RFC 3986 reads it, before userinfo and port are stripped. `owner_repo` reads a `scheme://` url's owner and repository from that same path, without query or fragment, so the two never disagree about one url: the `#@`/`?@` forms name host evil.com, no forge, and no owner/repo, and the push is refused for an unreadable destination. Unit rows cover the host, forge and owner/repo of both forms; an end-to-end case pushes to them with a stub `gh` that says yes and expects exit 1. All fail against the previous parsing.
…ost, or a file:// scheme names no host and no repository, so unowned-push refuses it as unreadable Three spellings still let `git::host` and `git::owner_repo` read github.com's acme/widget while git contacts another host, and a stub `gh` that said yes passed the push: - `ssh://evil.com%2F@github.com/acme/widget.git` (and `git+ssh://`, `git://`): git url-decodes the authority before splitting it, so the user ends at the decoded `/` and ssh connects to evil.com. - `[github.com:x@evil.com]:acme/widget.git`: git strips the brackets of a scp-like host and ssh connects to evil.com as user x. - `file://github.com/acme/widget.git`: a file:// url names no host, yet github.com was read from it. Rather than a second copy of git's parser, one predicate, `ambiguous`, fails closed: a `scheme://` authority containing `%`, any `file://` url, and a scp-like host part containing `[` yield None from both functions, and the push is refused for an unreadable destination. A percent-encoded credential in a url is refused with them. This corrects the previous commit's claim that `host` and `owner_repo` "never disagree": the contract, now written on `host`, is that they agree about a url or both yield None when it is ambiguous. Unit rows cover host, owner/repo and forge for each form, with github.com controls; one end-to-end case per form pushes with a stub `gh` that says yes and expects exit 1. All fail with `ambiguous` disabled.
…itory, so a push to an allowed bare repository by file:// passes again bddacc4 refused every file:// url as unreadable, so a push to file:///tmp/x/bare.git with allowed_repos = ["x/bare"] exited 1 where the same path spelled plainly passed, and the visibility guard, names and the shim lost origin's owner and repository the same way. host() now returns None for file:// and owner_repo() reads its path like a plain path, so file://github.com/... asks no forge and is judged by the allow-list alone.
HackingGate
force-pushed
the
fix-278-ghe-forge
branch
from
October 3, 2026 09:47
d9a1144 to
72218c6
Compare
HackingGate
added a commit
that referenced
this pull request
Oct 3, 2026
Three engine changes since 1.24.0. A rule whose `files.include` root is not on disk no longer selects nothing, prints one line on stderr and passes: the scan exits 2 naming the rule, the root and that the root does not exist. This holds for every rule, bundled sets included, so a repository that inherits `default-token-grant` and has no `.github/workflows` is now refused (#294). The relative-link check removes inline code spans from each line before it reads links, delimited as CommonMark does: a run of N backticks closes at the next run of exactly N, and an unmatched run stays literal. A regular expression in backticks such as `[2-9](\.\d+)` is no longer reported as a link to a missing file (#295). A remote counts as GitHub only when its host is github.com, www.github.com or raw.githubusercontent.com, the one definition private-names and the shim already used. A GitHub Enterprise remote is no longer asked about on github.com: unowned-push keeps the allow-list's refusal for it with exit 1, and the shim's visibility lookup reports could-not-tell. Any other unknown forge is refused as before (#296). encoding_rs is 0.8.42 (#281), and CI runs astral-sh/setup-uv 10.2.0 (#280). A consumer taking the pin to v1.25.0 must have every `files.include` root its rules name on disk, inherited sets included: a missing root now fails the scan with exit 2 where it warned, and the fix is to correct the root or remove it. A consumer pushing to a GitHub Enterprise remote that its allow-list does not name is now refused where github.com may have answered for it.
HackingGate
added a commit
that referenced
this pull request
Oct 3, 2026
Three engine changes since 1.24.0. A rule whose `files.include` root is not on disk no longer selects nothing, prints one line on stderr and passes: the scan exits 2 naming the rule, the root and that the root does not exist. This holds for every rule, bundled sets included, so a repository that inherits `default-token-grant` and has no `.github/workflows` is now refused (#294). The relative-link check removes inline code spans from each line before it reads links, delimited as CommonMark does: a run of N backticks closes at the next run of exactly N, and an unmatched run stays literal. A regular expression in backticks such as `[2-9](\.\d+)` is no longer reported as a link to a missing file (#295). A remote counts as GitHub only when its host is github.com, www.github.com or raw.githubusercontent.com, the one definition private-names and the shim already used. A GitHub Enterprise remote is no longer asked about on github.com: unowned-push keeps the allow-list's refusal for it with exit 1, and the shim's visibility lookup reports could-not-tell. Any other unknown forge is refused as before (#296). encoding_rs is 0.8.42 (#281), and CI runs astral-sh/setup-uv 10.2.0 (#280). A consumer taking the pin to v1.25.0 must have every `files.include` root its rules name on disk, inherited sets included: a missing root now fails the scan with exit 2 where it warned, and the fix is to correct the root or remove it. A consumer pushing to a GitHub Enterprise remote that its allow-list does not name is now refused where github.com may have answered for it.
HackingGate
added a commit
that referenced
this pull request
Oct 3, 2026
Three engine changes since 1.24.0. A rule whose `files.include` root is not on disk no longer selects nothing, prints one line on stderr and passes: the scan exits 2 naming the rule, the root and that the root does not exist. This holds for every rule, bundled sets included, so a repository that inherits `default-token-grant` and has no `.github/workflows` is now refused (#294). The relative-link check removes inline code spans from each line before it reads links, delimited as CommonMark does: a run of N backticks closes at the next run of exactly N, and an unmatched run stays literal. A regular expression in backticks such as `[2-9](\.\d+)` is no longer reported as a link to a missing file (#295). A remote counts as GitHub only when its host is github.com, www.github.com or raw.githubusercontent.com, the one definition private-names and the shim already used. A GitHub Enterprise remote is no longer asked about on github.com: unowned-push keeps the allow-list's refusal for it with exit 1, and the shim's visibility lookup reports could-not-tell. Any other unknown forge is refused as before. A remote URL's host now ends at the first `/`, `?` or `#`, and userinfo is stripped up to the last `@`, so `https://evil.com#@github.com/acme/widget.git` is read as evil.com, which is where git pushes, and unowned-push no longer accepts it on the strength of github.com ownership. Two spellings uphold cannot read the way git does now name no host and no repository, so unowned-push refuses them as an unreadable destination: a `%` anywhere in a `scheme://` URL's authority and a `[` in a scp-like host. A `file://` URL names no host, so it is never asked about on a forge, and its repository is read from the path like a plain local path, so the allow-list judges it by its path (#296). encoding_rs is 0.8.42 (#281), and CI runs astral-sh/setup-uv 10.2.0 (#280). A consumer taking the pin to v1.25.0 must have every `files.include` root its rules name on disk, inherited sets included: a missing root now fails the scan with exit 2 where it warned, and the fix is to correct the root or remove it. A consumer pushing to a GitHub Enterprise remote that its allow-list does not name is now refused where github.com may have answered for it. An ssh Host alias such as `git@github-work:me/repo`, or `ssh.github.com:443`, is no longer counted as GitHub, so a push through one to a destination the allow-list does not name is refused; name the destination in the allow-list, or use a github.com URL. A push through a remote URL carrying a percent-encoded credential is refused whatever the allow-list names; drop the encoded credential from the URL.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Forge::of_urlnow counts a host as GitHub only throughgit::is_github_host(moved fromguard::names, unchanged):github.com,www.github.com,raw.githubusercontent.com, in any URL or ssh spelling. There is now one definition of "GitHub" in the binary, shared by private-names, the unowned-push guard and the shim's visibility lookup.Why
Before this change, any host containing
githubcounted as GitHub, so a remote ongithub.acme.comreachedforge_owns.forge_ownsrunsgh apiwithout--hostname, so the question went to github.com. An operator who administersgithub.com/acme/widgetcould push togithub.acme.com/acme/widgetpast the allow-list.is_github_hostalready refused enterprise hosts for this reason.Unknown forges (GHE included)
ghcall. The allow-list's answer stands, so an off-list destination is refused with exit 1. It does not pass because ownership could not be asked.public-targetvisibility lookup (git shim via origin): returnsSilence::Refused("no forge client is known for that host...")instead of reading github.com's answer, so it is reported as could-not-tell.ghinvocation is still classified by its command name.ghhonours its ownGH_HOST/--hostname, so this change does not touch that case.Tests
the_forge_is_read_from_the_host_and_never_from_the_path: adds GHE https, scp-ssh andssh://port URLs plusnotgithub.com, allNone. The existing github.com controls still pass.an_enterprise_remote_is_not_answered_for_by_github_com(tests/guard_cli.rs): a stubghanswers yes to everything, and a push to a GHE remote over https or ssh is still refused with exit 1 and no forge line.Closes #278