mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
fix: npm Dependency Cooldown Select Stable Version (#291)
* fix: npm Dependency Cooldown Select Stable Version * fix: Code review fixes
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
package interceptors
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
packagev1 "buf.build/gen/go/safedep/api/protocolbuffers/go/safedep/messages/package/v1"
|
||||
"github.com/Masterminds/semver"
|
||||
"github.com/safedep/pmg/internal/audit"
|
||||
)
|
||||
|
||||
@@ -70,17 +72,51 @@ func recordCooldownStats(statsCollector *AnalysisStatsCollector, ecosystem packa
|
||||
}
|
||||
}
|
||||
|
||||
// cooldownLatestEligibleVersion returns the most recently published version not in tooNew.
|
||||
func cooldownLatestEligibleVersion(dates map[string]time.Time, tooNew map[string]bool) string {
|
||||
// cooldownHighestStableVersion returns the highest stable (non-prerelease) version
|
||||
// among candidates that does not exceed upperBound, ordered by semver. This mirrors
|
||||
// what npm treats as the "latest" dist-tag.
|
||||
//
|
||||
// Prerelease versions are excluded — semver classifies both alpha builds
|
||||
// (e.g. 1.2.0-alpha.1) and platform-specific builds (e.g. 1.2.0-win32-arm64) as
|
||||
// prereleases, so neither can be promoted to latest. Unparseable versions are skipped.
|
||||
//
|
||||
// upperBound is the version dist-tags.latest currently points to. Bounding by it keeps
|
||||
// a repaired latest on the lineage the maintainer marked as latest, rather than
|
||||
// promoting a higher major/minor published under a different channel (e.g. `next`).
|
||||
// An empty or unparseable upperBound applies no upper bound.
|
||||
func cooldownHighestStableVersion(candidates []string, upperBound string) string {
|
||||
var bound *semver.Version
|
||||
if upperBound != "" {
|
||||
if b, err := semver.NewVersion(upperBound); err == nil {
|
||||
// If latest itself points to a prerelease/platform build (e.g.
|
||||
// 1.0.0-win32-arm64), bound to its base release. The bound represents a
|
||||
// release line, and semver ranks 1.0.0 > 1.0.0-win32-arm64, so without
|
||||
// this the stable counterpart on the same line would be wrongly excluded.
|
||||
if b.Prerelease() != "" {
|
||||
if base, err := semver.NewVersion(fmt.Sprintf("%d.%d.%d", b.Major(), b.Minor(), b.Patch())); err == nil {
|
||||
b = base
|
||||
}
|
||||
}
|
||||
bound = b
|
||||
}
|
||||
}
|
||||
|
||||
var latest string
|
||||
var latestTime time.Time
|
||||
for version, publishDate := range dates {
|
||||
if tooNew[version] {
|
||||
var latestVer *semver.Version
|
||||
for _, version := range candidates {
|
||||
ver, err := semver.NewVersion(version)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
if publishDate.After(latestTime) {
|
||||
if ver.Prerelease() != "" {
|
||||
continue
|
||||
}
|
||||
if bound != nil && ver.GreaterThan(bound) {
|
||||
continue
|
||||
}
|
||||
if latestVer == nil || ver.GreaterThan(latestVer) {
|
||||
latest = version
|
||||
latestTime = publishDate
|
||||
latestVer = ver
|
||||
}
|
||||
}
|
||||
return latest
|
||||
|
||||
Reference in New Issue
Block a user