From da03795204223b2e33fbe38b788b2b8d2092b469 Mon Sep 17 00:00:00 2001 From: Gareth Jones Date: Sun, 12 Jun 2022 11:51:05 +1200 Subject: [PATCH] feat: support parsing commits from `pnpm.yaml` files (#107) --- README.md | 4 +-- pkg/lockfile/fixtures/pnpm/commits.yaml | 48 +++++++++++++++++++++++++ pkg/lockfile/parse-pnpm-lock.go | 24 +++++++++++-- pkg/lockfile/parse-pnpm-lock_test.go | 43 ++++++++++++++++++++++ 4 files changed, 115 insertions(+), 4 deletions(-) create mode 100644 pkg/lockfile/fixtures/pnpm/commits.yaml diff --git a/README.md b/README.md index 89290ef6..61968532 100644 --- a/README.md +++ b/README.md @@ -70,8 +70,8 @@ typically a few hours ahead of the offline databases, and supports commits; however it currently can produce false negatives for some ecosystems. > While the API supports commits, the detector currently has limited support for -> extracting them - only the `composer.lock`, `package-lock.json`, & `yarn.lock` -> parsers include commit details +> extracting them - only the `composer.lock`, `package-lock.json`, `yarn.lock`, +> & `pnpm.yaml` parsers include commit details You cannot use the API in `--offline` mode, but you can use both the offline databases and the API together; the detector will remove any duplicate results. diff --git a/pkg/lockfile/fixtures/pnpm/commits.yaml b/pkg/lockfile/fixtures/pnpm/commits.yaml new file mode 100644 index 00000000..83153c8c --- /dev/null +++ b/pkg/lockfile/fixtures/pnpm/commits.yaml @@ -0,0 +1,48 @@ +lockfileVersion: 5.3 + +specifiers: + my-bitbucket-package: ssh://git@bitbucket.org:my-org/my-bitbucket-package#main + '@my-scope/my-package': git@github.com:my-org/my-package.git + mocks: github:my-org/mocks#main + +dependencies: + my-bitbucket-package: git@bitbucket.org+my-org/my-bitbucket-package/6104ae42cd32c3d724036d3964678f197b2c9cdb + '@my-scope/my-package': github.com/my-org/my-package/267087851ad5fac92a184749c27cd539e2fc862e + mocks: github.com/my-org/mocks/590f321b4eb3f692bb211bd74e22947639a6f79d + +packages: + git@bitbucket.org+my-org/my-bitbucket-project/6104ae42cd32c3d724036d3964678f197b2c9cdb: + resolution: { commit: 6104ae42cd32c3d724036d3964678f197b2c9cdb, repo: git@bitbucket.org:my-org/my-bitbucket-project.git, type: git } + name: my-bitbucket-package + version: 1.0.0 + dev: false + + github.com/my-org/my-package/267087851ad5fac92a184749c27cd539e2fc862e: + resolution: {commit: 267087851ad5fac92a184749c27cd539e2fc862e, repo: git+ssh://git@github.com/my-org/my-package.git, type: git} + name: '@my-scope/my-package' + version: 1.0.0 + dependencies: + '@my-scope/my-other-package': github.com/my-org/my-other-package/1b54f894c648dde79b6f2060f9a6b47bb62c1125 + dev: false + + github.com/my-org/my-other-package/fbfc962ab51eb1d754749b68c064460221fbd689: + resolution: {commit: fbfc962ab51eb1d754749b68c064460221fbd689, repo: git+ssh://git@github.com/my-org/my-other-package.git, type: git} + name: '@my-scope/my-other-package' + version: 1.0.0 + dev: false + + github.com/my-org/faker-parser/d2dc42a9351d4d89ec48c525e34f612b6d77993f: + resolution: {tarball: https://codeload.github.com/my-org/faker-parser/tar.gz/d2dc42a9351d4d89ec48c525e34f612b6d77993f} + name: faker-parser + version: 0.0.1 + dependencies: + faker: 5.5.3 + dev: false + + github.com/my-org/mocks/590f321b4eb3f692bb211bd74e22947639a6f79d: + resolution: {tarball: https://codeload.github.com/my-org/mocks/tar.gz/590f321b4eb3f692bb211bd74e22947639a6f79d} + name: mocks + version: 20.0.1 + dependencies: + faker-parser: github.com/my-org/faker-parser/d2dc42a9351d4d89ec48c525e34f612b6d77993f + dev: false diff --git a/pkg/lockfile/parse-pnpm-lock.go b/pkg/lockfile/parse-pnpm-lock.go index fdf68dbb..1cb391a8 100644 --- a/pkg/lockfile/parse-pnpm-lock.go +++ b/pkg/lockfile/parse-pnpm-lock.go @@ -8,9 +8,17 @@ import ( "strings" ) +type PnpmLockPackageResolution struct { + Tarball string `yaml:"tarball"` + Commit string `yaml:"commit"` + Repo string `yaml:"repo"` + Type string `yaml:"type"` +} + type PnpmLockPackage struct { - Name string `yaml:"name"` - Version string `yaml:"version"` + Resolution PnpmLockPackageResolution `yaml:"resolution"` + Name string `yaml:"name"` + Version string `yaml:"version"` } type PnpmLockfile struct { @@ -79,10 +87,22 @@ func parsePnpmLock(lockfile PnpmLockfile) []PackageDetails { continue } + commit := pkg.Resolution.Commit + + if strings.HasPrefix(pkg.Resolution.Tarball, "https://codeload.github.com") { + re := regexp.MustCompile(`https://codeload\.github\.com(?:/[\w-.]+){2}/tar\.gz/(\w+)$`) + matched := re.FindStringSubmatch(pkg.Resolution.Tarball) + + if matched != nil { + commit = matched[1] + } + } + packages = append(packages, PackageDetails{ Name: name, Version: version, Ecosystem: PnpmEcosystem, + Commit: commit, }) } diff --git a/pkg/lockfile/parse-pnpm-lock_test.go b/pkg/lockfile/parse-pnpm-lock_test.go index fa9b2b0c..8974b031 100644 --- a/pkg/lockfile/parse-pnpm-lock_test.go +++ b/pkg/lockfile/parse-pnpm-lock_test.go @@ -347,3 +347,46 @@ func TestParsePnpmLock_Exotic(t *testing.T) { }, }) } + +func TestParsePnpmLock_Commits(t *testing.T) { + t.Parallel() + + packages, err := lockfile.ParsePnpmLock("fixtures/pnpm/commits.yaml") + + if err != nil { + t.Errorf("Got unexpected error: %v", err) + } + + expectPackages(t, packages, []lockfile.PackageDetails{ + { + Name: "my-bitbucket-package", + Version: "1.0.0", + Ecosystem: lockfile.PnpmEcosystem, + Commit: "6104ae42cd32c3d724036d3964678f197b2c9cdb", + }, + { + Name: "@my-scope/my-package", + Version: "1.0.0", + Ecosystem: lockfile.PnpmEcosystem, + Commit: "267087851ad5fac92a184749c27cd539e2fc862e", + }, + { + Name: "@my-scope/my-other-package", + Version: "1.0.0", + Ecosystem: lockfile.PnpmEcosystem, + Commit: "fbfc962ab51eb1d754749b68c064460221fbd689", + }, + { + Name: "faker-parser", + Version: "0.0.1", + Ecosystem: lockfile.PnpmEcosystem, + Commit: "d2dc42a9351d4d89ec48c525e34f612b6d77993f", + }, + { + Name: "mocks", + Version: "20.0.1", + Ecosystem: lockfile.PnpmEcosystem, + Commit: "590f321b4eb3f692bb211bd74e22947639a6f79d", + }, + }) +}