Summary
code_ownership/codeowners-rs can generate different CODEOWNERS line order on different platforms for the same input. In our case, macOS and Linux produced different orderings for two adjacent rules, causing validation to fail even though ownership content was otherwise the same.
The likely root cause is that the custom comparator used during generation is not a valid total ordering.
Affected code
- Rust bridge call site:
- Actual generator path:
Observed behavior
Two rules with the same owner can swap order between environments. For example, one environment emits:
/foo/**/*bar* @org/example-team
/foo/**/baz/**/* @org/example-team
Another emits:
/foo/**/baz/**/* @org/example-team
/foo/**/*bar* @org/example-team
This causes CODEOWNERS out of date validation failures.
Root cause
The comparator in file_generator.rs is:
pub fn compare_lines(a: &String, b: &String) -> Ordering {
if let Some((prefix, _)) = a.split_once("**")
&& b.starts_with(prefix)
{
return Ordering::Less;
}
if let Some((prefix, _)) = b.split_once("**")
&& a.starts_with(prefix)
{
return Ordering::Greater;
}
a.cmp(b)
}
For the two example lines above:
- both split on the first
"**" to the same prefix: "/foo/"
compare_lines(a, b) returns Less
compare_lines(b, a) also returns Less
That violates comparator requirements. Once ordering is inconsistent, sort output becomes unstable/nondeterministic across platforms or builds.
Why this is a bug
A sort comparator must define a consistent total order. In particular, if a < b, then b < a must not also be true. This comparator can produce contradictory results for overlapping glob prefixes.
Suggested fix
Replace compare_lines with a comparator that guarantees a total order. Options:
- Remove the custom prefix logic and use plain lexical sort if acceptable.
- Compute an explicit sort key and compare tuples.
- If special glob-priority behavior is needed, define it with a consistent key, for example:
- path specificity
- wildcard count
- path length
- lexical fallback
But whatever rule is chosen, it needs to be deterministic and symmetric.
Summary
code_ownership/codeowners-rscan generate differentCODEOWNERSline order on different platforms for the same input. In our case, macOS and Linux produced different orderings for two adjacent rules, causing validation to fail even though ownership content was otherwise the same.The likely root cause is that the custom comparator used during generation is not a valid total ordering.
Affected code
lib.rs#L84-L88runner.rs#L208-L214ownership.rs#L167-L170file_generator.rs#L44-L62Observed behavior
Two rules with the same owner can swap order between environments. For example, one environment emits:
Another emits:
This causes
CODEOWNERS out of datevalidation failures.Root cause
The comparator in
file_generator.rsis:For the two example lines above:
"**"to the same prefix:"/foo/"compare_lines(a, b)returnsLesscompare_lines(b, a)also returnsLessThat violates comparator requirements. Once ordering is inconsistent, sort output becomes unstable/nondeterministic across platforms or builds.
Why this is a bug
A sort comparator must define a consistent total order. In particular, if
a < b, thenb < amust not also be true. This comparator can produce contradictory results for overlapping glob prefixes.Suggested fix
Replace
compare_lineswith a comparator that guarantees a total order. Options:But whatever rule is chosen, it needs to be deterministic and symmetric.