Skip to content

feat: support checking if versions exist in crates.io #391

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion tools/osv-linter/internal/pkgchecker/ecosystems.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ func VersionsExistInEcosystem(pkg string, versions []string, ecosystem string) e
case "CRAN":
return nil
case "crates.io":
return nil
return versionsExistInCrates(pkg, versions)
case "Debian":
return nil
case "GIT":
Expand Down
64 changes: 64 additions & 0 deletions tools/osv-linter/internal/pkgchecker/ecosystems_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,70 @@ package pkgchecker

import "testing"

func Test_versionsExistInCrates(t *testing.T) {
t.Parallel()

type args struct {
pkg string
versions []string
}
tests := []struct {
name string
args args
wantErr bool
}{
{
name: "multiple_versions_which_all_exist",
args: args{
pkg: "defmt",
versions: []string{"0.0.0", "0.3.0", "0.3.100-rc.1", "1.0.0-rc.1", "1.0.1"},
},
wantErr: false,
},
{
name: "multiple_versions_with_one_that_does_not_exist",
args: args{
pkg: "defmt",
versions: []string{"1.1", "0.3.6-beta", "1.1.2"},
},
wantErr: true,
},
{
name: "an_invalid_version",
args: args{
pkg: "defmt",
versions: []string{"!"},
},
wantErr: true,
},
{
name: "an_invalid_package",
args: args{
pkg: "!",
versions: []string{"1.0.0"},
},
wantErr: true,
},
{
name: "a_package_that_does_not_exit",
args: args{
pkg: "not-a-real-package-hopefully",
versions: []string{"1.0.0"},
},
wantErr: true,
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
t.Parallel()

if err := versionsExistInCrates(tt.args.pkg, tt.args.versions); (err != nil) != tt.wantErr {
t.Errorf("versionsExistInCrates() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}

func Test_versionsExistInGo(t *testing.T) {
type args struct {
pkg string
Expand Down
52 changes: 52 additions & 0 deletions tools/osv-linter/internal/pkgchecker/version_check.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,58 @@ import (
"golang.org/x/mod/semver"
)

// Confirm that all specified versions of a package exist in crates.io.
func versionsExistInCrates(pkg string, versions []string) error {
packageInstanceURL := fmt.Sprintf("%s/%s", EcosystemBaseURLs["crates.io"], pkg)

resp, err := faulttolerant.Get(packageInstanceURL)
if err != nil {
return fmt.Errorf("unable to validate package: %v", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("unable to validate package: %q for %s", resp.Status, packageInstanceURL)
}

// Parse the known versions from the JSON.
respJSON, err := io.ReadAll(resp.Body)
if err != nil {
return fmt.Errorf("unable to retrieve JSON for %q: %v", pkg, err)
}
// Fetch all known versions of package.
versionsInRepository := []string{}
releases := gjson.GetBytes(respJSON, "versions")
releases.ForEach(func(key, value gjson.Result) bool {
versionsInRepository = append(versionsInRepository, value.Get("num").String())
return true // keep iterating.
})
// Determine which referenced versions are missing.
versionsMissing := []string{}
for _, versionToCheckFor := range versions {
versionFound := false
vc, err := semantic.Parse(versionToCheckFor, "RubyGems")
if err != nil {
versionsMissing = append(versionsMissing, versionToCheckFor)
continue
}
for _, pkgversion := range versionsInRepository {
if r, err := vc.CompareStr(pkgversion); r == 0 && err == nil {
versionFound = true
break
}
}
if versionFound {
continue
}
versionsMissing = append(versionsMissing, versionToCheckFor)
}
if len(versionsMissing) > 0 {
return &MissingVersionsError{Package: pkg, Ecosystem: "RubyGems", Missing: versionsMissing, Known: versionsInRepository}
}

return nil
}

// Confirm that all specified versions of a package exist in Go.
func versionsExistInGo(pkg string, versions []string) error {
if pkg == "stdlib" || pkg == "toolchain" {
Expand Down
Loading