diff --git a/README.md b/README.md
index bb7e730..abd7c17 100644
--- a/README.md
+++ b/README.md
@@ -63,7 +63,7 @@ Available Commands:
deps Get info about a package's dependencies
graph Generate a Graphviz compatible dependencies graph
help Help about any command
- info Get info about a package or a specific version of that
+ package Get info about a package or a specific version of that
packages Get info about a project's package versions (GitHub, GitLab, or BitBucket)
project Get info about a project (GitHub, GitLab, or BitBucket)
query Get info about multiple package versions using a query
@@ -88,7 +88,7 @@ For more information [read the API documentation](https://docs.deps.dev/api/v3).
Get information about a package, including a list of its available versions, with the default version marked if known.
```console
-depsdev info npm @colors/colors
+depsdev package npm @colors/colors
```
@@ -96,7 +96,7 @@ depsdev info npm @colors/colors
Get information about a specific package version including its licenses and any security advisories known to affect it.
```console
-depsdev info npm @colors/colors 1.5.0
+depsdev package npm @colors/colors 1.5.0
```
diff --git a/cmd/info.go b/cmd/package.go
similarity index 88%
rename from cmd/info.go
rename to cmd/package.go
index 6f2ffe4..7d28e1a 100644
--- a/cmd/info.go
+++ b/cmd/package.go
@@ -23,9 +23,9 @@ import (
"github.com/spf13/cobra"
)
-// infoCmd represents the info command when called with info subcommand.
-var infoCmd = &cobra.Command{
- Use: "info package-manager package-name [version]",
+// packageCmd represents the package command when called with package subcommand.
+var packageCmd = &cobra.Command{
+ Use: "package package-manager package-name [version]",
Short: "Get info about a package or a specific version of that",
Long: `Get information about a package, including a list of its available versions,
with the default version marked if known.
@@ -56,7 +56,7 @@ including its licenses and any security advisories known to affect it.`,
fmt.Println(vJSON)
} else {
- p, err := api.GetInfo(args[0], args[1])
+ p, err := api.GetPackage(args[0], args[1])
if err != nil {
log.Fatal(err)
}
diff --git a/cmd/packages.go b/cmd/packages.go
index 5a98aed..48c1080 100644
--- a/cmd/packages.go
+++ b/cmd/packages.go
@@ -36,7 +36,7 @@ var packagesCmd = &cobra.Command{
return nil
},
Run: func(cmd *cobra.Command, args []string) {
- v, err := api.GetPackageVersions(args[0])
+ v, err := api.GetProjectPackageVersions(args[0])
if err != nil {
log.Fatal(err)
}
diff --git a/cmd/root.go b/cmd/root.go
index 69c9769..9822bb0 100644
--- a/cmd/root.go
+++ b/cmd/root.go
@@ -49,7 +49,7 @@ func Execute() {
}
func init() {
- rootCmd.AddCommand(infoCmd)
+ rootCmd.AddCommand(packageCmd)
rootCmd.AddCommand(depsCmd)
rootCmd.AddCommand(advisoryCmd)
rootCmd.AddCommand(projectCmd)
diff --git a/pkg/depsdev/definitions/deps.go b/pkg/depsdev/definitions/deps.go
index 723db0c..8996450 100644
--- a/pkg/depsdev/definitions/deps.go
+++ b/pkg/depsdev/definitions/deps.go
@@ -32,3 +32,9 @@ type Edge struct {
ToNode int `json:"toNode,omitempty"`
Requirement string `json:"requirement,omitempty"`
}
+
+type Dependent struct {
+ DependentCount int `json:"dependentCount"`
+ DirectDependentCount int `json:"directDependentCount"`
+ IndirectDependentCount int `json:"indirectDependentCount"`
+}
diff --git a/pkg/depsdev/definitions/requirements.go b/pkg/depsdev/definitions/requirements.go
index 6771f99..1e028df 100644
--- a/pkg/depsdev/definitions/requirements.go
+++ b/pkg/depsdev/definitions/requirements.go
@@ -114,9 +114,3 @@ type File struct {
Exists string `json:"exists,omitempty"`
Missing string `json:"missing,omitempty"`
}
-
-type Dependent struct {
- DependentCount int `json:"dependentCount"`
- DirectDependentCount int `json:"directDependentCount"`
- IndirectDependentCount int `json:"indirectDependentCount"`
-}
diff --git a/pkg/depsdev/v3/api.go b/pkg/depsdev/v3/api.go
index b67ab44..a9b2305 100644
--- a/pkg/depsdev/v3/api.go
+++ b/pkg/depsdev/v3/api.go
@@ -34,10 +34,9 @@ func NewV3API() *APIv3 {
}
}
-// GetInfo returns information about a package,
-// including a list of its available versions,
+// GetPackage returns information about a package, including a list of its available versions,
// with the default version marked if known.
-func (a *APIv3) GetInfo(packageManager, packageName string) (def.Package, error) {
+func (a *APIv3) GetPackage(packageManager, packageName string) (def.Package, error) {
if !input.IsValidPackageManager(packageManager, input.AllValidPackageManagers) {
return def.Package{}, input.ErrInvalidPackageManager
}
@@ -77,8 +76,12 @@ func getVersion(c *client.Client, packageManager, packageName, version string) (
return response, nil
}
-// GetDependencies returns information about dependencies for a specific version of a package
-// for a specific package manager.
+// GetDependencies returns a resolved dependency graph for the given package version.
+// Dependencies are currently available for npm, Cargo, Maven and PyPI.
+// Dependencies are the resolution of the requirements (dependency constraints) specified by a version.
+// The dependency graph should be similar to one produced by installing the package version on a generic 64-bit Linux system,
+// with no other dependencies present. The precise meaning of this varies from system to system.
+// Example: npm react 18.2.0.
func (a *APIv3) GetDependencies(packageManager, packageName, version string) (def.Dependencies, error) {
return getDependencies(a.client, packageManager, packageName, version)
}
@@ -94,7 +97,8 @@ func getDependencies(c *client.Client, packageManager, packageName, version stri
return response, nil
}
-// GetProject returns information about a project (hosted on GitHub, GitLab or BitBucket).
+// GetProject returns information about projects hosted by GitHub, GitLab, or BitBucket, when known to us.
+// Example: github.com/facebook/react.
func (a *APIv3) GetProject(projectName string) (def.Project, error) {
return getProject(a.client, projectName)
}
@@ -110,7 +114,8 @@ func getProject(c *client.Client, projectName string) (def.Project, error) {
return response, nil
}
-// GetAdvisory returns information about an advisory.
+// GetAdvisory returns information about security advisories hosted by OSV.
+// Example: GHSA-2qrg-x229-3v8q.
func (a *APIv3) GetAdvisory(advisory string) (def.Advisory, error) {
return getAdvisory(a.client, advisory)
}
@@ -126,7 +131,15 @@ func getAdvisory(c *client.Client, advisory string) (def.Advisory, error) {
return response, nil
}
-// Query returns the result of the inputted query.
+// Query returns information about multiple package versions, which can be specified by name, content hash, or both.
+// If a hash was specified in the request, it returns the artifacts that matched the hash.
+// Querying by content hash is currently supported for npm, Cargo, Maven, NuGet, PyPI and RubyGems.
+// It is typical for hash queries to return many results; hashes are matched against multiple release artifacts
+// (such as JAR files) that comprise package versions, and any given artifact may appear in several package versions.
+// Examples:
+// hash.type=SHA1&hash.value=ulXBPXrC%2FUTfnMgHRFVxmjPzdbk%3D
+// versionKey.system=NPM&versionKey.name=react&versionKey.version=18.2.0
+// End of examples.
func (a *APIv3) Query(query string) (def.Results, error) {
return getQuery(a.client, query)
}
@@ -143,7 +156,9 @@ func getQuery(c *client.Client, query string) (def.Results, error) {
}
// GetRequirements returns the requirements for a given version in a system-specific format.
-// Requirements are currently available for Maven, npm and NuGet.
+// Requirements are currently available for Maven, npm, NuGet and RubyGems.
+// Requirements are the dependency constraints specified by the version.
+// Example: nuget castle.core 5.1.1.
func (a *APIv3) GetRequirements(packageManager, packageName, version string) (def.Requirements, error) {
var response def.Requirements
@@ -155,10 +170,11 @@ func (a *APIv3) GetRequirements(packageManager, packageName, version string) (de
return response, nil
}
-// GetPackageVersions returns the package versions which attest to being created from the specified
-// source code repository (hosted on GitHub, GitLab or BitBucket).
+// GetProjectPackageVersions returns known mappings between the requested project and package versions.
// At most 1500 package versions are returned.
-func (a *APIv3) GetPackageVersions(projectName string) (def.PackageVersions, error) {
+// Mappings which were derived from attestations are served first.
+// Example: github.com/facebook/react.
+func (a *APIv3) GetProjectPackageVersions(projectName string) (def.PackageVersions, error) {
var response def.PackageVersions
var path = fmt.Sprintf(GetProjectPackageVersionsPath, url.PathEscape(projectName))
diff --git a/pkg/depsdev/v3/api_internal_test.go b/pkg/depsdev/v3/api_internal_test.go
index b2105c7..53b92d6 100644
--- a/pkg/depsdev/v3/api_internal_test.go
+++ b/pkg/depsdev/v3/api_internal_test.go
@@ -51,7 +51,7 @@ func BenchmarkGetInfo(b *testing.B) {
)
for i := 0; i < b.N; i++ {
- info, err = api.GetInfo("npm", "react")
+ info, err = api.GetPackage("npm", "react")
require.NoError(b, err)
}
diff --git a/pkg/depsdev/v3/api_test.go b/pkg/depsdev/v3/api_test.go
index d8acf7b..785d160 100644
--- a/pkg/depsdev/v3/api_test.go
+++ b/pkg/depsdev/v3/api_test.go
@@ -29,18 +29,7 @@ var (
api = depsdev.NewV3API()
)
-func TestGetProject(t *testing.T) {
- t.Run("GetInfo npm defangjs", func(t *testing.T) {
- got, err := api.GetProject("github.com/edoardottt/defangjs")
- require.Nil(t, err)
-
- // no checking of the actual value because they can change over time
- // we just ensure the call to the API and unmarshaling of the response works properly
- assert.NotEmpty(t, got)
- })
-}
-
-func TestGetInfo(t *testing.T) {
+func TestGetPackage(t *testing.T) {
result := `{
"packageKey": {
"system": "NPM",
@@ -115,8 +104,8 @@ func TestGetInfo(t *testing.T) {
]
}`
- t.Run("GetInfo npm defangjs", func(t *testing.T) {
- got, err := api.GetInfo("npm", "defangjs")
+ t.Run("GetPackage npm defangjs", func(t *testing.T) {
+ got, err := api.GetPackage("npm", "defangjs")
require.Nil(t, err)
var d def.Package
@@ -197,6 +186,176 @@ func TestGetVersion(t *testing.T) {
})
}
+func TestGetRequirements(t *testing.T) {
+ result := `{
+ "npm": {
+ "dependencies": {
+ "dependencies": [
+ {
+ "name": "fast-redact",
+ "requirement": "^3.0.0"
+ },
+ {
+ "name": "fast-safe-stringify",
+ "requirement": "^2.0.8"
+ },
+ {
+ "name": "flatstr",
+ "requirement": "^1.0.12"
+ },
+ {
+ "name": "pino-std-serializers",
+ "requirement": "^3.1.0"
+ },
+ {
+ "name": "process-warning",
+ "requirement": "^1.0.0"
+ },
+ {
+ "name": "quick-format-unescaped",
+ "requirement": "^4.0.3"
+ },
+ {
+ "name": "sonic-boom",
+ "requirement": "^1.0.2"
+ }
+ ],
+ "devDependencies": [
+ {
+ "name": "airtap",
+ "requirement": "4.0.3"
+ },
+ {
+ "name": "benchmark",
+ "requirement": "^2.1.4"
+ },
+ {
+ "name": "bole",
+ "requirement": "^4.0.0"
+ },
+ {
+ "name": "bunyan",
+ "requirement": "^1.8.14"
+ },
+ {
+ "name": "docsify-cli",
+ "requirement": "^4.4.1"
+ },
+ {
+ "name": "eslint",
+ "requirement": "^7.17.0"
+ },
+ {
+ "name": "eslint-config-standard",
+ "requirement": "^16.0.2"
+ },
+ {
+ "name": "eslint-plugin-import",
+ "requirement": "^2.22.1"
+ },
+ {
+ "name": "eslint-plugin-node",
+ "requirement": "^11.1.0"
+ },
+ {
+ "name": "eslint-plugin-promise",
+ "requirement": "^5.1.0"
+ },
+ {
+ "name": "execa",
+ "requirement": "^5.0.0"
+ },
+ {
+ "name": "fastbench",
+ "requirement": "^1.0.1"
+ },
+ {
+ "name": "flush-write-stream",
+ "requirement": "^2.0.0"
+ },
+ {
+ "name": "import-fresh",
+ "requirement": "^3.2.1"
+ },
+ {
+ "name": "log",
+ "requirement": "^6.0.0"
+ },
+ {
+ "name": "loglevel",
+ "requirement": "^1.6.7"
+ },
+ {
+ "name": "pino-pretty",
+ "requirement": "^5.0.0"
+ },
+ {
+ "name": "pre-commit",
+ "requirement": "^1.2.2"
+ },
+ {
+ "name": "proxyquire",
+ "requirement": "^2.1.3"
+ },
+ {
+ "name": "pump",
+ "requirement": "^3.0.0"
+ },
+ {
+ "name": "semver",
+ "requirement": "^7.0.0"
+ },
+ {
+ "name": "split2",
+ "requirement": "^3.1.1"
+ },
+ {
+ "name": "steed",
+ "requirement": "^1.1.3"
+ },
+ {
+ "name": "strip-ansi",
+ "requirement": "^6.0.0"
+ },
+ {
+ "name": "tap",
+ "requirement": "^15.0.1"
+ },
+ {
+ "name": "tape",
+ "requirement": "^5.0.0"
+ },
+ {
+ "name": "through2",
+ "requirement": "^4.0.0"
+ },
+ {
+ "name": "winston",
+ "requirement": "^3.3.3"
+ }
+ ],
+ "optionalDependencies": [],
+ "peerDependencies": [],
+ "bundleDependencies": []
+ },
+ "Bundled": []
+ }
+ }`
+
+ t.Run("GetRequirements npm pino 6.14.0", func(t *testing.T) {
+ got, err := api.GetRequirements("npm", "pino", "6.14.0")
+ require.Nil(t, err)
+
+ var r def.Requirements
+
+ if err := json.Unmarshal([]byte(result), &r); err != nil {
+ log.Fatal(err)
+ }
+
+ require.Equal(t, r, got)
+ })
+}
+
func TestGetDependencies(t *testing.T) {
result := `{
"nodes": [
@@ -338,6 +497,28 @@ func TestGetDependencies(t *testing.T) {
})
}
+func TestGetProject(t *testing.T) {
+ t.Run("GetProject npm defangjs", func(t *testing.T) {
+ got, err := api.GetProject("github.com/edoardottt/defangjs")
+ require.Nil(t, err)
+
+ // no checking of the actual value because they can change over time
+ // we just ensure the call to the API and unmarshaling of the response works properly
+ assert.NotEmpty(t, got)
+ })
+}
+
+func TestGetProjectPackageVersions(t *testing.T) {
+ t.Run("GetProjectPackageVersions npm defangjs", func(t *testing.T) {
+ got, err := api.GetProjectPackageVersions("github.com/edoardottt/defangjs")
+ require.Nil(t, err)
+
+ // no checking of the actual value because they can change over time
+ // we just ensure the call to the API and unmarshaling of the response works properly
+ assert.NotEmpty(t, got)
+ })
+}
+
func TestGetAdvisory(t *testing.T) {
result := `{
"advisoryKey": {
@@ -366,172 +547,76 @@ func TestGetAdvisory(t *testing.T) {
})
}
-func TestGetRequirements(t *testing.T) {
+func TestQuery(t *testing.T) {
result := `{
- "npm": {
- "dependencies": {
- "dependencies": [
- {
- "name": "fast-redact",
- "requirement": "^3.0.0"
- },
- {
- "name": "fast-safe-stringify",
- "requirement": "^2.0.8"
- },
- {
- "name": "flatstr",
- "requirement": "^1.0.12"
- },
- {
- "name": "pino-std-serializers",
- "requirement": "^3.1.0"
- },
- {
- "name": "process-warning",
- "requirement": "^1.0.0"
- },
- {
- "name": "quick-format-unescaped",
- "requirement": "^4.0.3"
- },
- {
- "name": "sonic-boom",
- "requirement": "^1.0.2"
- }
- ],
- "devDependencies": [
- {
- "name": "airtap",
- "requirement": "4.0.3"
- },
- {
- "name": "benchmark",
- "requirement": "^2.1.4"
- },
- {
- "name": "bole",
- "requirement": "^4.0.0"
- },
- {
- "name": "bunyan",
- "requirement": "^1.8.14"
- },
- {
- "name": "docsify-cli",
- "requirement": "^4.4.1"
- },
- {
- "name": "eslint",
- "requirement": "^7.17.0"
- },
- {
- "name": "eslint-config-standard",
- "requirement": "^16.0.2"
- },
- {
- "name": "eslint-plugin-import",
- "requirement": "^2.22.1"
- },
- {
- "name": "eslint-plugin-node",
- "requirement": "^11.1.0"
- },
- {
- "name": "eslint-plugin-promise",
- "requirement": "^5.1.0"
- },
- {
- "name": "execa",
- "requirement": "^5.0.0"
- },
- {
- "name": "fastbench",
- "requirement": "^1.0.1"
- },
- {
- "name": "flush-write-stream",
- "requirement": "^2.0.0"
- },
- {
- "name": "import-fresh",
- "requirement": "^3.2.1"
- },
- {
- "name": "log",
- "requirement": "^6.0.0"
- },
- {
- "name": "loglevel",
- "requirement": "^1.6.7"
- },
- {
- "name": "pino-pretty",
- "requirement": "^5.0.0"
- },
- {
- "name": "pre-commit",
- "requirement": "^1.2.2"
- },
- {
- "name": "proxyquire",
- "requirement": "^2.1.3"
- },
- {
- "name": "pump",
- "requirement": "^3.0.0"
- },
- {
- "name": "semver",
- "requirement": "^7.0.0"
- },
- {
- "name": "split2",
- "requirement": "^3.1.1"
- },
- {
- "name": "steed",
- "requirement": "^1.1.3"
- },
- {
- "name": "strip-ansi",
- "requirement": "^6.0.0"
- },
- {
- "name": "tap",
- "requirement": "^15.0.1"
- },
- {
- "name": "tape",
- "requirement": "^5.0.0"
- },
- {
- "name": "through2",
- "requirement": "^4.0.0"
- },
- {
- "name": "winston",
- "requirement": "^3.3.3"
- }
- ],
- "optionalDependencies": [],
- "peerDependencies": [],
- "bundleDependencies": []
- },
- "Bundled": []
- }
- }`
+ "results": [
+ {
+ "version": {
+ "versionKey": {
+ "system": "NPM",
+ "name": "defangjs",
+ "version": "1.0.7"
+ },
+ "publishedAt": "2023-05-16T09:48:31Z",
+ "isDefault": true,
+ "licenses": [
+ "GPL-3.0"
+ ],
+ "advisoryKeys": [],
+ "links": [
+ {
+ "label": "HOMEPAGE",
+ "url": "https://github.com/edoardottt/defangjs#readme"
+ },
+ {
+ "label": "ISSUE_TRACKER",
+ "url": "https://github.com/edoardottt/defangjs/issues"
+ },
+ {
+ "label": "ORIGIN",
+ "url": "https://registry.npmjs.org/defangjs/1.0.7"
+ },
+ {
+ "label": "SOURCE_REPO",
+ "url": "git+https://github.com/edoardottt/defangjs.git"
+ }
+ ],
+ "slsaProvenances": [],
+ "attestations": [],
+ "registries": [
+ "https://registry.npmjs.org/"
+ ],
+ "relatedProjects": [
+ {
+ "projectKey": {
+ "id": "github.com/edoardottt/defangjs"
+ },
+ "relationProvenance": "UNVERIFIED_METADATA",
+ "relationType": "ISSUE_TRACKER"
+ },
+ {
+ "projectKey": {
+ "id": "github.com/edoardottt/defangjs"
+ },
+ "relationProvenance": "UNVERIFIED_METADATA",
+ "relationType": "SOURCE_REPO"
+ }
+ ]
+ }
+ }
+ ]
+ }`
- t.Run("GetRequirements npm pino 6.14.0", func(t *testing.T) {
- got, err := api.GetRequirements("npm", "pino", "6.14.0")
+ t.Run("Query versionKey.system=NPM&versionKey.name=defangjs&versionKey.version=1.0.7", func(t *testing.T) {
+ got, err := api.Query("versionKey.system=NPM&versionKey.name=defangjs&versionKey.version=1.0.7")
require.Nil(t, err)
- var r def.Requirements
+ var a def.Results
- if err := json.Unmarshal([]byte(result), &r); err != nil {
+ if err := json.Unmarshal([]byte(result), &a); err != nil {
log.Fatal(err)
}
- require.Equal(t, r, got)
+ require.Equal(t, a, got)
})
}
diff --git a/pkg/depsdev/v3alpha/api.go b/pkg/depsdev/v3alpha/api.go
index b8e9d72..18dc206 100644
--- a/pkg/depsdev/v3alpha/api.go
+++ b/pkg/depsdev/v3alpha/api.go
@@ -181,7 +181,7 @@ func (a *APIv3Alpha) GetRequirements(packageManager, packageName, version string
// GetProjectPackageVersions returns known mappings between the requested project and package versions.
// At most 1500 package versions are returned.
// Mappings which were derived from attestations are served first.
-func (a *APIv3Alpha) GetPackageVersions(projectName string) (def.PackageVersions, error) {
+func (a *APIv3Alpha) GetProjectPackageVersions(projectName string) (def.PackageVersions, error) {
var response def.PackageVersions
var path = fmt.Sprintf(GetProjectPackageVersionsPath, url.PathEscape(projectName))
diff --git a/pkg/depsdev/v3alpha/api_test.go b/pkg/depsdev/v3alpha/api_test.go
index 66a9bcd..cda27fa 100644
--- a/pkg/depsdev/v3alpha/api_test.go
+++ b/pkg/depsdev/v3alpha/api_test.go
@@ -30,7 +30,7 @@ var (
api = depsdev.NewV3AlphaAPI()
)
-func TestGetInfo(t *testing.T) {
+func TestGetPackage(t *testing.T) {
result := `{
"packageKey":{
"system":"NPM",
@@ -232,6 +232,176 @@ func TestGetVersion(t *testing.T) {
})
}
+func TestGetRequirements(t *testing.T) {
+ result := `{
+ "npm": {
+ "dependencies": {
+ "dependencies": [
+ {
+ "name": "fast-redact",
+ "requirement": "^3.0.0"
+ },
+ {
+ "name": "fast-safe-stringify",
+ "requirement": "^2.0.8"
+ },
+ {
+ "name": "flatstr",
+ "requirement": "^1.0.12"
+ },
+ {
+ "name": "pino-std-serializers",
+ "requirement": "^3.1.0"
+ },
+ {
+ "name": "process-warning",
+ "requirement": "^1.0.0"
+ },
+ {
+ "name": "quick-format-unescaped",
+ "requirement": "^4.0.3"
+ },
+ {
+ "name": "sonic-boom",
+ "requirement": "^1.0.2"
+ }
+ ],
+ "devDependencies": [
+ {
+ "name": "airtap",
+ "requirement": "4.0.3"
+ },
+ {
+ "name": "benchmark",
+ "requirement": "^2.1.4"
+ },
+ {
+ "name": "bole",
+ "requirement": "^4.0.0"
+ },
+ {
+ "name": "bunyan",
+ "requirement": "^1.8.14"
+ },
+ {
+ "name": "docsify-cli",
+ "requirement": "^4.4.1"
+ },
+ {
+ "name": "eslint",
+ "requirement": "^7.17.0"
+ },
+ {
+ "name": "eslint-config-standard",
+ "requirement": "^16.0.2"
+ },
+ {
+ "name": "eslint-plugin-import",
+ "requirement": "^2.22.1"
+ },
+ {
+ "name": "eslint-plugin-node",
+ "requirement": "^11.1.0"
+ },
+ {
+ "name": "eslint-plugin-promise",
+ "requirement": "^5.1.0"
+ },
+ {
+ "name": "execa",
+ "requirement": "^5.0.0"
+ },
+ {
+ "name": "fastbench",
+ "requirement": "^1.0.1"
+ },
+ {
+ "name": "flush-write-stream",
+ "requirement": "^2.0.0"
+ },
+ {
+ "name": "import-fresh",
+ "requirement": "^3.2.1"
+ },
+ {
+ "name": "log",
+ "requirement": "^6.0.0"
+ },
+ {
+ "name": "loglevel",
+ "requirement": "^1.6.7"
+ },
+ {
+ "name": "pino-pretty",
+ "requirement": "^5.0.0"
+ },
+ {
+ "name": "pre-commit",
+ "requirement": "^1.2.2"
+ },
+ {
+ "name": "proxyquire",
+ "requirement": "^2.1.3"
+ },
+ {
+ "name": "pump",
+ "requirement": "^3.0.0"
+ },
+ {
+ "name": "semver",
+ "requirement": "^7.0.0"
+ },
+ {
+ "name": "split2",
+ "requirement": "^3.1.1"
+ },
+ {
+ "name": "steed",
+ "requirement": "^1.1.3"
+ },
+ {
+ "name": "strip-ansi",
+ "requirement": "^6.0.0"
+ },
+ {
+ "name": "tap",
+ "requirement": "^15.0.1"
+ },
+ {
+ "name": "tape",
+ "requirement": "^5.0.0"
+ },
+ {
+ "name": "through2",
+ "requirement": "^4.0.0"
+ },
+ {
+ "name": "winston",
+ "requirement": "^3.3.3"
+ }
+ ],
+ "optionalDependencies": [],
+ "peerDependencies": [],
+ "bundleDependencies": []
+ },
+ "Bundled": []
+ }
+ }`
+
+ t.Run("GetRequirements npm pino 6.14.0", func(t *testing.T) {
+ got, err := api.GetRequirements("npm", "pino", "6.14.0")
+ require.Nil(t, err)
+
+ var r def.Requirements
+
+ if err := json.Unmarshal([]byte(result), &r); err != nil {
+ log.Fatal(err)
+ }
+
+ require.Equal(t, r, got)
+ })
+}
+
func TestGetDependencies(t *testing.T) {
result := `{
"nodes": [
@@ -373,6 +543,39 @@ func TestGetDependencies(t *testing.T) {
})
}
+func TestGetDependents(t *testing.T) {
+ t.Run("GetDependents npm pino 9.0.0", func(t *testing.T) {
+ got, err := api.GetDependents("npm", "pino", "9.0.0")
+ require.Nil(t, err)
+
+ require.GreaterOrEqual(t, got.DependentCount, 0)
+ require.GreaterOrEqual(t, got.DirectDependentCount, 0)
+ require.GreaterOrEqual(t, got.IndirectDependentCount, 0)
+ })
+}
+
+func TestGetProject(t *testing.T) {
+ t.Run("GetProject npm defangjs", func(t *testing.T) {
+ got, err := api.GetProject("github.com/edoardottt/defangjs")
+ require.Nil(t, err)
+
+ // no checking of the actual value because they can change over time
+ // we just ensure the call to the API and unmarshaling of the response works properly
+ assert.NotEmpty(t, got)
+ })
+}
+
+func TestGetProjectPackageVersions(t *testing.T) {
+ t.Run("GetProjectPackageVersions npm defangjs", func(t *testing.T) {
+ got, err := api.GetProjectPackageVersions("github.com/edoardottt/defangjs")
+ require.Nil(t, err)
+
+ // no checking of the actual value because they can change over time
+ // we just ensure the call to the API and unmarshaling of the response works properly
+ assert.NotEmpty(t, got)
+ })
+}
+
func TestGetAdvisory(t *testing.T) {
result := `{
"advisoryKey": {
@@ -401,173 +604,116 @@ func TestGetAdvisory(t *testing.T) {
})
}
-func TestGetRequirements(t *testing.T) {
- result := `{
- "npm": {
- "dependencies": {
- "dependencies": [
- {
- "name": "fast-redact",
- "requirement": "^3.0.0"
- },
- {
- "name": "fast-safe-stringify",
- "requirement": "^2.0.8"
- },
- {
- "name": "flatstr",
- "requirement": "^1.0.12"
- },
- {
- "name": "pino-std-serializers",
- "requirement": "^3.1.0"
- },
- {
- "name": "process-warning",
- "requirement": "^1.0.0"
- },
- {
- "name": "quick-format-unescaped",
- "requirement": "^4.0.3"
- },
- {
- "name": "sonic-boom",
- "requirement": "^1.0.2"
- }
+func TestPurlLookup(t *testing.T) {
+ t.Run("PurlLookup", func(t *testing.T) {
+ result := `{
+ "version": {
+ "versionKey": {
+ "system": "NPM",
+ "name": "@colors/colors",
+ "version": "1.5.0"
+ },
+ "purl": "pkg:npm/%40colors/colors@1.5.0",
+ "publishedAt": "2022-02-12T07:39:04Z",
+ "isDefault": false,
+ "isDeprecated": false,
+ "licenses": [
+ "MIT"
],
- "devDependencies": [
- {
- "name": "airtap",
- "requirement": "4.0.3"
- },
- {
- "name": "benchmark",
- "requirement": "^2.1.4"
- },
- {
- "name": "bole",
- "requirement": "^4.0.0"
- },
- {
- "name": "bunyan",
- "requirement": "^1.8.14"
- },
- {
- "name": "docsify-cli",
- "requirement": "^4.4.1"
- },
- {
- "name": "eslint",
- "requirement": "^7.17.0"
- },
- {
- "name": "eslint-config-standard",
- "requirement": "^16.0.2"
- },
- {
- "name": "eslint-plugin-import",
- "requirement": "^2.22.1"
- },
- {
- "name": "eslint-plugin-node",
- "requirement": "^11.1.0"
- },
- {
- "name": "eslint-plugin-promise",
- "requirement": "^5.1.0"
- },
- {
- "name": "execa",
- "requirement": "^5.0.0"
- },
- {
- "name": "fastbench",
- "requirement": "^1.0.1"
- },
- {
- "name": "flush-write-stream",
- "requirement": "^2.0.0"
- },
- {
- "name": "import-fresh",
- "requirement": "^3.2.1"
- },
- {
- "name": "log",
- "requirement": "^6.0.0"
- },
- {
- "name": "loglevel",
- "requirement": "^1.6.7"
- },
- {
- "name": "pino-pretty",
- "requirement": "^5.0.0"
- },
- {
- "name": "pre-commit",
- "requirement": "^1.2.2"
- },
- {
- "name": "proxyquire",
- "requirement": "^2.1.3"
- },
- {
- "name": "pump",
- "requirement": "^3.0.0"
- },
- {
- "name": "semver",
- "requirement": "^7.0.0"
- },
- {
- "name": "split2",
- "requirement": "^3.1.1"
- },
- {
- "name": "steed",
- "requirement": "^1.1.3"
- },
- {
- "name": "strip-ansi",
- "requirement": "^6.0.0"
- },
- {
- "name": "tap",
- "requirement": "^15.0.1"
- },
- {
- "name": "tape",
- "requirement": "^5.0.0"
- },
- {
- "name": "through2",
- "requirement": "^4.0.0"
- },
- {
- "name": "winston",
- "requirement": "^3.3.3"
- }
+ "licenseDetails": [
+ {
+ "license": "MIT",
+ "spdx": "MIT"
+ }
],
- "optionalDependencies": [],
- "peerDependencies": [],
- "bundleDependencies": []
- },
- "Bundled": []
+ "advisoryKeys": [],
+ "links": [
+ {
+ "label": "HOMEPAGE",
+ "url": "https://github.com/DABH/colors.js"
+ },
+ {
+ "label": "ISSUE_TRACKER",
+ "url": "https://github.com/DABH/colors.js/issues"
+ },
+ {
+ "label": "ORIGIN",
+ "url": "https://registry.npmjs.org/@colors%2Fcolors/1.5.0"
+ },
+ {
+ "label": "SOURCE_REPO",
+ "url": "git+ssh://git@github.com/DABH/colors.js.git"
+ }
+ ],
+ "slsaProvenances": [],
+ "attestations": [],
+ "registries": [
+ "https://registry.npmjs.org/"
+ ],
+ "relatedProjects": [
+ {
+ "projectKey": {
+ "id": "github.com/dabh/colors.js"
+ },
+ "relationProvenance": "UNVERIFIED_METADATA",
+ "relationType": "ISSUE_TRACKER"
+ },
+ {
+ "projectKey": {
+ "id": "github.com/dabh/colors.js"
+ },
+ "relationProvenance": "UNVERIFIED_METADATA",
+ "relationType": "SOURCE_REPO"
+ }
+ ],
+ "upstreamIdentifiers": [
+ {
+ "packageName": "@colors/colors",
+ "versionString": "1.5.0",
+ "source": "NPM_NPMJS_ORG"
+ }
+ ]
}
- }`
+ }`
- t.Run("GetRequirements npm pino 6.14.0", func(t *testing.T) {
- got, err := api.GetRequirements("npm", "pino", "6.14.0")
+ got, err := api.PurlLookup("pkg:npm/%40colors/colors@1.5.0")
require.Nil(t, err)
- var r def.Requirements
+ var a def.Purl
- if err := json.Unmarshal([]byte(result), &r); err != nil {
+ if err := json.Unmarshal([]byte(result), &a); err != nil {
log.Fatal(err)
}
- require.Equal(t, r, got)
+ require.Equal(t, a, got)
+ })
+
+ t.Run("PurlLookup batch multi pages", func(t *testing.T) {
+ const N = 300
+
+ reqs := def.PurlBatchBody{
+ Requests: []def.PurlBatchRequest{},
+ PageToken: "",
+ }
+
+ projects := make([]def.PurlBatchRequest, 0, N)
+ for i := 0; i < N; i++ {
+ projects = append(projects, def.PurlBatchRequest{Purl: "pkg:npm/%40colors/colors@1.5.0"})
+ }
+
+ reqs.Requests = projects
+
+ iter, err := api.PurlLookupBatch(reqs)
+
+ require.Nil(t, err)
+ assert.NotNil(t, iter)
+
+ defer iter.Close()
+
+ results, err := consumeIter(iter)
+ require.NoError(t, err)
+
+ assert.Equal(t, N, len(results))
})
}
@@ -781,7 +927,6 @@ func TestGetProjectBatch(t *testing.T) {
assert.Equal(t, N, len(results))
})
}
-
func TestPurlLookupBatch(t *testing.T) {
t.Run("PurlLookup batch", func(t *testing.T) {
iter, err := api.PurlLookupBatch((def.PurlBatchBody{
@@ -836,6 +981,90 @@ func TestPurlLookupBatch(t *testing.T) {
})
}
+func TestQuery(t *testing.T) {
+ result := `{
+ "results": [
+ {
+ "version": {
+ "versionKey": {
+ "system": "NPM",
+ "name": "defangjs",
+ "version": "1.0.7"
+ },
+ "purl": "pkg:npm/defangjs@1.0.7",
+ "publishedAt": "2023-05-16T09:48:31Z",
+ "isDefault": true,
+ "isDeprecated": false,
+ "licenses": [
+ "GPL-3.0"
+ ],
+ "licenseDetails": [
+ {
+ "license": "GPL-3.0",
+ "spdx": "GPL-3.0"
+ }
+ ],
+ "advisoryKeys": [],
+ "links": [
+ {
+ "label": "HOMEPAGE",
+ "url": "https://github.com/edoardottt/defangjs#readme"
+ },
+ {
+ "label": "ISSUE_TRACKER",
+ "url": "https://github.com/edoardottt/defangjs/issues"
+ },
+ {
+ "label": "ORIGIN",
+ "url": "https://registry.npmjs.org/defangjs/1.0.7"
+ },
+ {
+ "label": "SOURCE_REPO",
+ "url": "git+https://github.com/edoardottt/defangjs.git"
+ }
+ ],
+ "slsaProvenances": [],
+ "attestations": [],
+ "registries": [
+ "https://registry.npmjs.org/"
+ ],
+ "relatedProjects": [
+ {
+ "projectKey": {
+ "id": "github.com/edoardottt/defangjs"
+ },
+ "relationProvenance": "UNVERIFIED_METADATA",
+ "relationType": "ISSUE_TRACKER"
+ },
+ {
+ "projectKey": {
+ "id": "github.com/edoardottt/defangjs"
+ },
+ "relationProvenance": "UNVERIFIED_METADATA",
+ "relationType": "SOURCE_REPO"
+ }
+ ],
+ "upstreamIdentifiers": []
+ },
+ "artifacts": []
+ }
+ ]
+ }`
+
+ t.Run("Query versionKey.system=NPM&versionKey.name=defangjs&versionKey.version=1.0.7", func(t *testing.T) {
+ got, err := api.Query("versionKey.system=NPM&versionKey.name=defangjs&versionKey.version=1.0.7")
+ require.Nil(t, err)
+
+ var a def.Results
+
+ if err := json.Unmarshal([]byte(result), &a); err != nil {
+ log.Fatal(err)
+ }
+
+ require.Equal(t, a, got)
+ })
+}
+
func consumeIter[T any](iter *depsdev.Iterator[T]) ([]T, error) {
l := []T{}