Compare commits

...

12 Commits

Author SHA1 Message Date
Aqua Security automated builds
7326db14af release: v0.58.1 [release/v0.58] (#8120) 2024-12-24 08:46:29 +00:00
Aqua Security automated builds
03160e4fd1 fix(sbom): attach nested packages to Application [backport: release/v0.58] (#8168)
Signed-off-by: knqyf263 <knqyf263@gmail.com>
Co-authored-by: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com>
Co-authored-by: knqyf263 <knqyf263@gmail.com>
2024-12-24 08:22:17 +00:00
Aqua Security automated builds
8b930816bc fix(python): skip dev group's deps for poetry [backport: release/v0.58] (#8158)
Signed-off-by: nikpivkin <nikita.pivkin@smartforce.io>
Co-authored-by: Nikita Pivkin <nikita.pivkin@smartforce.io>
2024-12-23 07:37:07 +00:00
Aqua Security automated builds
18cd1a59cb fix(sbom): use root package for unknown dependencies (if exists) [backport: release/v0.58] (#8156)
Co-authored-by: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com>
2024-12-23 06:59:48 +00:00
Aqua Security automated builds
1bde3df0ee chore(deps): bump golang.org/x/net from v0.32.0 to v0.33.0 [backport: release/v0.58] (#8142)
Co-authored-by: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com>
Co-authored-by: DmitriyLewen <dmitriy.lewen@smartforce.io>
2024-12-20 11:30:20 +00:00
Aqua Security automated builds
90f9e884fd chore(deps): bump github.com/CycloneDX/cyclonedx-go from v0.9.1 to v0.9.2 [backport: release/v0.58] (#8136)
Co-authored-by: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com>
2024-12-19 09:57:47 +00:00
Aqua Security automated builds
33818e121f fix(redhat): correct rewriting of recommendations for the same vulnerability [backport: release/v0.58] (#8135)
Co-authored-by: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com>
2024-12-19 08:52:58 +00:00
Aqua Security automated builds
89b341f0c6 fix(oracle): add architectures support for advisories [backport: release/v0.58] (#8125)
Co-authored-by: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com>
2024-12-19 07:42:59 +00:00
Aqua Security automated builds
f842fe1675 fix(sbom): fix wrong overwriting of applications obtained from different sbom files but having same app type [backport: release/v0.58] (#8124)
Co-authored-by: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com>
2024-12-18 08:03:47 +00:00
Aqua Security automated builds
d52542f3b5 chore(deps): bump golang.org/x/crypto from 0.30.0 to 0.31.0 [backport: release/v0.58] (#8122)
Signed-off-by: knqyf263 <knqyf263@gmail.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: knqyf263 <knqyf263@gmail.com>
2024-12-18 07:43:58 +00:00
Aqua Security automated builds
9a56e7cd69 fix: handle BLOW_UNKNOWN error to download DBs [backport: release/v0.58] (#8121)
Co-authored-by: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com>
2024-12-18 06:58:00 +00:00
Aqua Security automated builds
4278a09f59 fix(java): correctly overwrite version from depManagement if dependency uses project.* props [backport: release/v0.58] (#8119)
Co-authored-by: DmitriyLewen <91113035+DmitriyLewen@users.noreply.github.com>
2024-12-18 05:53:44 +00:00
38 changed files with 1958 additions and 714 deletions

View File

@@ -1 +1 @@
{".":"0.58.0"}
{".":"0.58.1"}

View File

@@ -1,5 +1,19 @@
# Changelog
## [0.58.1](https://github.com/aquasecurity/trivy/compare/v0.58.0...v0.58.1) (2024-12-24)
### Bug Fixes
* handle `BLOW_UNKNOWN` error to download DBs [backport: release/v0.58] ([#8121](https://github.com/aquasecurity/trivy/issues/8121)) ([9a56e7c](https://github.com/aquasecurity/trivy/commit/9a56e7cd6964ffd4187a8e44a36d49b54587db56))
* **java:** correctly overwrite version from depManagement if dependency uses `project.*` props [backport: release/v0.58] ([#8119](https://github.com/aquasecurity/trivy/issues/8119)) ([4278a09](https://github.com/aquasecurity/trivy/commit/4278a09f59590ee16494e0a1ad31fb374f2e243f))
* **oracle:** add architectures support for advisories [backport: release/v0.58] ([#8125](https://github.com/aquasecurity/trivy/issues/8125)) ([89b341f](https://github.com/aquasecurity/trivy/commit/89b341f0c6dc7f24239f9a9e4809524ec289a864))
* **python:** skip dev group's deps for poetry [backport: release/v0.58] ([#8158](https://github.com/aquasecurity/trivy/issues/8158)) ([8b93081](https://github.com/aquasecurity/trivy/commit/8b930816bc527166ced5d57754ad7fccb1cef832))
* **redhat:** correct rewriting of recommendations for the same vulnerability [backport: release/v0.58] ([#8135](https://github.com/aquasecurity/trivy/issues/8135)) ([33818e1](https://github.com/aquasecurity/trivy/commit/33818e121f989fd12c15aa65affd2d01b867db61))
* **sbom:** attach nested packages to Application [backport: release/v0.58] ([#8168](https://github.com/aquasecurity/trivy/issues/8168)) ([03160e4](https://github.com/aquasecurity/trivy/commit/03160e4fd1b0a6aef8c4f3d96529e68fed7e70ee))
* **sbom:** fix wrong overwriting of applications obtained from different sbom files but having same app type [backport: release/v0.58] ([#8124](https://github.com/aquasecurity/trivy/issues/8124)) ([f842fe1](https://github.com/aquasecurity/trivy/commit/f842fe1675b434e72a8194628525c42fd3e155af))
* **sbom:** use root package for `unknown` dependencies (if exists) [backport: release/v0.58] ([#8156](https://github.com/aquasecurity/trivy/issues/8156)) ([18cd1a5](https://github.com/aquasecurity/trivy/commit/18cd1a59cbb32d87371fe8ab24497f06855e0c80))
## [0.58.0](https://github.com/aquasecurity/trivy/compare/v0.57.0...v0.58.0) (2024-12-02)

16
go.mod
View File

@@ -7,7 +7,7 @@ require (
github.com/Azure/azure-sdk-for-go/sdk/azcore v1.16.0
github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.8.0
github.com/BurntSushi/toml v1.4.0
github.com/CycloneDX/cyclonedx-go v0.9.1
github.com/CycloneDX/cyclonedx-go v0.9.2
github.com/GoogleCloudPlatform/docker-credential-gcr v2.0.5+incompatible
github.com/Masterminds/sprig/v3 v3.3.0
github.com/NYTimes/gziphandler v1.1.1
@@ -24,7 +24,7 @@ require (
github.com/aquasecurity/testdocker v0.0.0-20240730042311-4642e94c7fc8
github.com/aquasecurity/tml v0.6.1
github.com/aquasecurity/trivy-checks v1.4.0
github.com/aquasecurity/trivy-db v0.0.0-20241120092622-333d808d7e45
github.com/aquasecurity/trivy-db v0.0.0-20241209111357-8c398f13db0e
github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48
github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20241101182546-89bffc3932bc
github.com/aws/aws-sdk-go-v2 v1.32.5
@@ -119,13 +119,13 @@ require (
github.com/zclconf/go-cty v1.15.0
github.com/zclconf/go-cty-yaml v1.1.0
go.etcd.io/bbolt v1.3.11
golang.org/x/crypto v0.29.0
golang.org/x/crypto v0.31.0
golang.org/x/exp v0.0.0-20241009180824-f66d83c29e7c // indirect
golang.org/x/mod v0.22.0
golang.org/x/net v0.31.0
golang.org/x/sync v0.9.0
golang.org/x/term v0.26.0
golang.org/x/text v0.20.0
golang.org/x/net v0.33.0
golang.org/x/sync v0.10.0
golang.org/x/term v0.27.0
golang.org/x/text v0.21.0
golang.org/x/vuln v1.1.3
golang.org/x/xerrors v0.0.0-20231012003039-104605ab7028
google.golang.org/protobuf v1.35.2
@@ -388,7 +388,7 @@ require (
go.uber.org/multierr v1.11.0 // indirect
go.uber.org/zap v1.27.0 // indirect
golang.org/x/oauth2 v0.22.0 // indirect
golang.org/x/sys v0.27.0 // indirect
golang.org/x/sys v0.28.0 // indirect
golang.org/x/telemetry v0.0.0-20240522233618-39ace7a40ae7 // indirect
golang.org/x/time v0.7.0 // indirect
golang.org/x/tools v0.26.0 // indirect

36
go.sum
View File

@@ -245,8 +245,8 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0=
github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/CycloneDX/cyclonedx-go v0.9.1 h1:yffaWOZsv77oTJa/SdVZYdgAgFioCeycBUKkqS2qzQM=
github.com/CycloneDX/cyclonedx-go v0.9.1/go.mod h1:NE/EWvzELOFlG6+ljX/QeMlVt9VKcTwu8u0ccsACEsw=
github.com/CycloneDX/cyclonedx-go v0.9.2 h1:688QHn2X/5nRezKe2ueIVCt+NRqf7fl3AVQk+vaFcIo=
github.com/CycloneDX/cyclonedx-go v0.9.2/go.mod h1:vcK6pKgO1WanCdd61qx4bFnSsDJQ6SbM2ZuMIgq86Jg=
github.com/DATA-DOG/go-sqlmock v1.5.2 h1:OcvFkGmslmlZibjAjaHm3L//6LiuBgolP7OputlJIzU=
github.com/DATA-DOG/go-sqlmock v1.5.2/go.mod h1:88MAG/4G7SMwSE3CeA0ZKzrT5CiOU3OJ+JlNzwDqpNU=
github.com/DataDog/zstd v1.5.5 h1:oWf5W7GtOLgp6bciQYDmhHHjdhYkALu6S/5Ni9ZgSvQ=
@@ -355,8 +355,8 @@ github.com/aquasecurity/tml v0.6.1 h1:y2ZlGSfrhnn7t4ZJ/0rotuH+v5Jgv6BDDO5jB6A9gw
github.com/aquasecurity/tml v0.6.1/go.mod h1:OnYMWY5lvI9ejU7yH9LCberWaaTBW7hBFsITiIMY2yY=
github.com/aquasecurity/trivy-checks v1.4.0 h1:XFGPuA8C4f31GO9g7xOkubHq4W87y9iXrWnulsIoZFs=
github.com/aquasecurity/trivy-checks v1.4.0/go.mod h1:TSUbI3wBy9jgQl5lRUCR+B5pNiOxp6M26Jep8VCL/eM=
github.com/aquasecurity/trivy-db v0.0.0-20241120092622-333d808d7e45 h1:ljinbg7JTQvdnzuRsPYS6btA51SyGYWKCQInxSIwbRw=
github.com/aquasecurity/trivy-db v0.0.0-20241120092622-333d808d7e45/go.mod h1:Lg2avQhFy5qeGA0eMysI/61REVvWpEltverCarGc3l0=
github.com/aquasecurity/trivy-db v0.0.0-20241209111357-8c398f13db0e h1:O5j5SeCNBrXApgBTOobO06q4LMxJxIhcSGE7H6Y154E=
github.com/aquasecurity/trivy-db v0.0.0-20241209111357-8c398f13db0e/go.mod h1:gS8VhlNxhraiq60BBnJw9kGtjeMspQ9E8pX24jCL4jg=
github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48 h1:JVgBIuIYbwG+ekC5lUHUpGJboPYiCcxiz06RCtz8neI=
github.com/aquasecurity/trivy-java-db v0.0.0-20240109071736-184bd7481d48/go.mod h1:Ldya37FLi0e/5Cjq2T5Bty7cFkzUDwTcPeQua+2M8i8=
github.com/aquasecurity/trivy-kubernetes v0.6.7-0.20241101182546-89bffc3932bc h1:/mFBYIK9RY+L8s1CIbQbJ5B3v0YmoDSu5eAzavvMa+Y=
@@ -1348,8 +1348,8 @@ github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d h1:vfofYNRScrDd
github.com/syndtr/goleveldb v1.0.1-0.20220721030215-126854af5e6d/go.mod h1:RRCYJbIwD5jmqPI9XoAFR0OcDxqUctll6zUj/+B4S48=
github.com/tchap/go-patricia/v2 v2.3.1 h1:6rQp39lgIYZ+MHmdEq4xzuk1t7OdC35z/xm0BGhTkes=
github.com/tchap/go-patricia/v2 v2.3.1/go.mod h1:VZRHKAb53DLaG+nA9EaYYiaEx6YztwDlLElMsnSHD4k=
github.com/terminalstatic/go-xsd-validate v0.1.5 h1:RqpJnf6HGE2CB/lZB1A8BYguk8uRtcvYAPLCF15qguo=
github.com/terminalstatic/go-xsd-validate v0.1.5/go.mod h1:18lsvYFofBflqCrvo1umpABZ99+GneNTw2kEEc8UPJw=
github.com/terminalstatic/go-xsd-validate v0.1.6 h1:TenYeQ3eY631qNi1/cTmLH/s2slHPRKTTHT+XSHkepo=
github.com/terminalstatic/go-xsd-validate v0.1.6/go.mod h1:18lsvYFofBflqCrvo1umpABZ99+GneNTw2kEEc8UPJw=
github.com/testcontainers/testcontainers-go v0.34.0 h1:5fbgF0vIN5u+nD3IWabQwRybuB4GY8G2HHgCkbMzMHo=
github.com/testcontainers/testcontainers-go v0.34.0/go.mod h1:6P/kMkQe8yqPHfPWNulFGdFHTD8HB2vLq/231xY2iPQ=
github.com/testcontainers/testcontainers-go/modules/localstack v0.34.0 h1:WkjVmea0XQyGTY10Er8fOsVjHQ77iJCmTExnx6fC3Tw=
@@ -1494,8 +1494,8 @@ golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ=
golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg=
golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U=
golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -1597,8 +1597,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/net v0.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
golang.org/x/net v0.31.0 h1:68CPQngjLL0r2AlUKiSxtQFKvzRVbnzLwMUn5SzcLHo=
golang.org/x/net v0.31.0/go.mod h1:P4fl1q7dY2hnZFxEk4pPSkDHF+QqjitcnDjUQyMM+pM=
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1643,8 +1643,8 @@ golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJ
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.9.0 h1:fEo0HyrW1GIgZdpbhCRO0PkJajUS5H9IFUztCgEo2jQ=
golang.org/x/sync v0.9.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ=
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -1735,8 +1735,8 @@ golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.27.0 h1:wBqf8DvsY9Y/2P8gAfPDEYNuS30J4lPHJxXSb/nJZ+s=
golang.org/x/sys v0.27.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA=
golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/telemetry v0.0.0-20240522233618-39ace7a40ae7 h1:FemxDzfMUcK2f3YY4H+05K9CDzbSVr2+q/JKN45pey0=
golang.org/x/telemetry v0.0.0-20240522233618-39ace7a40ae7/go.mod h1:pRgIJT+bRLFKnoM1ldnzKoxTIn14Yxz928LQRYYgIN0=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
@@ -1747,8 +1747,8 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/term v0.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY=
golang.org/x/term v0.26.0 h1:WEQa6V3Gja/BhNxg540hBip/kkaYtRg3cxg4oXSw4AU=
golang.org/x/term v0.26.0/go.mod h1:Si5m1o57C5nBNQo5z1iq+XDijt21BDBDp2bK0QI8e3E=
golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q=
golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1763,8 +1763,8 @@ golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/text v0.20.0 h1:gK/Kv2otX8gz+wn7Rmb3vT96ZwuoxnQlY+HlJVj7Qug=
golang.org/x/text v0.20.0/go.mod h1:D4IsuqiFMhST5bX19pQ9ikHC2GsaKyk/oF+pn3ducp4=
golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo=
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=

View File

@@ -7,8 +7,14 @@
FixedVersion: "7.61.1-11.el8"
Entries:
- FixedVersion: "7.61.1-11.el8"
Arches:
- x86_64
- aarch64
- key: CVE-2019-5436
value:
FixedVersion: "7.61.1-12.el8"
Entries:
- FixedVersion: "7.61.1-12.el8"
Arches:
- x86_64
- aarch64

File diff suppressed because it is too large Load Diff

View File

@@ -154,11 +154,6 @@
"relatedSpdxElement": "SPDXRef-Package-7784b00da0cb0cb0",
"relationshipType": "CONTAINS"
},
{
"spdxElementId": "SPDXRef-Application-18fc3597717a3e56",
"relatedSpdxElement": "SPDXRef-Package-960543ac5c5f7e10",
"relationshipType": "CONTAINS"
},
{
"spdxElementId": "SPDXRef-Application-18fc3597717a3e56",
"relatedSpdxElement": "SPDXRef-Package-a4705eb108e4f15c",

View File

@@ -294,18 +294,10 @@
{
"ref": "3ff14136-e09f-4df9-80ea-000000000002",
"dependsOn": [
"pkg:npm/asap@2.0.6",
"pkg:npm/jquery@3.3.9",
"pkg:npm/js-tokens@4.0.0",
"pkg:npm/loose-envify@1.4.0",
"pkg:npm/object-assign@4.1.1",
"pkg:npm/promise@8.0.3",
"pkg:npm/prop-types@15.7.2",
"pkg:npm/react-is@16.8.6",
"pkg:npm/react@16.8.6",
"pkg:npm/redux@4.0.1",
"pkg:npm/scheduler@0.13.6",
"pkg:npm/symbol-observable@1.2.0"
"pkg:npm/redux@4.0.1"
]
},
{

View File

@@ -1470,6 +1470,52 @@ func TestPom_Parse(t *testing.T) {
},
},
},
{
name: "overwrite artifact version from dependencyManagement in the root POM when dependency uses `project.*` props",
inputFile: filepath.Join("testdata", "root-pom-dep-management-for-deps-with-project-props", "pom.xml"),
local: true,
want: []ftypes.Package{
{
ID: "com.example:root-pom-dep-management-for-deps-with-project-props:1.0.0",
Name: "com.example:root-pom-dep-management-for-deps-with-project-props",
Version: "1.0.0",
Relationship: ftypes.RelationshipRoot,
},
{
ID: "org.example:example-dependency:1.7.30",
Name: "org.example:example-dependency",
Version: "1.7.30",
Relationship: ftypes.RelationshipDirect,
Locations: ftypes.Locations{
{
StartLine: 21,
EndLine: 25,
},
},
},
{
ID: "org.example:example-api:2.0.0",
Name: "org.example:example-api",
Version: "2.0.0",
Licenses: []string{"The Apache Software License, Version 2.0"},
Relationship: ftypes.RelationshipIndirect,
},
},
wantDeps: []ftypes.Dependency{
{
ID: "com.example:root-pom-dep-management-for-deps-with-project-props:1.0.0",
DependsOn: []string{
"org.example:example-dependency:1.7.30",
},
},
{
ID: "org.example:example-dependency:1.7.30",
DependsOn: []string{
"org.example:example-api:2.0.0",
},
},
},
},
{
name: "transitive dependencyManagement should not be inherited",
inputFile: filepath.Join("testdata", "transitive-dependency-management", "pom.xml"),

View File

@@ -245,7 +245,7 @@ func (d pomDependency) Resolve(props map[string]string, depManagement, rootDepMa
// If this dependency is managed in the root POM,
// we need to overwrite fields according to the managed dependency.
if managed, found := findDep(d.Name(), rootDepManagement); found { // dependencyManagement from the root POM
if managed, found := findDep(dep.Name(), rootDepManagement); found { // dependencyManagement from the root POM
if managed.Version != "" {
dep.Version = evaluateVariable(managed.Version, props, nil)
}
@@ -264,7 +264,7 @@ func (d pomDependency) Resolve(props map[string]string, depManagement, rootDepMa
}
// Inherit version, scope and optional from dependencyManagement if empty
if managed, found := findDep(d.Name(), depManagement); found { // dependencyManagement from parent
if managed, found := findDep(dep.Name(), depManagement); found { // dependencyManagement from parent
if dep.Version == "" {
dep.Version = evaluateVariable(managed.Version, props, nil)
}

View File

@@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>example-dependency</artifactId>
<version>1.7.30</version>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>example-api</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,28 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>root-pom-dep-management-for-deps-with-project-props</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>example-api</artifactId>
<version>2.0.0</version>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.example</groupId>
<artifactId>example-dependency</artifactId>
<version>1.7.30</version>
</dependency>
</dependencies>
</project>

View File

@@ -2,13 +2,13 @@ package poetry
import (
"sort"
"strings"
"github.com/BurntSushi/toml"
"golang.org/x/xerrors"
version "github.com/aquasecurity/go-pep440-version"
"github.com/aquasecurity/trivy/pkg/dependency"
"github.com/aquasecurity/trivy/pkg/dependency/parser/python"
ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
"github.com/aquasecurity/trivy/pkg/log"
xio "github.com/aquasecurity/trivy/pkg/x/io"
@@ -105,7 +105,7 @@ func (p *Parser) parseDependencies(deps map[string]any, pkgVersions map[string][
}
func (p *Parser) parseDependency(name string, versRange any, pkgVersions map[string][]string) (string, error) {
name = NormalizePkgName(name)
name = python.NormalizePkgName(name)
vers, ok := pkgVersions[name]
if !ok {
return "", xerrors.Errorf("no version found for %q", name)
@@ -149,17 +149,6 @@ func matchVersion(currentVersion, constraint string) (bool, error) {
return c.Check(v), nil
}
// NormalizePkgName normalizes the package name based on pep-0426
func NormalizePkgName(name string) string {
// The package names don't use `_`, `.` or upper case, but dependency names can contain them.
// We need to normalize those names.
// cf. https://peps.python.org/pep-0426/#name
name = strings.ToLower(name) // e.g. https://github.com/python-poetry/poetry/blob/c8945eb110aeda611cc6721565d7ad0c657d453a/poetry.lock#L819
name = strings.ReplaceAll(name, "_", "-") // e.g. https://github.com/python-poetry/poetry/blob/c8945eb110aeda611cc6721565d7ad0c657d453a/poetry.lock#L50
name = strings.ReplaceAll(name, ".", "-") // e.g. https://github.com/python-poetry/poetry/blob/c8945eb110aeda611cc6721565d7ad0c657d453a/poetry.lock#L816
return name
}
func packageID(name, ver string) string {
return dependency.ID(ftypes.Poetry, name, ver)
}

View File

@@ -3,9 +3,9 @@ package poetry
import ftypes "github.com/aquasecurity/trivy/pkg/fanal/types"
var (
// docker run --name pipenv --rm -it python@sha256:e1141f10176d74d1a0e87a7c0a0a5a98dd98ec5ac12ce867768f40c6feae2fd9 sh
// docker run --name poetry --rm -it python@sha256:e1141f10176d74d1a0e87a7c0a0a5a98dd98ec5ac12ce867768f40c6feae2fd9 sh
// apk add curl
// curl -sSL https://install.python-poetry.org | python3 -
// curl -sSL https://install.python-poetry.org | POETRY_VERSION=1.1.7 python3 -
// export PATH=/root/.local/bin:$PATH
// poetry new normal && cd normal
// poetry add pypi@2.1
@@ -14,9 +14,9 @@ var (
{ID: "pypi@2.1", Name: "pypi", Version: "2.1"},
}
// docker run --name pipenv --rm -it python@sha256:e1141f10176d74d1a0e87a7c0a0a5a98dd98ec5ac12ce867768f40c6feae2fd9 sh
// docker run --name poetry --rm -it python@sha256:e1141f10176d74d1a0e87a7c0a0a5a98dd98ec5ac12ce867768f40c6feae2fd9 sh
// apk add curl
// curl -sSL https://install.python-poetry.org | python3 -
// curl -sSL https://install.python-poetry.org | POETRY_VERSION=1.1.7 python3 -
// export PATH=/root/.local/bin:$PATH
// poetry new many && cd many
// curl -o poetry.lock https://raw.githubusercontent.com/python-poetry/poetry/c8945eb110aeda611cc6721565d7ad0c657d453a/poetry.lock
@@ -108,9 +108,9 @@ var (
{ID: "xattr@0.10.1", DependsOn: []string{"cffi@1.15.1"}},
}
// docker run --name pipenv --rm -it python@sha256:e1141f10176d74d1a0e87a7c0a0a5a98dd98ec5ac12ce867768f40c6feae2fd9 sh
// docker run --name poetry --rm -it python@sha256:e1141f10176d74d1a0e87a7c0a0a5a98dd98ec5ac12ce867768f40c6feae2fd9 sh
// apk add curl
// curl -sSL https://install.python-poetry.org | python3 -
// curl -sSL https://install.python-poetry.org | POETRY_VERSION=1.1.7 python3 -
// export PATH=/root/.local/bin:$PATH
// poetry new web && cd web
// poetry add flask@1.0.3

View File

@@ -4,7 +4,10 @@ import (
"io"
"github.com/BurntSushi/toml"
"github.com/samber/lo"
"golang.org/x/xerrors"
"github.com/aquasecurity/trivy/pkg/dependency/parser/python"
)
type PyProject struct {
@@ -16,7 +19,26 @@ type Tool struct {
}
type Poetry struct {
Dependencies map[string]any `toml:"dependencies"`
Dependencies dependencies `toml:"dependencies"`
Groups map[string]Group `toml:"group"`
}
type Group struct {
Dependencies dependencies `toml:"dependencies"`
}
type dependencies map[string]struct{}
func (d *dependencies) UnmarshalTOML(data any) error {
m, ok := data.(map[string]any)
if !ok {
return xerrors.Errorf("dependencies must be map, but got: %T", data)
}
*d = lo.MapEntries(m, func(pkgName string, _ any) (string, struct{}) {
return python.NormalizePkgName(pkgName), struct{}{}
})
return nil
}
// Parser parses pyproject.toml defined in PEP518.
@@ -28,10 +50,10 @@ func NewParser() *Parser {
return &Parser{}
}
func (p *Parser) Parse(r io.Reader) (map[string]any, error) {
func (p *Parser) Parse(r io.Reader) (PyProject, error) {
var conf PyProject
if _, err := toml.NewDecoder(r).Decode(&conf); err != nil {
return nil, xerrors.Errorf("toml decode error: %w", err)
return PyProject{}, xerrors.Errorf("toml decode error: %w", err)
}
return conf.Tool.Poetry.Dependencies, nil
return conf, nil
}

View File

@@ -15,26 +15,33 @@ func TestParser_Parse(t *testing.T) {
tests := []struct {
name string
file string
want map[string]any
want pyproject.PyProject
wantErr assert.ErrorAssertionFunc
}{
{
name: "happy path",
file: "testdata/happy.toml",
want: map[string]any{
"flask": "^1.0",
"python": "^3.9",
"requests": map[string]any{
"version": "2.28.1",
"optional": true,
},
"virtualenv": []any{
map[string]any{
"version": "^20.4.3,!=20.4.5,!=20.4.6",
},
map[string]any{
"version": "<20.16.6",
"markers": "sys_platform == 'win32' and python_version == '3.9'",
want: pyproject.PyProject{
Tool: pyproject.Tool{
Poetry: pyproject.Poetry{
Dependencies: map[string]struct{}{
"flask": {},
"python": {},
"requests": {},
"virtualenv": {},
},
Groups: map[string]pyproject.Group{
"dev": {
Dependencies: map[string]struct{}{
"pytest": {},
},
},
"lint": {
Dependencies: map[string]struct{}{
"ruff": {},
},
},
},
},
},
},

View File

@@ -14,6 +14,13 @@ virtualenv = [
[tool.poetry.dev-dependencies]
[tool.poetry.group.dev.dependencies]
pytest = "8.3.4"
[tool.poetry.group.lint.dependencies]
ruff = "0.8.3"
[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

View File

@@ -0,0 +1,14 @@
package python
import "strings"
// NormalizePkgName normalizes the package name based on pep-0426
func NormalizePkgName(name string) string {
// The package names don't use `_`, `.` or upper case, but dependency names can contain them.
// We need to normalize those names.
// cf. https://peps.python.org/pep-0426/#name
name = strings.ToLower(name) // e.g. https://github.com/python-poetry/poetry/blob/c8945eb110aeda611cc6721565d7ad0c657d453a/poetry.lock#L819
name = strings.ReplaceAll(name, "_", "-") // e.g. https://github.com/python-poetry/poetry/blob/c8945eb110aeda611cc6721565d7ad0c657d453a/poetry.lock#L50
name = strings.ReplaceAll(name, ".", "-") // e.g. https://github.com/python-poetry/poetry/blob/c8945eb110aeda611cc6721565d7ad0c657d453a/poetry.lock#L816
return name
}

View File

@@ -0,0 +1,39 @@
package python_test
import (
"testing"
"github.com/stretchr/testify/assert"
"github.com/aquasecurity/trivy/pkg/dependency/parser/python"
)
func Test_NormalizePkgName(t *testing.T) {
tests := []struct {
pkgName string
expected string
}{
{
pkgName: "SecretStorage",
expected: "secretstorage",
},
{
pkgName: "pywin32-ctypes",
expected: "pywin32-ctypes",
},
{
pkgName: "jaraco.classes",
expected: "jaraco-classes",
},
{
pkgName: "green_gdk",
expected: "green-gdk",
},
}
for _, tt := range tests {
t.Run(tt.pkgName, func(t *testing.T) {
assert.Equal(t, tt.expected, python.NormalizePkgName(tt.pkgName))
})
}
}

View File

@@ -50,7 +50,7 @@ func (s *Scanner) Detect(ctx context.Context, osVer string, _ *ftypes.Repository
var vulns []types.DetectedVulnerability
for _, pkg := range pkgs {
advisories, err := s.vs.Get(osVer, pkg.Name)
advisories, err := s.vs.Get(osVer, pkg.Name, pkg.Arch)
if err != nil {
return nil, xerrors.Errorf("failed to get Oracle Linux advisory: %w", err)
}

View File

@@ -139,6 +139,60 @@ func TestScanner_Detect(t *testing.T) {
},
},
},
{
name: "different fixed versions for different arches",
fixtures: []string{
"testdata/fixtures/oracle7.yaml",
"testdata/fixtures/data-source.yaml",
},
args: args{
osVer: "7",
pkgs: []ftypes.Package{
{
Name: "rsyslog",
Version: "8.24.0",
Release: "57.0.0.el7",
Arch: "x86_64",
SrcName: "rsyslog",
SrcVersion: "8.24.0",
SrcRelease: "57.0.0.el7",
},
{
Name: "rsyslog",
Version: "8.24.0",
Release: "57.0.0.el7",
Arch: "aarch64",
SrcName: "rsyslog",
SrcVersion: "8.24.0",
SrcRelease: "57.0.0.el7",
},
},
},
want: []types.DetectedVulnerability{
{
VulnerabilityID: "CVE-2022-24903",
PkgName: "rsyslog",
InstalledVersion: "8.24.0-57.0.0.el7",
FixedVersion: "8.24.0-57.0.1.el7_9.3",
DataSource: &dbTypes.DataSource{
ID: vulnerability.OracleOVAL,
Name: "Oracle Linux OVAL definitions",
URL: "https://linux.oracle.com/security/oval/",
},
},
{
VulnerabilityID: "CVE-2022-24903",
PkgName: "rsyslog",
InstalledVersion: "8.24.0-57.0.0.el7",
FixedVersion: "8.24.0-57.0.4.el7_9.3",
DataSource: &dbTypes.DataSource{
ID: vulnerability.OracleOVAL,
Name: "Oracle Linux OVAL definitions",
URL: "https://linux.oracle.com/security/oval/",
},
},
},
},
{
name: "without ksplice",
fixtures: []string{

View File

@@ -7,6 +7,9 @@
FixedVersion: "7.29.0-59.0.1.el7_9.1"
Entries:
- FixedVersion: "7.29.0-59.0.1.el7_9.1"
Arches:
- x86_64
- aarch64
- bucket: glibc
pairs:
- key: CVE-2017-1000364
@@ -14,6 +17,9 @@
FixedVersion: "2:2.17-157.ksplice1.el7_3.4"
Entries:
- FixedVersion: "2:2.17-157.ksplice1.el7_3.4"
Arches:
- x86_64
- aarch64
- bucket: gnutls
pairs:
- key: CVE-2021-20232
@@ -21,5 +27,20 @@
FixedVersion: "3.6.16-4.el8"
Entries:
- FixedVersion: "10:3.6.16-4.0.1.el8_fips"
Arches:
- x86_64
- FixedVersion: "3.6.16-4.el8"
Arches:
- x86_64
- bucket: rsyslog
pairs:
- key: CVE-2022-24903
value:
FixedVersion: "8.24.0-57.0.1.el7_9.3"
Entries:
- FixedVersion: "8.24.0-57.0.1.el7_9.3"
Arches:
- x86_64
- FixedVersion: "8.24.0-57.0.4.el7_9.3"
Arches:
- aarch64

View File

@@ -9,11 +9,9 @@ import (
"time"
version "github.com/knqyf263/go-rpm-version"
"github.com/samber/lo"
"golang.org/x/xerrors"
dbTypes "github.com/aquasecurity/trivy-db/pkg/types"
ustrings "github.com/aquasecurity/trivy-db/pkg/utils/strings"
redhat "github.com/aquasecurity/trivy-db/pkg/vulnsrc/redhat-oval"
"github.com/aquasecurity/trivy-db/pkg/vulnsrc/vulnerability"
osver "github.com/aquasecurity/trivy/pkg/detector/ospkg/version"
@@ -116,24 +114,35 @@ func (s *Scanner) detect(osVer string, pkg ftypes.Package) ([]types.DetectedVuln
return nil, xerrors.Errorf("failed to get Red Hat advisories: %w", err)
}
installed := utils.FormatVersion(pkg)
installedVersion := version.NewVersion(installed)
uniqVulns := make(map[string]types.DetectedVulnerability)
// Choose the latest fixed version for each CVE-ID (empty for unpatched vulns).
// Take the single RHSA-ID with the latest fixed version (for patched vulns).
uniqAdvisories := make(map[string]dbTypes.Advisory)
for _, adv := range advisories {
// if Arches for advisory is empty or pkg.Arch is "noarch", then any Arches are affected
// If Arches for advisory are empty or pkg.Arch is "noarch", then any Arches are affected
if len(adv.Arches) != 0 && pkg.Arch != "noarch" {
if !slices.Contains(adv.Arches, pkg.Arch) {
continue
}
}
vulnID := adv.VulnerabilityID
if a, ok := uniqAdvisories[adv.VulnerabilityID]; ok {
if version.NewVersion(a.FixedVersion).LessThan(version.NewVersion(adv.FixedVersion)) {
uniqAdvisories[adv.VulnerabilityID] = adv
}
} else {
uniqAdvisories[adv.VulnerabilityID] = adv
}
}
var vulns []types.DetectedVulnerability
for _, adv := range uniqAdvisories {
vuln := types.DetectedVulnerability{
VulnerabilityID: vulnID,
VulnerabilityID: adv.VulnerabilityID,
VendorIDs: adv.VendorIDs, // Will be empty for unpatched vulnerabilities
PkgID: pkg.ID,
PkgName: pkg.Name,
InstalledVersion: utils.FormatVersion(pkg),
FixedVersion: version.NewVersion(adv.FixedVersion).String(), // Will be empty for unpatched vulnerabilities
PkgIdentifier: pkg.Identifier,
Status: adv.Status,
Layer: pkg.Layer,
@@ -144,43 +153,15 @@ func (s *Scanner) detect(osVer string, pkg ftypes.Package) ([]types.DetectedVuln
Custom: adv.Custom,
}
// unpatched vulnerabilities
if adv.FixedVersion == "" {
// Red Hat may contain several advisories for the same vulnerability (RHSA advisories).
// To avoid overwriting the fixed version by mistake, we should skip unpatched vulnerabilities if they were added earlier
if _, ok := uniqVulns[vulnID]; !ok {
uniqVulns[vulnID] = vuln
}
continue
}
// patched vulnerabilities
fixedVersion := version.NewVersion(adv.FixedVersion)
if installedVersion.LessThan(fixedVersion) {
vuln.VendorIDs = adv.VendorIDs
vuln.FixedVersion = fixedVersion.String()
if v, ok := uniqVulns[vulnID]; ok {
// In case two advisories resolve the same CVE-ID.
// e.g. The first fix might be incomplete.
v.VendorIDs = ustrings.Unique(append(v.VendorIDs, vuln.VendorIDs...))
// The newer fixed version should be taken.
if version.NewVersion(v.FixedVersion).LessThan(fixedVersion) {
v.FixedVersion = vuln.FixedVersion
}
uniqVulns[vulnID] = v
} else {
uniqVulns[vulnID] = vuln
}
// Keep unpatched and affected vulnerabilities
if adv.FixedVersion == "" || version.NewVersion(vuln.InstalledVersion).LessThan(version.NewVersion(adv.FixedVersion)) {
vulns = append(vulns, vuln)
}
}
vulns := lo.Values(uniqVulns)
sort.Slice(vulns, func(i, j int) bool {
return vulns[i].VulnerabilityID < vulns[j].VulnerabilityID
})
return vulns, nil
}

View File

@@ -79,8 +79,10 @@ func TestScanner_Detect(t *testing.T) {
},
},
{
VulnerabilityID: "CVE-2019-12735",
VendorIDs: []string{"RHSA-2019:1619"},
VulnerabilityID: "CVE-2019-12735",
VendorIDs: []string{
"RHSA-2019:1619",
},
PkgName: "vim-minimal",
InstalledVersion: "2:7.4.160-5.el7",
FixedVersion: "2:7.4.160-6.el7_6",
@@ -124,8 +126,10 @@ func TestScanner_Detect(t *testing.T) {
},
want: []types.DetectedVulnerability{
{
VulnerabilityID: "CVE-2019-17007",
VendorIDs: []string{"RHSA-2021:0876"},
VulnerabilityID: "CVE-2019-17007",
VendorIDs: []string{
"RHSA-2021:0876",
},
PkgName: "nss",
InstalledVersion: "3.36.0-7.1.el7_6",
FixedVersion: "3.36.0-9.el7_6",
@@ -141,7 +145,6 @@ func TestScanner_Detect(t *testing.T) {
VulnerabilityID: "CVE-2020-12403",
VendorIDs: []string{
"RHSA-2021:0538",
"RHSA-2021:0876",
},
PkgName: "nss",
InstalledVersion: "3.36.0-7.1.el7_6",
@@ -156,6 +159,53 @@ func TestScanner_Detect(t *testing.T) {
},
},
},
{
name: "happy path: CVE-ID and RHSA-ID for same vulnerability",
fixtures: []string{
"testdata/fixtures/redhat.yaml",
"testdata/fixtures/cpe.yaml",
},
args: args{
osVer: "8.3",
pkgs: []ftypes.Package{
{
Name: "expat",
Version: "2.2.5",
Release: "16.el8_10",
Epoch: 0,
Arch: "x86_64",
SrcName: "expat",
SrcVersion: "2.2.5",
SrcRelease: "16.el8_10",
SrcEpoch: 0,
Layer: ftypes.Layer{
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
},
BuildInfo: &ftypes.BuildInfo{
ContentSets: []string{"rhel-8-for-x86_64-baseos-rpms"},
},
},
},
},
want: []types.DetectedVulnerability{
{
VulnerabilityID: "CVE-2024-45490",
VendorIDs: []string{
"RHSA-2024:6989-3",
},
PkgName: "expat",
InstalledVersion: "2.2.5-16.el8_10",
FixedVersion: "2.2.5-18.el8_10",
SeveritySource: vulnerability.RedHat,
Vulnerability: dbTypes.Vulnerability{
Severity: dbTypes.SeverityMedium.String(),
},
Layer: ftypes.Layer{
DiffID: "sha256:932da51564135c98a49a34a193d6cd363d8fa4184d957fde16c9d8527b3f3b02",
},
},
},
},
{
name: "happy path: package without architecture",
fixtures: []string{
@@ -186,8 +236,10 @@ func TestScanner_Detect(t *testing.T) {
},
want: []types.DetectedVulnerability{
{
VulnerabilityID: "CVE-2016-5195",
VendorIDs: []string{"RHSA-2017:0372"},
VulnerabilityID: "CVE-2016-5195",
VendorIDs: []string{
"RHSA-2017:0372",
},
PkgName: "kernel-headers",
InstalledVersion: "3.10.0-1127.19-1.el7",
FixedVersion: "4.5.0-15.2.1.el7",
@@ -231,8 +283,10 @@ func TestScanner_Detect(t *testing.T) {
},
want: []types.DetectedVulnerability{
{
VulnerabilityID: "CVE-2016-5195",
VendorIDs: []string{"RHSA-2016:2098"},
VulnerabilityID: "CVE-2016-5195",
VendorIDs: []string{
"RHSA-2016:2098",
},
PkgName: "kernel-headers",
InstalledVersion: "3.10.0-326.36-3.el7",
FixedVersion: "3.10.0-327.36.3.el7",
@@ -266,8 +320,10 @@ func TestScanner_Detect(t *testing.T) {
},
want: []types.DetectedVulnerability{
{
VulnerabilityID: "CVE-2019-12735",
VendorIDs: []string{"RHSA-2019:1619"},
VulnerabilityID: "CVE-2019-12735",
VendorIDs: []string{
"RHSA-2019:1619",
},
PkgName: "vim-minimal",
InstalledVersion: "2:7.4.160-5.el8",
FixedVersion: "2:7.4.160-7.el8_7",
@@ -308,8 +364,10 @@ func TestScanner_Detect(t *testing.T) {
},
want: []types.DetectedVulnerability{
{
VulnerabilityID: "CVE-2019-11043",
VendorIDs: []string{"RHSA-2020:0322"},
VulnerabilityID: "CVE-2019-11043",
VendorIDs: []string{
"RHSA-2020:0322",
},
PkgName: "php",
InstalledVersion: "7.2.10-1.module_el8.2.0+313+b04d0a66",
FixedVersion: "7.2.11-1.1.module+el8.0.0+4664+17bd8d65",

View File

@@ -104,4 +104,67 @@
- ID: CVE-2016-5195
Severity: 3
Arches:
- aarch64
- aarch64
- bucket: expat
pairs:
- key: RHSA-2024:6989-2 # created for test only
value:
Entries:
- FixedVersion: 0:2.2.5-17.el8_10
Affected:
- 4
Arches:
- x86_64
Cves:
- ID: CVE-2024-45490
Severity: 2
- key: RHSA-2024:6989-3 # created for test only
value:
Entries:
- FixedVersion: 0:2.2.5-18.el8_10
Affected:
- 4
Arches:
- x86_64
Cves:
- ID: CVE-2024-45490
Severity: 2
- key: CVE-2024-45490
value:
Entries:
- Affected:
- 4
Cves:
- Severity: 2
Status: 5
- key: CVE-2024-45491
value:
Entries:
- Affected:
- 4
Cves:
- Severity: 2
Status: 5
- key: RHSA-2024:6989
value:
Entries:
- FixedVersion: 0:2.2.5-15.el8_10
Affected:
- 4
Arches:
- x86_64
Cves:
- ID: CVE-2024-45490
Severity: 2
- ID: CVE-2024-45491
Severity: 2
- ID: CVE-2024-45492
Severity: 2
- key: CVE-2024-45492
value:
Entries:
- Affected:
- 4
Cves:
- Severity: 2
Status: 5

View File

@@ -94,7 +94,7 @@ func (a poetryAnalyzer) parsePoetryLock(path string, r io.Reader) (*types.Applic
func (a poetryAnalyzer) mergePyProject(fsys fs.FS, dir string, app *types.Application) error {
// Parse pyproject.toml to identify the direct dependencies
path := filepath.Join(dir, types.PyProject)
p, err := a.parsePyProject(fsys, path)
project, err := a.parsePyProject(fsys, path)
if errors.Is(err, fs.ErrNotExist) {
// Assume all the packages are direct dependencies as it cannot identify them from poetry.lock
a.logger.Debug("pyproject.toml not found", log.FilePath(path))
@@ -105,7 +105,7 @@ func (a poetryAnalyzer) mergePyProject(fsys fs.FS, dir string, app *types.Applic
// Identify the direct/transitive dependencies
for i, pkg := range app.Packages {
if _, ok := p[pkg.Name]; ok {
if _, ok := project.Tool.Poetry.Dependencies[pkg.Name]; ok {
app.Packages[i].Relationship = types.RelationshipDirect
} else {
app.Packages[i].Indirect = true
@@ -113,26 +113,60 @@ func (a poetryAnalyzer) mergePyProject(fsys fs.FS, dir string, app *types.Applic
}
}
filterProdPackages(project, app)
return nil
}
func (a poetryAnalyzer) parsePyProject(fsys fs.FS, path string) (map[string]any, error) {
func filterProdPackages(project pyproject.PyProject, app *types.Application) {
packages := lo.SliceToMap(app.Packages, func(pkg types.Package) (string, types.Package) {
return pkg.ID, pkg
})
visited := make(map[string]struct{})
deps := project.Tool.Poetry.Dependencies
for group, groupDeps := range project.Tool.Poetry.Groups {
if group == "dev" {
continue
}
deps = lo.Assign(deps, groupDeps.Dependencies)
}
for _, pkg := range packages {
if _, prodDep := deps[pkg.Name]; !prodDep {
continue
}
walkPackageDeps(pkg.ID, packages, visited)
}
app.Packages = lo.Filter(app.Packages, func(pkg types.Package, _ int) bool {
_, ok := visited[pkg.ID]
return ok
})
}
func walkPackageDeps(pkgID string, packages map[string]types.Package, visited map[string]struct{}) {
if _, ok := visited[pkgID]; ok {
return
}
visited[pkgID] = struct{}{}
for _, dep := range packages[pkgID].DependsOn {
walkPackageDeps(dep, packages, visited)
}
}
func (a poetryAnalyzer) parsePyProject(fsys fs.FS, path string) (pyproject.PyProject, error) {
// Parse pyproject.toml
f, err := fsys.Open(path)
if err != nil {
return nil, xerrors.Errorf("file open error: %w", err)
return pyproject.PyProject{}, xerrors.Errorf("file open error: %w", err)
}
defer f.Close()
parsed, err := a.pyprojectParser.Parse(f)
project, err := a.pyprojectParser.Parse(f)
if err != nil {
return nil, err
return pyproject.PyProject{}, err
}
// Packages from `pyproject.toml` can use uppercase characters, `.` and `_`.
parsed = lo.MapKeys(parsed, func(_ any, pkgName string) string {
return poetry.NormalizePkgName(pkgName)
})
return parsed, nil
return project, nil
}

View File

@@ -181,6 +181,99 @@ func Test_poetryLibraryAnalyzer_Analyze(t *testing.T) {
dir: "testdata/sad",
want: &analyzer.AnalysisResult{},
},
{
// docker run --name poetry --rm -it python@sha256:e1141f10176d74d1a0e87a7c0a0a5a98dd98ec5ac12ce867768f40c6feae2fd9 sh
// wget -qO- https://install.python-poetry.org | POETRY_VERSION=1.8.5 python3 -
// export PATH="/root/.local/bin:$PATH"
// poetry new groups && cd groups
// poetry add requests@2.32.3
// poetry add --group dev pytest@8.3.4
// poetry add --group lint ruff@0.8.3
// poetry add --optional typing-inspect@0.9.0
name: "skip deps from groups",
dir: "testdata/with-groups",
want: &analyzer.AnalysisResult{
Applications: []types.Application{
{
Type: types.Poetry,
FilePath: "poetry.lock",
Packages: types.Packages{
{
ID: "certifi@2024.12.14",
Name: "certifi",
Version: "2024.12.14",
Indirect: true,
Relationship: types.RelationshipIndirect,
},
{
ID: "charset-normalizer@3.4.0",
Name: "charset-normalizer",
Version: "3.4.0",
Indirect: true,
Relationship: types.RelationshipIndirect,
},
{
ID: "idna@3.10",
Name: "idna",
Version: "3.10",
Indirect: true,
Relationship: types.RelationshipIndirect,
},
{
ID: "mypy-extensions@1.0.0",
Name: "mypy-extensions",
Version: "1.0.0",
Indirect: true,
Relationship: types.RelationshipIndirect,
},
{
ID: "requests@2.32.3",
Name: "requests",
Version: "2.32.3",
DependsOn: []string{
"certifi@2024.12.14",
"charset-normalizer@3.4.0",
"idna@3.10",
"urllib3@2.2.3",
},
Relationship: types.RelationshipDirect,
},
{
ID: "ruff@0.8.3",
Name: "ruff",
Version: "0.8.3",
Indirect: true,
Relationship: types.RelationshipIndirect,
},
{
ID: "typing-extensions@4.12.2",
Name: "typing-extensions",
Version: "4.12.2",
Indirect: true,
Relationship: types.RelationshipIndirect,
},
{
ID: "typing-inspect@0.9.0",
Name: "typing-inspect",
Version: "0.9.0",
DependsOn: []string{
"mypy-extensions@1.0.0",
"typing-extensions@4.12.2",
},
Relationship: types.RelationshipDirect,
},
{
ID: "urllib3@2.2.3",
Name: "urllib3",
Version: "2.2.3",
Indirect: true,
Relationship: types.RelationshipIndirect,
},
},
},
},
},
},
}
for _, tt := range tests {

View File

@@ -0,0 +1,372 @@
# This file is automatically @generated by Poetry 1.8.5 and should not be changed by hand.
[[package]]
name = "certifi"
version = "2024.12.14"
description = "Python package for providing Mozilla's CA Bundle."
optional = false
python-versions = ">=3.6"
files = [
{file = "certifi-2024.12.14-py3-none-any.whl", hash = "sha256:1275f7a45be9464efc1173084eaa30f866fe2e47d389406136d332ed4967ec56"},
{file = "certifi-2024.12.14.tar.gz", hash = "sha256:b650d30f370c2b724812bee08008be0c4163b163ddaec3f2546c1caf65f191db"},
]
[[package]]
name = "charset-normalizer"
version = "3.4.0"
description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet."
optional = false
python-versions = ">=3.7.0"
files = [
{file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4f9fc98dad6c2eaa32fc3af1417d95b5e3d08aff968df0cd320066def971f9a6"},
{file = "charset_normalizer-3.4.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0de7b687289d3c1b3e8660d0741874abe7888100efe14bd0f9fd7141bcbda92b"},
{file = "charset_normalizer-3.4.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5ed2e36c3e9b4f21dd9422f6893dec0abf2cca553af509b10cd630f878d3eb99"},
{file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:40d3ff7fc90b98c637bda91c89d51264a3dcf210cade3a2c6f838c7268d7a4ca"},
{file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1110e22af8ca26b90bd6364fe4c763329b0ebf1ee213ba32b68c73de5752323d"},
{file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:86f4e8cca779080f66ff4f191a685ced73d2f72d50216f7112185dc02b90b9b7"},
{file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7f683ddc7eedd742e2889d2bfb96d69573fde1d92fcb811979cdb7165bb9c7d3"},
{file = "charset_normalizer-3.4.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:27623ba66c183eca01bf9ff833875b459cad267aeeb044477fedac35e19ba907"},
{file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:f606a1881d2663630ea5b8ce2efe2111740df4b687bd78b34a8131baa007f79b"},
{file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0b309d1747110feb25d7ed6b01afdec269c647d382c857ef4663bbe6ad95a912"},
{file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:136815f06a3ae311fae551c3df1f998a1ebd01ddd424aa5603a4336997629e95"},
{file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:14215b71a762336254351b00ec720a8e85cada43b987da5a042e4ce3e82bd68e"},
{file = "charset_normalizer-3.4.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:79983512b108e4a164b9c8d34de3992f76d48cadc9554c9e60b43f308988aabe"},
{file = "charset_normalizer-3.4.0-cp310-cp310-win32.whl", hash = "sha256:c94057af19bc953643a33581844649a7fdab902624d2eb739738a30e2b3e60fc"},
{file = "charset_normalizer-3.4.0-cp310-cp310-win_amd64.whl", hash = "sha256:55f56e2ebd4e3bc50442fbc0888c9d8c94e4e06a933804e2af3e89e2f9c1c749"},
{file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0d99dd8ff461990f12d6e42c7347fd9ab2532fb70e9621ba520f9e8637161d7c"},
{file = "charset_normalizer-3.4.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c57516e58fd17d03ebe67e181a4e4e2ccab1168f8c2976c6a334d4f819fe5944"},
{file = "charset_normalizer-3.4.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:6dba5d19c4dfab08e58d5b36304b3f92f3bd5d42c1a3fa37b5ba5cdf6dfcbcee"},
{file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bf4475b82be41b07cc5e5ff94810e6a01f276e37c2d55571e3fe175e467a1a1c"},
{file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce031db0408e487fd2775d745ce30a7cd2923667cf3b69d48d219f1d8f5ddeb6"},
{file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ff4e7cdfdb1ab5698e675ca622e72d58a6fa2a8aa58195de0c0061288e6e3ea"},
{file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3710a9751938947e6327ea9f3ea6332a09bf0ba0c09cae9cb1f250bd1f1549bc"},
{file = "charset_normalizer-3.4.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:82357d85de703176b5587dbe6ade8ff67f9f69a41c0733cf2425378b49954de5"},
{file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:47334db71978b23ebcf3c0f9f5ee98b8d65992b65c9c4f2d34c2eaf5bcaf0594"},
{file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:8ce7fd6767a1cc5a92a639b391891bf1c268b03ec7e021c7d6d902285259685c"},
{file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:f1a2f519ae173b5b6a2c9d5fa3116ce16e48b3462c8b96dfdded11055e3d6365"},
{file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:63bc5c4ae26e4bc6be6469943b8253c0fd4e4186c43ad46e713ea61a0ba49129"},
{file = "charset_normalizer-3.4.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:bcb4f8ea87d03bc51ad04add8ceaf9b0f085ac045ab4d74e73bbc2dc033f0236"},
{file = "charset_normalizer-3.4.0-cp311-cp311-win32.whl", hash = "sha256:9ae4ef0b3f6b41bad6366fb0ea4fc1d7ed051528e113a60fa2a65a9abb5b1d99"},
{file = "charset_normalizer-3.4.0-cp311-cp311-win_amd64.whl", hash = "sha256:cee4373f4d3ad28f1ab6290684d8e2ebdb9e7a1b74fdc39e4c211995f77bec27"},
{file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0713f3adb9d03d49d365b70b84775d0a0d18e4ab08d12bc46baa6132ba78aaf6"},
{file = "charset_normalizer-3.4.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:de7376c29d95d6719048c194a9cf1a1b0393fbe8488a22008610b0361d834ecf"},
{file = "charset_normalizer-3.4.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:4a51b48f42d9358460b78725283f04bddaf44a9358197b889657deba38f329db"},
{file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b295729485b06c1a0683af02a9e42d2caa9db04a373dc38a6a58cdd1e8abddf1"},
{file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ee803480535c44e7f5ad00788526da7d85525cfefaf8acf8ab9a310000be4b03"},
{file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3d59d125ffbd6d552765510e3f31ed75ebac2c7470c7274195b9161a32350284"},
{file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8cda06946eac330cbe6598f77bb54e690b4ca93f593dee1568ad22b04f347c15"},
{file = "charset_normalizer-3.4.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:07afec21bbbbf8a5cc3651aa96b980afe2526e7f048fdfb7f1014d84acc8b6d8"},
{file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6b40e8d38afe634559e398cc32b1472f376a4099c75fe6299ae607e404c033b2"},
{file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b8dcd239c743aa2f9c22ce674a145e0a25cb1566c495928440a181ca1ccf6719"},
{file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:84450ba661fb96e9fd67629b93d2941c871ca86fc38d835d19d4225ff946a631"},
{file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:44aeb140295a2f0659e113b31cfe92c9061622cadbc9e2a2f7b8ef6b1e29ef4b"},
{file = "charset_normalizer-3.4.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:1db4e7fefefd0f548d73e2e2e041f9df5c59e178b4c72fbac4cc6f535cfb1565"},
{file = "charset_normalizer-3.4.0-cp312-cp312-win32.whl", hash = "sha256:5726cf76c982532c1863fb64d8c6dd0e4c90b6ece9feb06c9f202417a31f7dd7"},
{file = "charset_normalizer-3.4.0-cp312-cp312-win_amd64.whl", hash = "sha256:b197e7094f232959f8f20541ead1d9862ac5ebea1d58e9849c1bf979255dfac9"},
{file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:dd4eda173a9fcccb5f2e2bd2a9f423d180194b1bf17cf59e3269899235b2a114"},
{file = "charset_normalizer-3.4.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9e3c4c9e1ed40ea53acf11e2a386383c3304212c965773704e4603d589343ed"},
{file = "charset_normalizer-3.4.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:92a7e36b000bf022ef3dbb9c46bfe2d52c047d5e3f3343f43204263c5addc250"},
{file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:54b6a92d009cbe2fb11054ba694bc9e284dad30a26757b1e372a1fdddaf21920"},
{file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ffd9493de4c922f2a38c2bf62b831dcec90ac673ed1ca182fe11b4d8e9f2a64"},
{file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:35c404d74c2926d0287fbd63ed5d27eb911eb9e4a3bb2c6d294f3cfd4a9e0c23"},
{file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4796efc4faf6b53a18e3d46343535caed491776a22af773f366534056c4e1fbc"},
{file = "charset_normalizer-3.4.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e7fdd52961feb4c96507aa649550ec2a0d527c086d284749b2f582f2d40a2e0d"},
{file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:92db3c28b5b2a273346bebb24857fda45601aef6ae1c011c0a997106581e8a88"},
{file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ab973df98fc99ab39080bfb0eb3a925181454d7c3ac8a1e695fddfae696d9e90"},
{file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4b67fdab07fdd3c10bb21edab3cbfe8cf5696f453afce75d815d9d7223fbe88b"},
{file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:aa41e526a5d4a9dfcfbab0716c7e8a1b215abd3f3df5a45cf18a12721d31cb5d"},
{file = "charset_normalizer-3.4.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ffc519621dce0c767e96b9c53f09c5d215578e10b02c285809f76509a3931482"},
{file = "charset_normalizer-3.4.0-cp313-cp313-win32.whl", hash = "sha256:f19c1585933c82098c2a520f8ec1227f20e339e33aca8fa6f956f6691b784e67"},
{file = "charset_normalizer-3.4.0-cp313-cp313-win_amd64.whl", hash = "sha256:707b82d19e65c9bd28b81dde95249b07bf9f5b90ebe1ef17d9b57473f8a64b7b"},
{file = "charset_normalizer-3.4.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:dbe03226baf438ac4fda9e2d0715022fd579cb641c4cf639fa40d53b2fe6f3e2"},
{file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd9a8bd8900e65504a305bf8ae6fa9fbc66de94178c420791d0293702fce2df7"},
{file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b8831399554b92b72af5932cdbbd4ddc55c55f631bb13ff8fe4e6536a06c5c51"},
{file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a14969b8691f7998e74663b77b4c36c0337cb1df552da83d5c9004a93afdb574"},
{file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dcaf7c1524c0542ee2fc82cc8ec337f7a9f7edee2532421ab200d2b920fc97cf"},
{file = "charset_normalizer-3.4.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:425c5f215d0eecee9a56cdb703203dda90423247421bf0d67125add85d0c4455"},
{file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_aarch64.whl", hash = "sha256:d5b054862739d276e09928de37c79ddeec42a6e1bfc55863be96a36ba22926f6"},
{file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_i686.whl", hash = "sha256:f3e73a4255342d4eb26ef6df01e3962e73aa29baa3124a8e824c5d3364a65748"},
{file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_ppc64le.whl", hash = "sha256:2f6c34da58ea9c1a9515621f4d9ac379871a8f21168ba1b5e09d74250de5ad62"},
{file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_s390x.whl", hash = "sha256:f09cb5a7bbe1ecae6e87901a2eb23e0256bb524a79ccc53eb0b7629fbe7677c4"},
{file = "charset_normalizer-3.4.0-cp37-cp37m-musllinux_1_2_x86_64.whl", hash = "sha256:0099d79bdfcf5c1f0c2c72f91516702ebf8b0b8ddd8905f97a8aecf49712c621"},
{file = "charset_normalizer-3.4.0-cp37-cp37m-win32.whl", hash = "sha256:9c98230f5042f4945f957d006edccc2af1e03ed5e37ce7c373f00a5a4daa6149"},
{file = "charset_normalizer-3.4.0-cp37-cp37m-win_amd64.whl", hash = "sha256:62f60aebecfc7f4b82e3f639a7d1433a20ec32824db2199a11ad4f5e146ef5ee"},
{file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:af73657b7a68211996527dbfeffbb0864e043d270580c5aef06dc4b659a4b578"},
{file = "charset_normalizer-3.4.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:cab5d0b79d987c67f3b9e9c53f54a61360422a5a0bc075f43cab5621d530c3b6"},
{file = "charset_normalizer-3.4.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:9289fd5dddcf57bab41d044f1756550f9e7cf0c8e373b8cdf0ce8773dc4bd417"},
{file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b493a043635eb376e50eedf7818f2f322eabbaa974e948bd8bdd29eb7ef2a51"},
{file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9fa2566ca27d67c86569e8c85297aaf413ffab85a8960500f12ea34ff98e4c41"},
{file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8e538f46104c815be19c975572d74afb53f29650ea2025bbfaef359d2de2f7f"},
{file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fd30dc99682dc2c603c2b315bded2799019cea829f8bf57dc6b61efde6611c8"},
{file = "charset_normalizer-3.4.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2006769bd1640bdf4d5641c69a3d63b71b81445473cac5ded39740a226fa88ab"},
{file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:dc15e99b2d8a656f8e666854404f1ba54765871104e50c8e9813af8a7db07f12"},
{file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_i686.whl", hash = "sha256:ab2e5bef076f5a235c3774b4f4028a680432cded7cad37bba0fd90d64b187d19"},
{file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_ppc64le.whl", hash = "sha256:4ec9dd88a5b71abfc74e9df5ebe7921c35cbb3b641181a531ca65cdb5e8e4dea"},
{file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_s390x.whl", hash = "sha256:43193c5cda5d612f247172016c4bb71251c784d7a4d9314677186a838ad34858"},
{file = "charset_normalizer-3.4.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:aa693779a8b50cd97570e5a0f343538a8dbd3e496fa5dcb87e29406ad0299654"},
{file = "charset_normalizer-3.4.0-cp38-cp38-win32.whl", hash = "sha256:7706f5850360ac01d80c89bcef1640683cc12ed87f42579dab6c5d3ed6888613"},
{file = "charset_normalizer-3.4.0-cp38-cp38-win_amd64.whl", hash = "sha256:c3e446d253bd88f6377260d07c895816ebf33ffffd56c1c792b13bff9c3e1ade"},
{file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:980b4f289d1d90ca5efcf07958d3eb38ed9c0b7676bf2831a54d4f66f9c27dfa"},
{file = "charset_normalizer-3.4.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f28f891ccd15c514a0981f3b9db9aa23d62fe1a99997512b0491d2ed323d229a"},
{file = "charset_normalizer-3.4.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8aacce6e2e1edcb6ac625fb0f8c3a9570ccc7bfba1f63419b3769ccf6a00ed0"},
{file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd7af3717683bea4c87acd8c0d3d5b44d56120b26fd3f8a692bdd2d5260c620a"},
{file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5ff2ed8194587faf56555927b3aa10e6fb69d931e33953943bc4f837dfee2242"},
{file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e91f541a85298cf35433bf66f3fab2a4a2cff05c127eeca4af174f6d497f0d4b"},
{file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:309a7de0a0ff3040acaebb35ec45d18db4b28232f21998851cfa709eeff49d62"},
{file = "charset_normalizer-3.4.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:285e96d9d53422efc0d7a17c60e59f37fbf3dfa942073f666db4ac71e8d726d0"},
{file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:5d447056e2ca60382d460a604b6302d8db69476fd2015c81e7c35417cfabe4cd"},
{file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_i686.whl", hash = "sha256:20587d20f557fe189b7947d8e7ec5afa110ccf72a3128d61a2a387c3313f46be"},
{file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_ppc64le.whl", hash = "sha256:130272c698667a982a5d0e626851ceff662565379baf0ff2cc58067b81d4f11d"},
{file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_s390x.whl", hash = "sha256:ab22fbd9765e6954bc0bcff24c25ff71dcbfdb185fcdaca49e81bac68fe724d3"},
{file = "charset_normalizer-3.4.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:7782afc9b6b42200f7362858f9e73b1f8316afb276d316336c0ec3bd73312742"},
{file = "charset_normalizer-3.4.0-cp39-cp39-win32.whl", hash = "sha256:2de62e8801ddfff069cd5c504ce3bc9672b23266597d4e4f50eda28846c322f2"},
{file = "charset_normalizer-3.4.0-cp39-cp39-win_amd64.whl", hash = "sha256:95c3c157765b031331dd4db3c775e58deaee050a3042fcad72cbc4189d7c8dca"},
{file = "charset_normalizer-3.4.0-py3-none-any.whl", hash = "sha256:fe9f97feb71aa9896b81973a7bbada8c49501dc73e58a10fcef6663af95e5079"},
{file = "charset_normalizer-3.4.0.tar.gz", hash = "sha256:223217c3d4f82c3ac5e29032b3f1c2eb0fb591b72161f86d93f5719079dae93e"},
]
[[package]]
name = "colorama"
version = "0.4.6"
description = "Cross-platform colored terminal text."
optional = false
python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7"
files = [
{file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"},
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
]
[[package]]
name = "exceptiongroup"
version = "1.2.2"
description = "Backport of PEP 654 (exception groups)"
optional = false
python-versions = ">=3.7"
files = [
{file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"},
{file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"},
]
[package.extras]
test = ["pytest (>=6)"]
[[package]]
name = "idna"
version = "3.10"
description = "Internationalized Domain Names in Applications (IDNA)"
optional = false
python-versions = ">=3.6"
files = [
{file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"},
{file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"},
]
[package.extras]
all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"]
[[package]]
name = "iniconfig"
version = "2.0.0"
description = "brain-dead simple config-ini parsing"
optional = false
python-versions = ">=3.7"
files = [
{file = "iniconfig-2.0.0-py3-none-any.whl", hash = "sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374"},
{file = "iniconfig-2.0.0.tar.gz", hash = "sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3"},
]
[[package]]
name = "mypy-extensions"
version = "1.0.0"
description = "Type system extensions for programs checked with the mypy type checker."
optional = true
python-versions = ">=3.5"
files = [
{file = "mypy_extensions-1.0.0-py3-none-any.whl", hash = "sha256:4392f6c0eb8a5668a69e23d168ffa70f0be9ccfd32b5cc2d26a34ae5b844552d"},
{file = "mypy_extensions-1.0.0.tar.gz", hash = "sha256:75dbf8955dc00442a438fc4d0666508a9a97b6bd41aa2f0ffe9d2f2725af0782"},
]
[[package]]
name = "packaging"
version = "24.2"
description = "Core utilities for Python packages"
optional = false
python-versions = ">=3.8"
files = [
{file = "packaging-24.2-py3-none-any.whl", hash = "sha256:09abb1bccd265c01f4a3aa3f7a7db064b36514d2cba19a2f694fe6150451a759"},
{file = "packaging-24.2.tar.gz", hash = "sha256:c228a6dc5e932d346bc5739379109d49e8853dd8223571c7c5b55260edc0b97f"},
]
[[package]]
name = "pluggy"
version = "1.5.0"
description = "plugin and hook calling mechanisms for python"
optional = false
python-versions = ">=3.8"
files = [
{file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"},
{file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"},
]
[package.extras]
dev = ["pre-commit", "tox"]
testing = ["pytest", "pytest-benchmark"]
[[package]]
name = "pytest"
version = "8.3.4"
description = "pytest: simple powerful testing with Python"
optional = false
python-versions = ">=3.8"
files = [
{file = "pytest-8.3.4-py3-none-any.whl", hash = "sha256:50e16d954148559c9a74109af1eaf0c945ba2d8f30f0a3d3335edde19788b6f6"},
{file = "pytest-8.3.4.tar.gz", hash = "sha256:965370d062bce11e73868e0335abac31b4d3de0e82f4007408d242b4f8610761"},
]
[package.dependencies]
colorama = {version = "*", markers = "sys_platform == \"win32\""}
exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""}
iniconfig = "*"
packaging = "*"
pluggy = ">=1.5,<2"
tomli = {version = ">=1", markers = "python_version < \"3.11\""}
[package.extras]
dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"]
[[package]]
name = "requests"
version = "2.32.3"
description = "Python HTTP for Humans."
optional = false
python-versions = ">=3.8"
files = [
{file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"},
{file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"},
]
[package.dependencies]
certifi = ">=2017.4.17"
charset-normalizer = ">=2,<4"
idna = ">=2.5,<4"
urllib3 = ">=1.21.1,<3"
[package.extras]
socks = ["PySocks (>=1.5.6,!=1.5.7)"]
use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"]
[[package]]
name = "ruff"
version = "0.8.3"
description = "An extremely fast Python linter and code formatter, written in Rust."
optional = false
python-versions = ">=3.7"
files = [
{file = "ruff-0.8.3-py3-none-linux_armv6l.whl", hash = "sha256:8d5d273ffffff0acd3db5bf626d4b131aa5a5ada1276126231c4174543ce20d6"},
{file = "ruff-0.8.3-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:e4d66a21de39f15c9757d00c50c8cdd20ac84f55684ca56def7891a025d7e939"},
{file = "ruff-0.8.3-py3-none-macosx_11_0_arm64.whl", hash = "sha256:c356e770811858bd20832af696ff6c7e884701115094f427b64b25093d6d932d"},
{file = "ruff-0.8.3-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9c0a60a825e3e177116c84009d5ebaa90cf40dfab56e1358d1df4e29a9a14b13"},
{file = "ruff-0.8.3-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:75fb782f4db39501210ac093c79c3de581d306624575eddd7e4e13747e61ba18"},
{file = "ruff-0.8.3-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7f26bc76a133ecb09a38b7868737eded6941b70a6d34ef53a4027e83913b6502"},
{file = "ruff-0.8.3-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:01b14b2f72a37390c1b13477c1c02d53184f728be2f3ffc3ace5b44e9e87b90d"},
{file = "ruff-0.8.3-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:53babd6e63e31f4e96ec95ea0d962298f9f0d9cc5990a1bbb023a6baf2503a82"},
{file = "ruff-0.8.3-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1ae441ce4cf925b7f363d33cd6570c51435972d697e3e58928973994e56e1452"},
{file = "ruff-0.8.3-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d7c65bc0cadce32255e93c57d57ecc2cca23149edd52714c0c5d6fa11ec328cd"},
{file = "ruff-0.8.3-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:5be450bb18f23f0edc5a4e5585c17a56ba88920d598f04a06bd9fd76d324cb20"},
{file = "ruff-0.8.3-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:8faeae3827eaa77f5721f09b9472a18c749139c891dbc17f45e72d8f2ca1f8fc"},
{file = "ruff-0.8.3-py3-none-musllinux_1_2_i686.whl", hash = "sha256:db503486e1cf074b9808403991663e4277f5c664d3fe237ee0d994d1305bb060"},
{file = "ruff-0.8.3-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:6567be9fb62fbd7a099209257fef4ad2c3153b60579818b31a23c886ed4147ea"},
{file = "ruff-0.8.3-py3-none-win32.whl", hash = "sha256:19048f2f878f3ee4583fc6cb23fb636e48c2635e30fb2022b3a1cd293402f964"},
{file = "ruff-0.8.3-py3-none-win_amd64.whl", hash = "sha256:f7df94f57d7418fa7c3ffb650757e0c2b96cf2501a0b192c18e4fb5571dfada9"},
{file = "ruff-0.8.3-py3-none-win_arm64.whl", hash = "sha256:fe2756edf68ea79707c8d68b78ca9a58ed9af22e430430491ee03e718b5e4936"},
{file = "ruff-0.8.3.tar.gz", hash = "sha256:5e7558304353b84279042fc584a4f4cb8a07ae79b2bf3da1a7551d960b5626d3"},
]
[[package]]
name = "tomli"
version = "2.2.1"
description = "A lil' TOML parser"
optional = false
python-versions = ">=3.8"
files = [
{file = "tomli-2.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678e4fa69e4575eb77d103de3df8a895e1591b48e740211bd1067378c69e8249"},
{file = "tomli-2.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:023aa114dd824ade0100497eb2318602af309e5a55595f76b626d6d9f3b7b0a6"},
{file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ece47d672db52ac607a3d9599a9d48dcb2f2f735c6c2d1f34130085bb12b112a"},
{file = "tomli-2.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6972ca9c9cc9f0acaa56a8ca1ff51e7af152a9f87fb64623e31d5c83700080ee"},
{file = "tomli-2.2.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c954d2250168d28797dd4e3ac5cf812a406cd5a92674ee4c8f123c889786aa8e"},
{file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8dd28b3e155b80f4d54beb40a441d366adcfe740969820caf156c019fb5c7ec4"},
{file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e59e304978767a54663af13c07b3d1af22ddee3bb2fb0618ca1593e4f593a106"},
{file = "tomli-2.2.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:33580bccab0338d00994d7f16f4c4ec25b776af3ffaac1ed74e0b3fc95e885a8"},
{file = "tomli-2.2.1-cp311-cp311-win32.whl", hash = "sha256:465af0e0875402f1d226519c9904f37254b3045fc5084697cefb9bdde1ff99ff"},
{file = "tomli-2.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2d0f2fdd22b02c6d81637a3c95f8cd77f995846af7414c5c4b8d0545afa1bc4b"},
{file = "tomli-2.2.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:4a8f6e44de52d5e6c657c9fe83b562f5f4256d8ebbfe4ff922c495620a7f6cea"},
{file = "tomli-2.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8d57ca8095a641b8237d5b079147646153d22552f1c637fd3ba7f4b0b29167a8"},
{file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e340144ad7ae1533cb897d406382b4b6fede8890a03738ff1683af800d54192"},
{file = "tomli-2.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:db2b95f9de79181805df90bedc5a5ab4c165e6ec3fe99f970d0e302f384ad222"},
{file = "tomli-2.2.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:40741994320b232529c802f8bc86da4e1aa9f413db394617b9a256ae0f9a7f77"},
{file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:400e720fe168c0f8521520190686ef8ef033fb19fc493da09779e592861b78c6"},
{file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:02abe224de6ae62c19f090f68da4e27b10af2b93213d36cf44e6e1c5abd19fdd"},
{file = "tomli-2.2.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:b82ebccc8c8a36f2094e969560a1b836758481f3dc360ce9a3277c65f374285e"},
{file = "tomli-2.2.1-cp312-cp312-win32.whl", hash = "sha256:889f80ef92701b9dbb224e49ec87c645ce5df3fa2cc548664eb8a25e03127a98"},
{file = "tomli-2.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:7fc04e92e1d624a4a63c76474610238576942d6b8950a2d7f908a340494e67e4"},
{file = "tomli-2.2.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f4039b9cbc3048b2416cc57ab3bda989a6fcf9b36cf8937f01a6e731b64f80d7"},
{file = "tomli-2.2.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:286f0ca2ffeeb5b9bd4fcc8d6c330534323ec51b2f52da063b11c502da16f30c"},
{file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a92ef1a44547e894e2a17d24e7557a5e85a9e1d0048b0b5e7541f76c5032cb13"},
{file = "tomli-2.2.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9316dc65bed1684c9a98ee68759ceaed29d229e985297003e494aa825ebb0281"},
{file = "tomli-2.2.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e85e99945e688e32d5a35c1ff38ed0b3f41f43fad8df0bdf79f72b2ba7bc5272"},
{file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:ac065718db92ca818f8d6141b5f66369833d4a80a9d74435a268c52bdfa73140"},
{file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d920f33822747519673ee656a4b6ac33e382eca9d331c87770faa3eef562aeb2"},
{file = "tomli-2.2.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a198f10c4d1b1375d7687bc25294306e551bf1abfa4eace6650070a5c1ae2744"},
{file = "tomli-2.2.1-cp313-cp313-win32.whl", hash = "sha256:d3f5614314d758649ab2ab3a62d4f2004c825922f9e370b29416484086b264ec"},
{file = "tomli-2.2.1-cp313-cp313-win_amd64.whl", hash = "sha256:a38aa0308e754b0e3c67e344754dff64999ff9b513e691d0e786265c93583c69"},
{file = "tomli-2.2.1-py3-none-any.whl", hash = "sha256:cb55c73c5f4408779d0cf3eef9f762b9c9f147a77de7b258bef0a5628adc85cc"},
{file = "tomli-2.2.1.tar.gz", hash = "sha256:cd45e1dc79c835ce60f7404ec8119f2eb06d38b1deba146f07ced3bbc44505ff"},
]
[[package]]
name = "typing-extensions"
version = "4.12.2"
description = "Backported and Experimental Type Hints for Python 3.8+"
optional = true
python-versions = ">=3.8"
files = [
{file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"},
{file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"},
]
[[package]]
name = "typing-inspect"
version = "0.9.0"
description = "Runtime inspection utilities for typing module."
optional = true
python-versions = "*"
files = [
{file = "typing_inspect-0.9.0-py3-none-any.whl", hash = "sha256:9ee6fc59062311ef8547596ab6b955e1b8aa46242d854bfc78f4f6b0eff35f9f"},
{file = "typing_inspect-0.9.0.tar.gz", hash = "sha256:b23fc42ff6f6ef6954e4852c1fb512cdd18dbea03134f91f856a95ccc9461f78"},
]
[package.dependencies]
mypy-extensions = ">=0.3.0"
typing-extensions = ">=3.7.4"
[[package]]
name = "urllib3"
version = "2.2.3"
description = "HTTP library with thread-safe connection pooling, file post, and more."
optional = false
python-versions = ">=3.8"
files = [
{file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"},
{file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"},
]
[package.extras]
brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"]
h2 = ["h2 (>=4,<5)"]
socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"]
zstd = ["zstandard (>=0.18.0)"]
[metadata]
lock-version = "2.0"
python-versions = "^3.9"
content-hash = "fd0e5fc1dfc09e39acec1d9fe304fecccbdff1ca85271ab1f15a19d008db23cf"

View File

@@ -0,0 +1,23 @@
[tool.poetry]
name = "groups"
version = "0.1.0"
description = ""
authors = ["Your Name <you@example.com>"]
readme = "README.md"
[tool.poetry.dependencies]
python = "^3.9"
requests = "2.32.3"
typing-inspect = {version = "0.9.0", optional = true}
[tool.poetry.group.dev.dependencies]
pytest = "8.3.4"
[tool.poetry.group.lint.dependencies]
ruff = "0.8.3"
[build-system]
requires = ["poetry-core"]
build-backend = "poetry.core.masonry.api"

View File

@@ -4,6 +4,7 @@ import (
"context"
"os"
"path"
"slices"
"strings"
"golang.org/x/xerrors"
@@ -51,6 +52,14 @@ func (a sbomAnalyzer) Analyze(ctx context.Context, input analyzer.AnalysisInput)
handleBitnamiImages(path.Dir(input.FilePath), bom)
}
// FilePath for apps with aggregatingTypes is empty.
// Set the SBOM file path as Application.FilePath to correctly overwrite applications when merging layers.
for i, app := range bom.Applications {
if slices.Contains(ftypes.AggregatingTypes, app.Type) && app.FilePath == "" {
bom.Applications[i].FilePath = input.FilePath
}
}
return &analyzer.AnalysisResult{
PackageInfos: bom.Packages,
Applications: bom.Applications,

View File

@@ -28,7 +28,34 @@ func Test_sbomAnalyzer_Analyze(t *testing.T) {
want: &analyzer.AnalysisResult{
Applications: []types.Application{
{
Type: types.Jar,
Type: types.Bitnami,
FilePath: "opt/bitnami/elasticsearch",
Packages: types.Packages{
{
ID: "elasticsearch@8.9.1",
Name: "elasticsearch",
Version: "8.9.1",
Arch: "arm64",
Licenses: []string{"Elastic-2.0"},
Identifier: types.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: packageurl.TypeBitnami,
Name: "elasticsearch",
Version: "8.9.1",
Qualifiers: packageurl.Qualifiers{
{
Key: "arch",
Value: "arm64",
},
},
},
},
},
},
},
{
Type: types.Jar,
FilePath: "opt/bitnami/elasticsearch/.spdx-elasticsearch.spdx",
Packages: types.Packages{
{
ID: "co.elastic.apm:apm-agent:1.36.0",
@@ -88,32 +115,6 @@ func Test_sbomAnalyzer_Analyze(t *testing.T) {
},
},
},
{
Type: types.Bitnami,
FilePath: "opt/bitnami/elasticsearch",
Packages: types.Packages{
{
ID: "elasticsearch@8.9.1",
Name: "elasticsearch",
Version: "8.9.1",
Arch: "arm64",
Licenses: []string{"Elastic-2.0"},
Identifier: types.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: packageurl.TypeBitnami,
Name: "elasticsearch",
Version: "8.9.1",
Qualifiers: packageurl.Qualifiers{
{
Key: "arch",
Value: "arm64",
},
},
},
},
},
},
},
},
},
wantErr: require.NoError,
@@ -125,7 +126,8 @@ func Test_sbomAnalyzer_Analyze(t *testing.T) {
want: &analyzer.AnalysisResult{
Applications: []types.Application{
{
Type: types.Jar,
Type: types.Jar,
FilePath: "opt/bitnami/elasticsearch/.spdx-elasticsearch.cdx",
Packages: types.Packages{
{
FilePath: "opt/bitnami/elasticsearch/modules/apm/elastic-apm-agent-1.36.0.jar",

View File

@@ -262,6 +262,19 @@ func shouldTryOtherRepo(err error) bool {
}
}
// try the following artifact only if a temporary error occurs
return terr.Temporary()
// try the following artifact if a temporary error occurs
if terr.Temporary() {
return true
}
// `GCR` periodically returns `BLOB_UNKNOWN` error.
// cf. https://github.com/aquasecurity/trivy/discussions/8020
// In this case we need to check other repositories.
for _, e := range terr.Errors {
if e.Code == transport.BlobUnknownErrorCode {
return true
}
}
return false
}

View File

@@ -559,7 +559,6 @@ func TestMarshaler_MarshalReport(t *testing.T) {
{
Ref: "3ff14136-e09f-4df9-80ea-000000000004",
Dependencies: &[]string{
"3ff14136-e09f-4df9-80ea-000000000005",
"pkg:gem/actioncontroller@7.0.0",
},
},
@@ -1123,8 +1122,6 @@ func TestMarshaler_MarshalReport(t *testing.T) {
Ref: "3ff14136-e09f-4df9-80ea-000000000002",
Dependencies: &[]string{
"pkg:rpm/centos/acl@2.2.53-1.el8?arch=aarch64&distro=centos-8.3.2011&epoch=1",
// Trivy is unable to identify the direct OS packages as of today.
"pkg:rpm/centos/glibc@2.28-151.el8?arch=aarch64&distro=centos-8.3.2011",
},
},
{

View File

@@ -0,0 +1,172 @@
{
"$schema": "http://cyclonedx.org/schema/bom-1.6.schema.json",
"bomFormat": "CycloneDX",
"specVersion": "1.6",
"serialNumber": "urn:uuid:12346a7a-5819-43bf-9411-5c146304f023",
"version": 1,
"metadata": {
"timestamp": "2024-12-20T10:57:13+00:00",
"tools": {
"components": [
{
"type": "application",
"group": "aquasecurity",
"name": "trivy",
"version": "0.38.7-764-g30c7cb137"
}
]
},
"component": {
"bom-ref": "1cb40520-a22c-481f-ad77-6bc6960430c5",
"type": "application",
"name": "/test",
"properties": [
{
"name": "aquasecurity:trivy:SchemaVersion",
"value": "2"
}
]
}
},
"components": [
{
"bom-ref": "4021d631-e242-4e69-8a93-928665810a27",
"type": "application",
"name": "foo/bar/test.elf",
"properties": [
{
"name": "aquasecurity:trivy:Class",
"value": "lang-pkgs"
},
{
"name": "aquasecurity:trivy:Type",
"value": "gobinary"
}
]
},
{
"bom-ref": "pkg:golang/github.com/aquasecurity/go-pep440-version@v0.0.0-20210121094942-22b2f8951d46",
"type": "library",
"name": "github.com/aquasecurity/go-pep440-version",
"version": "v0.0.0-20210121094942-22b2f8951d46",
"purl": "pkg:golang/github.com/aquasecurity/go-pep440-version@v0.0.0-20210121094942-22b2f8951d46",
"properties": [
{
"name": "aquasecurity:trivy:PkgID",
"value": "github.com/aquasecurity/go-pep440-version@v0.0.0-20210121094942-22b2f8951d46"
},
{
"name": "aquasecurity:trivy:PkgType",
"value": "gobinary"
}
]
},
{
"bom-ref": "pkg:golang/github.com/aquasecurity/go-version@v0.0.0-20210121072130-637058cfe492",
"type": "library",
"name": "github.com/aquasecurity/go-version",
"version": "v0.0.0-20210121072130-637058cfe492",
"purl": "pkg:golang/github.com/aquasecurity/go-version@v0.0.0-20210121072130-637058cfe492",
"properties": [
{
"name": "aquasecurity:trivy:PkgID",
"value": "github.com/aquasecurity/go-version@v0.0.0-20210121072130-637058cfe492"
},
{
"name": "aquasecurity:trivy:PkgType",
"value": "gobinary"
}
]
},
{
"bom-ref": "pkg:golang/github.com/aquasecurity/test",
"type": "library",
"name": "github.com/aquasecurity/test",
"purl": "pkg:golang/github.com/aquasecurity/test",
"properties": [
{
"name": "aquasecurity:trivy:PkgID",
"value": "github.com/aquasecurity/test"
},
{
"name": "aquasecurity:trivy:PkgType",
"value": "gobinary"
}
]
},
{
"bom-ref": "pkg:golang/golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1",
"type": "library",
"name": "golang.org/x/xerrors",
"version": "v0.0.0-20200804184101-5ec99f83aff1",
"purl": "pkg:golang/golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1",
"properties": [
{
"name": "aquasecurity:trivy:PkgID",
"value": "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1"
},
{
"name": "aquasecurity:trivy:PkgType",
"value": "gobinary"
}
]
},
{
"bom-ref": "pkg:golang/stdlib@v1.15.2",
"type": "library",
"name": "stdlib",
"version": "v1.15.2",
"purl": "pkg:golang/stdlib@v1.15.2",
"properties": [
{
"name": "aquasecurity:trivy:PkgID",
"value": "stdlib@v1.15.2"
},
{
"name": "aquasecurity:trivy:PkgType",
"value": "gobinary"
}
]
}
],
"dependencies": [
{
"ref": "1cb40520-a22c-481f-ad77-6bc6960430c5",
"dependsOn": [
"4021d631-e242-4e69-8a93-928665810a27"
]
},
{
"ref": "4021d631-e242-4e69-8a93-928665810a27",
"dependsOn": [
"pkg:golang/github.com/aquasecurity/test"
]
},
{
"ref": "pkg:golang/github.com/aquasecurity/go-pep440-version@v0.0.0-20210121094942-22b2f8951d46",
"dependsOn": []
},
{
"ref": "pkg:golang/github.com/aquasecurity/go-version@v0.0.0-20210121072130-637058cfe492",
"dependsOn": []
},
{
"ref": "pkg:golang/github.com/aquasecurity/test",
"dependsOn": [
"pkg:golang/github.com/aquasecurity/go-pep440-version@v0.0.0-20210121094942-22b2f8951d46",
"pkg:golang/github.com/aquasecurity/go-version@v0.0.0-20210121072130-637058cfe492",
"pkg:golang/golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1",
"pkg:golang/stdlib@v1.15.2"
]
},
{
"ref": "pkg:golang/golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1",
"dependsOn": []
},
{
"ref": "pkg:golang/stdlib@v1.15.2",
"dependsOn": []
}
],
"vulnerabilities": []
}

View File

@@ -668,6 +668,93 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
},
},
},
{
name: "happy path for BOM with nested packages",
inputFile: "testdata/happy/nested-packages-bom.json",
want: types.SBOM{
Applications: []ftypes.Application{
{
Type: "gobinary",
FilePath: "foo/bar/test.elf",
Packages: ftypes.Packages{
{
ID: "github.com/aquasecurity/test",
Name: "github.com/aquasecurity/test",
Identifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: packageurl.TypeGolang,
Namespace: "github.com/aquasecurity",
Name: "test",
},
BOMRef: "pkg:golang/github.com/aquasecurity/test",
},
DependsOn: []string{
"github.com/aquasecurity/go-pep440-version@v0.0.0-20210121094942-22b2f8951d46",
"github.com/aquasecurity/go-version@v0.0.0-20210121072130-637058cfe492",
"golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1",
"stdlib@v1.15.2",
},
},
{
ID: "github.com/aquasecurity/go-pep440-version@v0.0.0-20210121094942-22b2f8951d46",
Name: "github.com/aquasecurity/go-pep440-version",
Version: "v0.0.0-20210121094942-22b2f8951d46",
Identifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: packageurl.TypeGolang,
Namespace: "github.com/aquasecurity",
Name: "go-pep440-version",
Version: "v0.0.0-20210121094942-22b2f8951d46",
},
BOMRef: "pkg:golang/github.com/aquasecurity/go-pep440-version@v0.0.0-20210121094942-22b2f8951d46",
},
},
{
ID: "github.com/aquasecurity/go-version@v0.0.0-20210121072130-637058cfe492",
Name: "github.com/aquasecurity/go-version",
Version: "v0.0.0-20210121072130-637058cfe492",
Identifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: packageurl.TypeGolang,
Namespace: "github.com/aquasecurity",
Name: "go-version",
Version: "v0.0.0-20210121072130-637058cfe492",
},
BOMRef: "pkg:golang/github.com/aquasecurity/go-version@v0.0.0-20210121072130-637058cfe492",
},
},
{
ID: "golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1",
Name: "golang.org/x/xerrors",
Version: "v0.0.0-20200804184101-5ec99f83aff1",
Identifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: packageurl.TypeGolang,
Namespace: "golang.org/x",
Name: "xerrors",
Version: "v0.0.0-20200804184101-5ec99f83aff1",
},
BOMRef: "pkg:golang/golang.org/x/xerrors@v0.0.0-20200804184101-5ec99f83aff1",
},
},
{
ID: "stdlib@v1.15.2",
Name: "stdlib",
Version: "v1.15.2",
Identifier: ftypes.PkgIdentifier{
PURL: &packageurl.PackageURL{
Type: packageurl.TypeGolang,
Name: "stdlib",
Version: "v1.15.2",
},
BOMRef: "pkg:golang/stdlib@v1.15.2",
},
},
},
},
},
},
},
{
name: "happy path only os component",
inputFile: "testdata/happy/os-only-bom.json",

View File

@@ -330,15 +330,7 @@ func (m *Decoder) parseSrcVersion(ctx context.Context, pkg *ftypes.Package, ver
// addOSPkgs traverses relationships and adds OS packages
func (m *Decoder) addOSPkgs(sbom *types.SBOM) {
var pkgs []ftypes.Package
for _, rel := range m.bom.Relationships()[m.osID] {
pkg, ok := m.pkgs[rel.Dependency]
if !ok {
continue
}
pkgs = append(pkgs, *pkg)
delete(m.pkgs, rel.Dependency) // Delete the added package
}
pkgs := m.traverseDependencies(m.osID)
if len(pkgs) == 0 {
return
}
@@ -348,18 +340,33 @@ func (m *Decoder) addOSPkgs(sbom *types.SBOM) {
// addLangPkgs traverses relationships and adds language-specific packages
func (m *Decoder) addLangPkgs(sbom *types.SBOM) {
for id, app := range m.apps {
for _, rel := range m.bom.Relationships()[id] {
pkg, ok := m.pkgs[rel.Dependency]
if !ok {
continue
}
app.Packages = append(app.Packages, *pkg)
delete(m.pkgs, rel.Dependency) // Delete the added package
}
app.Packages = append(app.Packages, m.traverseDependencies(id)...)
sbom.Applications = append(sbom.Applications, *app)
}
}
// traverseDependencies recursively retrieves all packages that the specified component depends on.
// It starts from the given component ID and traverses the dependency tree, collecting all
// dependent packages. The collected packages are removed from m.pkgs to prevent duplicate
// processing. This ensures that all dependencies, including transitive ones, are properly
// captured and associated with their parent component.
func (m *Decoder) traverseDependencies(id uuid.UUID) ftypes.Packages {
var pkgs ftypes.Packages
for _, rel := range m.bom.Relationships()[id] {
pkg, ok := m.pkgs[rel.Dependency]
if !ok {
continue
}
// Add the current package
pkgs = append(pkgs, *pkg)
delete(m.pkgs, rel.Dependency) // Delete the added package
// Add the nested packages
pkgs = append(pkgs, m.traverseDependencies(rel.Dependency)...)
}
return pkgs
}
// addOrphanPkgs adds orphan packages.
// Orphan packages are packages that are not related to any components.
func (m *Decoder) addOrphanPkgs(ctx context.Context, sbom *types.SBOM) error {

View File

@@ -417,18 +417,10 @@ func (*Encoder) belongToParent(pkg ftypes.Package, parents map[string]ftypes.Pac
// All packages are included in the parent
// Case 3: Relationship: known , DependsOn: unknown (e.g., go.mod without $GOPATH)
// All packages are included in the parent
// Case 4: Relationship: unknown, DependsOn: known (e.g., OS packages)
// All packages are included in the parent even if they have parents
switch {
// Case 1, 2 and 3
case len(parents[pkg.ID]) == 0:
return true
// Case 4
case pkg.Relationship == ftypes.RelationshipUnknown:
return true
default:
return false
}
// Case 4: Relationship: unknown, DependsOn: known (e.g., GoBinaries, OS packages)
// - Packages with parents: false. These packages are included in the packages from `parents` (e.g. GoBinaries deps and root package).
// - Packages without parents: true. These packages are included in the parent (e.g. OS packages without parents).
return len(parents[pkg.ID]) == 0
}
func filterProperties(props []core.Property) []core.Property {

View File

@@ -171,6 +171,61 @@ func TestEncoder_Encode(t *testing.T) {
},
},
},
{
Target: "trivy",
Type: ftypes.GoBinary,
Class: types.ClassLangPkg,
Packages: []ftypes.Package{
{
ID: "github.com/aquasecurity/trivy@v0.57.1",
Name: "github.com/aquasecurity/trivy",
Version: "v0.57.1",
Identifier: ftypes.PkgIdentifier{
UID: "106fee7e57f0b952",
PURL: &packageurl.PackageURL{
Type: packageurl.TypeGolang,
Namespace: "github.com/aquasecurity",
Name: "trivy",
Version: "v0.57.1",
},
},
Relationship: ftypes.RelationshipRoot,
DependsOn: []string{
"github.com/aquasecurity/go-version@v0.0.0-20240603093900-cf8a8d29271d",
"stdlib@v1.22.9",
},
},
{
ID: "stdlib@v1.22.9",
Name: "stdlib",
Version: "v1.22.9",
Identifier: ftypes.PkgIdentifier{
UID: "62e7c8aaebd94b1e",
PURL: &packageurl.PackageURL{
Type: packageurl.TypeGolang,
Name: "stdlib",
Version: "v1.22.9",
},
},
Relationship: ftypes.RelationshipDirect,
},
{
ID: "github.com/aquasecurity/go-version@v0.0.0-20240603093900-cf8a8d29271d",
Name: "github.com/aquasecurity/go-version",
Version: "v0.0.0-20240603093900-cf8a8d29271d",
Identifier: ftypes.PkgIdentifier{
UID: "350aed171d8ebed5",
PURL: &packageurl.PackageURL{
Type: packageurl.TypeGolang,
Namespace: "github.com/aquasecurity",
Name: "go-version",
Version: "v0.0.0-20240603093900-cf8a8d29271d",
},
},
Relationship: ftypes.RelationshipUnknown,
},
},
},
},
},
wantComponents: map[uuid.UUID]*core.Component{
@@ -351,6 +406,100 @@ func TestEncoder_Encode(t *testing.T) {
BOMRef: "3ff14136-e09f-4df9-80ea-000000000006",
},
},
uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000007"): {
Type: core.TypeApplication,
Name: "trivy",
Properties: []core.Property{
{
Name: core.PropertyClass,
Value: "lang-pkgs",
},
{
Name: core.PropertyType,
Value: "gobinary",
},
},
PkgIdentifier: ftypes.PkgIdentifier{
BOMRef: "3ff14136-e09f-4df9-80ea-000000000007",
},
},
uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000008"): {
Type: core.TypeLibrary,
Name: "github.com/aquasecurity/trivy",
Version: "v0.57.1",
SrcFile: "trivy",
Properties: []core.Property{
{
Name: core.PropertyPkgID,
Value: "github.com/aquasecurity/trivy@v0.57.1",
},
{
Name: core.PropertyPkgType,
Value: "gobinary",
},
},
PkgIdentifier: ftypes.PkgIdentifier{
UID: "106fee7e57f0b952",
PURL: &packageurl.PackageURL{
Type: packageurl.TypeGolang,
Namespace: "github.com/aquasecurity",
Name: "trivy",
Version: "v0.57.1",
},
BOMRef: "pkg:golang/github.com/aquasecurity/trivy@v0.57.1",
},
},
uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000009"): {
Type: core.TypeLibrary,
Name: "stdlib",
Version: "v1.22.9",
SrcFile: "trivy",
Properties: []core.Property{
{
Name: core.PropertyPkgID,
Value: "stdlib@v1.22.9",
},
{
Name: core.PropertyPkgType,
Value: "gobinary",
},
},
PkgIdentifier: ftypes.PkgIdentifier{
UID: "62e7c8aaebd94b1e",
PURL: &packageurl.PackageURL{
Type: packageurl.TypeGolang,
Name: "stdlib",
Version: "v1.22.9",
},
BOMRef: "pkg:golang/stdlib@v1.22.9",
},
},
uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000010"): {
Type: core.TypeLibrary,
Name: "github.com/aquasecurity/go-version",
Version: "v0.0.0-20240603093900-cf8a8d29271d",
SrcFile: "trivy",
Properties: []core.Property{
{
Name: core.PropertyPkgID,
Value: "github.com/aquasecurity/go-version@v0.0.0-20240603093900-cf8a8d29271d",
},
{
Name: core.PropertyPkgType,
Value: "gobinary",
},
},
PkgIdentifier: ftypes.PkgIdentifier{
UID: "350aed171d8ebed5",
PURL: &packageurl.PackageURL{
Type: packageurl.TypeGolang,
Namespace: "github.com/aquasecurity",
Name: "go-version",
Version: "v0.0.0-20240603093900-cf8a8d29271d",
},
BOMRef: "pkg:golang/github.com/aquasecurity/go-version@v0.0.0-20240603093900-cf8a8d29271d",
},
},
},
wantRels: map[uuid.UUID][]core.Relationship{
uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000001"): {
@@ -366,12 +515,12 @@ func TestEncoder_Encode(t *testing.T) {
Dependency: uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000006"),
Type: core.RelationshipContains,
},
},
uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000002"): {
{
Dependency: uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000003"),
Dependency: uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000007"),
Type: core.RelationshipContains,
},
},
uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000002"): {
{
Dependency: uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000004"),
Type: core.RelationshipContains,
@@ -386,6 +535,24 @@ func TestEncoder_Encode(t *testing.T) {
},
uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000005"): nil,
uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000006"): nil,
uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000007"): {
{
Dependency: uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000008"),
Type: core.RelationshipContains,
},
},
uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000008"): {
{
Dependency: uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000010"),
Type: core.RelationshipDependsOn,
},
{
Dependency: uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000009"),
Type: core.RelationshipDependsOn,
},
},
uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000009"): nil,
uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000010"): nil,
},
wantVulns: map[uuid.UUID][]core.Vulnerability{
uuid.MustParse("3ff14136-e09f-4df9-80ea-000000000004"): {