Skip to content

Commit a8b3c3c

Browse files
authored
Merge pull request #6 from aboutcode-org/throw-error
Return error for invalid or unsupported PURLs
2 parents aca52d3 + 359e6b9 commit a8b3c3c

5 files changed

Lines changed: 63 additions & 21 deletions

File tree

README.md

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
[![Version](https://img.shields.io/github/v/release/aboutcode-org/purlvalidator-go?style=for-the-badge)](https://github.com/aboutcode-org/purlvalidator-go/releases)
55
[![Test](https://img.shields.io/github/actions/workflow/status/aboutcode-org/purlvalidator-go/ci.yml?style=for-the-badge&logo=github)](https://github.com/aboutcode-org/purlvalidator-go/actions)
66

7-
**purlvalidator** is a Go library for validating [Package URLs (PURLs)](https://github.com/package-url/purl-spec). It works fully offline, including in **air-gapped** or **restricted environments**, and answers one key question: **Does the package this PURL represents actually exist?**
7+
**purlvalidator** is a Go library for validating [Package-URLs (PURLs)](https://github.com/package-url/purl-spec). It works fully offline, including in **air-gapped** or **restricted environments**, and answers one key question: **Does the package this PURL represents actually exist?**
88

99
## How It Works?
1010

11-
**purlvalidator** is shipped with a pre-built FST (Finite State Transducer), a set of compact automata containing latest Package URLs mined by the MineCode[^1]. Library uses this FST to perform lookups and confirm whether the **base PURL**[^2] exists.
11+
**purlvalidator** is shipped with a pre-built FST (Finite State Transducer), a set of compact automata containing latest Package-URLs mined by the MineCode[^1]. Library uses this FST to perform lookups and confirm whether the **base PURL**[^2] exists.
1212

1313
## Currently Supported Ecosystems
1414

@@ -30,15 +30,37 @@
3030
Add `purlvalidator` as dependency in your go.mod
3131

3232
```bash
33-
require github.com/aboutcode-org/purlvalidator-go v0.1.0
33+
require github.com/aboutcode-org/purlvalidator-go v1.0.0
3434
```
3535

36-
Use it in your code like this
36+
Use it in your code like this:
3737

38-
```rust
38+
```go
3939
import "github.com/aboutcode-org/purlvalidator-go"
4040

41-
var result bool = purlvalidator.Validate("pkg:nuget/FluentValidation");
41+
func main() {
42+
result, e := purlvalidator.Validate("pkg:nuget/FluentValidation");
43+
if err != nil {
44+
panic(err)
45+
}
46+
}
47+
```
48+
49+
Examples and errors:
50+
```go
51+
// This will return: true
52+
purlvalidator.Validate("pkg:nuget/FluentValidation");
53+
54+
// This will return: false
55+
purlvalidator.Validate("pkg:nuget/non-existent-foo-bar");
56+
57+
58+
// This will return an error: "only base PURL is supported (no version, qualifiers, or subpath)"
59+
purlvalidator.Validate("pkg:nuget/FluentValidation@10.2.3");
60+
61+
// This will return an error: "purl scheme is not \"pkg\": \"pkddg\""
62+
purlvalidator.Validate("test:nuget/FluentValidation");
63+
4264
```
4365

4466
## Contribution
@@ -90,4 +112,4 @@ limitations under the License.
90112
```
91113

92114
[^1]: MineCode continuously collects package metadata from various package ecosystems to maintain an up-to-date catalog of known packages.
93-
[^2]: A Base Package URL is a Package URL without a version or subpath.
115+
[^2]: A Base Package-URL is a Package-URL without a version, qualifiers or subpath.

go.mod

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ go 1.22.3
44

55
require github.com/blevesearch/vellum v1.1.0
66

7+
require github.com/package-url/packageurl-go v0.1.5
8+
79
require (
810
github.com/bits-and-blooms/bitset v1.2.0 // indirect
911
github.com/blevesearch/mmap-go v1.0.4 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,5 +4,7 @@ github.com/blevesearch/mmap-go v1.0.4 h1:OVhDhT5B/M1HNPpYPBKIEJaD0F3Si+CrEKULGCD
44
github.com/blevesearch/mmap-go v1.0.4/go.mod h1:EWmEAOmdAS9z/pi/+Toxu99DnsbhG1TIxUoRmJw/pSs=
55
github.com/blevesearch/vellum v1.1.0 h1:CinkGyIsgVlYf8Y2LUQHvdelgXr6PYuvoDIajq6yR9w=
66
github.com/blevesearch/vellum v1.1.0/go.mod h1:QgwWryE8ThtNPxtgWJof5ndPfx0/YMBh+W2weHKPw8Y=
7+
github.com/package-url/packageurl-go v0.1.5 h1:O4efRXja2XQ5CtiiYiCZ22k/m7i5ugLiAghgcC+eDgk=
8+
github.com/package-url/packageurl-go v0.1.5/go.mod h1:nKAWB8E6uk1MHqiS/lQb9pYBGH2+mdJ2PJc2s50dQY0=
79
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
810
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=

purlvalidator.go

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,11 @@ package purlvalidator
1313

1414
import (
1515
_ "embed"
16+
"fmt"
1617
"log"
17-
"strings"
1818

1919
"github.com/blevesearch/vellum"
20+
"github.com/package-url/packageurl-go"
2021
)
2122

2223
//go:embed purls.fst
@@ -32,12 +33,19 @@ func init() {
3233
}
3334
}
3435

35-
func validate_purl(packageURL string, fstMap *vellum.FST) bool {
36-
packageURL = strings.TrimSuffix(packageURL, "/")
37-
result, _ := fstMap.Contains([]byte(packageURL))
38-
return result
36+
func validate_purl(packageURL string, fstMap *vellum.FST) (bool, error) {
37+
instance, err := packageurl.FromString(packageURL)
38+
if err != nil {
39+
return false, err
40+
}
41+
if instance.Version != "" || len(instance.Qualifiers) > 0 || instance.Subpath != "" {
42+
return false, fmt.Errorf("only base PURL is supported (no version, qualifiers, or subpath)")
43+
}
44+
45+
result, err := fstMap.Contains([]byte(packageURL))
46+
return result, err
3947
}
4048

41-
func Validate(packageURL string) bool {
49+
func Validate(packageURL string) (bool, error) {
4250
return validate_purl(packageURL, validator)
4351
}

purlvalidator_test.go

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ func setup() {
4747

4848
func TestNonexistentPurl(t *testing.T) {
4949
purl := "pkg:nuget/nonexistent"
50-
result := validate_purl(purl, testValidator)
50+
result, _ := validate_purl(purl, testValidator)
5151
expected := false
5252

5353
if result != expected {
@@ -57,20 +57,28 @@ func TestNonexistentPurl(t *testing.T) {
5757

5858
func TestValidPurl(t *testing.T) {
5959
purl := "pkg:nuget/FluentUtils.FromCompositeAttribute"
60-
result := validate_purl(purl, testValidator)
60+
result, _ := validate_purl(purl, testValidator)
6161
expected := true
6262

6363
if result != expected {
6464
t.Errorf("validate_purl(\"%s\") = %t; expected %t", purl, result, expected)
6565
}
6666
}
6767

68-
func TestPurlWithTrailingSlash(t *testing.T) {
69-
purl := "pkg:nuget/FluentUtils.FromCompositeAttribute/"
70-
result := validate_purl(purl, testValidator)
71-
expected := true
68+
func TestErrorForInvalidPurl(t *testing.T) {
69+
purl := "test:nuget/FluentUtils.FromCompositeAttribute"
70+
_, err := validate_purl(purl, testValidator)
7271

73-
if result != expected {
74-
t.Errorf("validate_purl(\"%s\") = %t; expected %t", purl, result, expected)
72+
if err == nil {
73+
t.Errorf("expected error but got nil")
74+
}
75+
}
76+
77+
func TestErrorForUnsupportedPurl(t *testing.T) {
78+
purl := "pkg:nuget/EnterpriseLibrary.Common@6.0.1304"
79+
_, err := validate_purl(purl, testValidator)
80+
81+
if err == nil {
82+
t.Errorf("expected error but got nil")
7583
}
7684
}

0 commit comments

Comments
 (0)