Fix transformRuleInput prefix collision between fine-grained hub and spoke repos - #467
Merged
tinder-maxwellelliott merged 4 commits intoAug 19, 2026
Conversation
…spoke repos fineGrainedHashExternalRepos matching used an unbounded string prefix, so with hub-and-spoke repos (rules_python pip: @pip hub, @pip_<pkg> spokes) a spoke label looked like it belonged to the fine-grained hub and was never rewritten to its //external:<spoke> synthetic target -- the only node whose hash flips when the spoke's pinned version changes. Consumers behind hub aliases were therefore never impacted by version bumps. Match on the full repo name up to the // boundary instead. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
New WORKSPACE-mode fixture (hub_spoke_external) models pip-style hub-and-spoke external repos with a custom repository rule: a @pip hub of alias packages in front of a @pip_numpy spoke whose repository-rule attrs embed the pinned version. Bumping the version flips only the //external:pip_numpy seed; the consumer behind the hub alias must follow the chain @pip//numpy:pkg -> @pip_numpy//:lib -> //external:pip_numpy. Fails without the transformRuleInput boundary fix (the spoke label prefix-matched the fine-grained hub name and was never rewritten to its seed); passes with it. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Contributor
Author
|
@tinder-maxwellelliott we noticed this issue while using bazel-diff for rules_python in an internal repo. |
transform_external_input matched fine-grained repos by unbounded string prefix, the same bug the Kotlin transformRuleInput had: with hub-and-spoke repos a spoke label (@pip_numpy//:lib) looked like it belonged to the fine-grained hub (@pip) and was never rewritten to //external:pip_numpy, the only node whose hash flips on a pinned version bump. Match the repo name up to the // boundary, and cover it with a hash unit test plus a Rust e2e test over the same hub_spoke_external fixture. Co-authored-by: Cursor <cursoragent@cursor.com>
tinder-maxwellelliott
previously approved these changes
Aug 19, 2026
tinder-maxwellelliott
left a comment
Collaborator
There was a problem hiding this comment.
Thanks for the fix!
Contributor
Author
|
thanks for the review! would you be so kind as to cut a new release after this if possible so we can test? |
Collaborator
Will do |
The hub_spoke_external fixture declares @pip and @pip_numpy in a WORKSPACE file, and Bazel 9 removed WORKSPACE support outright -- --enable_workspace is inert there, so the fixture's repos never exist and generate-hashes fails with "No repository visible as '@pip'". That failed the jre21 9.x jobs while 8.x passed. Gate the Kotlin and Rust e2e cases on a Bazel that still loads WORKSPACE, matching the version gating the bzlmod e2e tests already use. The matching logic itself stays pinned on every version by BazelRuleTest and the Rust hash unit tests. Co-authored-by: Cursor <cursoragent@cursor.com>
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.
Summary
--fineGrainedHashExternalReposmatching inBazelRule.transformRuleInputused an unbounded string prefix (ruleInput.startsWith(it)). With hub-and-spoke external repos — e.g. rules_python's pip_parse in WORKSPACE mode, with a@piphub of alias packages and one@pip_<pkg>spoke repo per package — every spoke label (@pip_numpy//...) prefix-matches the fine-grained hub name (@pip), so it is never rewritten to its//external:pip_numpysynthetic target. That seed is the only node whose hash flips when the spoke's pinned version changes (the version literal lives in the spoke repository rule's attrs), so consumers behind hub aliases were silently dropped from the impacted set on version bumps.Related shape: the alias-wrap chain discussed in #197.
Fix: match repo names up to the
//boundary (ruleInput == it || ruleInput.startsWith("$it//")).BazelRuleTestunit test pinning the rewrite behavior.hub_spoke_external: custom repository rule modeling the pip hub/spoke shape) +E2ETest.testHubSpokeVersionBumpImpactsConsumer_fineGrainedHubPrefixCollision, modeled on the issue-197 regression test.Test plan
Got impacted: [//external:pip_numpy]— the orphaned spoke seed) while the seed-flip sanity assertion holds; with the fix it passes in ~9s.bazel test //cli:BazelRuleTest //cli:RuleHasherTest— pass.bazel test //cli:E2ETest— 39/39 pass (281s).bazel run //cli/format— clean.🤖 Generated with Claude Code