From 1bf9fe5d0071083b427b6e63c48ad2e1d4bc53d3 Mon Sep 17 00:00:00 2001 From: Brian Cerier Date: Thu, 10 Jul 2025 16:29:30 -0700 Subject: [PATCH] fix tilde upper bound --- constraint.go | 23 +++++++++++++++++------ constraint_test.go | 3 +++ 2 files changed, 20 insertions(+), 6 deletions(-) diff --git a/constraint.go b/constraint.go index 6047799..59fc45c 100644 --- a/constraint.go +++ b/constraint.go @@ -267,13 +267,10 @@ func constraintPessimistic(v, c *Version) bool { if v.LessThan(c) { return false } - // We'll use this more than once, so grab the length now so it's a little cleaner - // to write the later checks - cs := len(c.segments) // If the version being checked has less specificity than the constraint, then there // is no way for the version to be valid against the constraint - if cs > len(v.segments) { + if c.si > len(v.segments) { return false } @@ -286,10 +283,24 @@ func constraintPessimistic(v, c *Version) bool { } } - // Check the last part of the segment in the constraint. If the version segment at + // Check the last significant segment in the constraint. If the version segment at // this index is less than the constraints segment at this index, then it cannot // be valid against the constraint - if c.segments[cs-1] > v.segments[cs-1] { + lastSigIndex := c.si - 1 + if c.segments[lastSigIndex] > v.segments[lastSigIndex] { + return false + } + + // Upper bound check: prevent incrementing segments that shouldn't be incremented + // For ~> 1, prevent major version (index 0) from incrementing: 1.x.x but not 2.x.x + // For ~> 1.0, prevent major version (index 0) from incrementing: 1.x.x but not 2.x.x + // For ~> 1.0.0, prevent minor version (index 1) from incrementing: 1.0.x but not 1.1.x + // The rule is: use max(0, c.si - 2) for the upper bound segment + upperBoundIndex := 0 + if c.si > 2 { + upperBoundIndex = c.si - 2 + } + if v.segments[upperBoundIndex] >= c.segments[upperBoundIndex]+1 { return false } diff --git a/constraint_test.go b/constraint_test.go index e76d3b0..20c7a2b 100644 --- a/constraint_test.go +++ b/constraint_test.go @@ -51,6 +51,9 @@ func TestConstraintCheck(t *testing.T) { {"= 1.0", "1.1.5", false}, {"= 1.0", "1.0.0", true}, {"1.0", "1.0.0", true}, + {"~> 1", "1.9", true}, + {"~> 1", "2.0", false}, + {"~> 1", "2", false}, {"~> 1.0", "2.0", false}, {"~> 1.0", "1.1", true}, {"~> 1.0", "1.2.3", true},