diff --git a/go.mod b/go.mod index 142c2a85fda0..7af641f207f8 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/NYTimes/gziphandler v1.1.1 github.com/alicebob/miniredis/v2 v2.21.0 github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986 - github.com/aquasecurity/go-dep-parser v0.0.0-20220620143653-00462f6a05c8 + github.com/aquasecurity/go-dep-parser v0.0.0-20220626060741-179d0b167e5f github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798 github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46 @@ -44,7 +44,7 @@ require ( github.com/package-url/packageurl-go v0.1.1-0.20220203205134-d70459300c8a github.com/samber/lo v1.21.0 github.com/sosedoff/gitkit v0.3.0 - github.com/stretchr/testify v1.7.2 + github.com/stretchr/testify v1.7.3 github.com/testcontainers/testcontainers-go v0.13.0 github.com/tetratelabs/wazero v0.0.0-20220606011721-119b069ba23e github.com/twitchtv/twirp v8.1.2+incompatible @@ -229,7 +229,7 @@ require ( github.com/spf13/cast v1.4.1 // indirect github.com/spf13/cobra v1.4.0 // indirect github.com/spf13/pflag v1.0.5 // indirect - github.com/stretchr/objx v0.3.0 // indirect + github.com/stretchr/objx v0.4.0 // indirect github.com/ulikunitz/xz v0.5.8 // indirect github.com/vbatts/tar-split v0.11.2 // indirect github.com/vektah/gqlparser/v2 v2.4.4 // indirect diff --git a/go.sum b/go.sum index 3e80af05e988..7633c9cddb1a 100644 --- a/go.sum +++ b/go.sum @@ -195,10 +195,10 @@ github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6 github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986 h1:2a30xLN2sUZcMXl50hg+PJCIDdJgIvIbVcKqLJ/ZrtM= github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986/go.mod h1:NT+jyeCzXk6vXR5MTkdn4z64TgGfE5HMLC8qfj5unl8= +github.com/aquasecurity/go-dep-parser v0.0.0-20220626060741-179d0b167e5f h1:ObiLf3DY/Mr3hfqWHNgQ4vjVo/fFni216otahWzQXIE= +github.com/aquasecurity/go-dep-parser v0.0.0-20220626060741-179d0b167e5f/go.mod h1:MDQj3aeTQHSRbM1ZOGQVFziHvJtwf7moK+f9gYlUdeE= github.com/aquasecurity/defsec v0.68.6 h1:SjjvdQXyC+L1+hg2RAJHKHc+JiuFEKa6cwQYJw1n4VU= github.com/aquasecurity/defsec v0.68.6/go.mod h1:m59o8MPMXFbMgulxFOvFRW8tVg4gcnqZ9Gi3uvd/6zg= -github.com/aquasecurity/go-dep-parser v0.0.0-20220620143653-00462f6a05c8 h1:N4Fwm2ClxZd862T3jNAIx+ZlQJPYilUoIukMG3triGw= -github.com/aquasecurity/go-dep-parser v0.0.0-20220620143653-00462f6a05c8/go.mod h1:7EOQWQmyavVPY3fScbbPdd3dB/b0Q4ZbJ/NZCvNKrLs= github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce h1:QgBRgJvtEOBtUXilDb1MLi1p1MWoyFDXAu5DEUl5nwM= github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce/go.mod h1:HXgVzOPvXhVGLJs4ZKO817idqr/xhwsTcj17CLYY74s= github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798 h1:eveqE9ivrt30CJ7dOajOfBavhZ4zPqHcZe/4tKp0alc= @@ -1361,8 +1361,8 @@ github.com/stretchr/objx v0.0.0-20180129172003-8a3f7159479f/go.mod h1:HFkY916IF+ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/objx v0.3.0 h1:NGXK3lHquSN08v5vWalVI/L8XU9hdzE/G6xsrze47As= -github.com/stretchr/objx v0.3.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= +github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/testify v0.0.0-20180303142811-b89eecf5ca5d/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= @@ -1371,8 +1371,8 @@ github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s= -github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals= +github.com/stretchr/testify v1.7.3 h1:dAm0YRdRQlWojc3CrCRgPBzG5f941d0zvAKu7qY4e+I= +github.com/stretchr/testify v1.7.3/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw= github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= diff --git a/integration/fs_test.go b/integration/fs_test.go index 68d07472874a..2626b7f3a446 100644 --- a/integration/fs_test.go +++ b/integration/fs_test.go @@ -47,6 +47,14 @@ func TestFilesystem(t *testing.T) { }, golden: "testdata/nodejs.json.golden", }, + { + name: "pnpm", + args: args{ + securityChecks: "vuln", + input: "testdata/fixtures/fs/pnpm", + }, + golden: "testdata/pnpm.json.golden", + }, { name: "pip", args: args{ diff --git a/integration/testdata/fixtures/fs/pnpm/pnpm-lock.yaml b/integration/testdata/fixtures/fs/pnpm/pnpm-lock.yaml new file mode 100644 index 000000000000..be652ed3a442 --- /dev/null +++ b/integration/testdata/fixtures/fs/pnpm/pnpm-lock.yaml @@ -0,0 +1,19 @@ +lockfileVersion: 5.4 + +specifiers: + jquery: 3.3.9 + lodash: 4.17.4 + +dependencies: + jquery: 3.3.9 + lodash: 4.17.4 + +packages: + + /jquery/3.3.9: + resolution: {integrity: sha512-ggRCXln9zEqv6OqAGXFEcshF5dSBvCkzj6Gm2gzuR5fWawaX8t7cxKVkkygKODrDAzKdoYw3l/e3pm3vlT4IbQ==} + dev: false + + /lodash/4.17.4: + resolution: {integrity: sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=} + dev: false diff --git a/integration/testdata/pnpm.json.golden b/integration/testdata/pnpm.json.golden new file mode 100644 index 000000000000..5c83c2aa4886 --- /dev/null +++ b/integration/testdata/pnpm.json.golden @@ -0,0 +1,175 @@ +{ + "SchemaVersion": 2, + "ArtifactName": "testdata/fixtures/fs/pnpm", + "ArtifactType": "filesystem", + "Results": [ + { + "Target": "pnpm-lock.yaml", + "Class": "lang-pkgs", + "Type": "pnpm", + "Vulnerabilities": [ + { + "VulnerabilityID": "CVE-2019-11358", + "PkgID": "jquery@3.3.9", + "PkgName": "jquery", + "InstalledVersion": "3.3.9", + "FixedVersion": "3.4.0", + "Layer": {}, + "SeveritySource": "ghsa", + "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2019-11358", + "DataSource": { + "ID": "ghsa", + "Name": "GitHub Security Advisory Npm", + "URL": "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Anpm" + }, + "Title": "jquery: Prototype pollution in object's prototype leading to denial of service, remote code execution, or property injection", + "Description": "jQuery before 3.4.0, as used in Drupal, Backdrop CMS, and other products, mishandles jQuery.extend(true, {}, ...) because of Object.prototype pollution. If an unsanitized source object contained an enumerable __proto__ property, it could extend the native Object.prototype.", + "Severity": "MEDIUM", + "CweIDs": [ + "CWE-79" + ], + "CVSS": { + "nvd": { + "V2Vector": "AV:N/AC:M/Au:N/C:N/I:P/A:N", + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N", + "V2Score": 4.3, + "V3Score": 6.1 + }, + "redhat": { + "V3Vector": "CVSS:3.0/AV:N/AC:H/PR:N/UI:N/S:U/C:L/I:L/A:L", + "V3Score": 5.6 + } + }, + "References": [ + "http://lists.opensuse.org/opensuse-security-announce/2019-08/msg00006.html", + "http://lists.opensuse.org/opensuse-security-announce/2019-08/msg00025.html", + "http://packetstormsecurity.com/files/152787/dotCMS-5.1.1-Vulnerable-Dependencies.html", + "http://packetstormsecurity.com/files/153237/RetireJS-CORS-Issue-Script-Execution.html", + "http://packetstormsecurity.com/files/156743/OctoberCMS-Insecure-Dependencies.html", + "http://seclists.org/fulldisclosure/2019/May/10", + "http://seclists.org/fulldisclosure/2019/May/11", + "http://seclists.org/fulldisclosure/2019/May/13", + "http://www.openwall.com/lists/oss-security/2019/06/03/2", + "http://www.securityfocus.com/bid/108023", + "https://access.redhat.com/errata/RHBA-2019:1570", + "https://access.redhat.com/errata/RHSA-2019:1456", + "https://access.redhat.com/errata/RHSA-2019:2587", + "https://access.redhat.com/errata/RHSA-2019:3023", + "https://access.redhat.com/errata/RHSA-2019:3024", + "https://access.redhat.com/security/cve/CVE-2019-11358", + "https://backdropcms.org/security/backdrop-sa-core-2019-009", + "https://blog.jquery.com/2019/04/10/jquery-3-4-0-released/", + "https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-11358", + "https://github.com/DanielRuf/snyk-js-jquery-174006?files=1", + "https://github.com/advisories/GHSA-6c3j-c64m-qhgq", + "https://github.com/jquery/jquery/commit/753d591aea698e57d6db58c9f722cd0808619b1b", + "https://github.com/jquery/jquery/pull/4333", + "https://github.com/rails/jquery-rails/blob/master/CHANGELOG.md#434", + "https://hackerone.com/reports/454365", + "https://kb.pulsesecure.net/articles/Pulse_Security_Advisories/SA44601", + "https://linux.oracle.com/cve/CVE-2019-11358.html", + "https://linux.oracle.com/errata/ELSA-2020-4847.html", + "https://lists.apache.org/thread.html/08720ef215ee7ab3386c05a1a90a7d1c852bf0706f176a7816bf65fc@%3Ccommits.airflow.apache.org%3E", + "https://lists.apache.org/thread.html/519eb0fd45642dcecd9ff74cb3e71c20a4753f7d82e2f07864b5108f@%3Cdev.drill.apache.org%3E", + "https://lists.apache.org/thread.html/5928aa293e39d248266472210c50f176cac1535220f2486e6a7fa844@%3Ccommits.airflow.apache.org%3E", + "https://lists.apache.org/thread.html/6097cdbd6f0a337bedd9bb5cc441b2d525ff002a96531de367e4259f@%3Ccommits.airflow.apache.org%3E", + "https://lists.apache.org/thread.html/88fb0362fd40e5b605ea8149f63241537b8b6fb5bfa315391fc5cbb7@%3Ccommits.airflow.apache.org%3E", + "https://lists.apache.org/thread.html/b0656d359c7d40ec9f39c8cc61bca66802ef9a2a12ee199f5b0c1442@%3Cdev.drill.apache.org%3E", + "https://lists.apache.org/thread.html/b736d0784cf02f5a30fbb4c5902762a15ad6d47e17e2c5a17b7d6205@%3Ccommits.airflow.apache.org%3E", + "https://lists.apache.org/thread.html/ba79cf1658741e9f146e4c59b50aee56656ea95d841d358d006c18b6@%3Ccommits.roller.apache.org%3E", + "https://lists.apache.org/thread.html/bcce5a9c532b386c68dab2f6b3ce8b0cc9b950ec551766e76391caa3@%3Ccommits.nifi.apache.org%3E", + "https://lists.apache.org/thread.html/f9bc3e55f4e28d1dcd1a69aae6d53e609a758e34d2869b4d798e13cc@%3Cissues.drill.apache.org%3E", + "https://lists.apache.org/thread.html/r2041a75d3fc09dec55adfd95d598b38d22715303f65c997c054844c9@%3Cissues.flink.apache.org%3E", + "https://lists.apache.org/thread.html/r2baacab6e0acb5a2092eb46ae04fd6c3e8277b4fd79b1ffb7f3254fa@%3Cissues.flink.apache.org%3E", + "https://lists.apache.org/thread.html/r38f0d1aa3c923c22977fe7376508f030f22e22c1379fbb155bf29766@%3Cdev.syncope.apache.org%3E", + "https://lists.apache.org/thread.html/r41b5bfe009c845f67d4f68948cc9419ac2d62e287804aafd72892b08@%3Cissues.flink.apache.org%3E", + "https://lists.apache.org/thread.html/r7aac081cbddb6baa24b75e74abf0929bf309b176755a53e3ed810355@%3Cdev.flink.apache.org%3E", + "https://lists.apache.org/thread.html/r7d64895cc4dff84d0becfc572b20c0e4bf9bfa7b10c6f5f73e783734@%3Cdev.storm.apache.org%3E", + "https://lists.apache.org/thread.html/r7e8ebccb7c022e41295f6fdb7b971209b83702339f872ddd8cf8bf73@%3Cissues.flink.apache.org%3E", + "https://lists.apache.org/thread.html/rac25da84ecdcd36f6de5ad0d255f4e967209bbbebddb285e231da37d@%3Cissues.flink.apache.org%3E", + "https://lists.apache.org/thread.html/rca37935d661f4689cb4119f1b3b224413b22be161b678e6e6ce0c69b@%3Ccommits.nifi.apache.org%3E", + "https://lists.debian.org/debian-lts-announce/2019/05/msg00006.html", + "https://lists.debian.org/debian-lts-announce/2019/05/msg00029.html", + "https://lists.debian.org/debian-lts-announce/2020/02/msg00024.html", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/4UOAZIFCSZ3ENEFOR5IXX6NFAD3HV7FA/", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/5IABSKTYZ5JUGL735UKGXL5YPRYOPUYI/", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/KYH3OAGR2RTCHRA5NOKX2TES7SNQMWGO/", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/QV3PKZC3PQCO3273HAT76PAQZFBEO4KP/", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/RLXRX23725JL366CNZGJZ7AQQB7LHQ6F/", + "https://lists.fedoraproject.org/archives/list/package-announce@lists.fedoraproject.org/message/WZW27UCJ5CYFL4KFFFMYMIBNMIU2ALG5/", + "https://nvd.nist.gov/vuln/detail/CVE-2019-11358", + "https://seclists.org/bugtraq/2019/Apr/32", + "https://seclists.org/bugtraq/2019/Jun/12", + "https://seclists.org/bugtraq/2019/May/18", + "https://security.netapp.com/advisory/ntap-20190919-0001/", + "https://snyk.io/vuln/SNYK-JS-JQUERY-174006", + "https://www.debian.org/security/2019/dsa-4434", + "https://www.debian.org/security/2019/dsa-4460", + "https://www.drupal.org/sa-core-2019-006", + "https://www.oracle.com//security-alerts/cpujul2021.html", + "https://www.oracle.com/security-alerts/cpuApr2021.html", + "https://www.oracle.com/security-alerts/cpuapr2020.html", + "https://www.oracle.com/security-alerts/cpujan2020.html", + "https://www.oracle.com/security-alerts/cpujan2021.html", + "https://www.oracle.com/security-alerts/cpujul2020.html", + "https://www.oracle.com/security-alerts/cpuoct2020.html", + "https://www.oracle.com/security-alerts/cpuoct2021.html", + "https://www.oracle.com/technetwork/security-advisory/cpujul2019-5072835.html", + "https://www.oracle.com/technetwork/security-advisory/cpuoct2019-5072832.html", + "https://www.privacy-wise.com/mitigating-cve-2019-11358-in-old-versions-of-jquery/", + "https://www.synology.com/security/advisory/Synology_SA_19_19", + "https://www.tenable.com/security/tns-2019-08", + "https://www.tenable.com/security/tns-2020-02" + ], + "PublishedDate": "2019-04-20T00:29:00Z", + "LastModifiedDate": "2021-10-20T11:15:00Z" + }, + { + "VulnerabilityID": "CVE-2019-10744", + "PkgID": "lodash@4.17.4", + "PkgName": "lodash", + "InstalledVersion": "4.17.4", + "FixedVersion": "4.17.12", + "Layer": {}, + "SeveritySource": "ghsa", + "PrimaryURL": "https://avd.aquasec.com/nvd/cve-2019-10744", + "DataSource": { + "ID": "ghsa", + "Name": "GitHub Security Advisory Npm", + "URL": "https://github.com/advisories?query=type%3Areviewed+ecosystem%3Anpm" + }, + "Title": "nodejs-lodash: prototype pollution in defaultsDeep function leading to modifying properties", + "Description": "Versions of lodash lower than 4.17.12 are vulnerable to Prototype Pollution. The function defaultsDeep could be tricked into adding or modifying properties of Object.prototype using a constructor payload.", + "Severity": "CRITICAL", + "CVSS": { + "nvd": { + "V2Vector": "AV:N/AC:L/Au:N/C:N/I:P/A:P", + "V3Vector": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H", + "V2Score": 6.4, + "V3Score": 9.1 + }, + "redhat": { + "V3Vector": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:H", + "V3Score": 9.1 + } + }, + "References": [ + "https://access.redhat.com/errata/RHSA-2019:3024", + "https://access.redhat.com/security/cve/CVE-2019-10744", + "https://github.com/advisories/GHSA-jf85-cpcp-j695", + "https://github.com/lodash/lodash/pull/4336", + "https://nvd.nist.gov/vuln/detail/CVE-2019-10744", + "https://security.netapp.com/advisory/ntap-20191004-0005/", + "https://snyk.io/vuln/SNYK-JS-LODASH-450202", + "https://support.f5.com/csp/article/K47105354?utm_source=f5support\u0026amp;utm_medium=RSS", + "https://www.npmjs.com/advisories/1065", + "https://www.oracle.com/security-alerts/cpujan2021.html", + "https://www.oracle.com/security-alerts/cpuoct2020.html" + ], + "PublishedDate": "2019-07-26T00:15:00Z", + "LastModifiedDate": "2021-03-16T13:57:00Z" + } + ] + } + ] +} diff --git a/pkg/detector/library/driver.go b/pkg/detector/library/driver.go index c9e4ef92e922..03826fbb40f9 100644 --- a/pkg/detector/library/driver.go +++ b/pkg/detector/library/driver.go @@ -40,7 +40,7 @@ func NewDriver(libType string) (Driver, error) { case ftypes.Jar, ftypes.Pom: ecosystem = vulnerability.Maven comparer = maven.Comparer{} - case ftypes.Npm, ftypes.Yarn, ftypes.NodePkg, ftypes.JavaScript: + case ftypes.Npm, ftypes.Yarn, ftypes.Pnpm, ftypes.NodePkg, ftypes.JavaScript: ecosystem = vulnerability.Npm comparer = npm.Comparer{} case ftypes.NuGet: diff --git a/pkg/fanal/analyzer/all/import.go b/pkg/fanal/analyzer/all/import.go index 2596c14d418e..fa36fb6c144e 100644 --- a/pkg/fanal/analyzer/all/import.go +++ b/pkg/fanal/analyzer/all/import.go @@ -10,6 +10,7 @@ import ( _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/java/pom" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/nodejs/npm" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/nodejs/pkg" + _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/nodejs/pnpm" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/nodejs/yarn" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/php/composer" _ "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language/python/packaging" diff --git a/pkg/fanal/analyzer/const.go b/pkg/fanal/analyzer/const.go index dec94a76805e..64ec86500623 100644 --- a/pkg/fanal/analyzer/const.go +++ b/pkg/fanal/analyzer/const.go @@ -53,6 +53,7 @@ const ( TypeNpmPkgLock Type = "npm" TypeNodePkg Type = "node-pkg" TypeYarn Type = "yarn" + TypePnpm Type = "pnpm" // .NET TypeNuget Type = "nuget" @@ -103,13 +104,13 @@ var ( // TypeLanguages has all language analyzers TypeLanguages = []Type{TypeBundler, TypeGemSpec, TypeCargo, TypeComposer, TypeJar, TypePom, - TypeNpmPkgLock, TypeNodePkg, TypeYarn, TypeNuget, TypePythonPkg, TypePip, TypePipenv, + TypeNpmPkgLock, TypeNodePkg, TypeYarn, TypePnpm, TypeNuget, TypePythonPkg, TypePip, TypePipenv, TypePoetry, TypeGoBinary, TypeGoMod, } // TypeLockfiles has all lock file analyzers TypeLockfiles = []Type{TypeBundler, TypeNpmPkgLock, TypeYarn, - TypePip, TypePipenv, TypePoetry, TypeGoMod, TypePom, + TypePnpm, TypePip, TypePipenv, TypePoetry, TypeGoMod, TypePom, } // TypeIndividualPkgs has all analyzers for individual packages diff --git a/pkg/fanal/analyzer/language/nodejs/pnpm/pnpm.go b/pkg/fanal/analyzer/language/nodejs/pnpm/pnpm.go new file mode 100644 index 000000000000..26eba65d6f37 --- /dev/null +++ b/pkg/fanal/analyzer/language/nodejs/pnpm/pnpm.go @@ -0,0 +1,46 @@ +package pnpm + +import ( + "context" + "os" + "path/filepath" + + "golang.org/x/xerrors" + + "github.com/aquasecurity/go-dep-parser/pkg/nodejs/pnpm" + "github.com/aquasecurity/trivy/pkg/fanal/analyzer" + "github.com/aquasecurity/trivy/pkg/fanal/analyzer/language" + "github.com/aquasecurity/trivy/pkg/fanal/types" + "github.com/aquasecurity/trivy/pkg/fanal/utils" +) + +func init() { + analyzer.RegisterAnalyzer(&pnpmLibraryAnalyzer{}) +} + +const version = 1 + +var requiredFiles = []string{types.PnpmLock} + +type pnpmLibraryAnalyzer struct{} + +func (a pnpmLibraryAnalyzer) Analyze(_ context.Context, input analyzer.AnalysisInput) (*analyzer.AnalysisResult, error) { + res, err := language.Analyze(types.Pnpm, input.FilePath, input.Content, pnpm.NewParser()) + if err != nil { + return nil, xerrors.Errorf("unable to parse %s: %w", input.FilePath, err) + } + return res, nil +} + +func (a pnpmLibraryAnalyzer) Required(filePath string, _ os.FileInfo) bool { + fileName := filepath.Base(filePath) + return utils.StringInSlice(fileName, requiredFiles) +} + +func (a pnpmLibraryAnalyzer) Type() analyzer.Type { + return analyzer.TypePnpm +} + +func (a pnpmLibraryAnalyzer) Version() int { + return version +} diff --git a/pkg/fanal/analyzer/language/nodejs/pnpm/pnpm_test.go b/pkg/fanal/analyzer/language/nodejs/pnpm/pnpm_test.go new file mode 100644 index 000000000000..412261865a6b --- /dev/null +++ b/pkg/fanal/analyzer/language/nodejs/pnpm/pnpm_test.go @@ -0,0 +1,65 @@ +package pnpm + +import ( + "context" + "os" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + + "github.com/aquasecurity/trivy/pkg/fanal/analyzer" + "github.com/aquasecurity/trivy/pkg/fanal/types" +) + +func Test_pnpmPkgLibraryAnalyzer_Analyze(t *testing.T) { + tests := []struct { + name string + inputFile string + want *analyzer.AnalysisResult + wantErr string + }{ + { + name: "happy path", + inputFile: "testdata/pnpm-lock.yaml", + want: &analyzer.AnalysisResult{ + Applications: []types.Application{ + { + Type: types.Pnpm, + FilePath: "testdata/pnpm-lock.yaml", + Libraries: []types.Package{ + { + ID: "lodash@4.17.21", + Name: "lodash", + Version: "4.17.21", + }, + }, + }, + }, + }, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + f, err := os.Open(tt.inputFile) + require.NoError(t, err) + defer f.Close() + + a := pnpmLibraryAnalyzer{} + ctx := context.Background() + got, err := a.Analyze(ctx, analyzer.AnalysisInput{ + FilePath: tt.inputFile, + Content: f, + }) + + if tt.wantErr != "" { + require.NotNil(t, err) + assert.Contains(t, err.Error(), tt.wantErr) + return + } + + assert.NoError(t, err) + assert.Equal(t, tt.want, got) + }) + } +} diff --git a/pkg/fanal/analyzer/language/nodejs/pnpm/testdata/pnpm-lock.yaml b/pkg/fanal/analyzer/language/nodejs/pnpm/testdata/pnpm-lock.yaml new file mode 100644 index 000000000000..a319ff8e7d4f --- /dev/null +++ b/pkg/fanal/analyzer/language/nodejs/pnpm/testdata/pnpm-lock.yaml @@ -0,0 +1,13 @@ +lockfileVersion: 5.4 + +specifiers: + lodash: ^4.17.21 + +dependencies: + lodash: 4.17.21 + +packages: + + /lodash/4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: false \ No newline at end of file diff --git a/pkg/fanal/analyzer/secret/secret.go b/pkg/fanal/analyzer/secret/secret.go index 66b3b27d1132..f8b3a0888fa2 100644 --- a/pkg/fanal/analyzer/secret/secret.go +++ b/pkg/fanal/analyzer/secret/secret.go @@ -26,6 +26,7 @@ var ( "go.sum", "package-lock.json", "yarn.lock", + "pnpm-lock.yaml", "Pipfile.lock", "Gemfile.lock", } diff --git a/pkg/fanal/types/const.go b/pkg/fanal/types/const.go index b39719917aea..1c1592872523 100644 --- a/pkg/fanal/types/const.go +++ b/pkg/fanal/types/const.go @@ -19,6 +19,7 @@ const ( PythonPkg = "python-pkg" NodePkg = "node-pkg" Yarn = "yarn" + Pnpm = "pnpm" Jar = "jar" Pom = "pom" GoBinary = "gobinary" @@ -47,6 +48,7 @@ const ( NpmPkgLock = "package-lock.json" YarnLock = "yarn.lock" + PnpmLock = "pnpm-lock.yaml" ComposerLock = "composer.lock" diff --git a/pkg/purl/purl.go b/pkg/purl/purl.go index 73ff8a5e2e79..00515f49b7e8 100644 --- a/pkg/purl/purl.go +++ b/pkg/purl/purl.go @@ -222,7 +222,7 @@ func purlType(t string) string { return packageurl.TypePyPi case string(analyzer.TypeGoBinary), string(analyzer.TypeGoMod): return packageurl.TypeGolang - case string(analyzer.TypeNpmPkgLock), string(analyzer.TypeNodePkg), string(analyzer.TypeYarn): + case string(analyzer.TypeNpmPkgLock), string(analyzer.TypeNodePkg), string(analyzer.TypeYarn), string(analyzer.TypePnpm): return packageurl.TypeNPM case os.Alpine: return string(analyzer.TypeApk) diff --git a/pkg/purl/purl_test.go b/pkg/purl/purl_test.go index 16a4f708e5ff..001634d4ccea 100644 --- a/pkg/purl/purl_test.go +++ b/pkg/purl/purl_test.go @@ -72,6 +72,37 @@ func TestNewPackageURL(t *testing.T) { }, }, }, + { + name: "pnpm package", + typ: string(analyzer.TypePnpm), + pkg: ftypes.Package{ + Name: "@xtuc/ieee754", + Version: "1.2.0", + }, + want: purl.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeNPM, + Namespace: "@xtuc", + Name: "ieee754", + Version: "1.2.0", + }, + }, + }, + { + name: "pnpm package with non-namespace", + typ: string(analyzer.TypePnpm), + pkg: ftypes.Package{ + Name: "lodash", + Version: "4.17.21", + }, + want: purl.PackageURL{ + PackageURL: packageurl.PackageURL{ + Type: packageurl.TypeNPM, + Name: "lodash", + Version: "4.17.21", + }, + }, + }, { name: "pypi package", typ: string(analyzer.TypePip),