-
Notifications
You must be signed in to change notification settings - Fork 17
fix: reject leading-zero semver values in local evaluation #206
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
60a4f1b
9e241c6
a6b0aae
36f2a9f
4d1d37c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| "PostHog": patch | ||
| --- | ||
|
|
||
| Reject semver values with leading zeros in local flag evaluation. Per semver 2.0.0 §2, numeric identifiers must not include leading zeros — values like `1.07.3` are not valid semver and should not match targeting conditions. Both override values and flag values are now validated; invalid inputs cause `SemanticVersion.TryParse` to return false so the condition does not match. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2289,7 +2289,6 @@ public void HandlesSemverWildcardMinorOperator(string overrideValue, ComparisonO | |
| [InlineData("1.2.3-alpha", ComparisonOperator.SemverEquals, "1.2.3", true)] // Pre-release stripped | ||
| [InlineData("1.2.3+build", ComparisonOperator.SemverEquals, "1.2.3", true)] // Build metadata stripped | ||
| [InlineData(" 1.2.3 ", ComparisonOperator.SemverEquals, "1.2.3", true)] // Whitespace stripped | ||
| [InlineData("01.02.03", ComparisonOperator.SemverEquals, "1.2.3", true)] // Leading zeros | ||
| [InlineData("1.2", ComparisonOperator.SemverEquals, "1.2.0", true)] // Partial version | ||
| [InlineData("1", ComparisonOperator.SemverEquals, "1.0.0", true)] // Partial version | ||
| [InlineData("1.2.3.4", ComparisonOperator.SemverEquals, "1.2.3", true)] // Extra parts ignored | ||
|
|
@@ -2329,6 +2328,14 @@ public void HandlesSpecialVersionFormats(string overrideValue, ComparisonOperato | |
| [InlineData(".1.2.3", ComparisonOperator.SemverEquals)] | ||
| [InlineData("not-a-version", ComparisonOperator.SemverGreaterThan)] | ||
| [InlineData("", ComparisonOperator.SemverGreaterThan)] | ||
| // Leading-zero override values are invalid per semver 2.0.0 §2 | ||
| [InlineData("01.02.03", ComparisonOperator.SemverEquals)] | ||
| [InlineData("1.07.3", ComparisonOperator.SemverEquals)] | ||
| [InlineData("01.02.03", ComparisonOperator.SemverNotEquals)] | ||
| [InlineData("1.07.3", ComparisonOperator.SemverGreaterThan)] | ||
| [InlineData("01.2.3", ComparisonOperator.SemverGreaterThanOrEquals)] | ||
| [InlineData("1.2.03", ComparisonOperator.SemverLessThan)] | ||
| [InlineData("1.07.3", ComparisonOperator.SemverLessThanOrEquals)] | ||
| public void ThrowsInconclusiveMatchExceptionForInvalidOverrideVersion(string overrideValue, ComparisonOperator comparison) | ||
| { | ||
| var flags = CreateFlags( | ||
|
|
@@ -2358,11 +2365,28 @@ public void ThrowsInconclusiveMatchExceptionForInvalidOverrideVersion(string ove | |
|
|
||
| [Theory] | ||
| // Invalid version in filter value - should throw InconclusiveMatchException | ||
| [InlineData("not-a-version")] | ||
| [InlineData("")] | ||
| [InlineData("abc.def.ghi")] | ||
| [InlineData(".1.2.3")] | ||
| public void ThrowsInconclusiveMatchExceptionForInvalidFilterVersion(string filterValue) | ||
| [InlineData("not-a-version", ComparisonOperator.SemverEquals)] | ||
| [InlineData("", ComparisonOperator.SemverEquals)] | ||
| [InlineData("abc.def.ghi", ComparisonOperator.SemverEquals)] | ||
| [InlineData(".1.2.3", ComparisonOperator.SemverEquals)] | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
[InlineData("not-a-version", ComparisonOperator.SemverGreaterThan)]
[InlineData("", ComparisonOperator.SemverGreaterThan)]
[InlineData("abc.def.ghi", ComparisonOperator.SemverTilde)]
[InlineData(".1.2.3", ComparisonOperator.SemverCaret)] |
||
| // Mirror the override-version test: non-leading-zero malformed inputs must also fail | ||
| // under non-equals operators, not just SemverEquals. | ||
| [InlineData("not-a-version", ComparisonOperator.SemverGreaterThan)] | ||
| [InlineData("", ComparisonOperator.SemverGreaterThan)] | ||
| [InlineData("abc.def.ghi", ComparisonOperator.SemverTilde)] | ||
| [InlineData(".1.2.3", ComparisonOperator.SemverCaret)] | ||
| // Leading-zero filter values are invalid per semver 2.0.0 §2, across all operators | ||
| [InlineData("01.02.03", ComparisonOperator.SemverEquals)] | ||
| [InlineData("1.07.3", ComparisonOperator.SemverEquals)] | ||
| [InlineData("01.2.3", ComparisonOperator.SemverEquals)] | ||
| [InlineData("1.2.03", ComparisonOperator.SemverEquals)] | ||
| [InlineData("1.07.3", ComparisonOperator.SemverGreaterThan)] | ||
| [InlineData("01.2.3", ComparisonOperator.SemverGreaterThanOrEquals)] | ||
| [InlineData("1.2.03", ComparisonOperator.SemverLessThan)] | ||
| [InlineData("01.02.03", ComparisonOperator.SemverLessThanOrEquals)] | ||
| [InlineData("1.07.3", ComparisonOperator.SemverTilde)] | ||
| [InlineData("01.2.3", ComparisonOperator.SemverCaret)] | ||
| public void ThrowsInconclusiveMatchExceptionForInvalidFilterVersion(string filterValue, ComparisonOperator comparison) | ||
| { | ||
| var flags = CreateFlags( | ||
| key: "version", | ||
|
|
@@ -2372,7 +2396,7 @@ public void ThrowsInconclusiveMatchExceptionForInvalidFilterVersion(string filte | |
| Type = FilterType.Person, | ||
| Key = "app_version", | ||
| Value = new PropertyFilterValue(filterValue), | ||
| Operator = ComparisonOperator.SemverEquals | ||
| Operator = comparison | ||
| } | ||
| ] | ||
| ); | ||
|
|
@@ -2394,6 +2418,10 @@ public void ThrowsInconclusiveMatchExceptionForInvalidFilterVersion(string filte | |
| [InlineData("*")] | ||
| [InlineData("1.2.3")] // Not a wildcard pattern | ||
| [InlineData("abc.*")] | ||
| // Leading-zero wildcard patterns are invalid per semver 2.0.0 §2 | ||
| [InlineData("01.*")] | ||
| [InlineData("1.02.*")] | ||
| [InlineData("01.2.*")] | ||
| public void ThrowsInconclusiveMatchExceptionForInvalidWildcardPattern(string filterValue) | ||
| { | ||
| var flags = CreateFlags( | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -107,10 +107,12 @@ public void IgnoresExtraComponents(string input, int expectedMajor, int expected | |
| } | ||
|
|
||
| [Theory] | ||
| // Leading zeros are parsed as integers | ||
| [InlineData("01.02.03", 1, 2, 3)] | ||
| [InlineData("001.002.003", 1, 2, 3)] | ||
| public void ParsesLeadingZeros(string input, int expectedMajor, int expectedMinor, int expectedPatch) | ||
| // Literal "0" components are valid per semver 2.0.0 | ||
| [InlineData("0.0.1", 0, 0, 1)] | ||
| [InlineData("0.1.0", 0, 1, 0)] | ||
| [InlineData("1.0.0", 1, 0, 0)] | ||
| [InlineData("1.2.0", 1, 2, 0)] | ||
| public void ParsesLiteralZeroComponents(string input, int expectedMajor, int expectedMinor, int expectedPatch) | ||
| { | ||
| var result = SemanticVersion.TryParse(input, out var version); | ||
|
|
||
|
|
@@ -139,6 +141,19 @@ public void ParsesLeadingZeros(string input, int expectedMajor, int expectedMino | |
| [InlineData("1.-2.3")] // Negative minor | ||
| [InlineData("-1.2.3")] // Negative major | ||
| [InlineData("1.2.-3")] // Negative patch | ||
| [InlineData("01.02.03")] // Leading zeros (all components) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
[InlineData("1. 2.3")] // Embedded whitespace in minor (NumberStyles.None)
[InlineData("١.2.3")] // Arabic-Indic digit in major (InvariantCulture)
[InlineData("99999999999999.0.0")] // Overflows int.MaxValue |
||
| [InlineData("001.002.003")] // Multiple leading zeros | ||
| [InlineData("1.07.3")] // Leading zero in minor | ||
| [InlineData("1.2.03")] // Leading zero in patch | ||
| [InlineData("01.2.3")] // Leading zero in major | ||
| [InlineData("00.0.0")] // Leading zero on a zero major | ||
| [InlineData("v01.2.3")] // Leading zero with v-prefix | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
[InlineData("01.2.3-alpha")] // Leading zero + pre-release
[InlineData("01.2.3+build")] // Leading zero + build metadata
[InlineData(" 01.2.3 ")] // Leading zero + outer whitespace |
||
| [InlineData("01.2.3-alpha")] // Leading zero + pre-release | ||
| [InlineData("01.2.3+build")] // Leading zero + build metadata | ||
| [InlineData(" 01.2.3 ")] // Leading zero + outer whitespace | ||
| [InlineData("1. 2.3")] // Embedded whitespace in minor (NumberStyles.None rejects) | ||
| [InlineData("١.2.3")] // Arabic-Indic digit in major (InvariantCulture rejects) | ||
| [InlineData("99999999999999.0.0")] // Overflows int.MaxValue | ||
| public void ReturnsFalseForInvalidInput(string? input) | ||
| { | ||
| var result = SemanticVersion.TryParse(input, out var version); | ||
|
|
@@ -470,6 +485,14 @@ public void ParsesImplicitMinorWildcard(string pattern, string expectedLower, st | |
| [InlineData("1.2.3.*")] // Too specific | ||
| [InlineData(".1.*")] // Leading dot | ||
| [InlineData("abc.*")] // Non-numeric | ||
| [InlineData("01.*")] // Leading zero in major | ||
| [InlineData("1.02.*")] // Leading zero in minor | ||
| [InlineData("01.2.*")] // Leading zero in major (X.Y.*) | ||
| [InlineData("01")] // Leading zero in implicit major | ||
| [InlineData("01.2")] // Leading zero in implicit X.Y | ||
| [InlineData("1.02")] // Leading zero in implicit minor | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
[InlineData("v01.*")] // Leading zero with v-prefix
[InlineData("001.*")] // Multiple leading zeros |
||
| [InlineData("v01.*")] // Leading zero with v-prefix | ||
| [InlineData("001.*")] // Multiple leading zeros | ||
| public void ReturnsFalseForInvalidPatterns(string? pattern) | ||
| { | ||
| var result = SemanticVersion.TryParseWildcard(pattern, out var lower, out var upper); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
suggestion: The deletion of the explicitif (major < 0 || minor < 0 || patch < 0)check is safe only becauseNumberStyles.Nonerejects sign characters during parse. That coupling is load-bearing and invisible. The existing comment names the behavior; spelling out the dependency keeps the next person from "tightening" toNumberStyles.Integerand silently re-opening negative-component acceptance.