fix(xo-server-netbox): use numeric comparison to find the most specific prefix - #10297
Open
matlantin wants to merge 4 commits into
Open
fix(xo-server-netbox): use numeric comparison to find the most specific prefix#10297matlantin wants to merge 4 commits into
matlantin wants to merge 4 commits into
Conversation
matlantin
added a commit
to matlantin/xen-orchestra
that referenced
this pull request
Aug 25, 2026
pdonias
requested changes
Aug 31, 2026
matlantin
force-pushed
the
fix/netbox-prefix-string-comparison
branch
from
August 31, 2026 09:15
ff93cbb to
ca39e52
Compare
matlantin
added a commit
to matlantin/xen-orchestra
that referenced
this pull request
Aug 31, 2026
Author
|
Rebased onto current `master` (the branch had fallen behind after a release cleared `CHANGELOG.unreleased.md`'s package list) and re-added `xo-server-netbox patch` there. Also applied the `bits`-as-number suggestion in a follow-up commit — replied on that thread. @pdonias your directly-pushed changelog wording (issue link) is preserved, it matched what I'd already written when resolving the rebase conflict on that file. All 3 review comments should be addressed now. |
pdonias
requested changes
Aug 31, 2026
…ic prefix
`prefix.split('/')` returns bits as a string. Comparing it directly
with `>`/`===` works numerically only on the first iteration (against
the initial `highestBits = 0`), then degrades to a lexicographic
string comparison once `highestBits` itself becomes a string. E.g.
`"8" > "24"` is `true` as strings, even though 8 < 24 numerically.
Effect: any prefix with a single-digit mask (typically a /8 container
prefix) wins over a more specific two-digit prefix that also matches,
regardless of iteration order. Reported in vatesfr#10240.
Fixes vatesfr#10240
Per review feedback: destructure bits as a number at the point each prefix string is parsed, instead of casting with Number(bits) at each comparison site. Also renamed the raw split fragment in the second match block to bitsStr for consistency, since it's compared against the now-numeric highestBits.
…tency check too Per review feedback: mirror the prefix loop above so both blocks convert bits the same way, at the point of destructuring rather than inline at the comparison site.
matlantin
force-pushed
the
fix/netbox-prefix-string-comparison
branch
from
August 31, 2026 15:59
ca39e52 to
a2a5b35
Compare
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.
Fixes #10240.
Root cause
In
packages/xo-server-netbox/src/index.js, the "find the smallest (most specific) prefix" logic destructuresbitsfromprefix.split('/'), which is a string, then compares it with>/===againsthighestBits:The first comparison (
bits > 0) works correctly because JS coerces the string to a number when compared against a number. But oncehighestBitsitself becomes a string (assigned frombits), every subsequent comparison is lexicographic, not numeric:"8" > "24"evaluates totrue('8' > '2'character-by-character), even though 8 < 24 numerically.Effect: a prefix with a single-digit mask (typically a
/8container/supernet prefix) wins over any two-digit, more specific prefix (/10-/79) that also matches the IP, regardless of the ordernbPrefixesis iterated in. The same bug affects the later idempotency check (bits === highestBits), which never matches oncebitsandhighestBitsare of different types.Real-world repro: a NetBox instance with the common container-prefix hierarchy
10.0.0.0/8(container) →10.10.0.0/16(container) →10.10.10.0/24(active) — syncing a VM with IP10.10.10.7creates10.10.10.7/8in NetBox instead of the expected10.10.10.7/24. Subnets without a competing single-digit-mask container prefix (e.g. a bare192.168.1.0/24with no/8registered) are unaffected, which is why this went unnoticed for a while.Fix
Force numeric comparison in both places, matching the change validated on a production instance (fixed real IPs that were previously synced as
/8):Testing
10.x.x.xsubnet with a10.0.0.0/8container prefix registered were synced with a/8mask; after the fix (deployed to the runningxo-server, followed byxo-cli netbox.synchronize), the same VMs are synced with their correct, more specific/24mask, and re-running the sync is idempotent (no repeated create/delete).node --checkpasses on the modified file. This package has no existing unit tests to run.