mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-21 23:00:42 -08:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9aa9e173bf | ||
|
|
058f4839db | ||
|
|
9e3d2c5f95 | ||
|
|
2ad8e332e8 | ||
|
|
5f69937cc6 | ||
|
|
258d153461 | ||
|
|
ade033a837 | ||
|
|
f85c9fac6f | ||
|
|
9d7f5c948e | ||
|
|
f148eb10f2 | ||
|
|
97f95c4ddf | ||
|
|
abd62ae74e | ||
|
|
7c409fd270 | ||
|
|
1b68327b65 | ||
|
|
a2482c14e1 | ||
|
|
e866bd5b5d | ||
|
|
1870f28461 | ||
|
|
6c81e5505e |
6
.github/workflows/reusable-release.yaml
vendored
6
.github/workflows/reusable-release.yaml
vendored
@@ -90,6 +90,11 @@ jobs:
|
||||
run: |
|
||||
echo "$GPG_KEY" > gpg.key
|
||||
|
||||
# Create tmp dir for GoReleaser
|
||||
- name: "create tmp dir"
|
||||
run: |
|
||||
mkdir tmp
|
||||
|
||||
- name: GoReleaser
|
||||
uses: goreleaser/goreleaser-action@v5
|
||||
with:
|
||||
@@ -99,6 +104,7 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.ORG_REPO_TOKEN }}
|
||||
NFPM_DEFAULT_RPM_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }}
|
||||
GPG_FILE: "gpg.key"
|
||||
TMPDIR: "tmp"
|
||||
|
||||
- name: "remove gpg key"
|
||||
run: |
|
||||
|
||||
@@ -73,8 +73,11 @@
|
||||
{{- /* TODO: Type not extractable - https://github.com/aquasecurity/trivy-db/pull/24 */}}
|
||||
"type": "cve",
|
||||
"name": "{{ .VulnerabilityID }}",
|
||||
"value": "{{ .VulnerabilityID }}",
|
||||
"value": "{{ .VulnerabilityID }}"
|
||||
{{- /* cf. https://gitlab.com/gitlab-org/security-products/security-report-schemas/-/blob/e3d280d7f0862ca66a1555ea8b24016a004bb914/dist/container-scanning-report-format.json#L157-179 */}}
|
||||
{{- if .PrimaryURL | regexMatch "^(https?|ftp)://.+" -}},
|
||||
"url": "{{ .PrimaryURL }}"
|
||||
{{- end }}
|
||||
}
|
||||
],
|
||||
"links": [
|
||||
@@ -85,9 +88,13 @@
|
||||
{{- else -}}
|
||||
,
|
||||
{{- end -}}
|
||||
{{- if . | regexMatch "^(https?|ftp)://.+" -}}
|
||||
{
|
||||
"url": "{{ regexFind "[^ ]+" . }}"
|
||||
"url": "{{ . }}"
|
||||
}
|
||||
{{- else -}}
|
||||
{{- $l_first = true }}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -8,14 +8,15 @@ Trivy scans Infrastructure as Code (IaC) files for
|
||||
|
||||
## Supported configurations
|
||||
|
||||
| Config type | File patterns |
|
||||
|-------------------------------------|-------------------------------|
|
||||
| [Kubernetes](kubernetes.md) | *.yml, *.yaml, *.json |
|
||||
| [Docker](docker.md) | Dockerfile, Containerfile |
|
||||
| [Terraform](terraform.md) | *.tf, *.tf.json, *.tfvars, |
|
||||
| [CloudFormation](cloudformation.md) | *.yml, *.yaml, *.json |
|
||||
| [Azure ARM Template](azure-arm.md) | *.json |
|
||||
| [Helm](helm.md) | *.yaml, *.tpl, *.tar.gz, etc. |
|
||||
| Config type | File patterns |
|
||||
|-------------------------------------|-----------------------------------------------|
|
||||
| [Kubernetes](kubernetes.md) | \*.yml, \*.yaml, \*.json |
|
||||
| [Docker](docker.md) | Dockerfile, Containerfile |
|
||||
| [Terraform](terraform.md) | \*.tf, \*.tf.json, \*.tfvars |
|
||||
| [Terraform Plan](terraform.md) | tfplan, \*.tfplan, \*.tfplan.json, \*.tf.json |
|
||||
| [CloudFormation](cloudformation.md) | \*.yml, \*.yaml, \*.json |
|
||||
| [Azure ARM Template](azure-arm.md) | \*.json |
|
||||
| [Helm](helm.md) | \*.yaml, \*.tpl, \*.tar.gz, etc. |
|
||||
|
||||
[misconf]: ../../scanner/misconfiguration/index.md
|
||||
[secret]: ../../scanner/secret.md
|
||||
|
||||
@@ -42,7 +42,19 @@ Trivy parses your `pom.xml` file and tries to find files with dependencies from
|
||||
- relativePath field[^5]
|
||||
- local repository directory[^6].
|
||||
|
||||
If your machine doesn't have the necessary files - Trivy tries to find the information about these dependencies in the [maven repository](https://repo.maven.apache.org/maven2/).
|
||||
### remote repositories
|
||||
If your machine doesn't have the necessary files - Trivy tries to find the information about these dependencies in the remote repositories:
|
||||
|
||||
- [repositories from pom files][maven-pom-repos]
|
||||
- [maven central repository][maven-central]
|
||||
|
||||
Trivy reproduces Maven's repository selection and priority:
|
||||
|
||||
- for snapshot artifacts:
|
||||
- check only snapshot repositories from pom files (if exists)
|
||||
- for other artifacts:
|
||||
- check release repositories from pom files (if exists)
|
||||
- check [maven central][maven-central]
|
||||
|
||||
!!! Note
|
||||
Trivy only takes information about packages. We don't take a list of vulnerabilities for packages from the `maven repository`.
|
||||
@@ -92,4 +104,6 @@ Make sure that you have cache[^8] directory to find licenses from `*.pom` depend
|
||||
[^8]: The supported directories are `$GRADLE_USER_HOME/caches` and `$HOME/.gradle/caches` (`%HOMEPATH%\.gradle\caches` for Windows).
|
||||
|
||||
[dependency-graph]: ../../configuration/reporting.md#show-origins-of-vulnerable-dependencies
|
||||
[maven-invoker-plugin]: https://maven.apache.org/plugins/maven-invoker-plugin/usage.html
|
||||
[maven-invoker-plugin]: https://maven.apache.org/plugins/maven-invoker-plugin/usage.html
|
||||
[maven-central]: https://repo.maven.apache.org/maven2/
|
||||
[maven-pom-repos]: https://maven.apache.org/settings.html#repositories
|
||||
@@ -22,17 +22,15 @@ Check out [the coverage document][coverage] for details.
|
||||
To enable extended license scanning, you can use `--license-full`.
|
||||
In addition to package licenses, Trivy scans source code files, Markdown documents, text files and `LICENSE` documents to identify license usage within the image or filesystem.
|
||||
|
||||
By default, Trivy only classifies licenses that are matched with a confidence level of 0.9 or more by the classifer.
|
||||
By default, Trivy only classifies licenses that are matched with a confidence level of 0.9 or more by the classifier.
|
||||
To configure the confidence level, you can use `--license-confidence-level`. This enables us to classify licenses that might be matched with a lower confidence level by the classifer.
|
||||
|
||||
!!! note
|
||||
The full license scanning is expensive. It takes a while.
|
||||
|
||||
Currently, the standard license scanning doesn't support filesystem and repository scanning.
|
||||
|
||||
| License scanning | Image | Rootfs | Filesystem | Repository | SBOM |
|
||||
|:---------------------:|:-----:|:------:|:----------:|:----------:|:----:|
|
||||
| Standard | ✅ | ✅ | - | - | ✅ |
|
||||
| Standard | ✅ | ✅ | ✅[^1][^2] | ✅[^1][^2] | ✅ |
|
||||
| Full (--license-full) | ✅ | ✅ | ✅ | ✅ | - |
|
||||
|
||||
License checking classifies the identified licenses and map the classification to severity.
|
||||
@@ -344,6 +342,8 @@ license:
|
||||
permissive: []
|
||||
```
|
||||
|
||||
[^1]: See the list of supported language files [here](../coverage/language/index.md).
|
||||
[^2]: Some lock files require additional files (e.g. files from the cache directory) to detect licenses. Check [coverage][coverage] for more information.
|
||||
|
||||
[coverage]: ../coverage/index.md
|
||||
[google-license-classification]: https://opensource.google/documentation/reference/thirdparty/licenses
|
||||
|
||||
16
go.mod
16
go.mod
@@ -40,7 +40,7 @@ require (
|
||||
github.com/cheggaaa/pb/v3 v3.1.4
|
||||
github.com/containerd/containerd v1.7.13
|
||||
github.com/csaf-poc/csaf_distribution/v3 v3.0.0
|
||||
github.com/docker/docker v25.0.3+incompatible
|
||||
github.com/docker/docker v25.0.5+incompatible
|
||||
github.com/docker/go-connections v0.5.0
|
||||
github.com/fatih/color v1.16.0
|
||||
github.com/go-git/go-git/v5 v5.11.0
|
||||
@@ -52,8 +52,8 @@ require (
|
||||
github.com/google/go-containerregistry v0.19.0
|
||||
github.com/google/licenseclassifier/v2 v2.0.0
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/google/wire v0.5.0
|
||||
github.com/hashicorp/go-getter v1.7.3
|
||||
github.com/google/wire v0.6.0
|
||||
github.com/hashicorp/go-getter v1.7.4
|
||||
github.com/hashicorp/go-multierror v1.1.1
|
||||
github.com/hashicorp/go-retryablehttp v0.7.5
|
||||
github.com/hashicorp/golang-lru/v2 v2.0.6
|
||||
@@ -107,9 +107,9 @@ require (
|
||||
go.uber.org/zap v1.27.0
|
||||
golang.org/x/exp v0.0.0-20231110203233-9a3e6036ecaa
|
||||
golang.org/x/mod v0.15.0
|
||||
golang.org/x/net v0.21.0
|
||||
golang.org/x/net v0.23.0
|
||||
golang.org/x/sync v0.6.0
|
||||
golang.org/x/term v0.17.0
|
||||
golang.org/x/term v0.18.0
|
||||
golang.org/x/text v0.14.0
|
||||
golang.org/x/xerrors v0.0.0-20220907171357-04be3eba64a2
|
||||
google.golang.org/protobuf v1.33.0
|
||||
@@ -136,7 +136,7 @@ require (
|
||||
github.com/owenrumney/squealer v1.2.2
|
||||
github.com/zclconf/go-cty v1.14.1
|
||||
github.com/zclconf/go-cty-yaml v1.0.3
|
||||
golang.org/x/crypto v0.19.0
|
||||
golang.org/x/crypto v0.21.0
|
||||
helm.sh/helm/v3 v3.14.2
|
||||
)
|
||||
|
||||
@@ -388,9 +388,9 @@ require (
|
||||
go.starlark.net v0.0.0-20230525235612-a134d8f9ddca // indirect
|
||||
go.uber.org/multierr v1.11.0 // indirect
|
||||
golang.org/x/oauth2 v0.16.0 // indirect
|
||||
golang.org/x/sys v0.17.0 // indirect
|
||||
golang.org/x/sys v0.18.0 // indirect
|
||||
golang.org/x/time v0.5.0 // indirect
|
||||
golang.org/x/tools v0.16.1 // indirect
|
||||
golang.org/x/tools v0.17.0 // indirect
|
||||
google.golang.org/api v0.155.0 // indirect
|
||||
google.golang.org/appengine v1.6.8 // indirect
|
||||
google.golang.org/genproto v0.0.0-20240123012728-ef4313101c80 // indirect
|
||||
|
||||
55
go.sum
55
go.sum
@@ -717,8 +717,8 @@ github.com/docker/distribution v2.8.3+incompatible h1:AtKxIZ36LoNK51+Z6RpzLpddBi
|
||||
github.com/docker/distribution v2.8.3+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
|
||||
github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v23.0.0-rc.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v25.0.3+incompatible h1:D5fy/lYmY7bvZa0XTZ5/UJPljor41F+vdyJG5luQLfQ=
|
||||
github.com/docker/docker v25.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker v25.0.5+incompatible h1:UmQydMduGkrD5nQde1mecF/YnSbTOaPeFIeP5C4W+DE=
|
||||
github.com/docker/docker v25.0.5+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
|
||||
github.com/docker/docker-credential-helpers v0.6.3/go.mod h1:WRaJzqw3CTB9bk10avuGsjVBZsD05qeibJ1/TYlvc0Y=
|
||||
github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A=
|
||||
github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0=
|
||||
@@ -1016,7 +1016,7 @@ github.com/google/s2a-go v0.1.7 h1:60BLSyTrOV4/haCDW4zb1guZItoSq8foHCXrAnjBo/o=
|
||||
github.com/google/s2a-go v0.1.7/go.mod h1:50CgR4k1jNlWBu4UfS4AcfhVe1r6pdZPygJ3R8F0Qdw=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
|
||||
github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||
github.com/google/subcommands v1.2.0/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk=
|
||||
github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
@@ -1024,8 +1024,8 @@ github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+
|
||||
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||
github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8=
|
||||
github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU=
|
||||
github.com/google/wire v0.6.0 h1:HBkoIh4BdSxoyo9PveV8giw7ZsaBOvzWKfcg/6MrVwI=
|
||||
github.com/google/wire v0.6.0/go.mod h1:F4QhpQ9EDIdJ1Mbop/NZBRB+5yrR6qg3BnctaoUk6NA=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.0.0-20220520183353-fd19c99a87aa/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.1.0/go.mod h1:17drOmN3MwGY7t0e+Ei9b45FFGA3fBs3x36SsCg1hq8=
|
||||
github.com/googleapis/enterprise-certificate-proxy v0.2.0/go.mod h1:8C0jb7/mgJe/9KK8Lm7X9ctZC2t60YyIpYEI16jx0Qg=
|
||||
@@ -1081,8 +1081,8 @@ github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brv
|
||||
github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ=
|
||||
github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48=
|
||||
github.com/hashicorp/go-getter v1.7.3 h1:bN2+Fw9XPFvOCjB0UOevFIMICZ7G2XSQHzfvLUyOM5E=
|
||||
github.com/hashicorp/go-getter v1.7.3/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744=
|
||||
github.com/hashicorp/go-getter v1.7.4 h1:3yQjWuxICvSpYwqSayAdKRFcvBl1y/vogCxczWSmix0=
|
||||
github.com/hashicorp/go-getter v1.7.4/go.mod h1:W7TalhMmbPmsSMdNjD0ZskARur/9GJ17cfHTRtXV744=
|
||||
github.com/hashicorp/go-hclog v0.9.2/go.mod h1:5CU+agLiy3J7N7QjHK5d05KxGsuXiQLrjA0H7acj2lQ=
|
||||
github.com/hashicorp/go-hclog v1.5.0 h1:bI2ocEMgcVlz55Oj1xZNBsVi900c7II+fWDyV9o+13c=
|
||||
github.com/hashicorp/go-hclog v1.5.0/go.mod h1:W4Qnvbt70Wk/zYJryRzDRU/4r0kIg0PVHBcfoyhpF5M=
|
||||
@@ -1774,8 +1774,10 @@ golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0
|
||||
golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
|
||||
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
|
||||
golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
|
||||
golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo=
|
||||
golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU=
|
||||
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.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA=
|
||||
golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs=
|
||||
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=
|
||||
@@ -1814,6 +1816,9 @@ golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
||||
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
|
||||
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
|
||||
golang.org/x/mod v0.14.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8=
|
||||
golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
|
||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
@@ -1882,8 +1887,11 @@ golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
|
||||
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
|
||||
golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
|
||||
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||
golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4=
|
||||
golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
|
||||
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.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
|
||||
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
|
||||
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=
|
||||
@@ -1926,6 +1934,8 @@ golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJ
|
||||
golang.org/x/sync v0.0.0-20220601150217-0de741cfad7f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
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 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
|
||||
golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -2046,8 +2056,11 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.17.0 h1:25cE3gD+tdBA7lp7QfhuV+rJiE9YXTcS3VG1SqssI/Y=
|
||||
golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/sys v0.8.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.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
|
||||
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
@@ -2055,8 +2068,11 @@ golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
|
||||
golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
|
||||
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
|
||||
golang.org/x/term v0.17.0 h1:mkTF7LCd6WGJNL3K1Ad7kwxNfYAW6a8a8QqtMblp/4U=
|
||||
golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk=
|
||||
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.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8=
|
||||
golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58=
|
||||
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=
|
||||
@@ -2070,6 +2086,8 @@ golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ=
|
||||
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||
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 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||
golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||
@@ -2088,7 +2106,6 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3
|
||||
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
||||
@@ -2140,8 +2157,10 @@ golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.4/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
|
||||
golang.org/x/tools v0.16.1 h1:TLyB3WofjdOEepBHAU20JdNC1Zbg87elYofWYAY5oZA=
|
||||
golang.org/x/tools v0.16.1/go.mod h1:kYVVN6I1mBNoB1OX+noeBjbRk4IUEPa7JJ+TJMEooJ0=
|
||||
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
|
||||
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
|
||||
golang.org/x/tools v0.17.0 h1:FvmRgNOcs3kOa+T20R1uhfP9F6HgG2mfxDv1vrx1Htc=
|
||||
golang.org/x/tools v0.17.0/go.mod h1:xsh6VxdV005rRVaS6SSAf9oiAqljS7UZUacMZ8Bnsps=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
|
||||
@@ -242,6 +242,16 @@ func TestClientServer(t *testing.T) {
|
||||
},
|
||||
golden: "testdata/pom.json.golden",
|
||||
},
|
||||
{
|
||||
name: "scan package-lock.json with repo command in client/server mode",
|
||||
args: csArgs{
|
||||
Command: "repo",
|
||||
RemoteAddrOption: "--server",
|
||||
Target: "testdata/fixtures/repo/npm/",
|
||||
ListAllPackages: true,
|
||||
},
|
||||
golden: "testdata/npm.json.golden",
|
||||
},
|
||||
{
|
||||
name: "scan sample.pem with repo command in client/server mode",
|
||||
args: csArgs{
|
||||
@@ -588,6 +598,10 @@ func setupClient(t *testing.T, c csArgs, addr string, cacheDir string, golden st
|
||||
osArgs = append(osArgs, "--format", "json")
|
||||
}
|
||||
|
||||
if c.ListAllPackages {
|
||||
osArgs = append(osArgs, "--list-all-pkgs")
|
||||
}
|
||||
|
||||
if c.IgnoreUnfixed {
|
||||
osArgs = append(osArgs, "--ignore-unfixed")
|
||||
}
|
||||
|
||||
@@ -30,3 +30,4 @@
|
||||
19.04,Disco Dingo,disco,2018-10-18,2019-04-18,2020-01-18
|
||||
19.10,Eoan Ermine,eoan,2019-04-18,2019-10-17,2020-07-17
|
||||
20.04 LTS,Focal Fossa,focal,2020-04-23,2025-04-23,2030-04-23
|
||||
22.04 LTS,Jammy Jellyfish,jammy,2022-04-21,2027-04-21,2032-04-21
|
||||
|
||||
|
@@ -50,6 +50,7 @@ golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgw
|
||||
golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||
|
||||
@@ -31,8 +31,9 @@ const (
|
||||
)
|
||||
|
||||
type options struct {
|
||||
offline bool
|
||||
remoteRepos []string
|
||||
offline bool
|
||||
releaseRemoteRepos []string
|
||||
snapshotRemoteRepos []string
|
||||
}
|
||||
|
||||
type option func(*options)
|
||||
@@ -43,25 +44,26 @@ func WithOffline(offline bool) option {
|
||||
}
|
||||
}
|
||||
|
||||
func WithRemoteRepos(repos []string) option {
|
||||
func WithReleaseRemoteRepos(repos []string) option {
|
||||
return func(opts *options) {
|
||||
opts.remoteRepos = repos
|
||||
opts.releaseRemoteRepos = repos
|
||||
}
|
||||
}
|
||||
|
||||
type parser struct {
|
||||
rootPath string
|
||||
cache pomCache
|
||||
localRepository string
|
||||
remoteRepositories []string
|
||||
offline bool
|
||||
servers []Server
|
||||
rootPath string
|
||||
cache pomCache
|
||||
localRepository string
|
||||
releaseRemoteRepos []string
|
||||
snapshotRemoteRepos []string
|
||||
offline bool
|
||||
servers []Server
|
||||
}
|
||||
|
||||
func NewParser(filePath string, opts ...option) types.Parser {
|
||||
o := &options{
|
||||
offline: false,
|
||||
remoteRepos: []string{centralURL},
|
||||
offline: false,
|
||||
releaseRemoteRepos: []string{centralURL}, // Maven doesn't use central repository for snapshot dependencies
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
@@ -76,12 +78,13 @@ func NewParser(filePath string, opts ...option) types.Parser {
|
||||
}
|
||||
|
||||
return &parser{
|
||||
rootPath: filepath.Clean(filePath),
|
||||
cache: newPOMCache(),
|
||||
localRepository: localRepository,
|
||||
remoteRepositories: o.remoteRepos,
|
||||
offline: o.offline,
|
||||
servers: s.Servers,
|
||||
rootPath: filepath.Clean(filePath),
|
||||
cache: newPOMCache(),
|
||||
localRepository: localRepository,
|
||||
releaseRemoteRepos: o.releaseRemoteRepos,
|
||||
snapshotRemoteRepos: o.snapshotRemoteRepos,
|
||||
offline: o.offline,
|
||||
servers: s.Servers,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -105,10 +108,10 @@ func (p *parser) Parse(r xio.ReadSeekerAt) ([]types.Library, []types.Dependency,
|
||||
// Cache root POM
|
||||
p.cache.put(result.artifact, result)
|
||||
|
||||
return p.parseRoot(root.artifact())
|
||||
return p.parseRoot(root.artifact(), make(map[string]struct{}))
|
||||
}
|
||||
|
||||
func (p *parser) parseRoot(root artifact) ([]types.Library, []types.Dependency, error) {
|
||||
func (p *parser) parseRoot(root artifact, uniqModules map[string]struct{}) ([]types.Library, []types.Dependency, error) {
|
||||
// Prepare a queue for dependencies
|
||||
queue := newArtifactQueue()
|
||||
|
||||
@@ -132,7 +135,12 @@ func (p *parser) parseRoot(root artifact) ([]types.Library, []types.Dependency,
|
||||
// Modules should be handled separately so that they can have independent dependencies.
|
||||
// It means multi-module allows for duplicate dependencies.
|
||||
if art.Module {
|
||||
moduleLibs, moduleDeps, err := p.parseRoot(art)
|
||||
if _, ok := uniqModules[art.String()]; ok {
|
||||
continue
|
||||
}
|
||||
uniqModules[art.String()] = struct{}{}
|
||||
|
||||
moduleLibs, moduleDeps, err := p.parseRoot(art, uniqModules)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
@@ -316,7 +324,9 @@ func (p *parser) analyze(pom *pom, opts analysisOptions) (analysisResult, error)
|
||||
}
|
||||
|
||||
// Update remoteRepositories
|
||||
p.remoteRepositories = utils.UniqueStrings(append(pom.repositories(p.servers), p.remoteRepositories...))
|
||||
pomReleaseRemoteRepos, pomSnapshotRemoteRepos := pom.repositories(p.servers)
|
||||
p.releaseRemoteRepos = lo.Uniq(append(pomReleaseRemoteRepos, p.releaseRemoteRepos...))
|
||||
p.snapshotRemoteRepos = lo.Uniq(append(pomSnapshotRemoteRepos, p.snapshotRemoteRepos...))
|
||||
|
||||
// Parent
|
||||
parent, err := p.parseParent(pom.filePath, pom.content.Parent)
|
||||
@@ -607,7 +617,7 @@ func (p *parser) tryRepository(groupID, artifactID, version string) (*pom, error
|
||||
}
|
||||
|
||||
// Search remote remoteRepositories
|
||||
loaded, err = p.fetchPOMFromRemoteRepositories(paths)
|
||||
loaded, err = p.fetchPOMFromRemoteRepositories(paths, isSnapshot(version))
|
||||
if err == nil {
|
||||
return loaded, nil
|
||||
}
|
||||
@@ -622,15 +632,21 @@ func (p *parser) loadPOMFromLocalRepository(paths []string) (*pom, error) {
|
||||
return p.openPom(localPath)
|
||||
}
|
||||
|
||||
func (p *parser) fetchPOMFromRemoteRepositories(paths []string) (*pom, error) {
|
||||
func (p *parser) fetchPOMFromRemoteRepositories(paths []string, snapshot bool) (*pom, error) {
|
||||
// Do not try fetching pom.xml from remote repositories in offline mode
|
||||
if p.offline {
|
||||
log.Logger.Debug("Fetching the remote pom.xml is skipped")
|
||||
return nil, xerrors.New("offline mode")
|
||||
}
|
||||
|
||||
remoteRepos := p.releaseRemoteRepos
|
||||
// Maven uses only snapshot repos for snapshot artifacts
|
||||
if snapshot {
|
||||
remoteRepos = p.snapshotRemoteRepos
|
||||
}
|
||||
|
||||
// try all remoteRepositories
|
||||
for _, repo := range p.remoteRepositories {
|
||||
for _, repo := range remoteRepos {
|
||||
fetched, err := fetchPOMFromRemoteRepository(repo, paths)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("fetch repository error: %w", err)
|
||||
@@ -694,3 +710,8 @@ func parsePom(r io.Reader) (*pomXML, error) {
|
||||
func packageID(name, version string) string {
|
||||
return dependency.ID(ftypes.Pom, name, version)
|
||||
}
|
||||
|
||||
// cf. https://github.com/apache/maven/blob/259404701402230299fe05ee889ecdf1c9dae816/maven-artifact/src/main/java/org/apache/maven/artifact/DefaultArtifact.java#L482-L486
|
||||
func isSnapshot(ver string) bool {
|
||||
return strings.HasSuffix(ver, "SNAPSHOT") || ver == "LATEST"
|
||||
}
|
||||
|
||||
@@ -70,7 +70,7 @@ func TestPom_Parse(t *testing.T) {
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "remote repository",
|
||||
name: "remote release repository",
|
||||
inputFile: filepath.Join("testdata", "happy", "pom.xml"),
|
||||
local: false,
|
||||
want: []types.Library{
|
||||
@@ -114,6 +114,37 @@ func TestPom_Parse(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "snapshot dependency",
|
||||
inputFile: filepath.Join("testdata", "snapshot", "pom.xml"),
|
||||
local: false,
|
||||
want: []types.Library{
|
||||
{
|
||||
ID: "com.example:happy:1.0.0",
|
||||
Name: "com.example:happy",
|
||||
Version: "1.0.0",
|
||||
},
|
||||
{
|
||||
ID: "org.example:example-dependency:1.2.3-SNAPSHOT",
|
||||
Name: "org.example:example-dependency",
|
||||
Version: "1.2.3-SNAPSHOT",
|
||||
Locations: types.Locations{
|
||||
{
|
||||
StartLine: 14,
|
||||
EndLine: 18,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
wantDeps: []types.Dependency{
|
||||
{
|
||||
ID: "com.example:happy:1.0.0",
|
||||
DependsOn: []string{
|
||||
"org.example:example-dependency:1.2.3-SNAPSHOT",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "offline mode",
|
||||
inputFile: filepath.Join("testdata", "offline", "pom.xml"),
|
||||
@@ -959,6 +990,43 @@ func TestPom_Parse(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "Infinity loop for modules",
|
||||
inputFile: filepath.Join("testdata", "modules-infinity-loop", "pom.xml"),
|
||||
local: true,
|
||||
want: []types.Library{
|
||||
// as module
|
||||
{
|
||||
ID: "org.example:module-1:2.0.0",
|
||||
Name: "org.example:module-1",
|
||||
Version: "2.0.0",
|
||||
},
|
||||
// as dependency
|
||||
{
|
||||
ID: "org.example:module-1:2.0.0",
|
||||
Name: "org.example:module-1",
|
||||
Version: "2.0.0",
|
||||
},
|
||||
{
|
||||
ID: "org.example:module-2:3.0.0",
|
||||
Name: "org.example:module-2",
|
||||
Version: "3.0.0",
|
||||
},
|
||||
{
|
||||
ID: "org.example:root:1.0.0",
|
||||
Name: "org.example:root",
|
||||
Version: "1.0.0",
|
||||
},
|
||||
},
|
||||
wantDeps: []types.Dependency{
|
||||
{
|
||||
ID: "org.example:module-2:3.0.0",
|
||||
DependsOn: []string{
|
||||
"org.example:module-1:2.0.0",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "multi module soft requirement",
|
||||
inputFile: filepath.Join("testdata", "multi-module-soft-requirement", "pom.xml"),
|
||||
@@ -1258,7 +1326,7 @@ func TestPom_Parse(t *testing.T) {
|
||||
remoteRepos = []string{ts.URL}
|
||||
}
|
||||
|
||||
p := pom.NewParser(tt.inputFile, pom.WithRemoteRepos(remoteRepos), pom.WithOffline(tt.offline))
|
||||
p := pom.NewParser(tt.inputFile, pom.WithReleaseRemoteRepos(remoteRepos), pom.WithOffline(tt.offline))
|
||||
|
||||
gotLibs, gotDeps, err := p.Parse(f)
|
||||
if tt.wantErr != "" {
|
||||
|
||||
@@ -115,11 +115,13 @@ func (p pom) licenses() []string {
|
||||
})
|
||||
}
|
||||
|
||||
func (p pom) repositories(servers []Server) []string {
|
||||
var urls []string
|
||||
func (p pom) repositories(servers []Server) ([]string, []string) {
|
||||
var releaseRepos, snapshotRepos []string
|
||||
for _, rep := range p.content.Repositories.Repository {
|
||||
snapshot := rep.Snapshots.Enabled == "true"
|
||||
release := rep.Releases.Enabled == "true"
|
||||
// Add only enabled repositories
|
||||
if rep.Releases.Enabled == "false" && rep.Snapshots.Enabled == "false" {
|
||||
if !release && !snapshot {
|
||||
continue
|
||||
}
|
||||
|
||||
@@ -139,9 +141,15 @@ func (p pom) repositories(servers []Server) []string {
|
||||
}
|
||||
|
||||
log.Logger.Debugf("Adding repository %s: %s", rep.ID, rep.URL)
|
||||
urls = append(urls, repoURL.String())
|
||||
if snapshot {
|
||||
snapshotRepos = append(snapshotRepos, repoURL.String())
|
||||
}
|
||||
if release {
|
||||
releaseRepos = append(releaseRepos, repoURL.String())
|
||||
}
|
||||
}
|
||||
return urls
|
||||
|
||||
return releaseRepos, snapshotRepos
|
||||
}
|
||||
|
||||
type pomXML struct {
|
||||
|
||||
16
pkg/dependency/parser/java/pom/testdata/modules-infinity-loop/module-1/module-2/pom.xml
vendored
Normal file
16
pkg/dependency/parser/java/pom/testdata/modules-infinity-loop/module-1/module-2/pom.xml
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
<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>
|
||||
|
||||
<artifactId>module-2</artifactId>
|
||||
<groupId>org.example</groupId>
|
||||
<version>3.0.0</version>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.example</groupId>
|
||||
<artifactId>module-1</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
12
pkg/dependency/parser/java/pom/testdata/modules-infinity-loop/module-1/pom.xml
vendored
Normal file
12
pkg/dependency/parser/java/pom/testdata/modules-infinity-loop/module-1/pom.xml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
<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>
|
||||
|
||||
<artifactId>module-1</artifactId>
|
||||
<groupId>org.example</groupId>
|
||||
<version>2.0.0</version>
|
||||
|
||||
<modules>
|
||||
<module>module-2</module>
|
||||
</modules>
|
||||
</project>
|
||||
13
pkg/dependency/parser/java/pom/testdata/modules-infinity-loop/pom.xml
vendored
Normal file
13
pkg/dependency/parser/java/pom/testdata/modules-infinity-loop/pom.xml
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
<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>
|
||||
|
||||
<artifactId>root</artifactId>
|
||||
<groupId>org.example</groupId>
|
||||
<version>1.0.0</version>
|
||||
|
||||
<modules>
|
||||
<module>module-1</module>
|
||||
<module>module-2</module>
|
||||
</modules>
|
||||
</project>
|
||||
@@ -0,0 +1,23 @@
|
||||
<?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.2.3-SNAPSHOT</version>
|
||||
|
||||
<packaging>jar</packaging>
|
||||
<name>Example API Dependency</name>
|
||||
<description>The example API</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.example</groupId>
|
||||
<artifactId>example-api</artifactId>
|
||||
<version>2.0.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
20
pkg/dependency/parser/java/pom/testdata/snapshot/pom.xml
vendored
Normal file
20
pkg/dependency/parser/java/pom/testdata/snapshot/pom.xml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
<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>happy</artifactId>
|
||||
<version>1.0.0</version>
|
||||
|
||||
<name>happy</name>
|
||||
<description>Example</description>
|
||||
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.example</groupId>
|
||||
<artifactId>example-dependency</artifactId>
|
||||
<version>1.2.3-SNAPSHOT</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
</project>
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"path"
|
||||
"slices"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
@@ -115,28 +116,42 @@ func (p *Parser) parseV2(packages map[string]Package) ([]types.Library, []types.
|
||||
EndLine: pkg.EndLine,
|
||||
}
|
||||
|
||||
var ref types.ExternalRef
|
||||
if pkg.Resolved != "" {
|
||||
ref = types.ExternalRef{
|
||||
Type: types.RefOther,
|
||||
URL: pkg.Resolved,
|
||||
}
|
||||
}
|
||||
|
||||
pkgIndirect := isIndirectLib(pkgPath, directDeps)
|
||||
|
||||
// There are cases when similar libraries use same dependencies
|
||||
// we need to add location for each these dependencies
|
||||
if savedLib, ok := libs[pkgID]; ok {
|
||||
savedLib.Dev = savedLib.Dev && pkg.Dev
|
||||
savedLib.Indirect = savedLib.Indirect && pkgIndirect
|
||||
|
||||
if ref.URL != "" && !slices.Contains(savedLib.ExternalReferences, ref) {
|
||||
savedLib.ExternalReferences = append(savedLib.ExternalReferences, ref)
|
||||
sortExternalReferences(savedLib.ExternalReferences)
|
||||
}
|
||||
|
||||
savedLib.Locations = append(savedLib.Locations, location)
|
||||
sort.Sort(savedLib.Locations)
|
||||
|
||||
libs[pkgID] = savedLib
|
||||
continue
|
||||
}
|
||||
|
||||
lib := types.Library{
|
||||
ID: pkgID,
|
||||
Name: pkgName,
|
||||
Version: pkg.Version,
|
||||
Indirect: isIndirectLib(pkgPath, directDeps),
|
||||
Dev: pkg.Dev,
|
||||
ExternalReferences: []types.ExternalRef{
|
||||
{
|
||||
Type: types.RefOther,
|
||||
URL: pkg.Resolved,
|
||||
},
|
||||
},
|
||||
Locations: []types.Location{location},
|
||||
ID: pkgID,
|
||||
Name: pkgName,
|
||||
Version: pkg.Version,
|
||||
Indirect: pkgIndirect,
|
||||
Dev: pkg.Dev,
|
||||
ExternalReferences: lo.Ternary(ref.URL != "", []types.ExternalRef{ref}, nil),
|
||||
Locations: []types.Location{location},
|
||||
}
|
||||
libs[pkgID] = lib
|
||||
|
||||
@@ -385,3 +400,12 @@ func (t *Package) UnmarshalJSONWithMetadata(node jfather.Node) error {
|
||||
func packageID(name, version string) string {
|
||||
return dependency.ID(ftypes.Npm, name, version)
|
||||
}
|
||||
|
||||
func sortExternalReferences(refs []types.ExternalRef) {
|
||||
sort.Slice(refs, func(i, j int) bool {
|
||||
if refs[i].Type != refs[j].Type {
|
||||
return refs[i].Type < refs[j].Type
|
||||
}
|
||||
return refs[i].URL < refs[j].URL
|
||||
})
|
||||
}
|
||||
|
||||
@@ -41,6 +41,12 @@ func TestParse(t *testing.T) {
|
||||
want: npmV3WithWorkspaceLibs,
|
||||
wantDeps: npmV3WithWorkspaceDeps,
|
||||
},
|
||||
{
|
||||
name: "lock file v3 contains same dev and non-dev dependencies",
|
||||
file: "testdata/package-lock_v3_with-same-dev-and-non-dev.json",
|
||||
want: npmV3WithSameDevAndNonDevLibs,
|
||||
wantDeps: npmV3WithSameDevAndNonDevDeps,
|
||||
},
|
||||
{
|
||||
name: "lock version v3 with workspace and without direct deps field",
|
||||
file: "testdata/package-lock_v3_without_root_deps_field.json",
|
||||
|
||||
@@ -1516,4 +1516,89 @@ var (
|
||||
DependsOn: []string{"debug@2.6.9"},
|
||||
},
|
||||
}
|
||||
|
||||
npmV3WithSameDevAndNonDevLibs = []types.Library{
|
||||
{
|
||||
ID: "fsevents@1.2.9",
|
||||
Name: "fsevents",
|
||||
Version: "1.2.9",
|
||||
Dev: true,
|
||||
ExternalReferences: []types.ExternalRef{
|
||||
{
|
||||
Type: types.RefOther,
|
||||
URL: "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz",
|
||||
},
|
||||
},
|
||||
Locations: []types.Location{
|
||||
{
|
||||
StartLine: 18,
|
||||
EndLine: 37,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "minimist@0.0.8",
|
||||
Name: "minimist",
|
||||
Version: "0.0.8",
|
||||
Indirect: false,
|
||||
Dev: false,
|
||||
ExternalReferences: []types.ExternalRef{
|
||||
{
|
||||
Type: types.RefOther,
|
||||
URL: "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
||||
},
|
||||
},
|
||||
Locations: []types.Location{
|
||||
{
|
||||
StartLine: 38,
|
||||
EndLine: 43,
|
||||
},
|
||||
{
|
||||
StartLine: 68,
|
||||
EndLine: 72,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "mkdirp@0.5.1",
|
||||
Name: "mkdirp",
|
||||
Version: "0.5.1",
|
||||
Indirect: true,
|
||||
Dev: true,
|
||||
Locations: []types.Location{
|
||||
{
|
||||
StartLine: 44,
|
||||
EndLine: 55,
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
ID: "node-pre-gyp@0.12.0",
|
||||
Name: "node-pre-gyp",
|
||||
Version: "0.12.0",
|
||||
Indirect: true,
|
||||
Dev: true,
|
||||
Locations: []types.Location{
|
||||
{
|
||||
StartLine: 56,
|
||||
EndLine: 67,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
npmV3WithSameDevAndNonDevDeps = []types.Dependency{
|
||||
{
|
||||
ID: "fsevents@1.2.9",
|
||||
DependsOn: []string{"node-pre-gyp@0.12.0"},
|
||||
},
|
||||
{
|
||||
ID: "mkdirp@0.5.1",
|
||||
DependsOn: []string{"minimist@0.0.8"},
|
||||
},
|
||||
{
|
||||
ID: "node-pre-gyp@0.12.0",
|
||||
DependsOn: []string{"mkdirp@0.5.1"},
|
||||
},
|
||||
}
|
||||
)
|
||||
|
||||
74
pkg/dependency/parser/nodejs/npm/testdata/package-lock_v3_with-same-dev-and-non-dev.json
vendored
Normal file
74
pkg/dependency/parser/nodejs/npm/testdata/package-lock_v3_with-same-dev-and-non-dev.json
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
{
|
||||
"name": "5139",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "5139",
|
||||
"version": "1.0.0",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"minimist": "^0.0.8"
|
||||
},
|
||||
"devDependencies": {
|
||||
"fsevents": "^1.2.9"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents": {
|
||||
"version": "1.2.9",
|
||||
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz",
|
||||
"integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==",
|
||||
"bundleDependencies": [
|
||||
"node-pre-gyp"
|
||||
],
|
||||
"deprecated": "The v1 package contains DANGEROUS / INSECURE binaries. Upgrade to safe fsevents v2",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"dependencies": {
|
||||
"node-pre-gyp": "^0.12.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents/node_modules/minimist": {
|
||||
"version": "0.0.8",
|
||||
"dev": true,
|
||||
"inBundle": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/fsevents/node_modules/mkdirp": {
|
||||
"version": "0.5.1",
|
||||
"dev": true,
|
||||
"inBundle": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"minimist": "0.0.8"
|
||||
},
|
||||
"bin": {
|
||||
"mkdirp": "bin/cmd.js"
|
||||
}
|
||||
},
|
||||
"node_modules/fsevents/node_modules/node-pre-gyp": {
|
||||
"version": "0.12.0",
|
||||
"dev": true,
|
||||
"inBundle": true,
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"mkdirp": "^0.5.1"
|
||||
},
|
||||
"bin": {
|
||||
"node-pre-gyp": "bin/node-pre-gyp"
|
||||
}
|
||||
},
|
||||
"node_modules/minimist": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
|
||||
"integrity": "sha512-miQKw5Hv4NS1Psg2517mV4e4dYNaO3++hjAvLOAzKqZ61rH8NS1SK+vbfBWZ5PY/Me/bEWhUwqMghEW5Fb9T7Q=="
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import (
|
||||
"io"
|
||||
"regexp"
|
||||
|
||||
"github.com/samber/lo"
|
||||
"golang.org/x/xerrors"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/dependency"
|
||||
@@ -21,7 +22,7 @@ type packageJSON struct {
|
||||
Dependencies map[string]string `json:"dependencies"`
|
||||
OptionalDependencies map[string]string `json:"optionalDependencies"`
|
||||
DevDependencies map[string]string `json:"devDependencies"`
|
||||
Workspaces []string `json:"workspaces"`
|
||||
Workspaces any `json:"workspaces"`
|
||||
}
|
||||
|
||||
type Package struct {
|
||||
@@ -65,7 +66,7 @@ func (p *Parser) Parse(r io.Reader) (Package, error) {
|
||||
Dependencies: pkgJSON.Dependencies,
|
||||
OptionalDependencies: pkgJSON.OptionalDependencies,
|
||||
DevDependencies: pkgJSON.DevDependencies,
|
||||
Workspaces: pkgJSON.Workspaces,
|
||||
Workspaces: parseWorkspaces(pkgJSON.Workspaces),
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -82,6 +83,29 @@ func parseLicense(val interface{}) string {
|
||||
return ""
|
||||
}
|
||||
|
||||
// parseWorkspaces returns slice of workspaces
|
||||
func parseWorkspaces(val any) []string {
|
||||
// Workspaces support 2 types - https://github.com/SchemaStore/schemastore/blob/d9516961f8a5b0e65a457808070147b5a866f60b/src/schemas/json/package.json#L777
|
||||
switch ws := val.(type) {
|
||||
// Workspace as object (map[string][]string)
|
||||
// e.g. "workspaces": {"packages": ["packages/*", "plugins/*"]},
|
||||
case map[string]interface{}:
|
||||
// Take only workspaces for `packages` - https://classic.yarnpkg.com/blog/2018/02/15/nohoist/
|
||||
if pkgsWorkspaces, ok := ws["packages"]; ok {
|
||||
return lo.Map(pkgsWorkspaces.([]interface{}), func(workspace interface{}, _ int) string {
|
||||
return workspace.(string)
|
||||
})
|
||||
}
|
||||
// Workspace as string array
|
||||
// e.g. "workspaces": ["packages/*", "backend"],
|
||||
case []interface{}:
|
||||
return lo.Map(ws, func(workspace interface{}, _ int) string {
|
||||
return workspace.(string)
|
||||
})
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func IsValidName(name string) bool {
|
||||
// Name is optional field
|
||||
// https://docs.npmjs.com/cli/v9/configuring-npm/package-json#name
|
||||
|
||||
@@ -76,6 +76,20 @@ func TestParse(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path - workspace as struct",
|
||||
inputFile: "testdata/workspace_as_map_package.json",
|
||||
want: packagejson.Package{
|
||||
Library: types.Library{
|
||||
ID: "example@1.0.0",
|
||||
Name: "example",
|
||||
Version: "1.0.0",
|
||||
},
|
||||
Workspaces: []string{
|
||||
"packages/*",
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "invalid package name",
|
||||
inputFile: "testdata/invalid_name.json",
|
||||
|
||||
8
pkg/dependency/parser/nodejs/packagejson/testdata/workspace_as_map_package.json
vendored
Normal file
8
pkg/dependency/parser/nodejs/packagejson/testdata/workspace_as_map_package.json
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"name": "example",
|
||||
"version": "1.0.0",
|
||||
"workspaces": {
|
||||
"packages": ["packages/*"],
|
||||
"nohoist": ["**/react-native", "**/react-native/**"]
|
||||
}
|
||||
}
|
||||
@@ -55,7 +55,8 @@ func (c *CompositeFS) CopyFileToTemp(opener Opener, info os.FileInfo) (string, e
|
||||
return "", xerrors.Errorf("copy error: %w", err)
|
||||
}
|
||||
|
||||
if err = os.Chmod(f.Name(), info.Mode()); err != nil {
|
||||
// Use 0600 instead of file permissions to avoid errors when a file uses incorrect permissions (e.g. 0044).
|
||||
if err = os.Chmod(f.Name(), 0600); err != nil {
|
||||
return "", xerrors.Errorf("chmod error: %w", err)
|
||||
}
|
||||
|
||||
|
||||
@@ -36,7 +36,7 @@ resource "aws_s3_bucket_public_access_block" "example_access_block"{
|
||||
hasPublicAccess: true,
|
||||
},
|
||||
{
|
||||
desc: "public access block is found when using the bucket name as the lookup",
|
||||
desc: "public access block is found when using the bucket id as the lookup",
|
||||
source: `
|
||||
resource "aws_s3_bucket" "example" {
|
||||
bucket = "bucketname"
|
||||
@@ -254,6 +254,33 @@ func Test_Adapt(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "non-valid SSE algorithm",
|
||||
terraform: `
|
||||
resource "aws_s3_bucket" "this" {
|
||||
bucket = "test"
|
||||
}
|
||||
|
||||
resource "aws_s3_bucket_server_side_encryption_configuration" "this" {
|
||||
bucket = aws_s3_bucket.this.id
|
||||
rule {
|
||||
apply_server_side_encryption_by_default {
|
||||
sse_algorithm = ""
|
||||
}
|
||||
}
|
||||
}`,
|
||||
expected: s3.S3{
|
||||
Buckets: []s3.Bucket{
|
||||
{
|
||||
Name: iacTypes.String("test", iacTypes.NewTestMetadata()),
|
||||
Encryption: s3.Encryption{
|
||||
Enabled: iacTypes.Bool(false, iacTypes.NewTestMetadata()),
|
||||
},
|
||||
ACL: iacTypes.String("private", iacTypes.NewTestMetadata()),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
|
||||
@@ -1,6 +1,10 @@
|
||||
package s3
|
||||
|
||||
import (
|
||||
"slices"
|
||||
|
||||
s3types "github.com/aws/aws-sdk-go-v2/service/s3/types"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/iac/providers/aws/s3"
|
||||
"github.com/aquasecurity/trivy/pkg/iac/terraform"
|
||||
iacTypes "github.com/aquasecurity/trivy/pkg/iac/types"
|
||||
@@ -194,11 +198,13 @@ func isEncrypted(sseConfgihuration *terraform.Block) iacTypes.BoolValue {
|
||||
sseConfgihuration,
|
||||
"rule.apply_server_side_encryption_by_default.sse_algorithm",
|
||||
func(attr *terraform.Attribute, parent *terraform.Block) iacTypes.BoolValue {
|
||||
if attr.IsNil() {
|
||||
if attr.IsNil() || !attr.IsString() {
|
||||
return iacTypes.BoolDefault(false, parent.GetMetadata())
|
||||
}
|
||||
algoVal := attr.Value().AsString()
|
||||
isValidAlgo := slices.Contains(s3types.ServerSideEncryption("").Values(), s3types.ServerSideEncryption(algoVal))
|
||||
return iacTypes.Bool(
|
||||
true,
|
||||
isValidAlgo,
|
||||
attr.GetMetadata(),
|
||||
)
|
||||
},
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
"io/fs"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
"github.com/liamg/memoryfs"
|
||||
|
||||
@@ -38,6 +39,8 @@ type Scanner struct {
|
||||
skipRequired bool
|
||||
frameworks []framework.Framework
|
||||
spec string
|
||||
regoScanner *rego.Scanner
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
func (s *Scanner) SetSpec(spec string) {
|
||||
@@ -120,6 +123,10 @@ func (s *Scanner) SetRegoErrorLimit(_ int) {}
|
||||
|
||||
func (s *Scanner) ScanFS(ctx context.Context, target fs.FS, path string) (scan.Results, error) {
|
||||
|
||||
if err := s.initRegoScanner(target); err != nil {
|
||||
return nil, fmt.Errorf("failed to init rego scanner: %w", err)
|
||||
}
|
||||
|
||||
var results []scan.Result
|
||||
if err := fs.WalkDir(target, path, func(path string, d fs.DirEntry, err error) error {
|
||||
select {
|
||||
@@ -150,6 +157,7 @@ func (s *Scanner) ScanFS(ctx context.Context, target fs.FS, path string) (scan.R
|
||||
} else {
|
||||
results = append(results, scanResults...)
|
||||
}
|
||||
return fs.SkipDir
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -174,14 +182,6 @@ func (s *Scanner) getScanResults(path string, ctx context.Context, target fs.FS)
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
regoScanner := rego.NewScanner(types.SourceKubernetes, s.options...)
|
||||
policyFS := target
|
||||
if s.policyFS != nil {
|
||||
policyFS = s.policyFS
|
||||
}
|
||||
if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, policyFS, s.policyDirs, s.policyReaders); err != nil {
|
||||
return nil, fmt.Errorf("policies load: %w", err)
|
||||
}
|
||||
for _, file := range chartFiles {
|
||||
file := file
|
||||
s.debug.Log("Processing rendered chart file: %s", file.TemplateFilePath)
|
||||
@@ -191,7 +191,7 @@ func (s *Scanner) getScanResults(path string, ctx context.Context, target fs.FS)
|
||||
return nil, fmt.Errorf("unmarshal yaml: %w", err)
|
||||
}
|
||||
for _, manifest := range manifests {
|
||||
fileResults, err := regoScanner.ScanInput(ctx, rego.Input{
|
||||
fileResults, err := s.regoScanner.ScanInput(ctx, rego.Input{
|
||||
Path: file.TemplateFilePath,
|
||||
Contents: manifest,
|
||||
FS: target,
|
||||
@@ -219,3 +219,18 @@ func (s *Scanner) getScanResults(path string, ctx context.Context, target fs.FS)
|
||||
}
|
||||
return results, nil
|
||||
}
|
||||
|
||||
func (s *Scanner) initRegoScanner(srcFS fs.FS) error {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if s.regoScanner != nil {
|
||||
return nil
|
||||
}
|
||||
regoScanner := rego.NewScanner(types.SourceKubernetes, s.options...)
|
||||
regoScanner.SetParentDebugLogger(s.debug)
|
||||
if err := regoScanner.LoadPolicies(s.loadEmbeddedLibraries, s.loadEmbeddedPolicies, srcFS, s.policyDirs, s.policyReaders); err != nil {
|
||||
return err
|
||||
}
|
||||
s.regoScanner = regoScanner
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -318,3 +318,44 @@ deny[res] {
|
||||
require.NoError(t, err)
|
||||
assert.NotNil(t, code)
|
||||
}
|
||||
|
||||
func TestScanSubchartOnce(t *testing.T) {
|
||||
check := `# METADATA
|
||||
# title: "Test rego"
|
||||
# description: "Test rego"
|
||||
# scope: package
|
||||
# schemas:
|
||||
# - input: schema["kubernetes"]
|
||||
# custom:
|
||||
# id: ID001
|
||||
# avd_id: AVD-USR-ID001
|
||||
# severity: LOW
|
||||
# input:
|
||||
# selector:
|
||||
# - type: kubernetes
|
||||
# subtypes:
|
||||
# - kind: pod
|
||||
package user.kubernetes.ID001
|
||||
|
||||
import data.lib.kubernetes
|
||||
|
||||
deny[res] {
|
||||
container := kubernetes.containers[_]
|
||||
container.securityContext.readOnlyRootFilesystem == false
|
||||
res := result.new("set 'securityContext.readOnlyRootFilesystem' to true", container)
|
||||
}
|
||||
`
|
||||
|
||||
scanner := helm.New(
|
||||
options.ScannerWithEmbeddedPolicies(false),
|
||||
options.ScannerWithEmbeddedLibraries(true),
|
||||
options.ScannerWithPolicyNamespaces("user"),
|
||||
options.ScannerWithPolicyReader(strings.NewReader(check)),
|
||||
)
|
||||
|
||||
results, err := scanner.ScanFS(context.TODO(), os.DirFS("testdata/with-subchart"), ".")
|
||||
require.NoError(t, err)
|
||||
require.Len(t, results, 1)
|
||||
|
||||
assert.Len(t, results.GetFailed(), 0)
|
||||
}
|
||||
|
||||
6
pkg/iac/scanners/helm/test/testdata/with-subchart/Chart.yaml
vendored
Normal file
6
pkg/iac/scanners/helm/test/testdata/with-subchart/Chart.yaml
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
apiVersion: v2
|
||||
name: test
|
||||
description: A Helm chart for Kubernetes
|
||||
type: application
|
||||
version: 0.1.0
|
||||
appVersion: "1.16.0"
|
||||
6
pkg/iac/scanners/helm/test/testdata/with-subchart/charts/nginx/Chart.yaml
vendored
Normal file
6
pkg/iac/scanners/helm/test/testdata/with-subchart/charts/nginx/Chart.yaml
vendored
Normal file
@@ -0,0 +1,6 @@
|
||||
apiVersion: v2
|
||||
name: nginx
|
||||
description: A Helm chart for Kubernetes
|
||||
type: application
|
||||
version: 0.1.0
|
||||
appVersion: "1.16.0"
|
||||
12
pkg/iac/scanners/helm/test/testdata/with-subchart/charts/nginx/templates/pod.yaml
vendored
Normal file
12
pkg/iac/scanners/helm/test/testdata/with-subchart/charts/nginx/templates/pod.yaml
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: nginx
|
||||
spec:
|
||||
containers:
|
||||
- name: nginx
|
||||
image: nginx:1.14.2
|
||||
ports:
|
||||
- containerPort: 8080
|
||||
securityContext:
|
||||
readOnlyRootFilesystem: {{ .Values.readOnlyFs }}
|
||||
1
pkg/iac/scanners/helm/test/testdata/with-subchart/charts/nginx/values.yaml
vendored
Normal file
1
pkg/iac/scanners/helm/test/testdata/with-subchart/charts/nginx/values.yaml
vendored
Normal file
@@ -0,0 +1 @@
|
||||
readOnlyFs: false
|
||||
2
pkg/iac/scanners/helm/test/testdata/with-subchart/values.yaml
vendored
Normal file
2
pkg/iac/scanners/helm/test/testdata/with-subchart/values.yaml
vendored
Normal file
@@ -0,0 +1,2 @@
|
||||
nginx:
|
||||
readOnlyFs: true
|
||||
@@ -65,6 +65,7 @@ func ConvertToRPCPkgs(pkgs []ftypes.Package) []*common.Package {
|
||||
SrcRelease: pkg.SrcRelease,
|
||||
SrcEpoch: int32(pkg.SrcEpoch),
|
||||
Licenses: pkg.Licenses,
|
||||
Locations: ConvertToRPCLocations(pkg.Locations),
|
||||
Layer: ConvertToRPCLayer(pkg.Layer),
|
||||
FilePath: pkg.FilePath,
|
||||
DependsOn: pkg.DependsOn,
|
||||
@@ -90,6 +91,17 @@ func ConvertToRPCPkgIdentifier(pkg ftypes.PkgIdentifier) *common.PkgIdentifier {
|
||||
}
|
||||
}
|
||||
|
||||
func ConvertToRPCLocations(pkgLocs []ftypes.Location) []*common.Location {
|
||||
var locations []*common.Location
|
||||
for _, pkgLoc := range pkgLocs {
|
||||
locations = append(locations, &common.Location{
|
||||
StartLine: int32(pkgLoc.StartLine),
|
||||
EndLine: int32(pkgLoc.EndLine),
|
||||
})
|
||||
}
|
||||
return locations
|
||||
}
|
||||
|
||||
func ConvertToRPCCustomResources(resources []ftypes.CustomResource) []*common.CustomResource {
|
||||
var rpcResources []*common.CustomResource
|
||||
for _, r := range resources {
|
||||
@@ -207,6 +219,7 @@ func ConvertFromRPCPkgs(rpcPkgs []*common.Package) []ftypes.Package {
|
||||
SrcRelease: pkg.SrcRelease,
|
||||
SrcEpoch: int(pkg.SrcEpoch),
|
||||
Licenses: pkg.Licenses,
|
||||
Locations: ConvertFromRPCLocation(pkg.Locations),
|
||||
Layer: ConvertFromRPCLayer(pkg.Layer),
|
||||
FilePath: pkg.FilePath,
|
||||
DependsOn: pkg.DependsOn,
|
||||
@@ -237,6 +250,17 @@ func ConvertFromRPCPkgIdentifier(pkg *common.PkgIdentifier) ftypes.PkgIdentifier
|
||||
return pkgID
|
||||
}
|
||||
|
||||
func ConvertFromRPCLocation(locs []*common.Location) []ftypes.Location {
|
||||
var pkgLocs []ftypes.Location
|
||||
for _, loc := range locs {
|
||||
pkgLocs = append(pkgLocs, ftypes.Location{
|
||||
StartLine: int(loc.StartLine),
|
||||
EndLine: int(loc.EndLine),
|
||||
})
|
||||
}
|
||||
return pkgLocs
|
||||
}
|
||||
|
||||
// ConvertToRPCVulns returns common.Vulnerability
|
||||
func ConvertToRPCVulns(vulns []types.DetectedVulnerability) []*common.Vulnerability {
|
||||
var rpcVulns []*common.Vulnerability
|
||||
|
||||
@@ -39,6 +39,16 @@ func TestConvertToRpcPkgs(t *testing.T) {
|
||||
SrcRelease: "1",
|
||||
SrcEpoch: 2,
|
||||
Licenses: []string{"MIT"},
|
||||
Locations: []ftypes.Location{
|
||||
{
|
||||
StartLine: 10,
|
||||
EndLine: 20,
|
||||
},
|
||||
{
|
||||
StartLine: 22,
|
||||
EndLine: 32,
|
||||
},
|
||||
},
|
||||
Layer: ftypes.Layer{
|
||||
Digest: "sha256:6a428f9f83b0a29f1fdd2ccccca19a9bab805a925b8eddf432a5a3d3da04afbc",
|
||||
DiffID: "sha256:39982b2a789afc156fff00c707d0ff1c6ab4af8f1666a8df4787714059ce24e7",
|
||||
@@ -60,6 +70,16 @@ func TestConvertToRpcPkgs(t *testing.T) {
|
||||
SrcRelease: "1",
|
||||
SrcEpoch: 2,
|
||||
Licenses: []string{"MIT"},
|
||||
Locations: []*common.Location{
|
||||
{
|
||||
StartLine: 10,
|
||||
EndLine: 20,
|
||||
},
|
||||
{
|
||||
StartLine: 22,
|
||||
EndLine: 32,
|
||||
},
|
||||
},
|
||||
Layer: &common.Layer{
|
||||
Digest: "sha256:6a428f9f83b0a29f1fdd2ccccca19a9bab805a925b8eddf432a5a3d3da04afbc",
|
||||
DiffId: "sha256:39982b2a789afc156fff00c707d0ff1c6ab4af8f1666a8df4787714059ce24e7",
|
||||
@@ -101,6 +121,16 @@ func TestConvertFromRpcPkgs(t *testing.T) {
|
||||
SrcRelease: "1",
|
||||
SrcEpoch: 2,
|
||||
Licenses: []string{"MIT"},
|
||||
Locations: []*common.Location{
|
||||
{
|
||||
StartLine: 10,
|
||||
EndLine: 20,
|
||||
},
|
||||
{
|
||||
StartLine: 22,
|
||||
EndLine: 32,
|
||||
},
|
||||
},
|
||||
Layer: &common.Layer{
|
||||
Digest: "sha256:6a428f9f83b0a29f1fdd2ccccca19a9bab805a925b8eddf432a5a3d3da04afbc",
|
||||
DiffId: "sha256:39982b2a789afc156fff00c707d0ff1c6ab4af8f1666a8df4787714059ce24e7",
|
||||
@@ -122,6 +152,16 @@ func TestConvertFromRpcPkgs(t *testing.T) {
|
||||
SrcRelease: "1",
|
||||
SrcEpoch: 2,
|
||||
Licenses: []string{"MIT"},
|
||||
Locations: []ftypes.Location{
|
||||
{
|
||||
StartLine: 10,
|
||||
EndLine: 20,
|
||||
},
|
||||
{
|
||||
StartLine: 22,
|
||||
EndLine: 32,
|
||||
},
|
||||
},
|
||||
Layer: ftypes.Layer{
|
||||
Digest: "sha256:6a428f9f83b0a29f1fdd2ccccca19a9bab805a925b8eddf432a5a3d3da04afbc",
|
||||
DiffID: "sha256:39982b2a789afc156fff00c707d0ff1c6ab4af8f1666a8df4787714059ce24e7",
|
||||
|
||||
@@ -238,12 +238,20 @@ func (b *BOM) AddComponent(c *Component) {
|
||||
}
|
||||
|
||||
func (b *BOM) AddRelationship(parent, child *Component, relationshipType RelationshipType) {
|
||||
// Check the wrong parent to avoid `panic`
|
||||
if parent == nil {
|
||||
return
|
||||
}
|
||||
if parent.id == uuid.Nil {
|
||||
b.AddComponent(parent)
|
||||
}
|
||||
|
||||
if child == nil {
|
||||
b.relationships[parent.id] = nil // Meaning no dependencies
|
||||
// It is possible that `relationships` already contains this parent.
|
||||
// Check this to avoid overwriting.
|
||||
if _, ok := b.relationships[parent.id]; !ok {
|
||||
b.relationships[parent.id] = nil // Meaning no dependencies
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
54
pkg/sbom/spdx/testdata/happy/with-file-as-relationship-parent.json
vendored
Normal file
54
pkg/sbom/spdx/testdata/happy/with-file-as-relationship-parent.json
vendored
Normal file
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"files": [
|
||||
{
|
||||
"fileName": "./Modules/Microsoft.PowerShell.PSResourceGet/_manifest/spdx_2.2/manifest.spdx.json",
|
||||
"SPDXID": "SPDXRef-File--Modules-Microsoft.PowerShell.PSResourceGet--manifest-spdx-2.2-manifest.spdx.json-2B9FB98F5CA97DC84FD382A8F8E68F663C003362",
|
||||
"checksums": [
|
||||
{
|
||||
"algorithm": "SHA256",
|
||||
"checksumValue": "4201b0989938842ef8c11a006184e0b1466bd7f9bb2af61d89a4c8318d43466e"
|
||||
},
|
||||
{
|
||||
"algorithm": "SHA1",
|
||||
"checksumValue": "2b9fb98f5ca97dc84fd382a8f8e68f663c003362"
|
||||
}
|
||||
],
|
||||
"licenseConcluded": "NOASSERTION",
|
||||
"licenseInfoInFiles": [
|
||||
"NOASSERTION"
|
||||
],
|
||||
"copyrightText": "NOASSERTION",
|
||||
"fileTypes": [
|
||||
"SPDX"
|
||||
]
|
||||
}
|
||||
],
|
||||
"externalDocumentRefs": [],
|
||||
"relationships": [
|
||||
{
|
||||
"relationshipType": "DESCRIBES",
|
||||
"relatedSpdxElement": "SPDXRef-RootPackage",
|
||||
"spdxElementId": "SPDXRef-DOCUMENT"
|
||||
},
|
||||
{
|
||||
"relationshipType": "DESCRIBED_BY",
|
||||
"relatedSpdxElement": "SPDXRef-DOCUMENT",
|
||||
"spdxElementId": "SPDXRef-File--Modules-Microsoft.PowerShell.PSResourceGet--manifest-spdx-2.2-manifest.spdx.json-2B9FB98F5CA97DC84FD382A8F8E68F663C003362"
|
||||
}
|
||||
],
|
||||
"spdxVersion": "SPDX-2.2",
|
||||
"dataLicense": "CC0-1.0",
|
||||
"SPDXID": "SPDXRef-DOCUMENT",
|
||||
"name": "PowerShell Linux Arm32 7.5.0-preview.2",
|
||||
"documentNamespace": "https://sbom.microsoft/1:2QSF7qZlbE-F7QrUJlEo7g:pHp_nUFvDUijZ4LrJ4RhoQ/696:458654/PowerShell%20Linux%20Arm32:7.5.0-preview.2:pDkyTHXmgUOdzSXIq9CiqA",
|
||||
"creationInfo": {
|
||||
"created": "2024-02-22T00:43:53Z",
|
||||
"creators": [
|
||||
"Organization: Microsoft",
|
||||
"Tool: Microsoft.SBOMTool-2.2.3"
|
||||
]
|
||||
},
|
||||
"documentDescribes": [
|
||||
"SPDXRef-RootPackage"
|
||||
]
|
||||
}
|
||||
@@ -87,8 +87,16 @@ func (s *SPDX) unmarshal(spdxDocument *spdx.Document) error {
|
||||
continue
|
||||
}
|
||||
|
||||
compA := components[rel.RefA.ElementRefID]
|
||||
compB := components[rel.RefB.ElementRefID]
|
||||
compA, ok := components[rel.RefA.ElementRefID]
|
||||
if !ok { // Skip if parent is not Package
|
||||
continue
|
||||
}
|
||||
|
||||
compB, ok := components[rel.RefB.ElementRefID]
|
||||
if !ok { // Skip if child is not Package
|
||||
continue
|
||||
}
|
||||
|
||||
s.BOM.AddRelationship(compA, compB, s.parseRelationshipType(rel.Relationship))
|
||||
}
|
||||
|
||||
@@ -255,6 +263,10 @@ func (s *SPDX) parseExternalReferences(refs []*spdx.PackageExternalReference) (*
|
||||
}
|
||||
|
||||
func (s *SPDX) isTrivySBOM(spdxDocument *spdx.Document) bool {
|
||||
if spdxDocument == nil || spdxDocument.CreationInfo == nil || spdxDocument.CreationInfo.Creators == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
for _, c := range spdxDocument.CreationInfo.Creators {
|
||||
if c.CreatorType == "Tool" && strings.HasPrefix(c.Creator, "trivy") {
|
||||
return true
|
||||
|
||||
@@ -314,6 +314,11 @@ func TestUnmarshaler_Unmarshal(t *testing.T) {
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "happy path with file as parent of relationship",
|
||||
inputFile: "testdata/happy/with-file-as-relationship-parent.json",
|
||||
want: types.SBOM{},
|
||||
},
|
||||
{
|
||||
name: "happy path only os component",
|
||||
inputFile: "testdata/happy/os-only-bom.json",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -42,17 +42,18 @@ message Package {
|
||||
string arch = 5;
|
||||
// src package containing some binary packages
|
||||
// e.g. bind
|
||||
string src_name = 6;
|
||||
string src_version = 7;
|
||||
string src_release = 8;
|
||||
int32 src_epoch = 9;
|
||||
repeated string licenses = 15;
|
||||
Layer layer = 11;
|
||||
string file_path = 12;
|
||||
repeated string depends_on = 14;
|
||||
string digest = 16;
|
||||
bool dev = 17;
|
||||
bool indirect = 18;
|
||||
string src_name = 6;
|
||||
string src_version = 7;
|
||||
string src_release = 8;
|
||||
int32 src_epoch = 9;
|
||||
repeated string licenses = 15;
|
||||
repeated Location locations = 20;
|
||||
Layer layer = 11;
|
||||
string file_path = 12;
|
||||
repeated string depends_on = 14;
|
||||
string digest = 16;
|
||||
bool dev = 17;
|
||||
bool indirect = 18;
|
||||
}
|
||||
|
||||
message PkgIdentifier {
|
||||
@@ -60,6 +61,11 @@ message PkgIdentifier {
|
||||
string bom_ref = 2;
|
||||
}
|
||||
|
||||
message Location {
|
||||
int32 start_line = 1;
|
||||
int32 end_line = 2;
|
||||
}
|
||||
|
||||
message Misconfiguration {
|
||||
string file_type = 1;
|
||||
string file_path = 2;
|
||||
|
||||
Reference in New Issue
Block a user