mirror of
https://github.com/aquasecurity/trivy.git
synced 2025-12-12 15:50:15 -08:00
feat(misconf): Added fs.FS based scanning via latest defsec (#2084)
Co-authored-by: knqyf263 <knqyf263@gmail.com>
This commit is contained in:
@@ -53,54 +53,7 @@ $ trivy image --skip-update --offline-scan alpine:3.12
|
||||
|
||||
## Air-Gapped Environment for misconfigurations
|
||||
|
||||
### Download misconfiguration policies
|
||||
At first, you need to download misconfiguration policies for use in air-gapped environments.
|
||||
Please follow [oras installation instruction][oras].
|
||||
|
||||
Download `bundle.tar.gz`:
|
||||
|
||||
```
|
||||
$ oras pull ghcr.io/aquasecurity/appshield:latest -a
|
||||
```
|
||||
|
||||
### Transfer misconfiguration policies into the air-gapped environment
|
||||
The way of transfer depends on the environment.
|
||||
|
||||
```
|
||||
$ rsync -av -e ssh /path/to/bundle.tar.gz [user]@[host]:dst
|
||||
```
|
||||
|
||||
### Put the misconfiguration policies in Trivy's cache directory
|
||||
You have to know where to put the misconfiguration policies file. The following command shows the default cache directory.
|
||||
|
||||
```
|
||||
$ ssh user@host
|
||||
$ trivy -h | grep cache
|
||||
--cache-dir value cache directory (default: "/home/myuser/.cache/trivy") [$TRIVY_CACHE_DIR]
|
||||
```
|
||||
|
||||
Put the misconfiguration policies file in the cache directory + `/policy/content`.
|
||||
|
||||
```
|
||||
$ mkdir -p /home/myuser/.cache/trivy/policy/content
|
||||
$ cd /home/myuser/.cache/trivy/policy/content
|
||||
$ mv /path/to/bundle.tar.gz .
|
||||
```
|
||||
|
||||
Then, decompress it.
|
||||
`bundle.tar.gz ` file includes two folders: `docker`, `kubernetes` and file: `.manifest`.
|
||||
|
||||
```
|
||||
$ tar xvf bundle.tar.gz
|
||||
x ./docker/
|
||||
...
|
||||
x ./kubernetes/
|
||||
...
|
||||
x ./.manifest
|
||||
$ rm bundle.tar.gz
|
||||
```
|
||||
|
||||
In an air-gapped environment it is your responsibility to update policies on a regular basis, so that the scanner can detect recently-identified misconfigurations.
|
||||
No special measures are required to detect misconfigurations in an air-gapped environment.
|
||||
|
||||
### Run Trivy with --skip-policy-update option
|
||||
In an air-gapped environment, specify `--skip-policy-update` so that Trivy doesn't attempt to download the latest misconfiguration policies.
|
||||
|
||||
@@ -63,7 +63,7 @@ Please see [LICENSE][license] for Trivy licensing information.
|
||||
|
||||
[installation]: ../getting-started/installation.md
|
||||
[vuln]: ../docs/vulnerability/scanning/index.md
|
||||
[misconf]: ../docs/misconfiguration/index.md
|
||||
[misconf]: ../docs/misconfiguration/scanning.md
|
||||
[container]: ../docs/vulnerability/scanning/image.md
|
||||
[rootfs]: ../docs/vulnerability/scanning/rootfs.md
|
||||
[filesystem]: ../docs/vulnerability/scanning/filesystem.md
|
||||
|
||||
@@ -3,20 +3,19 @@
|
||||
Trivy uses cfsec internally to scan both JSON and YAML configuration files, but Trivy doesn't support some features provided by cfsec.
|
||||
This section describes the differences between Trivy and cfsec.
|
||||
|
||||
| Feature | Trivy | cfsec |
|
||||
| --------------------------- | --------------------------------------- | -------------------- |
|
||||
| Built-in Policies | :material-check: | :material-check: |
|
||||
| Custom Policies | Rego[^1] | :material-close: |
|
||||
| Policy Metadata[^2] | :material-check: | :material-check: |
|
||||
| Show Successes | :material-check: | :material-check: |
|
||||
| Disable Policies | :material-check: | :material-check: |
|
||||
| Show Issue Lines | :material-close: | :material-check: |
|
||||
| View Statistics | :material-close: | :material-check: |
|
||||
| Filtering by Severity | :material-check: | :material-close: |
|
||||
| Supported Formats | Dockerfile, JSON, YAML, Terraform, etc. | CloudFormation JSON and YAML |
|
||||
| Feature | Trivy | cfsec |
|
||||
|-----------------------|--------------------------------------------------------|------------------------------|
|
||||
| Built-in Policies | :material-check: | :material-check: |
|
||||
| Custom Policies | :material-check: | :material-close: |
|
||||
| Policy Metadata[^1] | :material-check: | :material-check: |
|
||||
| Show Successes | :material-check: | :material-check: |
|
||||
| Disable Policies | :material-check: | :material-check: |
|
||||
| Show Issue Lines | :material-check: | :material-check: |
|
||||
| View Statistics | :material-close: | :material-check: |
|
||||
| Filtering by Severity | :material-check: | :material-close: |
|
||||
| Supported Formats | Dockerfile, JSON, YAML, Terraform, CloudFormation etc. | CloudFormation JSON and YAML |
|
||||
|
||||
[^1]: CloudFormation files are not supported
|
||||
[^2]: To enrich the results such as ID, Title, Description, Severity, etc.
|
||||
[^1]: To enrich the results such as ID, Title, Description, Severity, etc.
|
||||
|
||||
cfsec is designed for CloudFormation.
|
||||
People who use only want to scan their CloudFormation templates should use cfsec.
|
||||
|
||||
@@ -3,21 +3,20 @@
|
||||
Trivy uses tfsec internally to scan Terraform HCL files, but Trivy doesn't support some features provided by tfsec.
|
||||
This section describes the differences between Trivy and tfsec.
|
||||
|
||||
| Feature | Trivy | tfsec |
|
||||
| --------------------------- | --------------------------------------- | -------------------- |
|
||||
| Built-in Policies | :material-check: | :material-check: |
|
||||
| Custom Policies | Rego[^1] | JSON and YAML |
|
||||
| Policy Metadata[^2] | :material-check: | :material-check: |
|
||||
| Show Successes | :material-check: | :material-check: |
|
||||
| Disable Policies | :material-check: | :material-check: |
|
||||
| Show Issue Lines | :material-close: | :material-check: |
|
||||
| Support .tfvars | :material-close: | :material-check: |
|
||||
| View Statistics | :material-close: | :material-check: |
|
||||
| Filtering by Severity | :material-check: | :material-close: |
|
||||
| Supported Formats | Dockerfile, JSON, YAML, Terraform, etc. | Terraform |
|
||||
| Feature | Trivy | tfsec |
|
||||
|-----------------------|--------------------------------------------------------|----------------------|
|
||||
| Built-in Policies | :material-check: | :material-check: |
|
||||
| Custom Policies | Rego | Rego, JSON, and YAML |
|
||||
| Policy Metadata[^1] | :material-check: | :material-check: |
|
||||
| Show Successes | :material-check: | :material-check: |
|
||||
| Disable Policies | :material-check: | :material-check: |
|
||||
| Show Issue Lines | :material-check: | :material-check: |
|
||||
| Support .tfvars | :material-close: | :material-check: |
|
||||
| View Statistics | :material-close: | :material-check: |
|
||||
| Filtering by Severity | :material-check: | :material-check: |
|
||||
| Supported Formats | Dockerfile, JSON, YAML, Terraform, CloudFormation etc. | Terraform |
|
||||
|
||||
[^1]: Terraform HCL files are not supported.
|
||||
[^2]: To enrich the results such as ID, Title, Description, Severity, etc.
|
||||
[^1]: To enrich the results such as ID, Title, Description, Severity, etc.
|
||||
|
||||
tfsec is designed for Terraform.
|
||||
People who use only Terraform should use tfsec.
|
||||
|
||||
@@ -1,56 +0,0 @@
|
||||
# Filesystem
|
||||
|
||||
## Quick start
|
||||
|
||||
Trivy scans a filesystem such as a virtual machine to detect misconfigurations.
|
||||
|
||||
You have to specify `--security-checks config` to enable misconfiguration detection.
|
||||
|
||||
```bash
|
||||
$ trivy fs --security-checks config /path/to/dir
|
||||
```
|
||||
|
||||
Internally, it is the same as [config subcommand](iac.md).
|
||||
|
||||
## Vulnerability and Misconfiguration scanning
|
||||
The difference between `fs` and `config` subcommand is that `fs` can detect both vulnerabilities and misconfiguration at the same time.
|
||||
|
||||
You have to specify `--security-checks vuln,config` to enable vulnerability and misconfiguration detection.
|
||||
|
||||
``` bash
|
||||
$ ls myapp/
|
||||
Dockerfile Pipfile.lock
|
||||
$ trivy fs --security-checks vuln,config --severity HIGH,CRITICAL myapp/
|
||||
2021-07-09T12:03:27.564+0300 INFO Detected OS: unknown
|
||||
2021-07-09T12:03:27.564+0300 INFO Number of language-specific files: 1
|
||||
2021-07-09T12:03:27.564+0300 INFO Detecting pipenv vulnerabilities...
|
||||
2021-07-09T12:03:27.566+0300 INFO Detected config files: 1
|
||||
|
||||
Pipfile.lock (pipenv)
|
||||
=====================
|
||||
Total: 1 (HIGH: 1, CRITICAL: 0)
|
||||
|
||||
+----------+------------------+----------+-------------------+---------------+---------------------------------------+
|
||||
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
|
||||
+----------+------------------+----------+-------------------+---------------+---------------------------------------+
|
||||
| httplib2 | CVE-2021-21240 | HIGH | 0.12.1 | 0.19.0 | python-httplib2: Regular |
|
||||
| | | | | | expression denial of |
|
||||
| | | | | | service via malicious header |
|
||||
| | | | | | -->avd.aquasec.com/nvd/cve-2021-21240 |
|
||||
+----------+------------------+----------+-------------------+---------------+---------------------------------------+
|
||||
|
||||
Dockerfile (dockerfile)
|
||||
=======================
|
||||
Tests: 23 (SUCCESSES: 22, FAILURES: 1, EXCEPTIONS: 0)
|
||||
Failures: 1 (HIGH: 1, CRITICAL: 0)
|
||||
|
||||
+---------------------------+------------+----------------------+----------+------------------------------------------+
|
||||
| TYPE | MISCONF ID | CHECK | SEVERITY | MESSAGE |
|
||||
+---------------------------+------------+----------------------+----------+------------------------------------------+
|
||||
| Dockerfile Security Check | DS002 | Image user is 'root' | HIGH | Last USER command in |
|
||||
| | | | | Dockerfile should not be 'root' |
|
||||
| | | | | -->avd.aquasec.com/appshield/ds002 |
|
||||
+---------------------------+------------+----------------------+----------+------------------------------------------+
|
||||
```
|
||||
|
||||
In the above example, Trivy detected vulnerabilities of Python dependencies and misconfigurations in Dockerfile.
|
||||
@@ -1,8 +0,0 @@
|
||||
# Misconfiguration Scanning
|
||||
Trivy provides built-in policies to detect configuration issues in Docker, Kubernetes and Terraform.
|
||||
Also, you can write your own policies in [Rego][rego] to scan JSON, YAML, HCL, etc, like [Conftest][conftest].
|
||||
|
||||

|
||||
|
||||
[rego]: https://www.openpolicyagent.org/docs/latest/policy-language/
|
||||
[conftest]: https://github.com/open-policy-agent/conftest/
|
||||
@@ -2,40 +2,21 @@
|
||||
|
||||
## Policy Sources
|
||||
|
||||
Built-in policies are mainly written in [Rego][rego].
|
||||
Those policies are managed under [AppShield repository][appshield].
|
||||
Terraform policies are currently powered by [tfsec][tfsec] and CloudFormation policies are powered by [cfsec][cfsec].
|
||||
Built-in policies are mainly written in [Rego][rego] and Go.
|
||||
Those policies are managed under [defsec repository][defsec].
|
||||
|
||||
| Config type | Source |
|
||||
| ------------------------- | ----------------------- |
|
||||
| Kubernetes | [AppShield][kubernetes] |
|
||||
| Dockerfile, Containerfile | [AppShield][docker] |
|
||||
| Terraform | [tfsec][tfsec-checks] |
|
||||
| CloudFormation | [cfsec][cfsec-checks] |
|
||||
| Config type | Source |
|
||||
|---------------------------|----------------------|
|
||||
| Kubernetes | [defsec][kubernetes] |
|
||||
| Dockerfile, Containerfile | [defsec][docker] |
|
||||
| Terraform | [defsec][defsec] |
|
||||
| CloudFormation | [defsec][defsec] |
|
||||
|
||||
For suggestions or issues regarding policy content, please open an issue under [AppShield][appshield], [tfsec][tfsec] or [cfsec][cfsec] repository.
|
||||
For suggestions or issues regarding policy content, please open an issue under the [defsec][defsec] repository.
|
||||
|
||||
Ansible are coming soon.
|
||||
|
||||
## Policy Distribution
|
||||
AppShield policies are distributed as an OPA bundle on [GitHub Container Registry][ghcr] (GHCR).
|
||||
When misconfiguration detection is enabled, Trivy pulls the OPA bundle from GHCR as an OCI artifact and stores it in the cache.
|
||||
Those policies are then loaded into Trivy OPA engine and used for detecting misconfigurations.
|
||||
|
||||
## Update Interval
|
||||
Trivy checks for updates to OPA bundle on GHCR every 24 hours and pulls it if there are any updates.
|
||||
|
||||
[rego]: https://www.openpolicyagent.org/docs/latest/policy-language/
|
||||
[appshield]: https://github.com/aquasecurity/appshield
|
||||
[kubernetes]: https://github.com/aquasecurity/appshield/tree/master/kubernetes
|
||||
[docker]: https://github.com/aquasecurity/appshield/tree/master/docker
|
||||
[tfsec-checks]: https://tfsec.dev/
|
||||
[tfsec]: https://github.com/aquasecurity/tfsec
|
||||
[cfsec-checks]: https://cfsec.dev/
|
||||
[cfsec]: https://github.com/aquasecurity/cfsec
|
||||
[ghcr]: https://github.com/aquasecurity/appshield/pkgs/container/appshield
|
||||
|
||||
[dockerfile-bestpractice]: https://docs.docker.com/develop/develop-images/dockerfile_best-practices/
|
||||
[pss]: https://kubernetes.io/docs/concepts/security/pod-security-standards/
|
||||
[azure]: https://docs.microsoft.com/en-us/azure/security/fundamentals/network-best-practices
|
||||
[kics]: https://github.com/Checkmarx/kics/
|
||||
[defsec]: https://github.com/aquasecurity/defsec
|
||||
[kubernetes]: https://github.com/aquasecurity/defsec/tree/master/internal/rules/kubernetes
|
||||
[docker]: https://github.com/aquasecurity/appshield/tree/master/internal/rules/docker
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Exceptions
|
||||
Exceptions lets you to specify cases where you allow policy violations.
|
||||
Exceptions let you specify cases where you allow policy violations.
|
||||
Trivy supports two types of exceptions.
|
||||
|
||||
!!! info
|
||||
@@ -22,7 +22,7 @@ The `exception` rule must be defined under `namespace.exceptions`.
|
||||
|
||||
exception[ns] {
|
||||
ns := data.namespaces[_]
|
||||
startswith(ns, "appshield")
|
||||
startswith(ns, "builtin.kubernetes")
|
||||
}
|
||||
```
|
||||
|
||||
@@ -79,7 +79,7 @@ If you want to apply rule-based exceptions to built-in policies, you have to def
|
||||
|
||||
!!! example
|
||||
``` rego
|
||||
package appshield.kubernetes.KSV012
|
||||
package builtin.kubernetes.KSV012
|
||||
|
||||
exception[rules] {
|
||||
input.metadata.name == "can-run-as-root"
|
||||
@@ -87,12 +87,12 @@ If you want to apply rule-based exceptions to built-in policies, you have to def
|
||||
}
|
||||
```
|
||||
|
||||
This exception is applied to [KSV012][ksv012] in AppShield.
|
||||
You can get the package names in [AppShield repository][appshield] or the JSON output from Trivy.
|
||||
This exception is applied to [KSV012][ksv012] in defsec.
|
||||
You can get the package names in the [defsec repository][defsec] or the JSON output from Trivy.
|
||||
|
||||
For more details, see [an example][rule-example].
|
||||
|
||||
[ns-example]: https://github.com/aquasecurity/trivy/tree/{{ git.commit }}/examples/misconf/namespace-exception
|
||||
[rule-example]: https://github.com/aquasecurity/trivy/tree/{{ git.commit }}/examples/misconf/rule-exception
|
||||
[ksv012]: https://github.com/aquasecurity/appshield/blob/57bccc1897b2500a731415bda3990b0d4fbc959e/kubernetes/policies/pss/restricted/3_runs_as_root.rego
|
||||
[appshield]: https://github.com/aquasecurity/appshield/
|
||||
[ksv012]: https://github.com/aquasecurity/defsec/blob/master/internal/rules/kubernetes/policies/pss/restricted/3_runs_as_root.rego
|
||||
[defsec]: https://github.com/aquasecurity/defsec/
|
||||
@@ -1,4 +1,8 @@
|
||||
# Infrastructure as Code (IaC)
|
||||
# Misconfiguration Scanning
|
||||
Trivy provides built-in policies to detect configuration issues in Docker, Kubernetes, Terraform and CloudFormation.
|
||||
Also, you can write your own policies in [Rego][rego] to scan JSON, YAML, etc, like [Conftest][conftest].
|
||||
|
||||

|
||||
|
||||
## Quick start
|
||||
|
||||
@@ -8,7 +12,6 @@ Simply specify a directory containing IaC files such as Terraform, CloudFormatio
|
||||
$ trivy config [YOUR_IaC_DIRECTORY]
|
||||
```
|
||||
|
||||
Trivy will automatically fetch the managed policies and will keep them up-to-date in future scans.
|
||||
|
||||
!!! example
|
||||
```
|
||||
@@ -32,7 +35,62 @@ Trivy will automatically fetch the managed policies and will keep them up-to-dat
|
||||
| | | | | -->avd.aquasec.com/appshield/ds002 |
|
||||
+---------------------------+------------+----------------------+----------+------------------------------------------+
|
||||
```
|
||||
|
||||
You can also enable misconfiguration detection in container image, filesystem and git repository scanning via `--security-checks config`.
|
||||
|
||||
```bash
|
||||
$ trivy image --security-checks config IMAGE_NAME
|
||||
```
|
||||
|
||||
```bash
|
||||
$ trivy fs --security-checks config /path/to/dir
|
||||
```
|
||||
|
||||
!!! note
|
||||
Misconfiguration detection is not enabled by default in `image`, `fs` and `repo` subcommands.
|
||||
|
||||
Unlike the `config` subcommand, `image`, `fs` and `repo` subcommands can also scan for vulnerabilities and secrets at the same time.
|
||||
You can specify `--security-checks vuln,config,secret` to enable vulnerability and secret detection as well as misconfiguration detection.
|
||||
|
||||
|
||||
!!! example
|
||||
``` bash
|
||||
$ ls myapp/
|
||||
Dockerfile Pipfile.lock
|
||||
$ trivy fs --security-checks vuln,config,secret --severity HIGH,CRITICAL myapp/
|
||||
2021-07-09T12:03:27.564+0300 INFO Number of language-specific files: 1
|
||||
2021-07-09T12:03:27.564+0300 INFO Detecting pipenv vulnerabilities...
|
||||
2021-07-09T12:03:27.566+0300 INFO Detected config files: 1
|
||||
|
||||
Pipfile.lock (pipenv)
|
||||
=====================
|
||||
Total: 1 (HIGH: 1, CRITICAL: 0)
|
||||
|
||||
+----------+------------------+----------+-------------------+---------------+---------------------------------------+
|
||||
| LIBRARY | VULNERABILITY ID | SEVERITY | INSTALLED VERSION | FIXED VERSION | TITLE |
|
||||
+----------+------------------+----------+-------------------+---------------+---------------------------------------+
|
||||
| httplib2 | CVE-2021-21240 | HIGH | 0.12.1 | 0.19.0 | python-httplib2: Regular |
|
||||
| | | | | | expression denial of |
|
||||
| | | | | | service via malicious header |
|
||||
| | | | | | -->avd.aquasec.com/nvd/cve-2021-21240 |
|
||||
+----------+------------------+----------+-------------------+---------------+---------------------------------------+
|
||||
|
||||
Dockerfile (dockerfile)
|
||||
=======================
|
||||
Tests: 23 (SUCCESSES: 22, FAILURES: 1, EXCEPTIONS: 0)
|
||||
Failures: 1 (HIGH: 1, CRITICAL: 0)
|
||||
|
||||
+---------------------------+------------+----------------------+----------+------------------------------------------+
|
||||
| TYPE | MISCONF ID | CHECK | SEVERITY | MESSAGE |
|
||||
+---------------------------+------------+----------------------+----------+------------------------------------------+
|
||||
| Dockerfile Security Check | DS002 | Image user is 'root' | HIGH | Last USER command in |
|
||||
| | | | | Dockerfile should not be 'root' |
|
||||
| | | | | -->avd.aquasec.com/appshield/ds002 |
|
||||
+---------------------------+------------+----------------------+----------+------------------------------------------+
|
||||
```
|
||||
|
||||
In the above example, Trivy detected vulnerabilities of Python dependencies and misconfigurations in Dockerfile.
|
||||
|
||||
## Type detection
|
||||
The specified directory can contain mixed types of IaC files.
|
||||
Trivy automatically detects config types and applies relevant policies.
|
||||
@@ -125,39 +183,42 @@ Failures: 9 (HIGH: 6, CRITICAL: 1)
|
||||
+------------------------------------------+------------+------------------------------------------+----------+--------------------------------------------------------+
|
||||
```
|
||||
|
||||
</details>
|
||||
</details>
|
||||
|
||||
You can see the config type next to each file name.
|
||||
|
||||
!!! example
|
||||
``` bash
|
||||
Dockerfile (dockerfile)
|
||||
=======================
|
||||
Tests: 23 (SUCCESSES: 22, FAILURES: 1, EXCEPTIONS: 0)
|
||||
Failures: 1 (HIGH: 1, CRITICAL: 0)
|
||||
|
||||
...
|
||||
|
||||
deployment.yaml (kubernetes)
|
||||
============================
|
||||
Tests: 28 (SUCCESSES: 15, FAILURES: 13, EXCEPTIONS: 0)
|
||||
Failures: 13 (HIGH: 1, CRITICAL: 0)
|
||||
|
||||
...
|
||||
|
||||
main.tf (terraform)
|
||||
===================
|
||||
Tests: 23 (SUCCESSES: 14, FAILURES: 9, EXCEPTIONS: 0)
|
||||
Failures: 9 (HIGH: 6, CRITICAL: 1)
|
||||
``` bash
|
||||
Dockerfile (dockerfile)
|
||||
=======================
|
||||
Tests: 23 (SUCCESSES: 22, FAILURES: 1, EXCEPTIONS: 0)
|
||||
Failures: 1 (HIGH: 1, CRITICAL: 0)
|
||||
|
||||
...
|
||||
...
|
||||
|
||||
bucket.yaml (cloudformation)
|
||||
============================
|
||||
Tests: 9 (SUCCESSES: 3, FAILURES: 6, EXCEPTIONS: 0)
|
||||
Failures: 6 (UNKNOWN: 0, LOW: 0, MEDIUM: 2, HIGH: 4, CRITICAL: 0)
|
||||
deployment.yaml (kubernetes)
|
||||
============================
|
||||
Tests: 28 (SUCCESSES: 15, FAILURES: 13, EXCEPTIONS: 0)
|
||||
Failures: 13 (HIGH: 1, CRITICAL: 0)
|
||||
|
||||
```
|
||||
...
|
||||
|
||||
main.tf (terraform)
|
||||
===================
|
||||
Tests: 23 (SUCCESSES: 14, FAILURES: 9, EXCEPTIONS: 0)
|
||||
Failures: 9 (HIGH: 6, CRITICAL: 1)
|
||||
|
||||
...
|
||||
|
||||
bucket.yaml (cloudformation)
|
||||
============================
|
||||
Tests: 9 (SUCCESSES: 3, FAILURES: 6, EXCEPTIONS: 0)
|
||||
Failures: 6 (UNKNOWN: 0, LOW: 0, MEDIUM: 2, HIGH: 4, CRITICAL: 0)
|
||||
```
|
||||
|
||||
## Examples
|
||||
See [here](https://github.com/aquasecurity/trivy/tree/{{ git.tag }}/examples/misconf/mixed)
|
||||
|
||||
[rego]: https://www.openpolicyagent.org/docs/latest/policy-language/
|
||||
[conftest]: https://github.com/open-policy-agent/conftest/
|
||||
|
||||
## Example
|
||||
See [here](https://github.com/aquasecurity/trivy/tree/125c457517f05b6498bc68eaeec6e683dd36c49a/examples/misconf/mixed)
|
||||
@@ -30,7 +30,7 @@ See [Integrations][integrations] for details.
|
||||
[os]: ../docs/vulnerability/detection/os.md
|
||||
[lang]: ../docs/vulnerability/detection/language.md
|
||||
|
||||
[misconf]: ../docs/misconfiguration/index.md
|
||||
[misconf]: ../docs/misconfiguration/scanning.md
|
||||
|
||||
[secret]: ../docs/secret/scanning.md
|
||||
|
||||
|
||||
@@ -80,5 +80,5 @@ Failures: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 1, CRITICAL: 0)
|
||||
For more details, see [here][misconf].
|
||||
|
||||
[vulnerability]: ../docs/vulnerability/scanning/index.md
|
||||
[misconf]: ../docs/misconfiguration/index.md
|
||||
[misconf]: ../docs/misconfiguration/scanning.md
|
||||
[secret]: ../docs/secret/scanning.md
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
"elements": [
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 573,
|
||||
"versionNonce": 2034670720,
|
||||
"version": 791,
|
||||
"versionNonce": 1617738570,
|
||||
"isDeleted": false,
|
||||
"id": "BkXuq_6BxgqZGZWc8oCtu",
|
||||
"fillStyle": "hachure",
|
||||
@@ -24,12 +24,15 @@
|
||||
"seed": 1632394695,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElementIds": []
|
||||
"boundElements": [],
|
||||
"updated": 1652181399352,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 572,
|
||||
"versionNonce": 425683840,
|
||||
"version": 716,
|
||||
"versionNonce": 910620246,
|
||||
"isDeleted": false,
|
||||
"id": "YQURTHNPSe05RPSlYRcok",
|
||||
"fillStyle": "hachure",
|
||||
@@ -47,18 +50,23 @@
|
||||
"seed": 891391049,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElementIds": [],
|
||||
"boundElements": [],
|
||||
"updated": 1652181399352,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 36,
|
||||
"fontFamily": 1,
|
||||
"text": "Trivy",
|
||||
"baseline": 32,
|
||||
"textAlign": "left",
|
||||
"verticalAlign": "top"
|
||||
"verticalAlign": "top",
|
||||
"containerId": null,
|
||||
"originalText": "Trivy"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 822,
|
||||
"versionNonce": 1061096576,
|
||||
"version": 1310,
|
||||
"versionNonce": 1854587402,
|
||||
"isDeleted": false,
|
||||
"id": "6dpF2EyZBtYgO6MrvGj0-",
|
||||
"fillStyle": "hachure",
|
||||
@@ -67,27 +75,32 @@
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 771.2554931640625,
|
||||
"y": 469.7777099609375,
|
||||
"x": 731.2024841308594,
|
||||
"y": 467.7408447265625,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "transparent",
|
||||
"width": 507,
|
||||
"height": 35,
|
||||
"width": 612,
|
||||
"height": 36,
|
||||
"seed": 687997545,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElementIds": [],
|
||||
"boundElements": [],
|
||||
"updated": 1652181399352,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 28,
|
||||
"fontFamily": 1,
|
||||
"text": "Vulnerability/Misconfiguration Scanner",
|
||||
"text": "Vulnerability/Misconfiguration/Secret Scanner",
|
||||
"baseline": 25,
|
||||
"textAlign": "left",
|
||||
"verticalAlign": "top"
|
||||
"verticalAlign": "top",
|
||||
"containerId": null,
|
||||
"originalText": "Vulnerability/Misconfiguration/Secret Scanner"
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 763,
|
||||
"versionNonce": 560331648,
|
||||
"version": 1129,
|
||||
"versionNonce": 1307232406,
|
||||
"isDeleted": false,
|
||||
"id": "cpnTMy7L2AUg9IDJppF4H",
|
||||
"fillStyle": "hachure",
|
||||
@@ -96,21 +109,24 @@
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 602.28369140625,
|
||||
"y": 258.8445587158203,
|
||||
"x": 647.7814331054688,
|
||||
"y": 188.2161407470703,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fab005",
|
||||
"width": 397.493408203125,
|
||||
"height": 103.28388977050778,
|
||||
"width": 248.74017333984375,
|
||||
"height": 77.74984135828628,
|
||||
"seed": 77164935,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElementIds": []
|
||||
"boundElements": [],
|
||||
"updated": 1652181524751,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 1072,
|
||||
"versionNonce": 212434048,
|
||||
"version": 1279,
|
||||
"versionNonce": 1197686422,
|
||||
"isDeleted": false,
|
||||
"id": "9-blmNVtLesthMSY_f60t",
|
||||
"fillStyle": "hachure",
|
||||
@@ -119,27 +135,32 @@
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 630.9301147460938,
|
||||
"y": 292.4002990722656,
|
||||
"x": 664.1268412090633,
|
||||
"y": 211.45297413880115,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "transparent",
|
||||
"width": 331,
|
||||
"height": 35,
|
||||
"width": 214.77717842516898,
|
||||
"height": 35.96269034095853,
|
||||
"seed": 860091815,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElementIds": [],
|
||||
"fontSize": 28,
|
||||
"boundElements": [],
|
||||
"updated": 1652181521001,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 27.970981376301072,
|
||||
"fontFamily": 1,
|
||||
"text": "Infrastructure as Code",
|
||||
"baseline": 25,
|
||||
"text": "Container image",
|
||||
"baseline": 24.96269034095853,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "top"
|
||||
"verticalAlign": "top",
|
||||
"containerId": null,
|
||||
"originalText": "Container image"
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 1194,
|
||||
"versionNonce": 131337088,
|
||||
"version": 1482,
|
||||
"versionNonce": 773738186,
|
||||
"isDeleted": false,
|
||||
"id": "gugZxhi7ThlcjWY_MFO7q",
|
||||
"fillStyle": "hachure",
|
||||
@@ -148,21 +169,24 @@
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 1021.5928955078125,
|
||||
"y": 261.56090545654297,
|
||||
"x": 907.46728515625,
|
||||
"y": 189.15813446044922,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#be4bdb",
|
||||
"width": 441.0702514648438,
|
||||
"height": 99.05134582519533,
|
||||
"width": 255.61367797851565,
|
||||
"height": 77.69438171386717,
|
||||
"seed": 1232790121,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElementIds": []
|
||||
"boundElements": [],
|
||||
"updated": 1652181510952,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 1270,
|
||||
"versionNonce": 591785088,
|
||||
"version": 1444,
|
||||
"versionNonce": 80370390,
|
||||
"isDeleted": false,
|
||||
"id": "K48gtpesBxIGJxLTnI2CB",
|
||||
"fillStyle": "hachure",
|
||||
@@ -171,8 +195,8 @@
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 1173.3179931640625,
|
||||
"y": 294.12510681152344,
|
||||
"x": 963.9347534179688,
|
||||
"y": 212.18040466308594,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "transparent",
|
||||
"width": 137,
|
||||
@@ -180,70 +204,23 @@
|
||||
"seed": 449264361,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElementIds": [],
|
||||
"boundElements": [],
|
||||
"updated": 1652181510952,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 28,
|
||||
"fontFamily": 1,
|
||||
"text": "Filesystem",
|
||||
"baseline": 25,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "top"
|
||||
"verticalAlign": "top",
|
||||
"containerId": null,
|
||||
"originalText": "Filesystem"
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 1319,
|
||||
"versionNonce": 1264839808,
|
||||
"isDeleted": false,
|
||||
"id": "BYJwfkhd1BilbLQGc973f",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 1233.3157348632812,
|
||||
"y": 168.29967880249023,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#82c91e",
|
||||
"width": 229.03393554687523,
|
||||
"height": 77.80606079101562,
|
||||
"seed": 1923498546,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElementIds": []
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 659,
|
||||
"versionNonce": 2122259328,
|
||||
"isDeleted": false,
|
||||
"id": "eedUyCpr8i1aY_3PHsHAB",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 1241.1352844238281,
|
||||
"y": 191.2939567565918,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#82c91e",
|
||||
"width": 216,
|
||||
"height": 35,
|
||||
"seed": 595309038,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElementIds": [],
|
||||
"fontSize": 28,
|
||||
"fontFamily": 1,
|
||||
"text": "Misconfiguration",
|
||||
"baseline": 25,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle"
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 1397,
|
||||
"versionNonce": 20077696,
|
||||
"version": 1545,
|
||||
"versionNonce": 819004246,
|
||||
"isDeleted": false,
|
||||
"id": "SPkrBrH6DGvkgQXtZQjIJ",
|
||||
"fillStyle": "hachure",
|
||||
@@ -252,21 +229,24 @@
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 1023.8157043457031,
|
||||
"y": 168.7816276550293,
|
||||
"x": 1174.8193054199219,
|
||||
"y": 190.58329391479492,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fa5252",
|
||||
"width": 200.7496337890626,
|
||||
"backgroundColor": "#12b886",
|
||||
"width": 250.91937255859386,
|
||||
"height": 77.80606079101562,
|
||||
"seed": 1896460914,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElementIds": []
|
||||
"boundElements": [],
|
||||
"updated": 1652181500681,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 840,
|
||||
"versionNonce": 655338368,
|
||||
"version": 1036,
|
||||
"versionNonce": 1127482634,
|
||||
"isDeleted": false,
|
||||
"id": "n06MNIqirDmVZBkDg_UPV",
|
||||
"fillStyle": "hachure",
|
||||
@@ -275,27 +255,32 @@
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 1040.526611328125,
|
||||
"y": 194.3111228942871,
|
||||
"x": 1200.8165283203125,
|
||||
"y": 212.65081405639648,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#82c91e",
|
||||
"width": 160,
|
||||
"height": 35,
|
||||
"width": 201,
|
||||
"height": 36,
|
||||
"seed": 1131832750,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElementIds": [],
|
||||
"boundElements": [],
|
||||
"updated": 1652181500682,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 28,
|
||||
"fontFamily": 1,
|
||||
"text": "Vulnerability",
|
||||
"text": "Git Repository",
|
||||
"baseline": 25,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle"
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "Git Repository"
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 1441,
|
||||
"versionNonce": 1393118080,
|
||||
"version": 1826,
|
||||
"versionNonce": 405213130,
|
||||
"isDeleted": false,
|
||||
"id": "8SHSNGf7PNddFLi2ZA3Vi",
|
||||
"fillStyle": "hachure",
|
||||
@@ -304,21 +289,24 @@
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 673.6463928222656,
|
||||
"y": 167.8159294128418,
|
||||
"x": 642.0580139160156,
|
||||
"y": 280.92316818237305,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#82c91e",
|
||||
"width": 278.48516845703136,
|
||||
"width": 788.2601318359375,
|
||||
"height": 77.80606079101562,
|
||||
"seed": 1986948530,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElementIds": []
|
||||
"boundElements": [],
|
||||
"updated": 1652181559488,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 851,
|
||||
"versionNonce": 2114620544,
|
||||
"version": 1093,
|
||||
"versionNonce": 573822154,
|
||||
"isDeleted": false,
|
||||
"id": "3Z5w3RXdgpvP43dlHqq26",
|
||||
"fillStyle": "hachure",
|
||||
@@ -327,26 +315,32 @@
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 701.5146789550781,
|
||||
"y": 189.60757064819336,
|
||||
"x": 851.4863586425781,
|
||||
"y": 300.9854393005371,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#82c91e",
|
||||
"width": 216,
|
||||
"height": 35,
|
||||
"width": 339,
|
||||
"height": 36,
|
||||
"seed": 1077804654,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElementIds": [],
|
||||
"boundElements": [],
|
||||
"updated": 1652181415054,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 28,
|
||||
"fontFamily": 1,
|
||||
"text": "Misconfiguration",
|
||||
"text": "Misconfiguration scanning",
|
||||
"baseline": 25,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle"
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "Misconfiguration scanning"
|
||||
}
|
||||
],
|
||||
"appState": {
|
||||
"gridSize": null,
|
||||
"viewBackgroundColor": "#ffffff"
|
||||
}
|
||||
},
|
||||
"files": {}
|
||||
}
|
||||
@@ -5,8 +5,8 @@
|
||||
"elements": [
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 787,
|
||||
"versionNonce": 1318065410,
|
||||
"version": 788,
|
||||
"versionNonce": 555477386,
|
||||
"isDeleted": false,
|
||||
"id": "BkXuq_6BxgqZGZWc8oCtu",
|
||||
"fillStyle": "hachure",
|
||||
@@ -25,14 +25,14 @@
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1650567161407,
|
||||
"updated": 1652177570112,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 653,
|
||||
"versionNonce": 1863936606,
|
||||
"version": 713,
|
||||
"versionNonce": 44400470,
|
||||
"isDeleted": false,
|
||||
"id": "YQURTHNPSe05RPSlYRcok",
|
||||
"fillStyle": "hachure",
|
||||
@@ -41,8 +41,8 @@
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 1137.7821926540798,
|
||||
"y": 764.0207858615452,
|
||||
"x": 1118.2101508246528,
|
||||
"y": 763.5906914605034,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "transparent",
|
||||
"width": 88,
|
||||
@@ -51,7 +51,7 @@
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1650567336690,
|
||||
"updated": 1652177702292,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 36,
|
||||
@@ -65,8 +65,8 @@
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 1139,
|
||||
"versionNonce": 1994750018,
|
||||
"version": 1191,
|
||||
"versionNonce": 1166344150,
|
||||
"isDeleted": false,
|
||||
"id": "6dpF2EyZBtYgO6MrvGj0-",
|
||||
"fillStyle": "hachure",
|
||||
@@ -75,8 +75,8 @@
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 900.5941772460938,
|
||||
"y": 819.7337171766493,
|
||||
"x": 875.3033447265625,
|
||||
"y": 820.7327100965712,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "transparent",
|
||||
"width": 612,
|
||||
@@ -85,7 +85,7 @@
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1650567334181,
|
||||
"updated": 1652177705177,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 28,
|
||||
@@ -99,8 +99,8 @@
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 805,
|
||||
"versionNonce": 1609410334,
|
||||
"version": 858,
|
||||
"versionNonce": 1118008458,
|
||||
"isDeleted": false,
|
||||
"id": "cpnTMy7L2AUg9IDJppF4H",
|
||||
"fillStyle": "hachure",
|
||||
@@ -110,23 +110,23 @@
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 600.9835205078125,
|
||||
"y": 627.2060089111328,
|
||||
"y": 635.5783640543619,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fab005",
|
||||
"width": 298.6342163085937,
|
||||
"height": 96.74092102050778,
|
||||
"width": 335.3091227213542,
|
||||
"height": 82.36856587727866,
|
||||
"seed": 77164935,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1650567155021,
|
||||
"updated": 1652177872265,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 1011,
|
||||
"versionNonce": 477782466,
|
||||
"version": 1077,
|
||||
"versionNonce": 1122201878,
|
||||
"isDeleted": false,
|
||||
"id": "9-blmNVtLesthMSY_f60t",
|
||||
"fillStyle": "hachure",
|
||||
@@ -135,32 +135,32 @@
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 628.7854614257812,
|
||||
"y": 658.9062805175781,
|
||||
"x": 649.8531494140625,
|
||||
"y": 660.223378499349,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "transparent",
|
||||
"width": 238,
|
||||
"height": 35,
|
||||
"width": 224,
|
||||
"height": 36,
|
||||
"seed": 860091815,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1650567155021,
|
||||
"updated": 1652177872265,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 28,
|
||||
"fontFamily": 1,
|
||||
"text": "Container Images",
|
||||
"text": "Container Image",
|
||||
"baseline": 25,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "top",
|
||||
"containerId": null,
|
||||
"originalText": "Container Images"
|
||||
"originalText": "Container Image"
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 1051,
|
||||
"versionNonce": 1210520414,
|
||||
"version": 1118,
|
||||
"versionNonce": 1679315786,
|
||||
"isDeleted": false,
|
||||
"id": "gugZxhi7ThlcjWY_MFO7q",
|
||||
"fillStyle": "hachure",
|
||||
@@ -169,24 +169,24 @@
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 911.257568359375,
|
||||
"y": 625.7697677612305,
|
||||
"x": 954.3485412597656,
|
||||
"y": 635.849225362142,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#be4bdb",
|
||||
"width": 452.44976806640636,
|
||||
"height": 99.05134582519533,
|
||||
"width": 409.35879516601574,
|
||||
"height": 82.97188822428383,
|
||||
"seed": 1232790121,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1650567155021,
|
||||
"updated": 1652177872265,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 1202,
|
||||
"versionNonce": 842114,
|
||||
"version": 1300,
|
||||
"versionNonce": 1187044950,
|
||||
"isDeleted": false,
|
||||
"id": "K48gtpesBxIGJxLTnI2CB",
|
||||
"fillStyle": "hachure",
|
||||
@@ -195,17 +195,17 @@
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 1065.672119140625,
|
||||
"y": 656.4816131591797,
|
||||
"x": 1084.4311319986978,
|
||||
"y": 660.9795074462891,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "transparent",
|
||||
"width": 137,
|
||||
"height": 35,
|
||||
"width": 139,
|
||||
"height": 36,
|
||||
"seed": 449264361,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1650567155021,
|
||||
"updated": 1652177872265,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 28,
|
||||
@@ -219,8 +219,8 @@
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 1163,
|
||||
"versionNonce": 1149481794,
|
||||
"version": 1204,
|
||||
"versionNonce": 688085514,
|
||||
"isDeleted": false,
|
||||
"id": "La6f87LDZ0uEIZB947bXo",
|
||||
"fillStyle": "hachure",
|
||||
@@ -230,23 +230,23 @@
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 1375.0136108398438,
|
||||
"y": 626.2495651245117,
|
||||
"y": 636.5654322306316,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#12b886",
|
||||
"width": 452.76554361979186,
|
||||
"height": 96.3990020751953,
|
||||
"height": 80.08313496907543,
|
||||
"seed": 2005637801,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1650567157857,
|
||||
"updated": 1652177872265,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 1371,
|
||||
"versionNonce": 1552918366,
|
||||
"version": 1432,
|
||||
"versionNonce": 1593746326,
|
||||
"isDeleted": false,
|
||||
"id": "aOgRPVQ81jhOfkvzjWTMF",
|
||||
"fillStyle": "hachure",
|
||||
@@ -255,162 +255,32 @@
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 1490.9330512152778,
|
||||
"y": 654.3717736138237,
|
||||
"x": 1498.8465237087673,
|
||||
"y": 658.0244835747612,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "transparent",
|
||||
"width": 224,
|
||||
"width": 201,
|
||||
"height": 36,
|
||||
"seed": 1284472935,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1650567166643,
|
||||
"updated": 1652177872265,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 28,
|
||||
"fontFamily": 1,
|
||||
"text": "Git Repositories",
|
||||
"text": "Git Repository",
|
||||
"baseline": 25,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "top",
|
||||
"containerId": null,
|
||||
"originalText": "Git Repositories"
|
||||
"originalText": "Git Repository"
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 2340,
|
||||
"versionNonce": 1952732126,
|
||||
"isDeleted": false,
|
||||
"id": "p8fn5gPx8DfP8QE1lN98-",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 1064.5642678676506,
|
||||
"y": 537.71609717149,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#82c91e",
|
||||
"width": 144.5880126953128,
|
||||
"height": 77.80606079101562,
|
||||
"seed": 684019996,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1650567155021,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 2497,
|
||||
"versionNonce": 832692482,
|
||||
"isDeleted": false,
|
||||
"id": "kFTL0HnUdDs_ngg2xVFbn",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 600.7947366176511,
|
||||
"y": 538.67312842149,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fa5252",
|
||||
"width": 144.5880126953128,
|
||||
"height": 77.80606079101562,
|
||||
"seed": 541443108,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1650567155021,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 2345,
|
||||
"versionNonce": 1129796482,
|
||||
"isDeleted": false,
|
||||
"id": "KIztJcYHiVtM-GMlZAXAE",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 753.0955178676511,
|
||||
"y": 538.61062842149,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#4c6ef5",
|
||||
"width": 145,
|
||||
"height": 77.80606079101562,
|
||||
"seed": 424425892,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1650567234562,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 2329,
|
||||
"versionNonce": 1518497986,
|
||||
"isDeleted": false,
|
||||
"id": "IWq_LcOearBV5cvqbJ_-o",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 911.3064553676511,
|
||||
"y": 537.97781592149,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fa5252",
|
||||
"width": 144.5880126953128,
|
||||
"height": 77.80606079101562,
|
||||
"seed": 468230812,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1650567155021,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 2318,
|
||||
"versionNonce": 1504408670,
|
||||
"isDeleted": false,
|
||||
"id": "TXeK066NA0hvyPSeZl1a5",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 1218.075986617651,
|
||||
"y": 536.86062842149,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#4c6ef5",
|
||||
"width": 144.5880126953128,
|
||||
"height": 77.80606079101562,
|
||||
"seed": 1408574372,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1650567155021,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 2364,
|
||||
"versionNonce": 3868802,
|
||||
"version": 2792,
|
||||
"versionNonce": 183831882,
|
||||
"isDeleted": false,
|
||||
"id": "10WjipxoLx2zzSI91pXbR",
|
||||
"fillStyle": "hachure",
|
||||
@@ -419,24 +289,24 @@
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 1375.544736617651,
|
||||
"y": 537.04812842149,
|
||||
"x": 599.7894943723566,
|
||||
"y": 905.6027750791251,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#fa5252",
|
||||
"width": 144.5880126953128,
|
||||
"height": 77.80606079101562,
|
||||
"width": 344.482180700969,
|
||||
"height": 83.67398764683533,
|
||||
"seed": 1813731484,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1650567155021,
|
||||
"updated": 1652177825759,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 2355,
|
||||
"versionNonce": 2067347614,
|
||||
"version": 2771,
|
||||
"versionNonce": 617525398,
|
||||
"isDeleted": false,
|
||||
"id": "M7Cngti6H0_kawKRN8yJ6",
|
||||
"fillStyle": "hachure",
|
||||
@@ -445,58 +315,24 @@
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 1528.868955367651,
|
||||
"y": 535.89187842149,
|
||||
"x": 963.2554264391833,
|
||||
"y": 904.2447769132434,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#82c91e",
|
||||
"width": 144.5880126953128,
|
||||
"height": 77.80606079101562,
|
||||
"width": 402.42137951281796,
|
||||
"height": 86.03696372105414,
|
||||
"seed": 1260603804,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1650567155021,
|
||||
"updated": 1652177777585,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 597,
|
||||
"versionNonce": 1519036482,
|
||||
"isDeleted": false,
|
||||
"id": "GHDrLyBOErQtv_WT5Lx3p",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 614.2293679653073,
|
||||
"y": 565.5605338169978,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#82c91e",
|
||||
"width": 114,
|
||||
"height": 25,
|
||||
"seed": 13297180,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1650567155021,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 20,
|
||||
"fontFamily": 1,
|
||||
"text": "Vulnerability",
|
||||
"baseline": 18,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "Vulnerability"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 655,
|
||||
"versionNonce": 1728345310,
|
||||
"version": 1057,
|
||||
"versionNonce": 405881110,
|
||||
"isDeleted": false,
|
||||
"id": "Iq57wFRtO1a8AU0rT6lRD",
|
||||
"fillStyle": "hachure",
|
||||
@@ -505,23 +341,23 @@
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 1533.6317117153076,
|
||||
"y": 565.2714713169978,
|
||||
"x": 1046.152429428344,
|
||||
"y": 930.8676815998951,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#82c91e",
|
||||
"width": 136.25488281249991,
|
||||
"height": 21.80078124999998,
|
||||
"width": 218,
|
||||
"height": 36,
|
||||
"seed": 1329695396,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1650567155021,
|
||||
"updated": 1652177655817,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 17.440624999999976,
|
||||
"fontSize": 28,
|
||||
"fontFamily": 1,
|
||||
"text": "Misconfiguration",
|
||||
"baseline": 14.800781249999979,
|
||||
"baseline": 25,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
@@ -529,42 +365,8 @@
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 666,
|
||||
"versionNonce": 1364217858,
|
||||
"isDeleted": false,
|
||||
"id": "gjnZl9nxrqzliwPk8sbK-",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 1067.4339578090576,
|
||||
"y": 565.8827994419978,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#82c91e",
|
||||
"width": 136.25488281249991,
|
||||
"height": 21.80078124999998,
|
||||
"seed": 290336932,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1650567155021,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 17.440624999999976,
|
||||
"fontFamily": 1,
|
||||
"text": "Misconfiguration",
|
||||
"baseline": 14.800781249999979,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "Misconfiguration"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 613,
|
||||
"versionNonce": 1721641246,
|
||||
"version": 883,
|
||||
"versionNonce": 969949898,
|
||||
"isDeleted": false,
|
||||
"id": "_cm6xpfcL9Yv2XBK5MBZF",
|
||||
"fillStyle": "hachure",
|
||||
@@ -573,134 +375,32 @@
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 1390.1199929653073,
|
||||
"y": 563.8456900669978,
|
||||
"x": 681.3134368986982,
|
||||
"y": 931.5212932384402,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#82c91e",
|
||||
"width": 114,
|
||||
"height": 25,
|
||||
"width": 161,
|
||||
"height": 36,
|
||||
"seed": 807441828,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1650567155021,
|
||||
"updated": 1652177624726,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 20,
|
||||
"fontSize": 28,
|
||||
"fontFamily": 1,
|
||||
"text": "Vulnerability",
|
||||
"baseline": 18,
|
||||
"baseline": 25,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "Vulnerability"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 635,
|
||||
"versionNonce": 2022375362,
|
||||
"isDeleted": false,
|
||||
"id": "An4-igVUkLzCwSdvDmtZl",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 925.6707742153073,
|
||||
"y": 560.4550650669978,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#82c91e",
|
||||
"width": 114,
|
||||
"height": 25,
|
||||
"seed": 1262859164,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1650567155021,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 20,
|
||||
"fontFamily": 1,
|
||||
"text": "Vulnerability",
|
||||
"baseline": 18,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "Vulnerability"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 681,
|
||||
"versionNonce": 1813371650,
|
||||
"isDeleted": false,
|
||||
"id": "p3-AVxdx5KP6eNViMVTLq",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 792.0184304653073,
|
||||
"y": 564.4160025669978,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#82c91e",
|
||||
"width": 65,
|
||||
"height": 25,
|
||||
"seed": 729823772,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1650567236437,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 20,
|
||||
"fontFamily": 1,
|
||||
"text": "Secret",
|
||||
"baseline": 18,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "Secret"
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 692,
|
||||
"versionNonce": 621238878,
|
||||
"isDeleted": false,
|
||||
"id": "7fe9NOM7QTEEW7nyXAMjh",
|
||||
"fillStyle": "hachure",
|
||||
"strokeWidth": 1,
|
||||
"strokeStyle": "solid",
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 1259.0613992153073,
|
||||
"y": 562.4238150669978,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#82c91e",
|
||||
"width": 65,
|
||||
"height": 25,
|
||||
"seed": 968541220,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1650567238433,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 20,
|
||||
"fontFamily": 1,
|
||||
"text": "Secret",
|
||||
"baseline": 18,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
"originalText": "Secret"
|
||||
},
|
||||
{
|
||||
"type": "rectangle",
|
||||
"version": 2417,
|
||||
"versionNonce": 1222703518,
|
||||
"version": 2874,
|
||||
"versionNonce": 1934391254,
|
||||
"isDeleted": false,
|
||||
"id": "Fq7meULupm1A9leboPlko",
|
||||
"fillStyle": "hachure",
|
||||
@@ -709,24 +409,24 @@
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 1684.2588079543348,
|
||||
"y": 536.1830067815082,
|
||||
"x": 1389.3043677318824,
|
||||
"y": 903.8533384764222,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#4c6ef5",
|
||||
"width": 144.5880126953128,
|
||||
"height": 77.80606079101562,
|
||||
"width": 437.15079032010976,
|
||||
"height": 84.42746665074158,
|
||||
"seed": 230693534,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1650567155021,
|
||||
"updated": 1652177785481,
|
||||
"link": null,
|
||||
"locked": false
|
||||
},
|
||||
{
|
||||
"type": "text",
|
||||
"version": 760,
|
||||
"versionNonce": 503898690,
|
||||
"version": 1121,
|
||||
"versionNonce": 110517002,
|
||||
"isDeleted": false,
|
||||
"id": "OUGk8nZzvgcKUHhKUcQov",
|
||||
"fillStyle": "hachure",
|
||||
@@ -735,23 +435,23 @@
|
||||
"roughness": 1,
|
||||
"opacity": 100,
|
||||
"angle": 0,
|
||||
"x": 1723.2672240242127,
|
||||
"y": 561.8650424396028,
|
||||
"x": 1556.0451356485157,
|
||||
"y": 930.8040952304675,
|
||||
"strokeColor": "#000000",
|
||||
"backgroundColor": "#82c91e",
|
||||
"width": 65,
|
||||
"height": 25,
|
||||
"width": 91,
|
||||
"height": 36,
|
||||
"seed": 2044527454,
|
||||
"groupIds": [],
|
||||
"strokeSharpness": "sharp",
|
||||
"boundElements": [],
|
||||
"updated": 1650567240607,
|
||||
"updated": 1652177636085,
|
||||
"link": null,
|
||||
"locked": false,
|
||||
"fontSize": 20,
|
||||
"fontSize": 28,
|
||||
"fontFamily": 1,
|
||||
"text": "Secret",
|
||||
"baseline": 18,
|
||||
"baseline": 25,
|
||||
"textAlign": "center",
|
||||
"verticalAlign": "middle",
|
||||
"containerId": null,
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.1 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.3 MiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.1 MiB After Width: | Height: | Size: 2.0 MiB |
@@ -8,7 +8,7 @@ hide:
|
||||
|
||||
`Trivy` (`tri` pronounced like **tri**gger, `vy` pronounced like en**vy**) is a simple and comprehensive [vulnerability][vulnerability]/[misconfiguration][misconf]/[secret][secret] scanner for containers and other artifacts.
|
||||
`Trivy` detects vulnerabilities of [OS packages][os] (Alpine, RHEL, CentOS, etc.) and [language-specific packages][lang] (Bundler, Composer, npm, yarn, etc.).
|
||||
In addition, `Trivy` scans [Infrastructure as Code (IaC) files][iac] such as Terraform and Kubernetes, to detect potential configuration issues that expose your deployments to the risk of attack.
|
||||
In addition, `Trivy` scans [Infrastructure as Code (IaC) files][misconf] such as Terraform and Kubernetes, to detect potential configuration issues that expose your deployments to the risk of attack.
|
||||
`Trivy` also scans [hardcoded secrets][secret] like passwords, API keys and tokens.
|
||||
`Trivy` is easy to use. Just install the binary and you're ready to scan.
|
||||
All you need to do for scanning is to specify a target such as an image name of the container.
|
||||
@@ -44,11 +44,10 @@ Learn about our open source work and portfolio [here][oss].
|
||||
Contact us about any matter by opening a GitHub Discussion [here][discussions]
|
||||
|
||||
[vulnerability]: docs/vulnerability/scanning/index.md
|
||||
[misconf]: docs/misconfiguration/index.md
|
||||
[misconf]: docs/misconfiguration/scanning.md
|
||||
[secret]: docs/secret/scanning.md
|
||||
[os]: docs/vulnerability/detection/os.md
|
||||
[lang]: docs/vulnerability/detection/language.md
|
||||
[iac]: docs/misconfiguration/iac.md
|
||||
|
||||
[aquasec]: https://aquasec.com
|
||||
[oss]: https://www.aquasec.com/products/open-source-projects/
|
||||
|
||||
57
go.mod
57
go.mod
@@ -7,8 +7,8 @@ require (
|
||||
github.com/Masterminds/sprig/v3 v3.2.2
|
||||
github.com/NYTimes/gziphandler v1.1.1
|
||||
github.com/aquasecurity/bolt-fixtures v0.0.0-20200903104109-d34e7f983986
|
||||
github.com/aquasecurity/fanal v0.0.0-20220503160602-873c6de8f5ae
|
||||
github.com/aquasecurity/go-dep-parser v0.0.0-20220422134844-880747206031
|
||||
github.com/aquasecurity/fanal v0.0.0-20220510103759-9ad40432d340
|
||||
github.com/aquasecurity/go-dep-parser v0.0.0-20220503151658-d316f5cc2cff
|
||||
github.com/aquasecurity/go-gem-version v0.0.0-20201115065557-8eed6fe000ce
|
||||
github.com/aquasecurity/go-npm-version v0.0.0-20201110091526-0b796d180798
|
||||
github.com/aquasecurity/go-pep440-version v0.0.0-20210121094942-22b2f8951d46
|
||||
@@ -30,6 +30,7 @@ require (
|
||||
github.com/knqyf263/go-deb-version v0.0.0-20190517075300-09fca494f03d
|
||||
github.com/knqyf263/go-rpm-version v0.0.0-20170716094938-74609b86c936
|
||||
github.com/masahiro331/go-mvn-version v0.0.0-20210429150710-d3157d602a08
|
||||
github.com/mitchellh/hashstructure/v2 v2.0.2
|
||||
github.com/olekukonko/tablewriter v0.0.5
|
||||
github.com/open-policy-agent/opa v0.40.0
|
||||
github.com/owenrumney/go-sarif/v2 v2.1.1
|
||||
@@ -46,7 +47,7 @@ require (
|
||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1
|
||||
google.golang.org/protobuf v1.28.0
|
||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
|
||||
k8s.io/utils v0.0.0-20210930125809-cb0fa318a74b
|
||||
k8s.io/utils v0.0.0-20211116205334-6203023598ed
|
||||
)
|
||||
|
||||
require (
|
||||
@@ -68,7 +69,6 @@ require (
|
||||
github.com/Masterminds/semver v1.5.0 // indirect
|
||||
github.com/Masterminds/semver/v3 v3.1.1 // indirect
|
||||
github.com/Microsoft/go-winio v0.5.1 // indirect
|
||||
github.com/Microsoft/hcsshim v0.9.2 // indirect
|
||||
github.com/OneOfOne/xxhash v1.2.8 // indirect
|
||||
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 // indirect
|
||||
github.com/VividCortex/ewma v1.1.1 // indirect
|
||||
@@ -76,23 +76,21 @@ require (
|
||||
github.com/agext/levenshtein v1.2.3 // indirect
|
||||
github.com/apparentlymart/go-cidr v1.1.0 // indirect
|
||||
github.com/apparentlymart/go-textseg/v13 v13.0.0 // indirect
|
||||
github.com/aquasecurity/defsec v0.28.5-0.20220426090908-0df04f1fa28b // indirect
|
||||
github.com/aquasecurity/tfsec v1.8.0 // indirect
|
||||
github.com/aws/aws-sdk-go v1.43.31 // indirect
|
||||
github.com/aquasecurity/defsec v0.56.0 // indirect
|
||||
github.com/aws/aws-sdk-go v1.44.5 // indirect
|
||||
github.com/bgentry/go-netrc v0.0.0-20140422174119-9fd32a8b3d3d // indirect
|
||||
github.com/bmatcuk/doublestar v1.3.4 // indirect
|
||||
github.com/briandowns/spinner v1.12.0 // indirect
|
||||
github.com/cespare/xxhash/v2 v2.1.2 // indirect
|
||||
github.com/containerd/cgroups v1.0.3 // indirect
|
||||
github.com/containerd/containerd v1.6.2 // indirect
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.10.1 // indirect
|
||||
github.com/containerd/containerd v1.6.3-0.20220401172941-5ff8fce1fcc6 // indirect
|
||||
github.com/containerd/stargz-snapshotter/estargz v0.11.3 // indirect
|
||||
github.com/containerd/typeurl v1.0.2 // indirect
|
||||
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
|
||||
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||
github.com/dimchansky/utfbom v1.1.1 // indirect
|
||||
github.com/docker/cli v20.10.11+incompatible // indirect
|
||||
github.com/docker/distribution v2.7.1+incompatible // indirect
|
||||
github.com/docker/cli v20.10.13+incompatible // indirect
|
||||
github.com/docker/distribution v2.8.0+incompatible // indirect
|
||||
github.com/docker/docker-credential-helpers v0.6.4 // indirect
|
||||
github.com/docker/go-units v0.4.0 // indirect
|
||||
github.com/emirpasic/gods v1.12.0 // indirect
|
||||
@@ -111,40 +109,40 @@ require (
|
||||
github.com/hashicorp/go-multierror v1.1.1 // indirect
|
||||
github.com/hashicorp/go-retryablehttp v0.7.1 // indirect
|
||||
github.com/hashicorp/go-safetemp v1.0.0 // indirect
|
||||
github.com/hashicorp/go-uuid v1.0.2 // indirect
|
||||
github.com/hashicorp/go-uuid v1.0.3 // indirect
|
||||
github.com/hashicorp/go-version v1.4.0 // indirect
|
||||
github.com/hashicorp/hcl v1.0.0 // indirect
|
||||
github.com/hashicorp/hcl/v2 v2.11.1 // indirect
|
||||
github.com/huandu/xstrings v1.3.1 // indirect
|
||||
github.com/hashicorp/hcl/v2 v2.12.0 // indirect
|
||||
github.com/huandu/xstrings v1.3.2 // indirect
|
||||
github.com/imdario/mergo v0.3.12 // indirect
|
||||
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
|
||||
github.com/klauspost/compress v1.14.2 // indirect
|
||||
github.com/klauspost/compress v1.15.1 // indirect
|
||||
github.com/knqyf263/go-rpmdb v0.0.0-20220209103220-0f7a6d951a6d // indirect
|
||||
github.com/knqyf263/nested v0.0.1 // indirect
|
||||
github.com/liamg/iamgo v0.0.6 // indirect
|
||||
github.com/liamg/jfather v0.0.7 // indirect
|
||||
github.com/liamg/memoryfs v1.4.1 // indirect
|
||||
github.com/liamg/tml v0.6.0 // indirect
|
||||
github.com/magiconair/properties v1.8.5 // indirect
|
||||
github.com/mattn/go-colorable v0.1.12 // indirect
|
||||
github.com/mattn/go-isatty v0.0.14 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.12 // indirect
|
||||
github.com/mitchellh/copystructure v1.0.0 // indirect
|
||||
github.com/mitchellh/copystructure v1.2.0 // indirect
|
||||
github.com/mitchellh/go-homedir v1.1.0 // indirect
|
||||
github.com/mitchellh/go-testing-interface v1.0.0 // indirect
|
||||
github.com/mitchellh/go-wordwrap v1.0.1 // indirect
|
||||
github.com/mitchellh/mapstructure v1.4.3 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.0 // indirect
|
||||
github.com/moby/buildkit v0.9.3 // indirect
|
||||
github.com/moby/sys/mount v0.2.0 // indirect
|
||||
github.com/mitchellh/reflectwalk v1.0.2 // indirect
|
||||
github.com/moby/buildkit v0.10.3 // indirect
|
||||
github.com/moby/sys/mount v0.3.0 // indirect
|
||||
github.com/moby/sys/mountinfo v0.6.0 // indirect
|
||||
github.com/moby/term v0.0.0-20210610120745-9d4ed1856297 // indirect
|
||||
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.2 // indirect
|
||||
github.com/opencontainers/runc v1.1.0 // indirect
|
||||
github.com/owenrumney/squealer v0.3.2 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
|
||||
github.com/opencontainers/runc v1.1.1 // indirect
|
||||
github.com/owenrumney/squealer v1.0.1-0.20220510063705-c0be93f0edea // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/rcrowley/go-metrics v0.0.0-20200313005456-10cdbea86bc0 // indirect
|
||||
@@ -158,7 +156,6 @@ require (
|
||||
github.com/spdx/tools-golang v0.3.0
|
||||
github.com/spf13/cast v1.4.1 // indirect
|
||||
github.com/stretchr/objx v0.3.0 // indirect
|
||||
github.com/tmccombs/hcl2json v0.3.4 // indirect
|
||||
github.com/ulikunitz/xz v0.5.8 // indirect
|
||||
github.com/vbatts/tar-split v0.11.2 // indirect
|
||||
github.com/xanzy/ssh-agent v0.3.0 // indirect
|
||||
@@ -196,10 +193,10 @@ require (
|
||||
modernc.org/sqlite v1.14.5 // indirect
|
||||
modernc.org/strutil v1.1.1 // indirect
|
||||
modernc.org/token v1.0.0 // indirect
|
||||
sigs.k8s.io/yaml v1.3.0 // indirect
|
||||
)
|
||||
|
||||
require github.com/mitchellh/hashstructure/v2 v2.0.2
|
||||
|
||||
// To resolve CVE-2022-23648
|
||||
replace github.com/containerd/containerd v1.5.9 => github.com/containerd/containerd v1.5.10
|
||||
|
||||
// See https://github.com/moby/moby/issues/42939#issuecomment-1114255529
|
||||
replace github.com/docker/docker => github.com/docker/docker v20.10.3-0.20220224222438-c78f6963a1c0+incompatible
|
||||
|
||||
@@ -68,8 +68,8 @@ func TestFilesystem(t *testing.T) {
|
||||
name: "dockerfile",
|
||||
args: args{
|
||||
securityChecks: "config",
|
||||
policyPaths: []string{"testdata/fixtures/fs/dockerfile/policy"},
|
||||
input: "testdata/fixtures/fs/dockerfile",
|
||||
namespaces: []string{"testing"},
|
||||
},
|
||||
golden: "testdata/dockerfile.json.golden",
|
||||
},
|
||||
|
||||
@@ -20,34 +20,42 @@
|
||||
"Class": "config",
|
||||
"Type": "dockerfile",
|
||||
"MisconfSummary": {
|
||||
"Successes": 0,
|
||||
"Successes": 23,
|
||||
"Failures": 2,
|
||||
"Exceptions": 0
|
||||
},
|
||||
"Misconfigurations": [
|
||||
{
|
||||
"Type": "N/A",
|
||||
"Type": "Dockerfile Security Check",
|
||||
"ID": "N/A",
|
||||
"Title": "N/A",
|
||||
"Description": "Rego module: data.user.bar",
|
||||
"Message": "something bad: bar",
|
||||
"Namespace": "user.bar",
|
||||
"Query": "data.user.bar.deny",
|
||||
"Severity": "UNKNOWN",
|
||||
"Status": "FAIL",
|
||||
"Layer": {},
|
||||
"IacMetadata": {}
|
||||
"IacMetadata": {
|
||||
"Provider": "Generic",
|
||||
"Service": "general"
|
||||
}
|
||||
},
|
||||
{
|
||||
"Type": "N/A",
|
||||
"Type": "Dockerfile Security Check",
|
||||
"ID": "N/A",
|
||||
"Title": "N/A",
|
||||
"Description": "Rego module: data.user.foo",
|
||||
"Message": "something bad: foo",
|
||||
"Namespace": "user.foo",
|
||||
"Query": "data.user.foo.deny",
|
||||
"Severity": "UNKNOWN",
|
||||
"Status": "FAIL",
|
||||
"Layer": {},
|
||||
"IacMetadata": {}
|
||||
"IacMetadata": {
|
||||
"Provider": "Generic",
|
||||
"Service": "general"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
"MisconfSummary": {
|
||||
"Successes": 0,
|
||||
"Failures": 0,
|
||||
"Exceptions": 1
|
||||
"Exceptions": 23
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
"Class": "config",
|
||||
"Type": "dockerfile",
|
||||
"MisconfSummary": {
|
||||
"Successes": 0,
|
||||
"Successes": 22,
|
||||
"Failures": 0,
|
||||
"Exceptions": 1
|
||||
}
|
||||
|
||||
19
integration/testdata/dockerfile.json.golden
vendored
19
integration/testdata/dockerfile.json.golden
vendored
@@ -20,7 +20,7 @@
|
||||
"Class": "config",
|
||||
"Type": "dockerfile",
|
||||
"MisconfSummary": {
|
||||
"Successes": 0,
|
||||
"Successes": 22,
|
||||
"Failures": 1,
|
||||
"Exceptions": 0
|
||||
},
|
||||
@@ -29,20 +29,23 @@
|
||||
"Type": "Dockerfile Security Check",
|
||||
"ID": "DS002",
|
||||
"Title": "Image user should not be 'root'",
|
||||
"Description": "It is a good practice to run the container as a non-root user.",
|
||||
"Message": "Specify at least 1 USER command in Dockerfile",
|
||||
"Namespace": "appshield.dockerfile.DS002",
|
||||
"Query": "data.appshield.dockerfile.DS002.deny",
|
||||
"Description": "Running containers with 'root' user can lead to a container escape situation. It is a best practice to run containers as non-root users, which can be done by adding a 'USER' statement to the Dockerfile.",
|
||||
"Message": "Specify at least 1 USER command in Dockerfile with non-root user as argument",
|
||||
"Namespace": "builtin.dockerfile.DS002",
|
||||
"Query": "data.builtin.dockerfile.DS002.deny",
|
||||
"Resolution": "Add 'USER \u003cnon root user name\u003e' line to the Dockerfile",
|
||||
"Severity": "HIGH",
|
||||
"PrimaryURL": "https://avd.aquasec.com/appshield/ds002",
|
||||
"PrimaryURL": "https://avd.aquasec.com/misconfig/ds002",
|
||||
"References": [
|
||||
"https://docs.docker.com/develop/develop-images/dockerfile_best-practices/",
|
||||
"https://avd.aquasec.com/appshield/ds002"
|
||||
"https://avd.aquasec.com/misconfig/ds002"
|
||||
],
|
||||
"Status": "FAIL",
|
||||
"Layer": {},
|
||||
"IacMetadata": {}
|
||||
"IacMetadata": {
|
||||
"Provider": "Dockerfile",
|
||||
"Service": "general"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
FROM alpine:3.13
|
||||
FROM alpine:3.13
|
||||
|
||||
USER nobody
|
||||
@@ -1,49 +0,0 @@
|
||||
package appshield.dockerfile.DS002
|
||||
|
||||
import data.lib.docker
|
||||
|
||||
__rego_metadata__ := {
|
||||
"id": "DS002",
|
||||
"title": "Image user should not be 'root'",
|
||||
"version": "v1.0.0",
|
||||
"severity": "HIGH",
|
||||
"type": "Dockerfile Security Check",
|
||||
"description": "It is a good practice to run the container as a non-root user.",
|
||||
"recommended_actions": "Add 'USER <non root user name>' line to the Dockerfile",
|
||||
"url": "https://docs.docker.com/develop/develop-images/dockerfile_best-practices/"
|
||||
}
|
||||
|
||||
__rego_input__ := {
|
||||
"combine": false,
|
||||
"selector": [{"type": "dockerfile"}],
|
||||
}
|
||||
|
||||
# get_user returns all the usernames from
|
||||
# the USER command.
|
||||
get_user[username] {
|
||||
user := docker.user[_]
|
||||
username := user.Value[_]
|
||||
}
|
||||
|
||||
# fail_user_count is true if there is no USER command.
|
||||
fail_user_count {
|
||||
count(get_user) < 1
|
||||
}
|
||||
|
||||
# fail_last_user_root is true if the last USER command
|
||||
# value is "root"
|
||||
fail_last_user_root {
|
||||
user := cast_array(get_user)
|
||||
len := count(get_user)
|
||||
user[minus(len, 1)] == "root"
|
||||
}
|
||||
|
||||
deny[msg] {
|
||||
fail_user_count
|
||||
msg = "Specify at least 1 USER command in Dockerfile"
|
||||
}
|
||||
|
||||
deny[res] {
|
||||
fail_last_user_root
|
||||
res := "Last USER command in Dockerfile should not be root"
|
||||
}
|
||||
@@ -4,5 +4,5 @@ import data.namespaces
|
||||
|
||||
exception[ns] {
|
||||
ns := data.namespaces[_]
|
||||
startswith(ns, "appshield")
|
||||
startswith(ns, "builtin")
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
package appshield.dockerfile.DS002
|
||||
|
||||
import data.lib.docker
|
||||
|
||||
__rego_metadata__ := {
|
||||
"id": "DS002",
|
||||
"title": "Image user should not be 'root'",
|
||||
"version": "v1.0.0",
|
||||
"severity": "HIGH",
|
||||
"type": "Dockerfile Security Check",
|
||||
"description": "It is a good practice to run the container as a non-root user.",
|
||||
"recommended_actions": "Add 'USER <non root user name>' line to the Dockerfile",
|
||||
}
|
||||
|
||||
__rego_input__ := {
|
||||
"combine": false,
|
||||
"selector": [{"type": "dockerfile"}],
|
||||
}
|
||||
|
||||
# get_user returns all the usernames from
|
||||
# the USER command.
|
||||
get_user[username] {
|
||||
user := docker.user[_]
|
||||
username := user.Value[_]
|
||||
}
|
||||
|
||||
# fail_user_count is true if there is no USER command.
|
||||
fail_user_count {
|
||||
count(get_user) < 1
|
||||
}
|
||||
|
||||
# fail_last_user_root is true if the last USER command
|
||||
# value is "root"
|
||||
fail_last_user_root {
|
||||
user := cast_array(get_user)
|
||||
len := count(get_user)
|
||||
user[minus(len, 1)] == "root"
|
||||
}
|
||||
|
||||
deny[msg] {
|
||||
fail_user_count
|
||||
msg = "Specify at least 1 USER command in Dockerfile"
|
||||
}
|
||||
|
||||
deny[res] {
|
||||
fail_last_user_root
|
||||
res := "Last USER command in Dockerfile should not be root"
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
package appshield.dockerfile.DS002
|
||||
package builtin.dockerfile.DS002
|
||||
|
||||
exception[rules] {
|
||||
instruction := input.stages[_][_]
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
package appshield.dockerfile.DS002
|
||||
|
||||
import data.lib.docker
|
||||
|
||||
__rego_metadata__ := {
|
||||
"id": "DS002",
|
||||
"title": "Image user should not be 'root'",
|
||||
"version": "v1.0.0",
|
||||
"severity": "HIGH",
|
||||
"type": "Dockerfile Security Check",
|
||||
"description": "It is a good practice to run the container as a non-root user.",
|
||||
"recommended_actions": "Add 'USER <non root user name>' line to the Dockerfile",
|
||||
}
|
||||
|
||||
__rego_input__ := {
|
||||
"combine": false,
|
||||
"selector": [{"type": "dockerfile"}],
|
||||
}
|
||||
|
||||
# get_user returns all the usernames from
|
||||
# the USER command.
|
||||
get_user[username] {
|
||||
user := docker.user[_]
|
||||
username := user.Value[_]
|
||||
}
|
||||
|
||||
# fail_user_count is true if there is no USER command.
|
||||
fail_user_count {
|
||||
count(get_user) < 1
|
||||
}
|
||||
|
||||
# fail_last_user_root is true if the last USER command
|
||||
# value is "root"
|
||||
fail_last_user_root {
|
||||
user := cast_array(get_user)
|
||||
len := count(get_user)
|
||||
user[minus(len, 1)] == "root"
|
||||
}
|
||||
|
||||
deny[msg] {
|
||||
fail_user_count
|
||||
msg = "Specify at least 1 USER command in Dockerfile"
|
||||
}
|
||||
|
||||
deny[res] {
|
||||
fail_last_user_root
|
||||
res := "Last USER command in Dockerfile should not be root"
|
||||
}
|
||||
2
integration/testdata/gomod.json.golden
vendored
2
integration/testdata/gomod.json.golden
vendored
@@ -158,4 +158,4 @@
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -37,10 +37,7 @@ nav:
|
||||
- Languages:
|
||||
- Go: docs/vulnerability/languages/golang.md
|
||||
- Misconfiguration:
|
||||
- Scanning:
|
||||
- Overview: docs/misconfiguration/index.md
|
||||
- Infrastructure as Code: docs/misconfiguration/iac.md
|
||||
- Filesystem: docs/misconfiguration/filesystem.md
|
||||
- Scanning: docs/misconfiguration/scanning.md
|
||||
- Policy:
|
||||
- Built-in Policies: docs/misconfiguration/policy/builtin.md
|
||||
- Exceptions: docs/misconfiguration/policy/exceptions.md
|
||||
|
||||
@@ -25,7 +25,7 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/utils"
|
||||
)
|
||||
|
||||
const defaultPolicyNamespace = "appshield"
|
||||
var defaultPolicyNamespaces = []string{"appshield", "defsec", "builtin"}
|
||||
|
||||
var errSkipScan = errors.New("skip subsequent processes")
|
||||
|
||||
@@ -223,16 +223,10 @@ func scan(ctx context.Context, opt Option, initializeScanner InitializeScanner,
|
||||
// ScannerOption is filled only when config scanning is enabled.
|
||||
var configScannerOptions config.ScannerOption
|
||||
if slices.Contains(opt.SecurityChecks, types.SecurityCheckConfig) {
|
||||
noProgress := opt.Quiet || opt.NoProgress
|
||||
builtinPolicyPaths, err := operation.InitBuiltinPolicies(ctx, opt.CacheDir, noProgress, opt.SkipPolicyUpdate)
|
||||
if err != nil {
|
||||
return types.Report{}, xerrors.Errorf("failed to initialize built-in policies: %w", err)
|
||||
}
|
||||
|
||||
configScannerOptions = config.ScannerOption{
|
||||
Trace: opt.Trace,
|
||||
Namespaces: append(opt.PolicyNamespaces, defaultPolicyNamespace),
|
||||
PolicyPaths: append(opt.PolicyPaths, builtinPolicyPaths...),
|
||||
Namespaces: append(opt.PolicyNamespaces, defaultPolicyNamespaces...),
|
||||
PolicyPaths: opt.PolicyPaths,
|
||||
DataPaths: opt.DataPaths,
|
||||
FilePatterns: opt.FilePatterns,
|
||||
}
|
||||
|
||||
@@ -15,7 +15,6 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/commands/option"
|
||||
"github.com/aquasecurity/trivy/pkg/db"
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
"github.com/aquasecurity/trivy/pkg/policy"
|
||||
"github.com/aquasecurity/trivy/pkg/utils"
|
||||
)
|
||||
|
||||
@@ -123,40 +122,6 @@ func DownloadDB(appVersion, cacheDir, dbRepository string, quiet, skipUpdate boo
|
||||
return nil
|
||||
}
|
||||
|
||||
// InitBuiltinPolicies downloads the built-in policies and loads them
|
||||
func InitBuiltinPolicies(ctx context.Context, cacheDir string, quiet, skipUpdate bool) ([]string, error) {
|
||||
client, err := policy.NewClient(cacheDir, quiet)
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("policy client error: %w", err)
|
||||
}
|
||||
|
||||
needsUpdate := false
|
||||
if !skipUpdate {
|
||||
needsUpdate, err = client.NeedsUpdate()
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("unable to check if built-in policies need to be updated: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
if needsUpdate {
|
||||
log.Logger.Info("Need to update the built-in policies")
|
||||
log.Logger.Info("Downloading the built-in policies...")
|
||||
if err = client.DownloadBuiltinPolicies(ctx); err != nil {
|
||||
return nil, xerrors.Errorf("failed to download built-in policies: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
policyPaths, err := client.LoadBuiltinPolicies()
|
||||
if err != nil {
|
||||
if skipUpdate {
|
||||
log.Logger.Info("No built-in policies were loaded")
|
||||
return nil, nil
|
||||
}
|
||||
return nil, xerrors.Errorf("policy load error: %w", err)
|
||||
}
|
||||
return policyPaths, nil
|
||||
}
|
||||
|
||||
func showDBInfo(cacheDir string) error {
|
||||
m := metadata.NewClient(cacheDir)
|
||||
meta, err := m.Get()
|
||||
|
||||
@@ -1,213 +0,0 @@
|
||||
package policy
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"time"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/oci"
|
||||
|
||||
"github.com/open-policy-agent/opa/bundle"
|
||||
"golang.org/x/xerrors"
|
||||
"k8s.io/utils/clock"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/log"
|
||||
)
|
||||
|
||||
const (
|
||||
bundleVersion = 1
|
||||
bundleRepository = "ghcr.io/aquasecurity/appshield"
|
||||
policyMediaType = "application/vnd.cncf.openpolicyagent.layer.v1.tar+gzip"
|
||||
updateInterval = 24 * time.Hour
|
||||
)
|
||||
|
||||
type options struct {
|
||||
artifact *oci.Artifact
|
||||
clock clock.Clock
|
||||
}
|
||||
|
||||
// Option is a functional option
|
||||
type Option func(*options)
|
||||
|
||||
// WithOCIArtifact takes an OCI artifact
|
||||
func WithOCIArtifact(art *oci.Artifact) Option {
|
||||
return func(opts *options) {
|
||||
opts.artifact = art
|
||||
}
|
||||
}
|
||||
|
||||
// WithClock takes a clock
|
||||
func WithClock(clock clock.Clock) Option {
|
||||
return func(opts *options) {
|
||||
opts.clock = clock
|
||||
}
|
||||
}
|
||||
|
||||
// Metadata holds default policy metadata
|
||||
type Metadata struct {
|
||||
Digest string
|
||||
DownloadedAt time.Time
|
||||
}
|
||||
|
||||
// Client implements policy operations
|
||||
type Client struct {
|
||||
*options
|
||||
policyDir string
|
||||
quiet bool
|
||||
}
|
||||
|
||||
// NewClient is the factory method for policy client
|
||||
func NewClient(cacheDir string, quiet bool, opts ...Option) (*Client, error) {
|
||||
o := &options{
|
||||
clock: clock.RealClock{},
|
||||
}
|
||||
|
||||
for _, opt := range opts {
|
||||
opt(o)
|
||||
}
|
||||
|
||||
return &Client{
|
||||
options: o,
|
||||
policyDir: filepath.Join(cacheDir, "policy"),
|
||||
quiet: quiet,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// LoadBuiltinPolicies loads default policies
|
||||
func (c *Client) LoadBuiltinPolicies() ([]string, error) {
|
||||
f, err := os.Open(c.manifestPath())
|
||||
if err != nil {
|
||||
return nil, xerrors.Errorf("manifest file open error (%s): %w", c.manifestPath(), err)
|
||||
}
|
||||
|
||||
var manifest bundle.Manifest
|
||||
if err = json.NewDecoder(f).Decode(&manifest); err != nil {
|
||||
return nil, xerrors.Errorf("json decode error (%s): %w", c.manifestPath(), err)
|
||||
}
|
||||
|
||||
// If the "roots" field is not included in the manifest it defaults to [""]
|
||||
// which means that ALL data and policy must come from the bundle.
|
||||
if manifest.Roots == nil || len(*manifest.Roots) == 0 {
|
||||
return []string{c.contentDir()}, nil
|
||||
}
|
||||
|
||||
var policyPaths []string
|
||||
for _, root := range *manifest.Roots {
|
||||
policyPaths = append(policyPaths, filepath.Join(c.contentDir(), root))
|
||||
}
|
||||
|
||||
return policyPaths, nil
|
||||
}
|
||||
|
||||
// NeedsUpdate returns if the default policy should be updated
|
||||
func (c *Client) NeedsUpdate() (bool, error) {
|
||||
f, err := os.Open(c.metadataPath())
|
||||
if err != nil {
|
||||
log.Logger.Debugf("Failed to open the policy metadata: %s", err)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
var meta Metadata
|
||||
if err = json.NewDecoder(f).Decode(&meta); err != nil {
|
||||
log.Logger.Warnf("Policy metadata decode error: %s", err)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// No need to update if it's been within a day since the last update.
|
||||
if c.clock.Now().Before(meta.DownloadedAt.Add(updateInterval)) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
if err = c.populateOCIArtifact(); err != nil {
|
||||
return false, xerrors.Errorf("OPA bundle error: %w", err)
|
||||
}
|
||||
|
||||
digest, err := c.artifact.Digest()
|
||||
if err != nil {
|
||||
return false, xerrors.Errorf("digest error: %w", err)
|
||||
}
|
||||
|
||||
if meta.Digest != digest {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
// Update DownloadedAt with the current time.
|
||||
// Otherwise, if there are no updates in the remote registry,
|
||||
// the digest will be fetched every time even after this.
|
||||
if err = c.updateMetadata(meta.Digest, time.Now()); err != nil {
|
||||
return false, xerrors.Errorf("unable to update the policy metadata: %w", err)
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func (c *Client) populateOCIArtifact() error {
|
||||
if c.artifact == nil {
|
||||
repo := fmt.Sprintf("%s:%d", bundleRepository, bundleVersion)
|
||||
art, err := oci.NewArtifact(repo, policyMediaType, c.quiet)
|
||||
if err != nil {
|
||||
return xerrors.Errorf("OCI artifact error: %w", err)
|
||||
}
|
||||
c.artifact = art
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// DownloadBuiltinPolicies download default policies from GitHub Pages
|
||||
func (c *Client) DownloadBuiltinPolicies(ctx context.Context) error {
|
||||
if err := c.populateOCIArtifact(); err != nil {
|
||||
return xerrors.Errorf("OPA bundle error: %w", err)
|
||||
}
|
||||
|
||||
dst := c.contentDir()
|
||||
if err := c.artifact.Download(ctx, dst); err != nil {
|
||||
return xerrors.Errorf("download error: %w", err)
|
||||
}
|
||||
|
||||
digest, err := c.artifact.Digest()
|
||||
if err != nil {
|
||||
return xerrors.Errorf("digest error: %w", err)
|
||||
}
|
||||
log.Logger.Debugf("Digest of the built-in policies: %s", digest)
|
||||
|
||||
// Update metadata.json with the new digest and the current date
|
||||
if err = c.updateMetadata(digest, c.clock.Now()); err != nil {
|
||||
return xerrors.Errorf("unable to update the policy metadata: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) updateMetadata(digest string, now time.Time) error {
|
||||
f, err := os.Create(c.metadataPath())
|
||||
if err != nil {
|
||||
return xerrors.Errorf("failed to open a policy manifest: %w", err)
|
||||
}
|
||||
defer f.Close()
|
||||
|
||||
meta := Metadata{
|
||||
Digest: digest,
|
||||
DownloadedAt: now,
|
||||
}
|
||||
|
||||
if err = json.NewEncoder(f).Encode(meta); err != nil {
|
||||
return xerrors.Errorf("json encode error: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *Client) contentDir() string {
|
||||
return filepath.Join(c.policyDir, "content")
|
||||
}
|
||||
|
||||
func (c *Client) metadataPath() string {
|
||||
return filepath.Join(c.policyDir, "metadata.json")
|
||||
}
|
||||
|
||||
func (c *Client) manifestPath() string {
|
||||
return filepath.Join(c.contentDir(), bundle.ManifestExt)
|
||||
}
|
||||
@@ -1,331 +0,0 @@
|
||||
package policy_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
v1 "github.com/google/go-containerregistry/pkg/v1"
|
||||
fakei "github.com/google/go-containerregistry/pkg/v1/fake"
|
||||
"github.com/google/go-containerregistry/pkg/v1/tarball"
|
||||
"github.com/google/go-containerregistry/pkg/v1/types"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
"k8s.io/utils/clock"
|
||||
fake "k8s.io/utils/clock/testing"
|
||||
|
||||
"github.com/aquasecurity/trivy/pkg/oci"
|
||||
"github.com/aquasecurity/trivy/pkg/policy"
|
||||
)
|
||||
|
||||
type fakeLayer struct {
|
||||
v1.Layer
|
||||
}
|
||||
|
||||
func (f fakeLayer) MediaType() (types.MediaType, error) {
|
||||
return "application/vnd.cncf.openpolicyagent.layer.v1.tar+gzip", nil
|
||||
}
|
||||
|
||||
func newFakeLayer(t *testing.T) v1.Layer {
|
||||
layer, err := tarball.LayerFromFile("testdata/bundle.tar.gz")
|
||||
require.NoError(t, err)
|
||||
|
||||
return fakeLayer{layer}
|
||||
}
|
||||
|
||||
type brokenLayer struct {
|
||||
v1.Layer
|
||||
}
|
||||
|
||||
func (b brokenLayer) MediaType() (types.MediaType, error) {
|
||||
return "application/vnd.cncf.openpolicyagent.layer.v1.tar+gzip", nil
|
||||
}
|
||||
|
||||
func (b brokenLayer) Compressed() (io.ReadCloser, error) {
|
||||
return nil, fmt.Errorf("compressed error")
|
||||
}
|
||||
|
||||
func newBrokenLayer(t *testing.T) v1.Layer {
|
||||
layer, err := tarball.LayerFromFile("testdata/bundle.tar.gz")
|
||||
require.NoError(t, err)
|
||||
|
||||
return brokenLayer{layer}
|
||||
}
|
||||
|
||||
func TestClient_LoadBuiltinPolicies(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
cacheDir string
|
||||
want []string
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
cacheDir: "testdata/happy",
|
||||
want: []string{
|
||||
"testdata/happy/policy/content/kubernetes",
|
||||
"testdata/happy/policy/content/docker",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "empty roots",
|
||||
cacheDir: "testdata/empty",
|
||||
want: []string{
|
||||
"testdata/empty/policy/content",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "broken manifest",
|
||||
cacheDir: "testdata/broken",
|
||||
want: []string{},
|
||||
wantErr: "json decode error",
|
||||
},
|
||||
{
|
||||
name: "no such file",
|
||||
cacheDir: "testdata/unknown",
|
||||
want: []string{},
|
||||
wantErr: "manifest file open error",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Mock image
|
||||
img := new(fakei.FakeImage)
|
||||
img.LayersReturns([]v1.Layer{newFakeLayer(t)}, nil)
|
||||
|
||||
// Mock OCI artifact
|
||||
mediaType := "application/vnd.cncf.openpolicyagent.layer.v1.tar+gzip"
|
||||
art, err := oci.NewArtifact("repo", mediaType, true, oci.WithImage(img))
|
||||
require.NoError(t, err)
|
||||
|
||||
c, err := policy.NewClient(tt.cacheDir, true, policy.WithOCIArtifact(art))
|
||||
require.NoError(t, err)
|
||||
|
||||
got, err := c.LoadBuiltinPolicies()
|
||||
if tt.wantErr != "" {
|
||||
require.NotNil(t, err)
|
||||
assert.Contains(t, err.Error(), tt.wantErr)
|
||||
return
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_NeedsUpdate(t *testing.T) {
|
||||
type digestReturns struct {
|
||||
h v1.Hash
|
||||
err error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
clock clock.Clock
|
||||
digestReturns digestReturns
|
||||
metadata interface{}
|
||||
want bool
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "recent download",
|
||||
clock: fake.NewFakeClock(time.Date(2021, 1, 1, 1, 0, 0, 0, time.UTC)),
|
||||
digestReturns: digestReturns{
|
||||
h: v1.Hash{Algorithm: "sha256", Hex: "01e033e78bd8a59fa4f4577215e7da06c05e1152526094d8d79d2aa06e98cb9d"},
|
||||
},
|
||||
metadata: policy.Metadata{
|
||||
Digest: `sha256:922e50f14ab484f11ae65540c3d2d76009020213f1027d4331d31141575e5414`,
|
||||
DownloadedAt: time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "same digest",
|
||||
clock: fake.NewFakeClock(time.Date(2021, 1, 2, 1, 0, 0, 0, time.UTC)),
|
||||
digestReturns: digestReturns{
|
||||
h: v1.Hash{Algorithm: "sha256", Hex: "01e033e78bd8a59fa4f4577215e7da06c05e1152526094d8d79d2aa06e98cb9d"},
|
||||
},
|
||||
metadata: policy.Metadata{
|
||||
Digest: `sha256:01e033e78bd8a59fa4f4577215e7da06c05e1152526094d8d79d2aa06e98cb9d`,
|
||||
DownloadedAt: time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
},
|
||||
want: false,
|
||||
},
|
||||
{
|
||||
name: "different digest",
|
||||
clock: fake.NewFakeClock(time.Date(2021, 1, 2, 1, 0, 0, 0, time.UTC)),
|
||||
digestReturns: digestReturns{
|
||||
h: v1.Hash{Algorithm: "sha256", Hex: "01e033e78bd8a59fa4f4577215e7da06c05e1152526094d8d79d2aa06e98cb9d"},
|
||||
},
|
||||
metadata: policy.Metadata{
|
||||
Digest: `sha256:922e50f14ab484f11ae65540c3d2d76009020213f1027d4331d31141575e5414`,
|
||||
DownloadedAt: time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
},
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "sad: Digest returns an error",
|
||||
clock: fake.NewFakeClock(time.Date(2021, 1, 2, 1, 0, 0, 0, time.UTC)),
|
||||
digestReturns: digestReturns{
|
||||
err: fmt.Errorf("error"),
|
||||
},
|
||||
metadata: policy.Metadata{
|
||||
Digest: `sha256:922e50f14ab484f11ae65540c3d2d76009020213f1027d4331d31141575e5414`,
|
||||
DownloadedAt: time.Date(2021, 1, 1, 0, 0, 0, 0, time.UTC),
|
||||
},
|
||||
want: false,
|
||||
wantErr: true,
|
||||
},
|
||||
{
|
||||
name: "sad: non-existent metadata",
|
||||
clock: fake.NewFakeClock(time.Date(2021, 1, 1, 1, 0, 0, 0, time.UTC)),
|
||||
want: true,
|
||||
},
|
||||
{
|
||||
name: "sad: broken metadata",
|
||||
clock: fake.NewFakeClock(time.Date(2021, 1, 1, 1, 0, 0, 0, time.UTC)),
|
||||
metadata: `"foo"`,
|
||||
want: true,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
// Set up a temporary directory
|
||||
tmpDir := t.TempDir()
|
||||
|
||||
// Mock image
|
||||
img := new(fakei.FakeImage)
|
||||
img.LayersReturns([]v1.Layer{newFakeLayer(t)}, nil)
|
||||
img.DigestReturns(tt.digestReturns.h, tt.digestReturns.err)
|
||||
|
||||
// Create a policy directory
|
||||
err := os.MkdirAll(filepath.Join(tmpDir, "policy"), os.ModePerm)
|
||||
require.NoError(t, err)
|
||||
|
||||
if tt.metadata != nil {
|
||||
b, err := json.Marshal(tt.metadata)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Write a metadata file
|
||||
metadataPath := filepath.Join(tmpDir, "policy", "metadata.json")
|
||||
err = os.WriteFile(metadataPath, b, os.ModePerm)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
mediaType := "application/vnd.cncf.openpolicyagent.layer.v1.tar+gzip"
|
||||
art, err := oci.NewArtifact("repo", mediaType, true, oci.WithImage(img))
|
||||
require.NoError(t, err)
|
||||
|
||||
c, err := policy.NewClient(tmpDir, true, policy.WithOCIArtifact(art), policy.WithClock(tt.clock))
|
||||
require.NoError(t, err)
|
||||
|
||||
// Assert results
|
||||
got, err := c.NeedsUpdate()
|
||||
assert.Equal(t, tt.wantErr, err != nil)
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestClient_DownloadBuiltinPolicies(t *testing.T) {
|
||||
type digestReturns struct {
|
||||
h v1.Hash
|
||||
err error
|
||||
}
|
||||
type layersReturns struct {
|
||||
layers []v1.Layer
|
||||
err error
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
clock clock.Clock
|
||||
layersReturns layersReturns
|
||||
digestReturns digestReturns
|
||||
want *policy.Metadata
|
||||
wantErr string
|
||||
}{
|
||||
{
|
||||
name: "happy path",
|
||||
clock: fake.NewFakeClock(time.Date(2021, 1, 1, 1, 0, 0, 0, time.UTC)),
|
||||
layersReturns: layersReturns{
|
||||
layers: []v1.Layer{newFakeLayer(t)},
|
||||
},
|
||||
digestReturns: digestReturns{
|
||||
h: v1.Hash{Algorithm: "sha256", Hex: "01e033e78bd8a59fa4f4577215e7da06c05e1152526094d8d79d2aa06e98cb9d"},
|
||||
},
|
||||
want: &policy.Metadata{
|
||||
Digest: "sha256:01e033e78bd8a59fa4f4577215e7da06c05e1152526094d8d79d2aa06e98cb9d",
|
||||
DownloadedAt: time.Date(2021, 1, 1, 1, 0, 0, 0, time.UTC),
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "sad: broken layer",
|
||||
clock: fake.NewFakeClock(time.Date(2021, 1, 1, 1, 0, 0, 0, time.UTC)),
|
||||
layersReturns: layersReturns{
|
||||
layers: []v1.Layer{newBrokenLayer(t)},
|
||||
},
|
||||
digestReturns: digestReturns{
|
||||
h: v1.Hash{Algorithm: "sha256", Hex: "01e033e78bd8a59fa4f4577215e7da06c05e1152526094d8d79d2aa06e98cb9d"},
|
||||
},
|
||||
wantErr: "compressed error",
|
||||
},
|
||||
{
|
||||
name: "sad: Digest returns an error",
|
||||
clock: fake.NewFakeClock(time.Date(2021, 1, 1, 1, 0, 0, 0, time.UTC)),
|
||||
layersReturns: layersReturns{
|
||||
layers: []v1.Layer{newFakeLayer(t)},
|
||||
},
|
||||
digestReturns: digestReturns{
|
||||
err: fmt.Errorf("error"),
|
||||
},
|
||||
want: &policy.Metadata{
|
||||
Digest: "sha256:01e033e78bd8a59fa4f4577215e7da06c05e1152526094d8d79d2aa06e98cb9d",
|
||||
DownloadedAt: time.Date(2021, 1, 1, 1, 0, 0, 0, time.UTC),
|
||||
},
|
||||
wantErr: "digest error",
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
tempDir := t.TempDir()
|
||||
|
||||
// Mock image
|
||||
img := new(fakei.FakeImage)
|
||||
img.DigestReturns(tt.digestReturns.h, tt.digestReturns.err)
|
||||
img.LayersReturns(tt.layersReturns.layers, tt.layersReturns.err)
|
||||
|
||||
// Mock OCI artifact
|
||||
mediaType := "application/vnd.cncf.openpolicyagent.layer.v1.tar+gzip"
|
||||
art, err := oci.NewArtifact("repo", mediaType, true, oci.WithImage(img))
|
||||
require.NoError(t, err)
|
||||
|
||||
c, err := policy.NewClient(tempDir, true, policy.WithClock(tt.clock), policy.WithOCIArtifact(art))
|
||||
require.NoError(t, err)
|
||||
|
||||
err = c.DownloadBuiltinPolicies(context.Background())
|
||||
if tt.wantErr != "" {
|
||||
require.NotNil(t, err)
|
||||
assert.Contains(t, err.Error(), tt.wantErr)
|
||||
return
|
||||
}
|
||||
assert.NoError(t, err)
|
||||
|
||||
// Assert metadata.json
|
||||
metadata := filepath.Join(tempDir, "policy", "metadata.json")
|
||||
b, err := os.ReadFile(metadata)
|
||||
require.NoError(t, err)
|
||||
|
||||
got := new(policy.Metadata)
|
||||
err = json.Unmarshal(b, got)
|
||||
require.NoError(t, err)
|
||||
|
||||
assert.Equal(t, tt.want, got)
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"revision": 1
|
||||
}
|
||||
BIN
pkg/policy/testdata/bundle.tar.gz
vendored
BIN
pkg/policy/testdata/bundle.tar.gz
vendored
Binary file not shown.
@@ -1,3 +0,0 @@
|
||||
{
|
||||
"revision": "1"
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
{
|
||||
"revision": "1",
|
||||
"roots": ["kubernetes", "docker"]
|
||||
}
|
||||
@@ -54,6 +54,8 @@ type sarifData struct {
|
||||
artifactLocation string
|
||||
message string
|
||||
cvssScore string
|
||||
startLine int
|
||||
endLine int
|
||||
}
|
||||
|
||||
func (sw *SarifWriter) addSarifRule(data *sarifData) {
|
||||
@@ -85,9 +87,14 @@ func (sw *SarifWriter) addSarifRule(data *sarifData) {
|
||||
func (sw *SarifWriter) addSarifResult(data *sarifData) {
|
||||
sw.addSarifRule(data)
|
||||
|
||||
region := sarif.NewRegion().WithStartLine(1)
|
||||
if data.startLine > 0 {
|
||||
region = sarif.NewSimpleRegion(data.startLine, data.endLine)
|
||||
}
|
||||
|
||||
location := sarif.NewPhysicalLocation().
|
||||
WithArtifactLocation(sarif.NewSimpleArtifactLocation(data.artifactLocation).WithUriBaseId("ROOTPATH")).
|
||||
WithRegion(sarif.NewRegion().WithStartLine(1))
|
||||
WithRegion(region)
|
||||
result := sarif.NewRuleResult(data.vulnerabilityId).
|
||||
WithRuleIndex(data.resultIndex).
|
||||
WithMessage(sarif.NewTextMessage(data.message)).
|
||||
@@ -153,6 +160,8 @@ func (sw SarifWriter) Write(report types.Report) error {
|
||||
url: misconf.PrimaryURL,
|
||||
resourceClass: string(res.Class),
|
||||
artifactLocation: toPathUri(res.Target),
|
||||
startLine: misconf.IacMetadata.StartLine,
|
||||
endLine: misconf.IacMetadata.EndLine,
|
||||
resultIndex: getRuleIndex(misconf.ID, ruleIndexes),
|
||||
fullDescription: html.EscapeString(misconf.Description),
|
||||
helpText: fmt.Sprintf("Misconfiguration %v\nType: %s\nSeverity: %v\nCheck: %v\nMessage: %v\nLink: [%v](%v)\n%s",
|
||||
|
||||
@@ -109,24 +109,24 @@ func TestWriter_Write(t *testing.T) {
|
||||
ExternalDocumentReferences: map[string]spdx.ExternalDocumentRef2_2{},
|
||||
},
|
||||
Packages: map[spdx.ElementID]*spdx.Package2_2{
|
||||
spdx.ElementID("e27d088813d330a4"): {
|
||||
PackageSPDXIdentifier: spdx.ElementID("e27d088813d330a4"),
|
||||
spdx.ElementID("65e3655ffcc41ab9"): {
|
||||
PackageSPDXIdentifier: spdx.ElementID("65e3655ffcc41ab9"),
|
||||
PackageName: "actioncontroller",
|
||||
PackageVersion: "7.0.0",
|
||||
PackageLicenseConcluded: "NONE",
|
||||
PackageLicenseDeclared: "NONE",
|
||||
IsFilesAnalyzedTagPresent: true,
|
||||
},
|
||||
spdx.ElementID("163ff5a6292fef8c"): {
|
||||
PackageSPDXIdentifier: spdx.ElementID("163ff5a6292fef8c"),
|
||||
spdx.ElementID("97cf5c89611089c6"): {
|
||||
PackageSPDXIdentifier: spdx.ElementID("97cf5c89611089c6"),
|
||||
PackageName: "actionpack",
|
||||
PackageVersion: "7.0.0",
|
||||
PackageLicenseConcluded: "NONE",
|
||||
PackageLicenseDeclared: "NONE",
|
||||
IsFilesAnalyzedTagPresent: true,
|
||||
},
|
||||
spdx.ElementID("a4aded544ebeda0a"): {
|
||||
PackageSPDXIdentifier: spdx.ElementID("a4aded544ebeda0a"),
|
||||
spdx.ElementID("3ee76dba6a695d6d"): {
|
||||
PackageSPDXIdentifier: spdx.ElementID("3ee76dba6a695d6d"),
|
||||
PackageName: "binutils",
|
||||
PackageVersion: "2.30",
|
||||
PackageLicenseConcluded: "GPLv3+",
|
||||
@@ -220,24 +220,24 @@ func TestWriter_Write(t *testing.T) {
|
||||
ExternalDocumentReferences: map[string]spdx.ExternalDocumentRef2_2{},
|
||||
},
|
||||
Packages: map[spdx.ElementID]*spdx.Package2_2{
|
||||
spdx.ElementID("d963712012fcbc8c"): {
|
||||
PackageSPDXIdentifier: spdx.ElementID("d963712012fcbc8c"),
|
||||
spdx.ElementID("40d016db96700ecb"): {
|
||||
PackageSPDXIdentifier: spdx.ElementID("40d016db96700ecb"),
|
||||
PackageName: "acl",
|
||||
PackageVersion: "2.2.53",
|
||||
PackageLicenseConcluded: "GPLv2+",
|
||||
PackageLicenseDeclared: "GPLv2+",
|
||||
IsFilesAnalyzedTagPresent: true,
|
||||
},
|
||||
spdx.ElementID("17ba95e087440896"): {
|
||||
PackageSPDXIdentifier: spdx.ElementID("17ba95e087440896"),
|
||||
spdx.ElementID("ff543ca421929db5"): {
|
||||
PackageSPDXIdentifier: spdx.ElementID("ff543ca421929db5"),
|
||||
PackageName: "actionpack",
|
||||
PackageVersion: "7.0.0",
|
||||
PackageLicenseConcluded: "NONE",
|
||||
PackageLicenseDeclared: "NONE",
|
||||
IsFilesAnalyzedTagPresent: true,
|
||||
},
|
||||
spdx.ElementID("50ac94ac1875540"): {
|
||||
PackageSPDXIdentifier: spdx.ElementID("50ac94ac1875540"),
|
||||
spdx.ElementID("639cce3bbd87450f"): {
|
||||
PackageSPDXIdentifier: spdx.ElementID("639cce3bbd87450f"),
|
||||
PackageName: "actionpack",
|
||||
PackageVersion: "7.0.1",
|
||||
PackageLicenseConcluded: "NONE",
|
||||
@@ -285,8 +285,8 @@ func TestWriter_Write(t *testing.T) {
|
||||
ExternalDocumentReferences: map[string]spdx.ExternalDocumentRef2_2{},
|
||||
},
|
||||
Packages: map[spdx.ElementID]*spdx.Package2_2{
|
||||
spdx.ElementID("5c11ed655628960c"): {
|
||||
PackageSPDXIdentifier: spdx.ElementID("5c11ed655628960c"),
|
||||
spdx.ElementID("9572b967bcbc8ea2"): {
|
||||
PackageSPDXIdentifier: spdx.ElementID("9572b967bcbc8ea2"),
|
||||
PackageName: "actioncable",
|
||||
PackageVersion: "6.1.4.1",
|
||||
PackageLicenseConcluded: "NONE",
|
||||
@@ -334,8 +334,8 @@ func TestWriter_Write(t *testing.T) {
|
||||
ExternalDocumentReferences: map[string]spdx.ExternalDocumentRef2_2{},
|
||||
},
|
||||
Packages: map[spdx.ElementID]*spdx.Package2_2{
|
||||
spdx.ElementID("983b94af8413fe04"): {
|
||||
PackageSPDXIdentifier: spdx.ElementID("983b94af8413fe04"),
|
||||
spdx.ElementID("1275fe237f4887b3"): {
|
||||
PackageSPDXIdentifier: spdx.ElementID("1275fe237f4887b3"),
|
||||
PackageName: "ruby-typeprof",
|
||||
PackageVersion: "0.20.1",
|
||||
PackageLicenseConcluded: "MIT",
|
||||
|
||||
@@ -21,7 +21,7 @@ import (
|
||||
"github.com/aquasecurity/trivy/pkg/types"
|
||||
|
||||
_ "github.com/aquasecurity/fanal/analyzer/all"
|
||||
_ "github.com/aquasecurity/fanal/hook/all"
|
||||
_ "github.com/aquasecurity/fanal/handler/all"
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -309,8 +309,8 @@ func toDetectedMisconfiguration(res ftypes.MisconfResult, defaultSeverity dbType
|
||||
}
|
||||
|
||||
var primaryURL string
|
||||
if strings.HasPrefix(res.Namespace, "appshield.") {
|
||||
primaryURL = fmt.Sprintf("https://avd.aquasec.com/appshield/%s", strings.ToLower(res.ID))
|
||||
if strings.HasPrefix(res.Namespace, "builtin.") {
|
||||
primaryURL = fmt.Sprintf("https://avd.aquasec.com/misconfig/%s", strings.ToLower(res.ID))
|
||||
res.References = append(res.References, primaryURL)
|
||||
} else if strings.Contains(res.Type, "tfsec") {
|
||||
for _, ref := range res.References {
|
||||
|
||||
@@ -687,7 +687,7 @@ func TestScanner_Scan(t *testing.T) {
|
||||
FilePath: "/app/configs/deployment.yaml",
|
||||
Successes: []ftypes.MisconfResult{
|
||||
{
|
||||
Namespace: "appshield.kubernetes.id200",
|
||||
Namespace: "builtin.kubernetes.id200",
|
||||
PolicyMetadata: ftypes.PolicyMetadata{
|
||||
ID: "ID200",
|
||||
Type: "Kubernetes Security Check",
|
||||
@@ -739,11 +739,11 @@ func TestScanner_Scan(t *testing.T) {
|
||||
ID: "ID200",
|
||||
Title: "Bad Deployment",
|
||||
Message: "No issues found",
|
||||
Namespace: "appshield.kubernetes.id200",
|
||||
Namespace: "builtin.kubernetes.id200",
|
||||
Severity: "MEDIUM",
|
||||
PrimaryURL: "https://avd.aquasec.com/appshield/id200",
|
||||
PrimaryURL: "https://avd.aquasec.com/misconfig/id200",
|
||||
References: []string{
|
||||
"https://avd.aquasec.com/appshield/id200",
|
||||
"https://avd.aquasec.com/misconfig/id200",
|
||||
},
|
||||
Status: types.StatusPassed,
|
||||
Layer: ftypes.Layer{
|
||||
|
||||
Reference in New Issue
Block a user