Showing preview only (358K chars total). Download the full file or copy to clipboard to get everything.
Repository: undistro/marvin
Branch: main
Commit: 8ecf9a6c1f66
Files: 128
Total size: 324.5 KB
Directory structure:
gitextract_roenwdf7/
├── .github/
│ ├── dependabot.yml
│ └── workflows/
│ ├── release.yml
│ └── test.yml
├── .gitignore
├── .goreleaser.yaml
├── .krew.yaml
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── MAINTAINERS.md
├── Makefile
├── README.md
├── checks.md
├── cmd/
│ ├── root.go
│ ├── scan.go
│ └── version.go
├── examples/
│ ├── labels.yml
│ └── replicas.yml
├── go.mod
├── go.sum
├── install.sh
├── internal/
│ └── builtins/
│ ├── cis/
│ │ ├── M-500_workload_in_default_namespace.yaml
│ │ └── M-500_workload_in_default_namespace_test.yaml
│ ├── embed.go
│ ├── embed_test.go
│ ├── general/
│ │ ├── M-400_image_tagged_latest.yaml
│ │ ├── M-400_image_tagged_latest_test.yaml
│ │ ├── M-401_unmanaged_pod.yaml
│ │ ├── M-401_unmanaged_pod_test.yaml
│ │ ├── M-402_readiness_probe.yaml
│ │ ├── M-402_readiness_probe_test.yaml
│ │ ├── M-403_liveness_probe.yaml
│ │ ├── M-403_liveness_probe_test.yaml
│ │ ├── M-404_memory_requests.yaml
│ │ ├── M-404_memory_requests_test.yaml
│ │ ├── M-405_cpu_requests.yaml
│ │ ├── M-405_cpu_requests_test.yaml
│ │ ├── M-406_memory_limit.yaml
│ │ ├── M-406_memory_limit_test.yaml
│ │ ├── M-407_cpu_limit.yaml
│ │ ├── M-407_cpu_limit_test.yaml
│ │ ├── M-408_sudo_container_entrypoint.yaml
│ │ ├── M-408_sudo_container_entrypoint_test.yaml
│ │ ├── M-409_deprecated_image_registry.yaml
│ │ ├── M-409_deprecated_image_registry_test.yaml
│ │ ├── M-410_resource_using_invalid_restartpolicy.yaml
│ │ ├── M-410_resource_using_invalid_restartpolicy_test.yaml
│ │ ├── M-411_role_binding_referencing_anonymous_or_unauthenticated.yaml
│ │ └── M-411_role_binding_referencing_anonymous_or_unauthenticated_test.yaml
│ ├── mitre/
│ │ ├── M-200_allowed_registries.yml
│ │ ├── M-200_allowed_registries_test.yml
│ │ ├── M-201_app_credentials.yml
│ │ ├── M-201_app_credentials_test.yml
│ │ ├── M-202_auto_mount_service_account_token.yml
│ │ ├── M-202_auto_mount_service_account_token_test.yml
│ │ ├── M-203_ssh_server.yml
│ │ └── M-203_ssh_server_test.yml
│ ├── nsa/
│ │ ├── M-300_read_only_root_filesystem.yml
│ │ └── M-300_read_only_root_filesystem_test.yml
│ └── pss/
│ ├── baseline/
│ │ ├── M-100_host_process.yml
│ │ ├── M-100_host_process_test.yml
│ │ ├── M-101_host_namespaces.yml
│ │ ├── M-101_host_namespaces_test.yml
│ │ ├── M-102_privileged_containers.yml
│ │ ├── M-102_privileged_containers_test.yml
│ │ ├── M-103_capabilities_baseline.yml
│ │ ├── M-103_capabilities_baseline_test.yml
│ │ ├── M-104_host_path_volumes.yml
│ │ ├── M-104_host_path_volumes_test.yml
│ │ ├── M-105_host_ports.yml
│ │ ├── M-105_host_ports_test.yml
│ │ ├── M-106_apparmor.yml
│ │ ├── M-106_apparmor_test.yml
│ │ ├── M-107_selinux.yml
│ │ ├── M-107_selinux_test.yml
│ │ ├── M-108_proc_mount.yml
│ │ ├── M-108_proc_mount_test.yml
│ │ ├── M-109_seccomp_baseline.yml
│ │ ├── M-109_seccomp_baseline_test.yml
│ │ ├── M-110_sysctls.yml
│ │ └── M-110_sysctls_test.yml
│ └── restricted/
│ ├── M-111_volume_types.yml
│ ├── M-111_volume_types_test.yml
│ ├── M-112_privilege_escalation.yml
│ ├── M-112_privilege_escalation_test.yml
│ ├── M-113_run_as_non_root.yml
│ ├── M-113_run_as_non_root_test.yml
│ ├── M-114_run_as_user.yml
│ ├── M-114_run_as_user_test.yml
│ ├── M-115_seccomp_restricted.yml
│ ├── M-115_seccomp_restricted_test.yml
│ ├── M-116_capabilities_restricted.yml
│ └── M-116_capabilities_restricted_test.yml
├── main.go
├── pkg/
│ ├── cmd/
│ │ └── scan.go
│ ├── loader/
│ │ ├── builtin.go
│ │ ├── builtin_test.go
│ │ ├── loader.go
│ │ ├── loader_test.go
│ │ └── testdata/
│ │ ├── checks/
│ │ │ ├── svc_lb.json
│ │ │ └── workloads/
│ │ │ ├── replicas.yaml
│ │ │ ├── replicas_test.yaml
│ │ │ └── unsupported.txt
│ │ └── invalid/
│ │ └── invalid.yml
│ ├── printers/
│ │ ├── interface.go
│ │ ├── json.go
│ │ ├── md.go
│ │ ├── table.go
│ │ └── yaml.go
│ ├── types/
│ │ ├── check.go
│ │ ├── check_test.go
│ │ ├── report.go
│ │ ├── report_test.go
│ │ ├── severity.go
│ │ ├── severity_test.go
│ │ ├── status.go
│ │ └── status_test.go
│ ├── validator/
│ │ ├── activation.go
│ │ ├── compiler.go
│ │ ├── compiler_test.go
│ │ ├── interface.go
│ │ ├── podspec.go
│ │ ├── podspec_test.go
│ │ └── validator.go
│ └── version/
│ ├── version.go
│ └── version_test.go
└── test/
└── builtins_test.go
================================================
FILE CONTENTS
================================================
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
- package-ecosystem: github-actions
directory: /
schedule:
interval: weekly
- package-ecosystem: gomod
directory: /
schedule:
interval: weekly
================================================
FILE: .github/workflows/release.yml
================================================
name: release
on:
push:
tags:
- 'v*'
permissions:
contents: write
packages: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
- name: fetch tags
run: git fetch --force --tags
- name: setup go
uses: actions/setup-go@v6
with:
go-version-file: 'go.mod'
cache: true
- name: release
id: goreleaser
uses: goreleaser/goreleaser-action@v7
with:
distribution: goreleaser
version: latest
args: release --clean
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: krew
uses: rajatjindal/krew-release-bot@v0.0.50
- name: setup qemu
uses: docker/setup-qemu-action@v3
- name: setup docker buildx
uses: docker/setup-buildx-action@v3
- name: login
uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: metadata
id: meta
uses: docker/metadata-action@v5
with:
images: ghcr.io/${{ github.repository }}
tags: |
type=semver,prefix=v,pattern={{version}}
type=semver,prefix=v,pattern={{major}}.{{minor}}
- name: create dockerfile.cross
run: |
sed -e '1 s/\(^FROM\)/FROM --platform=\$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross
cat Dockerfile.cross
- name: build and push
uses: docker/build-push-action@v6
with:
build-args: |
VERSION=${{ fromJSON(steps.goreleaser.outputs.metadata).version }}
COMMIT=${{ fromJSON(steps.goreleaser.outputs.metadata).commit }}
DATE=${{ fromJSON(steps.goreleaser.outputs.metadata).date }}
context: .
platforms: linux/arm64,linux/amd64,linux/s390x,linux/ppc64le
file: Dockerfile.cross
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
================================================
FILE: .github/workflows/test.yml
================================================
name: test
on:
pull_request:
branches: [main]
push:
branches: [main]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v6
- name: setup go
uses: actions/setup-go@v6
with:
go-version-file: 'go.mod'
cache: true
- name: test
run: make test
- name: build
run: make build
- name: check license headers
run: make checklicense
================================================
FILE: .gitignore
================================================
# Binaries for programs and plugins
*.exe
*.exe~
*.dll
*.so
*.dylib
bin
# 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/
.idea
dist/
================================================
FILE: .goreleaser.yaml
================================================
version: 2
before:
hooks:
- go mod tidy
builds:
- env:
- CGO_ENABLED=0
goos:
- linux
- windows
- darwin
ldflags:
- >-
-s -w
-X github.com/undistro/marvin/pkg/version.version={{.Version}}
-X github.com/undistro/marvin/pkg/version.commit={{.Commit}}
-X github.com/undistro/marvin/pkg/version.date={{.Date}}
archives:
- formats: [tar.gz]
name_template: >-
{{ .ProjectName }}_
{{- title .Os }}_
{{- if eq .Arch "amd64" }}x86_64
{{- else if eq .Arch "386" }}i386
{{- else }}{{ .Arch }}{{ end }}
{{- if .Arm }}v{{ .Arm }}{{ end }}
format_overrides:
- goos: windows
formats: [zip]
checksum:
name_template: 'checksums.txt'
snapshot:
version_template: "{{ incpatch .Version }}-next"
changelog:
sort: asc
filters:
exclude:
- '^docs:'
- '^test:'
release:
prerelease: auto
================================================
FILE: .krew.yaml
================================================
apiVersion: krew.googlecontainertools.github.com/v1alpha2
kind: Plugin
metadata:
name: marvin
spec:
homepage: https://github.com/undistro/marvin
shortDescription: Scan clusters with your own checks written in CEL.
description: |
Marvin scans a Kubernetes cluster by performing CEL expressions
to report potential issues, misconfigurations and vulnerabilities.
Marvin allows you to write your own checks by using CEL expressions.
version: {{ .TagName }}
platforms:
- selector:
matchLabels:
os: linux
arch: amd64
{{addURIAndSha "https://github.com/undistro/marvin/releases/download/{{ .TagName }}/marvin_Linux_x86_64.tar.gz" .TagName }}
bin: marvin
- selector:
matchLabels:
os: linux
arch: arm64
{{addURIAndSha "https://github.com/undistro/marvin/releases/download/{{ .TagName }}/marvin_Linux_arm64.tar.gz" .TagName }}
bin: marvin
- selector:
matchLabels:
os: darwin
arch: amd64
{{addURIAndSha "https://github.com/undistro/marvin/releases/download/{{ .TagName }}/marvin_Darwin_x86_64.tar.gz" .TagName }}
bin: marvin
- selector:
matchLabels:
os: darwin
arch: arm64
{{addURIAndSha "https://github.com/undistro/marvin/releases/download/{{ .TagName }}/marvin_Darwin_arm64.tar.gz" .TagName }}
bin: marvin
================================================
FILE: CODE_OF_CONDUCT.md
================================================
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, religion, or sexual identity
and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the
overall community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or
advances of any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email
address, without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
undistro@getup.io.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series
of actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or
permanent ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within
the community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.0, available at
https://www.contributor-covenant.org/version/2/0/code_of_conduct.html.
Community Impact Guidelines were inspired by [Mozilla's code of conduct
enforcement ladder](https://github.com/mozilla/diversity).
[homepage]: https://www.contributor-covenant.org
For answers to common questions about this code of conduct, see the FAQ at
https://www.contributor-covenant.org/faq. Translations are available at
https://www.contributor-covenant.org/translations.
================================================
FILE: CONTRIBUTING.md
================================================
# Contributing to Marvin
:+1::tada: Thanks for taking the time to contribute! :tada::+1:
The following is a set of guidelines for contributing to Marvin,
which are hosted in the [Undistro Organization](https://github.com/undistro) on GitHub.
## How Can I Contribute?
- **Giving us a star.** It may not seem like much, but it really makes a
difference. This is something that everyone can do to help out Marvin.
GitHub stars help the project gain visibility and stand out.
- **Reviewing the documentation.**
Most documentation just needs a review for proper spelling and grammar.
If you think a document can be improved in any way,
feel free to open a Pull Request with your suggestions.
- **Reporting bugs.** We use GitHub issues to track public bugs.
Report a bug by [opening a new issue](https://github.com/undistro/marvin/issues/new/choose).
- **Pull Request.** Unless you are fixing a known bug, we **strongly**
recommend discussing it with the core team via a GitHub issue before
getting started to ensure your work is consistent with Marvin's roadmap and architecture.
================================================
FILE: Dockerfile
================================================
# Copyright 2023 Undistro Authors
#
# 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.
FROM golang:1.25.4-alpine AS builder
ARG TARGETOS
ARG TARGETARCH
ARG VERSION
ARG COMMIT
ARG DATE
WORKDIR /workspace
COPY go.mod go.mod
COPY go.sum go.sum
RUN go mod download
COPY main.go main.go
COPY cmd/ cmd/
COPY internal/ internal/
COPY pkg/ pkg/
RUN CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} go build \
-ldflags="-s -w -X github.com/undistro/marvin/pkg/version.version=${VERSION:-docker} \
-X github.com/undistro/marvin/pkg/version.commit=${COMMIT} \
-X github.com/undistro/marvin/pkg/version.date=${DATE}" -a -o marvin main.go
FROM alpine:3.22
RUN apk update && apk upgrade && rm -rf /var/cache/apk
RUN addgroup -g 8494 -S nonroot && adduser -u 8494 -D -S nonroot -G nonroot
USER 8494:8494
WORKDIR /
COPY --from=builder /workspace/marvin .
ENTRYPOINT ["/marvin"]
================================================
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: MAINTAINERS.md
================================================
# Maintainers
Maintainers are approvers who have shown good technical judgement in guiding feature design & development, have
displayed overall knowledge of the project and features in the project, and are nurturing and receptive to everyone in
the community.
The following table lists the Marvin project core maintainers:
| Name | GitHub ID | Affiliation |
|-------------------------------------------------------------------|--------------------------------------------|----------------------------|
| [Matheus Moraes](https://www.linkedin.com/in/matheusfm/) | [@matheusfm](https://github.com/matheusfm) | [Getup](https://getup.io/) |
| [Kevin Conner](https://www.linkedin.com/in/kevin-conner-26b5554/) | [@knrc](https://github.com/knrc) | [Getup](https://getup.io/) |
================================================
FILE: Makefile
================================================
# Image URL to use all building/pushing image targets
TAG ?= latest
IMG ?= ghcr.io/undistro/marvin:${TAG}
# Setting SHELL to bash allows bash commands to be executed by recipes.
# Options are set to exit when a recipe line exits non-zero or a piped command fails.
SHELL = /usr/bin/env bash -o pipefail
.SHELLFLAGS = -ec
.PHONY: all
all: build
##@ General
.PHONY: help
help: ## Display this help.
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^[a-zA-Z_0-9-]+:.*?##/ { printf " \033[36m%-15s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)
##@ Development
.PHONY: fmt
fmt: ## Run go fmt against code.
go fmt ./...
.PHONY: vet
vet: ## Run go vet against code.
go vet ./...
.PHONY: test
test: fmt vet ## Run tests.
go test ./... -coverprofile cover.out
.PHONY: addlicense
addlicense: ## Add copyright license headers in source code files.
@test -s $(LOCALBIN)/addlicense || GOBIN=$(LOCALBIN) go install github.com/google/addlicense@latest
$(LOCALBIN)/addlicense -c "Undistro Authors" -l "apache" -ignore ".github/**" -ignore ".idea/**" -ignore "dist/**" -ignore ".goreleaser.yaml" -ignore ".krew.yaml" .
.PHONY: checklicense
checklicense: ## Check copyright license headers in source code files.
@test -s $(LOCALBIN)/addlicense || GOBIN=$(LOCALBIN) go install github.com/google/addlicense@latest
$(LOCALBIN)/addlicense -c "Undistro Authors" -l "apache" -ignore ".github/**" -ignore ".idea/**" -ignore "dist/**" -ignore ".goreleaser.yaml" -ignore ".krew.yaml" -check .
##@ Build
.PHONY: build
build: fmt vet ## Build marvin binary.
go build -ldflags="-s -w -X github.com/undistro/marvin/pkg/version.version=${TAG}" -o bin/marvin main.go
.PHONY: run
run: fmt vet ## Run marvin from your host.
go run ./main.go
PLATFORMS ?= linux/arm64,linux/amd64,linux/s390x,linux/ppc64le
.PHONY: docker-buildx
docker-buildx: test ## Build and push docker image for cross-platform support.
sed -e '1 s/\(^FROM\)/FROM --platform=\$$\{BUILDPLATFORM\}/; t' -e ' 1,// s//FROM --platform=\$$\{BUILDPLATFORM\}/' Dockerfile > Dockerfile.cross
- docker buildx create --name cross-builder
docker buildx use cross-builder
- docker buildx build --push --platform=$(PLATFORMS) --build-arg VERSION=${TAG} --tag ${IMG} -f Dockerfile.cross .
- docker buildx rm cross-builder
rm Dockerfile.cross
.PHONY: docker-build
docker-build: test ## Build docker image.
docker build --build-arg VERSION=${TAG} -t ${IMG} .
.PHONY: docker-push
docker-push: ## Push docker image.
docker push ${IMG}
## Location to install dependencies to
LOCALBIN ?= $(shell pwd)/bin
$(LOCALBIN):
mkdir -p $(LOCALBIN)
================================================
FILE: README.md
================================================
<div align="center">
<picture>
<source media="(prefers-color-scheme: dark)" srcset="assets/banner-dark.png">
<img alt="Marvin logo" src="assets/banner-light.png">
</picture>
[](https://pkg.go.dev/github.com/undistro/marvin)
[](https://artifacthub.io/packages/krew/krew-index/marvin)
[](https://github.com/undistro/marvin/actions/workflows/test.yml)


[](https://goreportcard.com/report/github.com/undistro/marvin)

</div>
Marvin is a CLI tool designed to help Kubernetes cluster administrators
ensure the security and reliability of their environments.
Using a comprehensive set of [CEL (Common Expression Language)](https://github.com/google/cel-spec) expressions,
Marvin performs extensive checks on cluster resources,
identifying potential issues, misconfigurations, and vulnerabilities that could pose a risk to the system.
It helps ensure that your Kubernetes clusters are always in compliance with best practices and industry standards.
Marvin is also used as a plugin in [Zora](https://zora-docs.undistro.io/latest/).
<!-- TOC -->
* [Installation](#installation)
* [Manually](#manually)
* [Install via script](#install-via-script)
* [Install via Krew](#install-via-krew)
* [Install from source](#install-from-source)
* [Usage](#usage)
* [Built-in checks](#built-in-checks)
* [Custom checks](#custom-checks)
* [Skipping resources](#skipping-resources)
* [RBAC](#rbac)
* [Contributing](#contributing)
* [License](#license)
<!-- TOC -->
_Please [star :star:](https://github.com/undistro/marvin/stargazers) the repo if you want us to continue developing and improving Marvin!_ :grin:
# Installation
The pre-compiled binaries are available in [GitHub releases page](https://github.com/undistro/marvin/releases)
and can be installed manually, via script or as a `kubectl` plugin with [Krew](https://krew.sigs.k8s.io).
## Manually
1. Download the file for your system/architecture from the [GitHub releases page](https://github.com/undistro/marvin/releases)
2. Unpack the downloaded archive (e.g `tar -xzf marvin_Linux_x86_64.tar.gz`)
3. Make sure the binary has execution bit turned on (`chmod +x ./marvin`)
4. Move the binary somewhere in your `$PATH` (e.g `sudo mv ./marvin /usr/local/bin/`)
## Install via script
The process above can be automated by the following script:
```shell
curl -sSfL https://raw.githubusercontent.com/undistro/marvin/main/install.sh | sh -s -- -b $HOME/.local/bin
```
## Install via [Krew](https://krew.sigs.k8s.io)
You can install Marvin as a `kubectl` plugin via [Krew](https://krew.sigs.k8s.io):
```shell
kubectl krew install marvin
```
Then you can use Marvin with `kubectl` prefix:
```shell
kubectl marvin version
```
## Install from source
```shell
go install github.com/undistro/marvin@latest
```
# Usage
## Built-in checks
Scan the current-context Kubernetes cluster performing the [built-in checks](internal/builtins):
```shell
marvin scan
```
```
SEVERITY ID CHECK STATUS FAILED PASSED SKIPPED
High M-101 Host namespaces Failed 8 25 0
High M-104 HostPath volume Failed 8 25 0
High M-201 Application credentials stored in configuration files Failed 2 45 0
High M-102 Privileged container Failed 2 31 0
High M-103 Insecure capabilities Failed 2 31 0
High M-100 Privileged access to the Windows node Passed 0 33 0
High M-105 Not allowed hostPort Passed 0 33 0
Medium M-113 Container could be running as root user Failed 33 0 0
Medium M-407 CPU not limited Failed 31 2 0
Medium M-406 Memory not limited Failed 27 6 0
Medium M-404 Memory requests not specified Failed 26 7 0
Medium M-402 Readiness and startup probe not configured Failed 25 8 0
Medium M-403 Liveness probe not configured Failed 25 8 0
Medium M-405 CPU requests not specified Failed 23 10 0
Medium M-106 Forbidden AppArmor profile Passed 0 33 0
Medium M-107 Forbidden SELinux options Passed 0 33 0
Medium M-108 Forbidden proc mount type Passed 0 33 0
Medium M-109 Forbidden seccomp profile Passed 0 33 0
Medium M-110 Unsafe sysctls Passed 0 33 0
Medium M-112 Allowed privilege escalation Passed 0 33 0
Medium M-114 Container running as root UID Passed 0 33 0
Medium M-200 Image registry not allowed Passed 0 33 0
Medium M-400 Image tagged latest Passed 0 33 0
Medium M-408 Sudo in container entrypoint Passed 0 33 0
Medium M-409 Deprecated image registry Passed 0 33 0
Medium M-500 Workload in default namespace Passed 0 33 0
Medium M-410 Not allowed restartPolicy Passed 0 18 0
Low M-116 Not allowed added/dropped capabilities Failed 33 0 0
Low M-202 Automounted service account token Failed 33 0 0
Low M-115 Not allowed seccomp profile Failed 29 4 0
Low M-300 Root filesystem write allowed Failed 29 4 0
Low M-111 Not allowed volume type Failed 8 25 0
Low M-203 SSH server running inside container Passed 0 39 0
Low M-401 Unmanaged Pod Passed 0 15 0
```
The default output format is `table` which represents a summary of checks result.
You can provide `json` or `yaml` in the `-o/--output` flag to get more details.
Run `marvin scan --help` to see all available options.
## Custom checks
Marvin allows you to write your own checks by using [CEL expressions](https://github.com/google/cel-spec) in a YAML file like the example below.
```yaml
id: CUSTOM-001
severity: Medium
message: "Replicas limit"
match:
resources:
- group: apps
version: v1
resource: deployments
validations:
- expression: >
object.spec.replicas <= 5
message: "Deployment with more than 5 replicas"
```
If an expression evaluates to `false`, the check fails.
This is how built-in Marvin checks are defined as well.
You can see all the built-in checks in the [`internal/builtins` folder](internal/builtins) for examples.
If you want to quickly test CEL expressions from your browser, check out the [CEL Playground](https://playcel.undistro.io/).
Then provide the directory path with your custom check files in the `-f/--checks` flag:
```shell
marvin scan --disable-builtin --checks ./examples/
```
```
SEVERITY ID CHECK STATUS FAILED PASSED SKIPPED
Medium CUSTOM-001 Replicas limit Passed 0 2 0
```
The flag `--disable-builtin` disables the built-in Marvin checks.
If the check matches a PodSpec (`Pod`, `ReplicationController`, `ReplicaSet`, `Deployment`, `StatefulSet`, `DaemonSet`, `Job` or `CronJob`)
the `podSpec` and `allContainers` inputs are available for expressions.
The `allContainers` input is a list of all containers including `initContainers` and `ephemeralContainers`.
## Skipping resources
You can use annotations to skip certain checks for specific resources in your cluster.
By adding the `marvin.undistro.io/skip` annotation to a resource,
you can specify a comma-separated list of check IDs to skip.
Example:
```shell
kubectl annotate deployment nginx marvin.undistro.io/skip='M-202, M-111'
```
By default, Marvin will respect the `marvin.undistro.io/skip` annotation when performing checks.
However, you can disable this behavior by using the `--disable-annotation-skip` flag.
This flag will cause Marvin to perform all checks on all resources.
If you prefer to use a different annotation to skip checks,
you can use the `--skip-annotation` flag to specify the annotation name.
Example: `--skip-annotation='my-company.com/skip-checks'`
## RBAC
Currently, the built-in checks look for the below resources
and Marvin needs view (`get` and `list`) permission to verify them.
- `v1/pods`
- `v1/configmaps`
- `v1/services`
- `apps/v1/deployments`
- `apps/v1/daemonsets`
- `apps/v1/statefulsets`
- `apps/v1/replicasets`
- `batch/v1/cronjobs`
- `batch/v1/jobs`
<details>
<summary> Here is a sample `ClusterRole` for Marvin: </summary>
```yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: marvin
rules:
- apiGroups: [ "" ]
resources:
- configmaps
- pods
- services
verbs: [ "get", "list" ]
- apiGroups: [ "apps" ]
resources:
- daemonsets
- deployments
- statefulsets
- replicasets
verbs: [ "get", "list" ]
- apiGroups: [ batch ]
resources:
- jobs
- cronjobs
verbs: [ "get", "list" ]
```
</details>
> **Note**
> You can write a custom check to look at any resource.
> But Marvin needs view permission.
> Remember to update RBAC for new resources you want to check.
# Contributing
We appreciate your contribution.
Please refer to our [contributing guideline](https://github.com/undistro/marvin/blob/main/CONTRIBUTING.md) for further information.
This project adheres to the Contributor Covenant [code of conduct](https://github.com/undistro/marvin/blob/main/CODE_OF_CONDUCT.md).
# License
Marvin is available under the Apache 2.0 license. See the [LICENSE](LICENSE) file for more info.
================================================
FILE: checks.md
================================================
# Checks Overview
In the table below, you can view all checks present on Marvin. Click on the #ID column item for more details about each check.
| Framework | #ID | Severity | Message |
|------------------|------------------------------------------------------------------------------------------------------|----------|------------------------------------------------------------------|
| CIS Benchmarks | [M-500](/internal/builtins/cis/M-500_default_namespace.yaml) | Medium | Workloads in default namespace |
| General | [M-400](/internal/builtins/general/M-400_image_tag_latest.yaml) | Medium | Image tagged latest |
| | [M-401](/internal/builtins/general/M-401_unmanaged_pod.yaml) | Low | Unmanaged Pod |
| | [M-402](/internal/builtins/general/M-402_readiness_probe.yaml) | Medium | Readiness and startup probe not configured |
| | [M-403](/internal/builtins/general/M-403_liveness_probe.yaml) | Medium | Liveness probe not configured |
| | [M-404](/internal/builtins/general/M-404_memory_requests.yaml) | Medium | Memory requests not specified |
| | [M-405](/internal/builtins/general/M-405_cpu_requests.yaml) | Medium | CPU requests not specified |
| | [M-406](/internal/builtins/general/M-406_memory_limit.yaml) | Medium | Memory not limited |
| | [M-407](/internal/builtins/general/M-407_cpu_limit.yaml) | Medium | CPU not limited |
| | [M-408](/internal/builtins/general/M-408_sudo_container_entrypoint.yaml) | Medium | Sudo in container entrypoint |
| | [M-409](/internal/builtins/general/M-409_deprecated_image_registry.yaml) | Medium | Deprecated image registry |
| | [M-410](/internal/builtins/general/M-410_resource_using_invalid_restartpolicy.yaml) | Medium | Resource is using an invalid restartPolicy |
| | [M-411](/internal/builtins/general/M-411_role_binding_referencing_anonymous_or_unauthanticated.yaml) | Medium | Role Binding referencing anonymous user or unauthenticated group |
| NSA-CISA | [M-300](/internal/builtins/nsa/M-300_read_only_root_filesystem.yml) | Low | Root filesystem write allowed |
| MITRE ATT&CK | [M-200](/internal/builtins/mitre/M-200_allowed_registries.yml) | Medium | Image registry not allowed |
| | [M-201](/internal/builtins/mitre/M-201_app_credentials.yml) | High | Application credentials stored in configuration files |
| | [M-202](/internal/builtins/mitre/M-202_auto_mount_service_account.yml) | Low | Automounted service account token |
| | [M-203](/internal/builtins/mitre/M-203_ssh.yml) | Low | SSH server running inside container |
| PSS - Baseline | [M-100](/internal/builtins/pss/baseline/M-100_host_process.yml) | High | Privileged access to the Windows node |
| | [M-101](/internal/builtins/pss/baseline/M-101_host_namespaces.yml) | High | Host namespaces |
| | [M-102](/internal/builtins/pss/baseline/M-102_privileged_containers.yml) | High | Privileged container |
| | [M-103](/internal/builtins/pss/baseline/M-103_capabilities.yml) | High | Insecure capabilities |
| | [M-104](/internal/builtins/pss/baseline/M-104_host_path_volumes.yml) | High | HostPath volume |
| | [M-105](/internal/builtins/pss/baseline/M-105_host_ports.yml) | High | Not allowed hostPort |
| | [M-106](/internal/builtins/pss/baseline/M-106_apparmor.yml) | Medium | Forbidden AppArmor profile |
| | [M-107](/internal/builtins/pss/baseline/M-107_selinux.yml) | Medium | Forbidden SELinux options |
| | [M-108](/internal/builtins/pss/baseline/M-108_proc_mount.yml) | Medium | Forbidden proc mount type |
| | [M-109](/internal/builtins/pss/baseline/M-109_seccomp.yml) | Medium | Forbidden seccomp profile |
| | [M-110](/internal/builtins/pss/baseline/M-110_sysctls.yml) | Medium | Unsafe sysctls |
| PSS - Restricted | [M-111](/internal/builtins/pss/restricted/M-111_volume_types.yml) | Low | Not allowed volume type |
| | [M-112](/internal/builtins/pss/restricted/M-112_privilege_escalation.yml) | Medium | Allowed privilege escalation |
| | [M-113](/internal/builtins/pss/restricted/M-113_run_as_non_root.yml) | Medium | Container could be running as root user |
| | [M-114](/internal/builtins/pss/restricted/M-114_run_as_user.yml) | Medium | Container running as root UID |
| | [M-115](/internal/builtins/pss/restricted/M-115_seccomp.yml) | Low | Not allowed seccomp profile |
| | [M-116](/internal/builtins/pss/restricted/M-116_capabilities.yml) | Low | Not allowed added/dropped capabilities |
================================================
FILE: cmd/root.go
================================================
// Copyright 2023 Undistro Authors
//
// 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.
package cmd
import (
"context"
"flag"
"os"
"path/filepath"
"strings"
"github.com/fatih/color"
"github.com/go-logr/logr"
"github.com/spf13/cobra"
"k8s.io/klog/v2"
"k8s.io/klog/v2/klogr"
)
var noColor bool
// rootCmd represents the base command when called without any subcommands
var rootCmd = &cobra.Command{
Use: "marvin",
Short: "A Kubernetes cluster scanner",
}
func Execute() {
err := rootCmd.Execute()
if err != nil {
os.Exit(1)
}
}
func isKubectlPlugin() bool {
return strings.HasPrefix(filepath.Base(os.Args[0]), "kubectl-")
}
func execName() string {
n := "marvin"
if isKubectlPlugin() {
return "kubectl " + n
}
return n
}
func init() {
cobra.OnInitialize(initNoColor)
if isKubectlPlugin() {
usageTpl := strings.NewReplacer("{{.UseLine}}", "kubectl {{.UseLine}}",
"{{.CommandPath}}", "kubectl {{.CommandPath}}").Replace(rootCmd.UsageTemplate())
rootCmd.SetUsageTemplate(usageTpl)
}
rootCmd.PersistentFlags().BoolVar(&noColor, "no-color", false, "Disable color output")
var allFlags flag.FlagSet
klog.InitFlags(&allFlags)
allFlags.VisitAll(func(f *flag.Flag) {
if f.Name == "v" {
rootCmd.PersistentFlags().AddGoFlag(f)
}
})
rootCmd.SetContext(logr.NewContext(context.Background(), klogr.New()))
}
func initNoColor() {
color.NoColor = noColor
}
================================================
FILE: cmd/scan.go
================================================
// Copyright 2023 Undistro Authors
//
// 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.
package cmd
import (
"fmt"
"os"
"github.com/spf13/cobra"
"github.com/undistro/marvin/pkg/cmd"
)
var (
scanOptions = cmd.NewScanOptions()
// scanCmd represents the scan command
scanCmd = &cobra.Command{
Use: "scan [flags]",
Short: "Scan a Kubernetes cluster",
Example: fmt.Sprintf(` # Scan the current cluster
%[1]s scan
# Scan the 'foo' namespace of the current cluster
%[1]s scan -n foo
# Scan the current cluster providing custom checks
%[1]s scan --checks ./examples/
# Scan the current cluster providing custom checks and disabling the built-in checks
%[1]s scan --disable-builtin --checks ./examples/
# Scan a specific cluster using a kubeconfig file
%[1]s scan --kubeconfig /path/to/kubeconfig.yml
# Scan the current cluster, but do not fail even if there are errors in the report
%[1]s scan --no-fail
# Scan the current cluster and generate output in JSON format
%[1]s scan -o json`, execName()),
RunE: func(c *cobra.Command, args []string) error {
if err := scanOptions.Init(c.Context()); err != nil {
return err
}
hasError, err := scanOptions.Run()
if err != nil {
return err
}
if hasError && !*scanOptions.NoFail {
os.Exit(2)
}
return nil
},
}
)
func init() {
rootCmd.AddCommand(scanCmd)
scanOptions.AddFlags(scanCmd.Flags())
}
================================================
FILE: cmd/version.go
================================================
// Copyright 2023 Undistro Authors
//
// 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.
package cmd
import (
"encoding/json"
"fmt"
"github.com/spf13/cobra"
"sigs.k8s.io/yaml"
"github.com/undistro/marvin/pkg/version"
)
var (
versionOutput string
// versionCmd represents the version command
versionCmd = &cobra.Command{
Use: "version",
Short: "Show the version of Marvin",
RunE: func(c *cobra.Command, args []string) error {
v := version.Get()
var s string
switch versionOutput {
case "json":
b, err := json.MarshalIndent(&v, "", " ")
if err != nil {
return err
}
s = string(b)
case "yaml":
b, err := yaml.Marshal(&v)
if err != nil {
return err
}
s = string(b)
default:
s = v.String()
}
fmt.Println(s)
return nil
},
}
)
func init() {
rootCmd.AddCommand(versionCmd)
versionCmd.Flags().StringVarP(&versionOutput, "output", "o", "", `Output format. One of: ("json", "yaml")`)
}
================================================
FILE: examples/labels.yml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
id: CUSTOM-002
severity: Low
message: "Required labels"
match:
resources:
- group: ""
version: v1
resource: pods
params:
requiredLabels:
- app
validations:
- expression: >
has(object.metadata.labels) &&
params.requiredLabels.all(req,
req in object.metadata.labels
)
message: "Pod without required labels"
================================================
FILE: examples/replicas.yml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
id: CUSTOM-001
severity: Medium
message: "Replicas limit"
match:
resources:
- group: apps
version: v1
resource: deployments
validations:
- expression: >
object.spec.replicas <= 5
message: "Deployment with more than 5 replicas"
================================================
FILE: go.mod
================================================
module github.com/undistro/marvin
go 1.25.4
require (
github.com/Masterminds/semver/v3 v3.4.0
github.com/fatih/color v1.18.0
github.com/go-logr/logr v1.4.3
github.com/google/cel-go v0.26.0
github.com/olekukonko/tablewriter v0.0.5
github.com/spf13/cobra v1.10.2
github.com/spf13/pflag v1.0.10
github.com/stretchr/testify v1.11.1
k8s.io/api v0.34.2
k8s.io/apimachinery v0.34.2
k8s.io/apiserver v0.34.2
k8s.io/cli-runtime v0.34.2
k8s.io/client-go v0.34.2
k8s.io/klog/v2 v2.130.1
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397
sigs.k8s.io/yaml v1.6.0
)
require (
cel.dev/expr v0.24.0 // indirect
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect
github.com/antlr4-go/antlr/v4 v4.13.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/blang/semver/v4 v4.0.0 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/emicklei/go-restful/v3 v3.12.2 // indirect
github.com/fxamacker/cbor/v2 v2.9.0 // indirect
github.com/go-errors/errors v1.4.2 // indirect
github.com/go-openapi/jsonpointer v0.21.0 // indirect
github.com/go-openapi/jsonreference v0.20.2 // indirect
github.com/go-openapi/swag v0.23.0 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/btree v1.1.3 // indirect
github.com/google/gnostic-models v0.7.0 // indirect
github.com/google/uuid v1.6.0 // indirect
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de // indirect
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/mattn/go-runewidth v0.0.16 // indirect
github.com/moby/term v0.5.0 // indirect
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee // indirect
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.22.0 // indirect
github.com/prometheus/client_model v0.6.1 // indirect
github.com/prometheus/common v0.62.0 // indirect
github.com/prometheus/procfs v0.15.1 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/stoewer/go-strcase v1.3.0 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/xlab/treeprint v1.2.0 // indirect
go.opentelemetry.io/otel v1.35.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect
go.yaml.in/yaml/v2 v2.4.2 // indirect
go.yaml.in/yaml/v3 v3.0.4 // indirect
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 // indirect
golang.org/x/net v0.38.0 // indirect
golang.org/x/oauth2 v0.27.0 // indirect
golang.org/x/sync v0.12.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/term v0.30.0 // indirect
golang.org/x/text v0.23.0 // indirect
golang.org/x/time v0.9.0 // indirect
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect
google.golang.org/protobuf v1.36.5 // indirect
gopkg.in/evanphx/json-patch.v4 v4.12.0 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
k8s.io/component-base v0.34.2 // indirect
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b // indirect
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect
sigs.k8s.io/kustomize/api v0.20.1 // indirect
sigs.k8s.io/kustomize/kyaml v0.20.1 // indirect
sigs.k8s.io/randfill v1.0.0 // indirect
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 // indirect
)
================================================
FILE: go.sum
================================================
cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=
cel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX06QTs6MXw941piREPl3Yfiw=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0=
github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E=
github.com/Masterminds/semver/v3 v3.4.0 h1:Zog+i5UMtVoCU8oKka5P7i9q9HgrJeGzI9SA1Xbatp0=
github.com/Masterminds/semver/v3 v3.4.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM=
github.com/antlr4-go/antlr/v4 v4.13.0 h1:lxCg3LAv+EUK6t1i0y1V6/SLeUi0eKEKdhQAlS8TVTI=
github.com/antlr4-go/antlr/v4 v4.13.0/go.mod h1:pfChB/xh/Unjila75QW7+VU4TSnWnnk9UTnmpPaOR2g=
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
github.com/blang/semver/v4 v4.0.0 h1:1PFHFE6yCCTv8C1TeyNNarDzntLi7wMI5i/pzqYIsAM=
github.com/blang/semver/v4 v4.0.0/go.mod h1:IbckMUScFkM3pff0VJDNKRiT6TG/YpiHIM2yvyW5YoQ=
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
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/emicklei/go-restful/v3 v3.12.2 h1:DhwDP0vY3k8ZzE0RunuJy8GhNpPL6zqLkDf9B/a0/xU=
github.com/emicklei/go-restful/v3 v3.12.2/go.mod h1:6n3XBCmQQb25CM2LCACGz8ukIrRry+4bhvbpWn3mrbc=
github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM=
github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU=
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
github.com/fxamacker/cbor/v2 v2.9.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
github.com/go-errors/errors v1.4.2 h1:J6MZopCL4uSllY1OfXM374weqZFFItUbrImctkmUxIA=
github.com/go-errors/errors v1.4.2/go.mod h1:sIVyrIiJhuEF+Pj9Ebtd6P/rEYROXFi3BopGUQ5a5Og=
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
github.com/go-openapi/jsonpointer v0.21.0 h1:YgdVicSA9vH5RiHs9TZW5oyafXZFc6+2Vc1rr/O9oNQ=
github.com/go-openapi/jsonpointer v0.21.0/go.mod h1:IUyH9l/+uyhIYQ/PXVA41Rexl+kOkAPDdXEYns6fzUY=
github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2KvnJRumpMGbE=
github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k=
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
github.com/go-openapi/swag v0.23.0 h1:vsEVJDUo2hPJ2tu0/Xc+4noaxyEffXNIs3cOULZ+GrE=
github.com/go-openapi/swag v0.23.0/go.mod h1:esZ8ITTYEsH1V2trKHjAN8Ai7xHb8RV+YSZ577vPjgQ=
github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI=
github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/google/btree v1.1.3 h1:CVpQJjYgC4VbzxeGVHfvZrv1ctoYCAI8vbl07Fcxlyg=
github.com/google/btree v1.1.3/go.mod h1:qOPhT0dTNdNzV6Z/lhRX0YXUafgPLFUh+gZMl761Gm4=
github.com/google/cel-go v0.26.0 h1:DPGjXackMpJWH680oGY4lZhYjIameYmR+/6RBdDGmaI=
github.com/google/cel-go v0.26.0/go.mod h1:A9O8OU9rdvrK5MQyrqfIxo1a0u4g3sF8KB6PUIaryMM=
github.com/google/gnostic-models v0.7.0 h1:qwTtogB15McXDaNqTZdzPJRHvaVJlAl+HVQnLmJEJxo=
github.com/google/gnostic-models v0.7.0/go.mod h1:whL5G0m6dmc5cPxKc5bdKdEN3UjI7OUGxBlw57miDrQ=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo=
github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79 h1:+ngKgrYPPJrOjhax5N+uePQ0Fh1Z7PheYoUI/0nzkPA=
github.com/gregjones/httpcache v0.0.0-20190611155906-901d90724c79/go.mod h1:FecbI9+v66THATjSRHfNgh1IVFe/9kFxbXtjV0ctIMA=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY=
github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y=
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/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/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
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/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc=
github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de h1:9TO3cAIGXtEhnIaL+V+BEER86oLrvS+kWobKpbJuye0=
github.com/liggitt/tabwriter v0.0.0-20181228230101-89fcab3d43de/go.mod h1:zAbeS9B/r2mtpb6U+EI2rYA5OAXxsYw6wTamcNW+zcE=
github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg=
github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc=
github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0=
github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y=
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 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 h1:n6/2gBQ3RWajuToeY6ZtZTIKv2v7ThUy5KKusIT0yc0=
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00/go.mod h1:Pm3mSP3c5uWn86xMLZ5Sa7JB9GsEZySvHYXCTK4E9q4=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
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/v2 v2.21.0 h1:7rg/4f3rB88pb5obDgNZrNHrQ4e6WpjonchcpuBRnZM=
github.com/onsi/ginkgo/v2 v2.21.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo=
github.com/onsi/gomega v1.35.1 h1:Cwbd75ZBPxFSuZ6T+rN/WCb/gOc6YgFBXLlZLhC7Ds4=
github.com/onsi/gomega v1.35.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog=
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
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_golang v1.22.0 h1:rb93p9lokFEsctTys46VnV1kLCDpVZ0a/Y92Vm0Zc6Q=
github.com/prometheus/client_golang v1.22.0/go.mod h1:R7ljNsLXhuQXYZYtw6GAE9AZg8Y7vEW5scdCXrWRXC0=
github.com/prometheus/client_model v0.6.1 h1:ZKSh/rekM+n3CeS952MLRAdFwIKqeY8b62p8ais2e9E=
github.com/prometheus/client_model v0.6.1/go.mod h1:OrxVMOVHjw3lKMa8+x6HeMGkHMQyHDk9E3jmP2AmGiY=
github.com/prometheus/common v0.62.0 h1:xasJaQlnWAeyHdUBeGjXmutelfJHWMRr+Fg4QszZ2Io=
github.com/prometheus/common v0.62.0/go.mod h1:vyBcEuLSvWos9B1+CyL7JZ2up+uFzXhkqml0W5zIY1I=
github.com/prometheus/procfs v0.15.1 h1:YagwOFzUgYfKKHX6Dr+sHT7km/hxC76UB0learggepc=
github.com/prometheus/procfs v0.15.1/go.mod h1:fB45yRUv8NstnjriLhBQLuOUt+WW4BsoGhij/e3PBqk=
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/go-internal v1.13.1 h1:KvO1DLK/DRN07sQ1LQKScxyZJuNnedQ5/wKSR38lUII=
github.com/rogpeppe/go-internal v1.13.1/go.mod h1:uMEvuHeurkdAXX61udpOXGD/AzZDWNMNyH2VO9fmH0o=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sergi/go-diff v1.2.0 h1:XU+rvMAioB0UC3q1MFrIQy4Vo5/4VsRDQQXHsEya6xQ=
github.com/sergi/go-diff v1.2.0/go.mod h1:STckp+ISIX8hZLjrqAeVduY0gWCT9IjLuqbuNXdaHfM=
github.com/spf13/cobra v1.10.2 h1:DMTTonx5m65Ic0GOoRY2c16WCbHxOOw6xxezuLaBpcU=
github.com/spf13/cobra v1.10.2/go.mod h1:7C1pvHqHw5A4vrJfjNwvOdzYu0Gml16OCs2GRiTUUS4=
github.com/spf13/pflag v1.0.9/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs=
github.com/stoewer/go-strcase v1.3.0/go.mod h1:fAH5hQ5pehh+j3nZfvwdk2RgEgQjAoM8wodgtPmh1xo=
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/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
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/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
github.com/xlab/treeprint v1.2.0 h1:HzHnuAF1plUN2zGlAFHbSQP2qJ0ZAD3XF5XD7OesXRQ=
github.com/xlab/treeprint v1.2.0/go.mod h1:gj5Gd3gPdKtR1ikdDK6fnFLdmIS0X30kTTuNd/WEJu0=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
go.yaml.in/yaml/v2 v2.4.2 h1:DzmwEr2rDGHl7lsFgAHxmNz/1NlQ7xLIrlN2h5d1eGI=
go.yaml.in/yaml/v2 v2.4.2/go.mod h1:081UH+NErpNdqlCXm3TtEran0rJZGxAYx9hb/ELlsPU=
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
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/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8=
golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY=
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/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/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-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8=
golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/oauth2 v0.27.0 h1:da9Vo7/tDv5RH/7nZDz1eMGS/q1Vv1N/7FCrBhI9I3M=
golang.org/x/oauth2 v0.27.0/go.mod h1:onh5ek6nERTohokkhCD/y2cV4Do3fxFHFuAejCkRWT8=
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-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw=
golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/term v0.30.0 h1:PQ39fJZ+mfadBm0y5WlL4vlM7Sx1Hgf13sMIY2+QS9Y=
golang.org/x/term v0.30.0/go.mod h1:NYYFdzHoI5wRh/h5tDMdMqCqPJZEuNqVR5xJLd/n67g=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY=
golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ=
golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0=
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/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950=
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/evanphx/json-patch.v4 v4.12.0 h1:n6jtcsulIzXPJaxegRbvFNNrZDjbij7ny3gmSPG+6V4=
gopkg.in/evanphx/json-patch.v4 v4.12.0/go.mod h1:p8EYWUEYMpynmqDbY58zCKCFZw8pRWMG4EsWvDvM72M=
gopkg.in/inf.v0 v0.9.1 h1:73M5CoZyi3ZLMOyDlQh031Cx6N9NDJ2Vvfl76EDAgDc=
gopkg.in/inf.v0 v0.9.1/go.mod h1:cWUDdTG/fYaXco+Dcufb5Vnc6Gp2YChqWtbxRZE0mXw=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/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=
k8s.io/api v0.34.2 h1:fsSUNZhV+bnL6Aqrp6O7lMTy6o5x2C4XLjnh//8SLYY=
k8s.io/api v0.34.2/go.mod h1:MMBPaWlED2a8w4RSeanD76f7opUoypY8TFYkSM+3XHw=
k8s.io/apimachinery v0.34.2 h1:zQ12Uk3eMHPxrsbUJgNF8bTauTVR2WgqJsTmwTE/NW4=
k8s.io/apimachinery v0.34.2/go.mod h1:/GwIlEcWuTX9zKIg2mbw0LRFIsXwrfoVxn+ef0X13lw=
k8s.io/apiserver v0.34.2 h1:2/yu8suwkmES7IzwlehAovo8dDE07cFRC7KMDb1+MAE=
k8s.io/apiserver v0.34.2/go.mod h1:gqJQy2yDOB50R3JUReHSFr+cwJnL8G1dzTA0YLEqAPI=
k8s.io/cli-runtime v0.34.2 h1:cct1GEuWc3IyVT8MSCoIWzRGw9HJ/C5rgP32H60H6aE=
k8s.io/cli-runtime v0.34.2/go.mod h1:X13tsrYexYUCIq8MarCBy8lrm0k0weFPTpcaNo7lms4=
k8s.io/client-go v0.34.2 h1:Co6XiknN+uUZqiddlfAjT68184/37PS4QAzYvQvDR8M=
k8s.io/client-go v0.34.2/go.mod h1:2VYDl1XXJsdcAxw7BenFslRQX28Dxz91U9MWKjX97fE=
k8s.io/component-base v0.34.2 h1:HQRqK9x2sSAsd8+R4xxRirlTjowsg6fWCPwWYeSvogQ=
k8s.io/component-base v0.34.2/go.mod h1:9xw2FHJavUHBFpiGkZoKuYZ5pdtLKe97DEByaA+hHbM=
k8s.io/klog/v2 v2.130.1 h1:n9Xl7H1Xvksem4KFG4PYbdQCQxqc/tTUyrgXaOhHSzk=
k8s.io/klog/v2 v2.130.1/go.mod h1:3Jpz1GvMt720eyJH1ckRHK1EDfpxISzJ7I9OYgaDtPE=
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b h1:MloQ9/bdJyIu9lb1PzujOPolHyvO06MXG5TUIj2mNAA=
k8s.io/kube-openapi v0.0.0-20250710124328-f3f2b991d03b/go.mod h1:UZ2yyWbFTpuhSbFhv24aGNOdoRdJZgsIObGBUaYVsts=
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397 h1:hwvWFiBzdWw1FhfY1FooPn3kzWuJ8tmbZBHi4zVsl1Y=
k8s.io/utils v0.0.0-20250604170112-4c0f3b243397/go.mod h1:OLgZIPagt7ERELqWJFomSt595RzquPNLL48iOWgYOg0=
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 h1:gBQPwqORJ8d8/YNZWEjoZs7npUVDpVXUUOFfW6CgAqE=
sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8/go.mod h1:mdzfpAEoE6DHQEN0uh9ZbOCuHbLK5wOm7dK4ctXE9Tg=
sigs.k8s.io/kustomize/api v0.20.1 h1:iWP1Ydh3/lmldBnH/S5RXgT98vWYMaTUL1ADcr+Sv7I=
sigs.k8s.io/kustomize/api v0.20.1/go.mod h1:t6hUFxO+Ph0VxIk1sKp1WS0dOjbPCtLJ4p8aADLwqjM=
sigs.k8s.io/kustomize/kyaml v0.20.1 h1:PCMnA2mrVbRP3NIB6v9kYCAc38uvFLVs8j/CD567A78=
sigs.k8s.io/kustomize/kyaml v0.20.1/go.mod h1:0EmkQHRUsJxY8Ug9Niig1pUMSCGHxQ5RklbpV/Ri6po=
sigs.k8s.io/randfill v1.0.0 h1:JfjMILfT8A6RbawdsK2JXGBR5AQVfd+9TbzrlneTyrU=
sigs.k8s.io/randfill v1.0.0/go.mod h1:XeLlZ/jmk4i1HRopwe7/aU3H5n1zNUcX6TM94b3QxOY=
sigs.k8s.io/structured-merge-diff/v6 v6.3.0 h1:jTijUJbW353oVOd9oTlifJqOGEkUw2jB/fXCbTiQEco=
sigs.k8s.io/structured-merge-diff/v6 v6.3.0/go.mod h1:M3W8sfWvn2HhQDIbGWj3S099YozAsymCo/wrT5ohRUE=
sigs.k8s.io/yaml v1.6.0 h1:G8fkbMSAFqgEFgh4b1wmtzDnioxFCUgTZhlbj5P9QYs=
sigs.k8s.io/yaml v1.6.0/go.mod h1:796bPqUfzR/0jLAl6XjHl3Ck7MiyVv8dbTdyT3/pMf4=
================================================
FILE: install.sh
================================================
#!/bin/sh
set -e
# Code generated by godownloader on 2023-02-28T17:14:26Z. DO NOT EDIT.
#
usage() {
this=$1
cat <<EOF
$this: download go binaries for undistro/marvin
Usage: $this [-b] bindir [-d] [tag]
-b sets bindir or installation directory, Defaults to ./bin
-d turns on debug logging
[tag] is a tag from
https://github.com/undistro/marvin/releases
If tag is missing, then the latest will be used.
Generated by godownloader
https://github.com/goreleaser/godownloader
EOF
exit 2
}
parse_args() {
#BINDIR is ./bin unless set be ENV
# over-ridden by flag below
BINDIR=${BINDIR:-./bin}
while getopts "b:dh?x" arg; do
case "$arg" in
b) BINDIR="$OPTARG" ;;
d) log_set_priority 10 ;;
h | \?) usage "$0" ;;
x) set -x ;;
esac
done
shift $((OPTIND - 1))
TAG=$1
}
# this function wraps all the destructive operations
# if a curl|bash cuts off the end of the script due to
# network, either nothing will happen or will syntax error
# out preventing half-done work
execute() {
tmpdir=$(mktemp -d)
log_debug "downloading files into ${tmpdir}"
http_download "${tmpdir}/${TARBALL}" "${TARBALL_URL}"
http_download "${tmpdir}/${CHECKSUM}" "${CHECKSUM_URL}"
hash_sha256_verify "${tmpdir}/${TARBALL}" "${tmpdir}/${CHECKSUM}"
srcdir="${tmpdir}"
(cd "${tmpdir}" && untar "${TARBALL}")
test ! -d "${BINDIR}" && install -d "${BINDIR}"
for binexe in $BINARIES; do
if [ "$OS" = "windows" ]; then
binexe="${binexe}.exe"
fi
install "${srcdir}/${binexe}" "${BINDIR}/"
log_info "installed ${BINDIR}/${binexe}"
done
rm -rf "${tmpdir}"
}
get_binaries() {
case "$PLATFORM" in
darwin/386) BINARIES="marvin" ;;
darwin/amd64) BINARIES="marvin" ;;
linux/386) BINARIES="marvin" ;;
linux/amd64) BINARIES="marvin" ;;
windows/386) BINARIES="marvin" ;;
windows/amd64) BINARIES="marvin" ;;
*)
log_crit "platform $PLATFORM is not supported. Make sure this script is up-to-date and file request at https://github.com/${PREFIX}/issues/new"
exit 1
;;
esac
}
tag_to_version() {
if [ -z "${TAG}" ]; then
log_info "checking GitHub for latest tag"
else
log_info "checking GitHub for tag '${TAG}'"
fi
REALTAG=$(github_release "$OWNER/$REPO" "${TAG}") && true
if test -z "$REALTAG"; then
log_crit "unable to find '${TAG}' - use 'latest' or see https://github.com/${PREFIX}/releases for details"
exit 1
fi
# if version starts with 'v', remove it
TAG="$REALTAG"
VERSION=${TAG#v}
}
adjust_format() {
# change format (tar.gz or zip) based on OS
true
}
adjust_os() {
# adjust archive name based on OS
case ${OS} in
386) OS=i386 ;;
amd64) OS=x86_64 ;;
darwin) OS=Darwin ;;
linux) OS=Linux ;;
windows) OS=Windows ;;
esac
true
}
adjust_arch() {
# adjust archive name based on ARCH
case ${ARCH} in
386) ARCH=i386 ;;
amd64) ARCH=x86_64 ;;
darwin) ARCH=Darwin ;;
linux) ARCH=Linux ;;
windows) ARCH=Windows ;;
esac
true
}
cat /dev/null <<EOF
------------------------------------------------------------------------
https://github.com/client9/shlib - portable posix shell functions
Public domain - http://unlicense.org
https://github.com/client9/shlib/blob/master/LICENSE.md
but credit (and pull requests) appreciated.
------------------------------------------------------------------------
EOF
is_command() {
command -v "$1" >/dev/null
}
echoerr() {
echo "$@" 1>&2
}
log_prefix() {
echo "$0"
}
_logp=6
log_set_priority() {
_logp="$1"
}
log_priority() {
if test -z "$1"; then
echo "$_logp"
return
fi
[ "$1" -le "$_logp" ]
}
log_tag() {
case $1 in
0) echo "emerg" ;;
1) echo "alert" ;;
2) echo "crit" ;;
3) echo "err" ;;
4) echo "warning" ;;
5) echo "notice" ;;
6) echo "info" ;;
7) echo "debug" ;;
*) echo "$1" ;;
esac
}
log_debug() {
log_priority 7 || return 0
echoerr "$(log_prefix)" "$(log_tag 7)" "$@"
}
log_info() {
log_priority 6 || return 0
echoerr "$(log_prefix)" "$(log_tag 6)" "$@"
}
log_err() {
log_priority 3 || return 0
echoerr "$(log_prefix)" "$(log_tag 3)" "$@"
}
log_crit() {
log_priority 2 || return 0
echoerr "$(log_prefix)" "$(log_tag 2)" "$@"
}
uname_os() {
os=$(uname -s | tr '[:upper:]' '[:lower:]')
case "$os" in
cygwin_nt*) os="windows" ;;
mingw*) os="windows" ;;
msys_nt*) os="windows" ;;
esac
echo "$os"
}
uname_arch() {
arch=$(uname -m)
case $arch in
x86_64) arch="amd64" ;;
x86) arch="386" ;;
i686) arch="386" ;;
i386) arch="386" ;;
aarch64) arch="arm64" ;;
armv5*) arch="armv5" ;;
armv6*) arch="armv6" ;;
armv7*) arch="armv7" ;;
esac
echo ${arch}
}
uname_os_check() {
os=$(uname_os)
case "$os" in
darwin) return 0 ;;
dragonfly) return 0 ;;
freebsd) return 0 ;;
linux) return 0 ;;
android) return 0 ;;
nacl) return 0 ;;
netbsd) return 0 ;;
openbsd) return 0 ;;
plan9) return 0 ;;
solaris) return 0 ;;
windows) return 0 ;;
esac
log_crit "uname_os_check '$(uname -s)' got converted to '$os' which is not a GOOS value. Please file bug at https://github.com/client9/shlib"
return 1
}
uname_arch_check() {
arch=$(uname_arch)
case "$arch" in
386) return 0 ;;
amd64) return 0 ;;
arm64) return 0 ;;
armv5) return 0 ;;
armv6) return 0 ;;
armv7) return 0 ;;
ppc64) return 0 ;;
ppc64le) return 0 ;;
mips) return 0 ;;
mipsle) return 0 ;;
mips64) return 0 ;;
mips64le) return 0 ;;
s390x) return 0 ;;
amd64p32) return 0 ;;
esac
log_crit "uname_arch_check '$(uname -m)' got converted to '$arch' which is not a GOARCH value. Please file bug report at https://github.com/client9/shlib"
return 1
}
untar() {
tarball=$1
case "${tarball}" in
*.tar.gz | *.tgz) tar --no-same-owner -xzf "${tarball}" ;;
*.tar) tar --no-same-owner -xf "${tarball}" ;;
*.zip) unzip "${tarball}" ;;
*)
log_err "untar unknown archive format for ${tarball}"
return 1
;;
esac
}
http_download_curl() {
local_file=$1
source_url=$2
header=$3
if [ -z "$header" ]; then
code=$(curl -w '%{http_code}' -sL -o "$local_file" "$source_url")
else
code=$(curl -w '%{http_code}' -sL -H "$header" -o "$local_file" "$source_url")
fi
if [ "$code" != "200" ]; then
log_debug "http_download_curl received HTTP status $code"
return 1
fi
return 0
}
http_download_wget() {
local_file=$1
source_url=$2
header=$3
if [ -z "$header" ]; then
wget -q -O "$local_file" "$source_url"
else
wget -q --header "$header" -O "$local_file" "$source_url"
fi
}
http_download() {
log_debug "http_download $2"
if is_command curl; then
http_download_curl "$@"
return
elif is_command wget; then
http_download_wget "$@"
return
fi
log_crit "http_download unable to find wget or curl"
return 1
}
http_copy() {
tmp=$(mktemp)
http_download "${tmp}" "$1" "$2" || return 1
body=$(cat "$tmp")
rm -f "${tmp}"
echo "$body"
}
github_release() {
owner_repo=$1
version=$2
test -z "$version" && version="latest"
giturl="https://github.com/${owner_repo}/releases/${version}"
json=$(http_copy "$giturl" "Accept:application/json")
test -z "$json" && return 1
version=$(echo "$json" | tr -s '\n' ' ' | sed 's/.*"tag_name":"//' | sed 's/".*//')
test -z "$version" && return 1
echo "$version"
}
hash_sha256() {
TARGET=${1:-/dev/stdin}
if is_command gsha256sum; then
hash=$(gsha256sum "$TARGET") || return 1
echo "$hash" | cut -d ' ' -f 1
elif is_command sha256sum; then
hash=$(sha256sum "$TARGET") || return 1
echo "$hash" | cut -d ' ' -f 1
elif is_command shasum; then
hash=$(shasum -a 256 "$TARGET" 2>/dev/null) || return 1
echo "$hash" | cut -d ' ' -f 1
elif is_command openssl; then
hash=$(openssl -dst openssl dgst -sha256 "$TARGET") || return 1
echo "$hash" | cut -d ' ' -f a
else
log_crit "hash_sha256 unable to find command to compute sha-256 hash"
return 1
fi
}
hash_sha256_verify() {
TARGET=$1
checksums=$2
if [ -z "$checksums" ]; then
log_err "hash_sha256_verify checksum file not specified in arg2"
return 1
fi
BASENAME=${TARGET##*/}
want=$(grep "${BASENAME}" "${checksums}" 2>/dev/null | tr '\t' ' ' | cut -d ' ' -f 1)
if [ -z "$want" ]; then
log_err "hash_sha256_verify unable to find checksum for '${TARGET}' in '${checksums}'"
return 1
fi
got=$(hash_sha256 "$TARGET")
if [ "$want" != "$got" ]; then
log_err "hash_sha256_verify checksum for '$TARGET' did not verify ${want} vs $got"
return 1
fi
}
cat /dev/null <<EOF
------------------------------------------------------------------------
End of functions from https://github.com/client9/shlib
------------------------------------------------------------------------
EOF
PROJECT_NAME="marvin"
OWNER=undistro
REPO="marvin"
BINARY=marvin
FORMAT=tar.gz
OS=$(uname_os)
ARCH=$(uname_arch)
PREFIX="$OWNER/$REPO"
# use in logging routines
log_prefix() {
echo "$PREFIX"
}
PLATFORM="${OS}/${ARCH}"
GITHUB_DOWNLOAD=https://github.com/${OWNER}/${REPO}/releases/download
uname_os_check "$OS"
uname_arch_check "$ARCH"
parse_args "$@"
get_binaries
tag_to_version
adjust_format
adjust_os
adjust_arch
log_info "found version: ${VERSION} for ${TAG}/${OS}/${ARCH}"
NAME=${PROJECT_NAME}_${OS}_${ARCH}
TARBALL=${NAME}.${FORMAT}
TARBALL_URL=${GITHUB_DOWNLOAD}/${TAG}/${TARBALL}
CHECKSUM=checksums.txt
CHECKSUM_URL=${GITHUB_DOWNLOAD}/${TAG}/${CHECKSUM}
execute
================================================
FILE: internal/builtins/cis/M-500_workload_in_default_namespace.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
id: M-500
slug: workload-in-default-namespace
severity: Medium
message: "Workload in default namespace"
match:
resources:
- group: ""
version: v1
resource: pods
- group: apps
version: v1
resource: deployments
- group: apps
version: v1
resource: daemonsets
- group: apps
version: v1
resource: statefulsets
- group: apps
version: v1
resource: replicasets
- group: batch
version: v1
resource: cronjobs
- group: batch
version: v1
resource: jobs
validations:
- expression: object.metadata.?namespace.orValue("default") != "default"
================================================
FILE: internal/builtins/cis/M-500_workload_in_default_namespace_test.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
- name: "Namespace set to default"
pass: false
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: default
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
- name: "Namespace not specified"
pass: false
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
volumes: []
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
- name: "Namespace specified"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
namespace: fooserver
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
volumes: []
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
================================================
FILE: internal/builtins/embed.go
================================================
// Copyright 2023 Undistro Authors
//
// 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.
package builtins
import (
"embed"
)
//go:embed *
var EmbedChecksFS embed.FS
================================================
FILE: internal/builtins/embed_test.go
================================================
// Copyright 2023 Undistro Authors
//
// 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.
package builtins
import (
"testing"
"github.com/stretchr/testify/assert"
)
func TestEmbedChecks(t *testing.T) {
entries, err := EmbedChecksFS.ReadDir(".")
assert.NoError(t, err)
assert.Greater(t, len(entries), 0)
}
================================================
FILE: internal/builtins/general/M-400_image_tagged_latest.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
id: M-400
slug: image-tagged-latest
severity: Medium
message: "Image tagged latest"
match:
resources:
- group: ""
version: v1
resource: pods
- group: apps
version: v1
resource: deployments
- group: apps
version: v1
resource: daemonsets
- group: apps
version: v1
resource: statefulsets
- group: apps
version: v1
resource: replicasets
- group: batch
version: v1
resource: cronjobs
- group: batch
version: v1
resource: jobs
validations:
- expression: >
allContainers.all(container,
container.image.contains(":") && // image digest contains ":"
[container.image.substring(container.image.lastIndexOf(":")+1)].all(image,
!image.contains("/") && !(image in ["latest", ""])
)
)
================================================
FILE: internal/builtins/general/M-400_image_tagged_latest_test.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
- name: "untagged"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
- name: "registry + untagged image"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: registry.com/nginx
- name: "registry + port + untagged image"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: registry.com:10443/nginx
- name: "latest tag"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:latest
- name: "registry + image tagged latest"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: registry.com/nginx:latest
- name: "registry + port + image tagged latest"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: registry.com:10443/nginx:latest
- name: "all ok"
pass: true
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- image: nginx:1
name: cont1
- image: nginx:1.25
name: cont2
- image: nginx@sha256:593dac25b7733ffb7afe1a72649a43e574778bf025ad60514ef40f6b5d606247
name: cont3
- image: registry.com/images/nginx:1
name: cont4
- image: registry.com:10443/nginx:1.25
name: cont5
- image: registry.com/nginx@sha256:593dac25b7733ffb7afe1a72649a43e574778bf025ad60514ef40f6b5d606247
name: cont6
================================================
FILE: internal/builtins/general/M-401_unmanaged_pod.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
id: M-401
slug: unmanaged-pod
severity: Low
message: "Unmanaged Pod"
match:
resources:
- group: ""
version: v1
resource: pods
variables:
- name: owners
expression: object.metadata.?ownerReferences.orValue([])
validations:
- expression: >
variables.owners != null && variables.owners.exists(o, o.?controller.orValue(false) == true)
================================================
FILE: internal/builtins/general/M-401_unmanaged_pod_test.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
- name: "ok"
pass: true
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx-7f7b76bc5b-6vb88
ownerReferences:
- apiVersion: apps/v1
blockOwnerDeletion: true
controller: true
kind: ReplicaSet
name: nginx-7f7b76bc5b
uid: daf540b6-b932-4b2d-a9b1-fa9cdfbff38b
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
- name: "controller false"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx-7f7b76bc5b-6vb88
ownerReferences:
- apiVersion: apps/v1
blockOwnerDeletion: true
controller: false
kind: ReplicaSet
name: nginx-7f7b76bc5b
uid: daf540b6-b932-4b2d-a9b1-fa9cdfbff38b
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
- name: "unmanaged"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
- name: "ownerReferences set to null"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
ownerReferences: null
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
- name: "ownerReferences empty"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
ownerReferences: []
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
================================================
FILE: internal/builtins/general/M-402_readiness_probe.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
id: M-402
slug: readiness-probe
severity: Medium
message: "Readiness and startup probe not configured"
match:
resources:
- group: ""
version: v1
resource: pods
- group: apps
version: v1
resource: deployments
- group: apps
version: v1
resource: daemonsets
- group: apps
version: v1
resource: statefulsets
- group: apps
version: v1
resource: replicasets
variables:
- name: owners
expression: object.metadata.?ownerReferences.orValue([])
validations:
- expression: >
(
object.kind == "Pod" &&
variables.owners != null &&
variables.owners.exists(o, o.?kind.orValue("") == "Job" && o.?apiVersion.orValue("") == "batch/v1")
)
||
podSpec.containers.all(c, has(c.readinessProbe) || has(c.startupProbe))
================================================
FILE: internal/builtins/general/M-402_readiness_probe_test.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
- name: "readinessProbe not specified"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
- name: "readinessProbe not specified in managed pod"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx-7f7b76bc5b-6vb88
ownerReferences:
- apiVersion: apps/v1
blockOwnerDeletion: true
controller: true
kind: ReplicaSet
name: nginx-7f7b76bc5b
uid: daf540b6-b932-4b2d-a9b1-fa9cdfbff38b
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
- name: "readinessProbe set to null"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
readinessProbe: null
- name: "readiness probe configured"
pass: true
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
readinessProbe:
httpGet:
port: 80
- name: "startup probe configured"
pass: true
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
startupProbe:
httpGet:
port: 80
- name: "managed pod with readiness probe configured"
pass: true
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx-7f7b76bc5b-6vb88
ownerReferences:
- apiVersion: apps/v1
blockOwnerDeletion: true
controller: true
kind: ReplicaSet
name: nginx-7f7b76bc5b
uid: daf540b6-b932-4b2d-a9b1-fa9cdfbff38b
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
readinessProbe:
httpGet:
port: 80
- name: "managed pod with startup probe configured"
pass: true
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx-7f7b76bc5b-6vb88
ownerReferences:
- apiVersion: apps/v1
blockOwnerDeletion: true
controller: true
kind: ReplicaSet
name: nginx-7f7b76bc5b
uid: daf540b6-b932-4b2d-a9b1-fa9cdfbff38b
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
startupProbe:
httpGet:
port: 80
- name: "job"
pass: true
input: |
apiVersion: v1
kind: Pod
metadata:
name: job-28119672-9sv4f
labels:
app: job
ownerReferences:
- apiVersion: batch/v1
blockOwnerDeletion: true
controller: true
kind: Job
name: job-28119672
uid: 3c506232-bf9b-475b-add5-d5e850ba6ceb
spec:
containers:
- name: job
image: job
- name: "ownerReferences set to null"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
ownerReferences: null
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
================================================
FILE: internal/builtins/general/M-403_liveness_probe.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
id: M-403
slug: liveness-probe
severity: Medium
message: "Liveness probe not configured"
match:
resources:
- group: ""
version: v1
resource: pods
- group: apps
version: v1
resource: deployments
- group: apps
version: v1
resource: daemonsets
- group: apps
version: v1
resource: statefulsets
- group: apps
version: v1
resource: replicasets
variables:
- name: owners
expression: object.metadata.?ownerReferences.orValue([])
validations:
- expression: >
(
object.kind == "Pod" &&
variables.owners != null &&
variables.owners.exists(o, o.?kind.orValue("") == "Job" && o.?apiVersion.orValue("") == "batch/v1")
)
||
podSpec.containers.all(c, has(c.livenessProbe))
================================================
FILE: internal/builtins/general/M-403_liveness_probe_test.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
- name: "livenessProbe not specified"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
- name: "livenessProbe not specified in managed pod"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx-7f7b76bc5b-6vb88
ownerReferences:
- apiVersion: apps/v1
blockOwnerDeletion: true
controller: true
kind: ReplicaSet
name: nginx-7f7b76bc5b
uid: daf540b6-b932-4b2d-a9b1-fa9cdfbff38b
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
- name: "livenessProbe set to null"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
livenessProbe: null
- name: "ok"
pass: true
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
livenessProbe:
httpGet:
port: 80
- name: "managed pod ok"
pass: true
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx-7f7b76bc5b-6vb88
ownerReferences:
- apiVersion: apps/v1
blockOwnerDeletion: true
controller: true
kind: ReplicaSet
name: nginx-7f7b76bc5b
uid: daf540b6-b932-4b2d-a9b1-fa9cdfbff38b
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
livenessProbe:
httpGet:
port: 80
- name: "job"
pass: true
input: |
apiVersion: v1
kind: Pod
metadata:
name: job-28119672-9sv4f
labels:
app: job
ownerReferences:
- apiVersion: batch/v1
blockOwnerDeletion: true
controller: true
kind: Job
name: job-28119672
uid: 3c506232-bf9b-475b-add5-d5e850ba6ceb
spec:
containers:
- name: job
image: job
================================================
FILE: internal/builtins/general/M-404_memory_requests.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
id: M-404
slug: memory-requests
severity: Medium
message: "Memory requests not specified"
match:
resources:
- group: ""
version: v1
resource: pods
- group: apps
version: v1
resource: deployments
- group: apps
version: v1
resource: daemonsets
- group: apps
version: v1
resource: statefulsets
- group: apps
version: v1
resource: replicasets
- group: batch
version: v1
resource: cronjobs
- group: batch
version: v1
resource: jobs
validations:
- expression: >
allContainers.all(c, c.?resources.?requests.?memory.orValue("") != "")
================================================
FILE: internal/builtins/general/M-404_memory_requests_test.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
- name: "resources not set"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
- name: "resources requests not set"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: 128Mi
- name: "memory requests not set"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
resources:
requests:
cpu: 10m
- name: "ok"
pass: true
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
resources:
requests:
cpu: 10m
memory: 64Mi
================================================
FILE: internal/builtins/general/M-405_cpu_requests.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
id: M-405
slug: cpu-requests
severity: Medium
message: "CPU requests not specified"
match:
resources:
- group: ""
version: v1
resource: pods
- group: apps
version: v1
resource: deployments
- group: apps
version: v1
resource: daemonsets
- group: apps
version: v1
resource: statefulsets
- group: apps
version: v1
resource: replicasets
- group: batch
version: v1
resource: cronjobs
- group: batch
version: v1
resource: jobs
validations:
- expression: >
allContainers.all(c, c.?resources.?requests.?cpu.orValue("") != "")
================================================
FILE: internal/builtins/general/M-405_cpu_requests_test.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
- name: "resources not set"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
- name: "resources requests not set"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: 128Mi
- name: "cpu requests not set"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
resources:
requests:
memory: 64Mi
- name: "ok"
pass: true
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
resources:
requests:
cpu: 10m
memory: 64Mi
================================================
FILE: internal/builtins/general/M-406_memory_limit.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
id: M-406
slug: memory-limit
severity: Medium
message: "Memory not limited"
match:
resources:
- group: ""
version: v1
resource: pods
- group: apps
version: v1
resource: deployments
- group: apps
version: v1
resource: daemonsets
- group: apps
version: v1
resource: statefulsets
- group: apps
version: v1
resource: replicasets
- group: batch
version: v1
resource: cronjobs
- group: batch
version: v1
resource: jobs
validations:
- expression: >
allContainers.all(c, c.?resources.?limits.?memory.orValue("") != "")
================================================
FILE: internal/builtins/general/M-406_memory_limit_test.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
- name: "resources not set"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
- name: "resources limits not set"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
resources:
requests:
memory: 64Mi
- name: "memory limits not set"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
cpu: 500m
- name: "ok"
pass: true
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: 128Mi
================================================
FILE: internal/builtins/general/M-407_cpu_limit.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
id: M-407
slug: cpu-limit
severity: Medium
message: "CPU not limited"
match:
resources:
- group: ""
version: v1
resource: pods
- group: apps
version: v1
resource: deployments
- group: apps
version: v1
resource: daemonsets
- group: apps
version: v1
resource: statefulsets
- group: apps
version: v1
resource: replicasets
- group: batch
version: v1
resource: cronjobs
- group: batch
version: v1
resource: jobs
validations:
- expression: >
allContainers.all(c, c.?resources.?limits.?cpu.orValue("") != "")
================================================
FILE: internal/builtins/general/M-407_cpu_limit_test.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
- name: "resources not set"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
- name: "resources limits not set"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
resources:
requests:
cpu: 5m
- name: "CPU limits not set"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: 128Mi
- name: "ok"
pass: true
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
cpu: 500m
================================================
FILE: internal/builtins/general/M-408_sudo_container_entrypoint.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
id: M-408
slug: sudo-container-entrypoint
severity: Medium
message: "Sudo in container entrypoint"
match:
resources:
- group: ""
version: v1
resource: pods
- group: apps
version: v1
resource: deployments
- group: apps
version: v1
resource: daemonsets
- group: apps
version: v1
resource: statefulsets
- group: apps
version: v1
resource: replicasets
- group: batch
version: v1
resource: cronjobs
- group: batch
version: v1
resource: jobs
validations:
- expression: >
allContainers.all(c,
c.?command.orValue([]).all(cmd, !cmd.contains("sudo"))
)
================================================
FILE: internal/builtins/general/M-408_sudo_container_entrypoint_test.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
- name: "command not set"
pass: true
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
- name: "command without sudo"
pass: true
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
command: ["printenv"]
resources:
requests:
cpu: 5m
- name: "command with sudo on entrypoint"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
command: ["sudo printenv"]
resources:
limits:
memory: 128Mi
================================================
FILE: internal/builtins/general/M-409_deprecated_image_registry.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
id: M-409
slug: deprecated-image-registry
severity: Medium
message: "Deprecated image registry"
match:
resources:
- group: ""
version: v1
resource: pods
- group: apps
version: v1
resource: deployments
- group: apps
version: v1
resource: daemonsets
- group: apps
version: v1
resource: statefulsets
- group: apps
version: v1
resource: replicasets
- group: batch
version: v1
resource: cronjobs
- group: batch
version: v1
resource: jobs
validations:
- expression: >
allContainers.all(c, !c.image.contains("k8s.grc.io"))
================================================
FILE: internal/builtins/general/M-409_deprecated_image_registry_test.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
- name: "registry not defined"
pass: true
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
- name: "registry deprecated"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: reg-fail
image: k8s.grc.io/pause
- name: "registry deprecated top"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: reg-fail
image: k8s.grc.io/pause
- name: reg-ok1
image: ok-registry.com:80/nginx@sha256:asdf
- name: reg-ok2
image: also-ok-registry.com:80/nginx@sha256:asdf
- name: "registry deprecated middle"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: reg-ok1
image: ok-registry.com:80/nginx@sha256:asdf
- name: reg-fail
image: k8s.grc.io/pause
- name: reg-ok2
image: also-ok-registry.com:80/nginx@sha256:asdf
- name: "registry deprecated bottom"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: reg-ok1
image: ok-registry.com:80/nginx@sha256:asdf
- name: reg-ok2
image: also-ok-registry.com:80/nginx@sha256:asdf
- name: reg-fail
image: k8s.grc.io/pause
================================================
FILE: internal/builtins/general/M-410_resource_using_invalid_restartpolicy.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
id: M-410
slug: resource-using-invalid-restartpolicy
severity: Medium
message: "Not allowed restartPolicy"
match:
resources:
- group: apps
version: v1
resource: deployments
- group: apps
version: v1
resource: daemonsets
- group: apps
version: v1
resource: replicasets
validations:
- expression: >
podSpec.?restartPolicy.orValue("Always") == 'Always'
================================================
FILE: internal/builtins/general/M-410_resource_using_invalid_restartpolicy_test.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
- name: "restartPolicy not defined"
pass: true
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
- name: "restartPolicy set OnFailure"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
restartPolicy: OnFailure
- name: "restartPolicy set Always"
pass: true
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
restartPolicy: Always
- name: "restartPolicy set Never"
pass: false
input: |
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
restartPolicy: Never
================================================
FILE: internal/builtins/general/M-411_role_binding_referencing_anonymous_or_unauthenticated.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
id: M-411
slug: role-binding-referencing-anonymous-or-unauthenticated
severity: Medium
message: "Role Binding referencing anonymous user or unauthenticated group"
match:
resources:
- group: "rbac.authorization.k8s.io"
version: v1
resource: rolebindings
- group: "rbac.authorization.k8s.io"
version: v1
resource: clusterrolebindings
validations:
- expression: >
!has(object.subjects) ||
object.subjects.all(subject,
!(subject.kind == "User" && subject.name == "system:anonymous") &&
!(subject.kind == "Group" && subject.name == "system:unauthenticated")
)
================================================
FILE: internal/builtins/general/M-411_role_binding_referencing_anonymous_or_unauthenticated_test.yaml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
- name: "anonymous user in role binding"
pass: false
input: |
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: binding-name
namespace: binding-namespace
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: role-name
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: system:anonymous
- kind: ServiceAccount
name: zora-operator
namespace: zora-system
- name: "anonymous user in cluster role binding"
pass: false
input: |
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: binding-name
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: role-name
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: User
name: system:anonymous
- kind: ServiceAccount
name: zora-operator
namespace: zora-system
- name: "unauthenticated group in role binding"
pass: false
input: |
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: binding-name
namespace: binding-namespace
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: role-name
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:unauthenticated
- kind: ServiceAccount
name: zora-operator
namespace: zora-system
- name: "unauthenticated group in cluster role binding"
pass: false
input: |
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: binding-name
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: role-name
subjects:
- apiGroup: rbac.authorization.k8s.io
kind: Group
name: system:unauthenticated
- kind: ServiceAccount
name: zora-operator
namespace: zora-system
- name: "valid role binding"
pass: true
input: |
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: binding-name
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: role-name
subjects:
- kind: ServiceAccount
name: zora-operator
namespace: zora-system
- name: "valid cluster role binding"
pass: true
input: |
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: binding-name
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: role-name
subjects:
- kind: ServiceAccount
name: zora-operator
namespace: zora-system
================================================
FILE: internal/builtins/mitre/M-200_allowed_registries.yml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
id: M-200
slug: allowed-registries
severity: Medium
message: "Image registry not allowed"
match:
resources:
- group: ""
version: v1
resource: pods
- group: apps
version: v1
resource: deployments
- group: apps
version: v1
resource: daemonsets
- group: apps
version: v1
resource: statefulsets
- group: apps
version: v1
resource: replicasets
- group: batch
version: v1
resource: cronjobs
- group: batch
version: v1
resource: jobs
params:
# use 'docker.io' for Docker Hub
allowedRegistries: []
validations:
- expression: >
size(params.allowedRegistries) == 0 ||
allContainers.all(container,
params.allowedRegistries.exists(registry,
((registry in ['docker.io', 'docker.io/library']) && !container.image.contains('/')) ||
container.image.startsWith(registry)
)
)
message: "Container image registry not allowed"
================================================
FILE: internal/builtins/mitre/M-200_allowed_registries_test.yml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
- name: "allowedRegistries param not specified"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
- name: "docker.io allowed"
pass: true
params:
allowedRegistries: [docker.io, ghcr.io]
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
- name: "docker.io allowed and container using full name"
pass: true
params:
allowedRegistries: [docker.io, ghcr.io]
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: docker.io/library/nginx:latest
selector:
matchLabels:
app: nginx
- name: "ghcr.io allowed"
pass: true
params:
allowedRegistries: [docker.io, ghcr.io]
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: ghcr.io/nginx/nginx
selector:
matchLabels:
app: nginx
- name: "docker.io/library allowed"
pass: true
params:
allowedRegistries: ["docker.io/library", ghcr.io]
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
- name: "not allowed"
pass: false
message: "Container image registry not allowed"
params:
allowedRegistries: [docker.io, ghcr.io]
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: gcr.io/nginx
selector:
matchLabels:
app: nginx
================================================
FILE: internal/builtins/mitre/M-201_app_credentials.yml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
id: M-201
slug: app-credentials
severity: High
message: "Application credentials stored in configuration files"
match:
resources:
- group: ""
version: v1
resource: pods
- group: apps
version: v1
resource: deployments
- group: apps
version: v1
resource: daemonsets
- group: apps
version: v1
resource: statefulsets
- group: apps
version: v1
resource: replicasets
- group: batch
version: v1
resource: cronjobs
- group: batch
version: v1
resource: jobs
- group: ""
version: v1
resource: configmaps
params:
sensitiveKeys:
- aws_access_key_id
- aws_secret_access_key
- azure_batchai_storage_account
- azure_batchai_storage_key
- azure_batch_account
- azure_batch_key
- secret
- key
- password
- pwd
- token
- jwt
- bearer
- credential
sensitiveValues:
- BEGIN \w+ PRIVATE KEY
- PRIVATE KEY
- eyJhbGciO
- JWT
- Bearer
- key
- secret
validations:
- expression: >
object.kind != 'ConfigMap' ||
!has(object.data) ||
object.data.all(key,
!params.sensitiveKeys.exists(sensitiveKey,
key.lowerAscii().contains(sensitiveKey)
) &&
!params.sensitiveValues.exists(sensitiveValue,
object.data[key].matches(sensitiveValue)
)
)
message: "ConfigMap could be storing sensitive data"
- expression: >
allContainers.all(container,
!has(container.env) ||
container.env.all(env,
!params.sensitiveKeys.exists(sensitiveKey,
env.name.lowerAscii().contains(sensitiveKey)
) &&
(!has(env.value) ||
!params.sensitiveValues.exists(sensitiveValue,
env.value.matches(sensitiveValue)
)
)
)
)
message: "Container could be storing sensitive data as environment variable"
================================================
FILE: internal/builtins/mitre/M-201_app_credentials_test.yml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
- name: "ConfigMap with no sensitive keys and values"
pass: true
input: |
apiVersion: v1
kind: ConfigMap
metadata:
name: config
data:
config: value
foo: bar
file.yaml: content
- name: "ConfigMap with no data"
pass: true
input: |
apiVersion: v1
kind: ConfigMap
metadata:
name: config
- name: "ConfigMap with empty data"
pass: true
input: |
apiVersion: v1
kind: ConfigMap
metadata:
name: config
data: {}
- name: "ConfigMap with sensitive key"
pass: false
message: "ConfigMap could be storing sensitive data"
input: |
apiVersion: v1
kind: ConfigMap
metadata:
name: config
data:
config: value
key: value
- name: "ConfigMap with sensitive value"
pass: false
message: "ConfigMap could be storing sensitive data"
input: |
apiVersion: v1
kind: ConfigMap
metadata:
name: config
data:
foo: bar
config: "PRIVATE KEY"
- name: "Container with no env"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
- name: "Container with empty env"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
env: []
selector:
matchLabels:
app: nginx
- name: "Container with no sensitive env"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
env:
- name: foo
value: bar
selector:
matchLabels:
app: nginx
- name: "Container with sensitive env name"
pass: false
message: "Container could be storing sensitive data as environment variable"
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
env:
- name: foo
value: bar
- name: key
value: bar
selector:
matchLabels:
app: nginx
- name: "Container with sensitive env value"
pass: false
message: "Container could be storing sensitive data as environment variable"
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
env:
- name: foo
value: "Bearer token"
selector:
matchLabels:
app: nginx
================================================
FILE: internal/builtins/mitre/M-202_auto_mount_service_account_token.yml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
id: M-202
slug: auto-mount-service-account-token
severity: Low
message: "Automounted service account token"
match:
resources:
- group: ""
version: v1
resource: pods
- group: apps
version: v1
resource: deployments
- group: apps
version: v1
resource: daemonsets
- group: apps
version: v1
resource: statefulsets
- group: apps
version: v1
resource: replicasets
- group: batch
version: v1
resource: cronjobs
- group: batch
version: v1
resource: jobs
validations:
- expression: >
podSpec.?automountServiceAccountToken.orValue(true) == false
message: "Pod with Service Account token mounted automatically"
================================================
FILE: internal/builtins/mitre/M-202_auto_mount_service_account_token_test.yml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
- name: "automountServiceAccountToken not specified"
pass: false
message: "Pod with Service Account token mounted automatically"
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
- name: "automountServiceAccountToken set to true"
pass: false
message: "Pod with Service Account token mounted automatically"
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
automountServiceAccountToken: true
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
- name: "automountServiceAccountToken set to false"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
automountServiceAccountToken: false
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
================================================
FILE: internal/builtins/mitre/M-203_ssh_server.yml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
id: M-203
slug: ssh-server
severity: Low
message: "SSH server running inside container"
match:
resources:
- group: ""
version: v1
resource: pods
- group: apps
version: v1
resource: deployments
- group: apps
version: v1
resource: daemonsets
- group: apps
version: v1
resource: statefulsets
- group: apps
version: v1
resource: replicasets
- group: batch
version: v1
resource: cronjobs
- group: batch
version: v1
resource: jobs
- group: ""
version: v1
resource: services
params:
sshPorts: [22, 2222]
validations:
- expression: >
object.kind != 'Service' ||
!has(object.spec.ports) ||
object.spec.ports.all(p,
!(p.port in params.sshPorts) &&
!(p.?targetPort.orValue(0) in params.sshPorts)
)
message: "Service should not be routing to SSH server"
- expression: >
allContainers.all(container,
!has(container.ports) ||
container.ports.all(port,
!(port.containerPort in params.sshPorts)
)
)
message: "Container could be running SSH server"
================================================
FILE: internal/builtins/mitre/M-203_ssh_server_test.yml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
- name: "Service with no targetPort"
pass: true
input: |
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
ports:
- port: 80
selector:
app: nginx
type: ClusterIP
- name: "Service with SSH port"
pass: false
message: "Service should not be routing to SSH server"
input: |
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
ports:
- port: 22
targetPort: 80
selector:
app: nginx
type: ClusterIP
- name: "Service with SSH targetPort"
pass: false
message: "Service should not be routing to SSH server"
input: |
apiVersion: v1
kind: Service
metadata:
name: nginx
spec:
ports:
- port: 8080
targetPort: 8080
name: http
- port: 80
targetPort: 2222
name: ssh
selector:
app: nginx
type: ClusterIP
- name: "Container with no ports"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
- name: "Container with empty ports"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports: []
selector:
matchLabels:
app: nginx
- name: "Container with no SSH ports"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
selector:
matchLabels:
app: nginx
- name: "Container with SSH port"
pass: false
message: "Container could be running SSH server"
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 80
- containerPort: 22
selector:
matchLabels:
app: nginx
- name: "Container with SSH port 2222"
pass: false
message: "Container could be running SSH server"
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
ports:
- containerPort: 2222
selector:
matchLabels:
app: nginx
================================================
FILE: internal/builtins/nsa/M-300_read_only_root_filesystem.yml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
id: M-300
slug: read-only-root-filesystem
severity: Low
message: "Root filesystem write allowed"
match:
resources:
- group: ""
version: v1
resource: pods
- group: apps
version: v1
resource: deployments
- group: apps
version: v1
resource: daemonsets
- group: apps
version: v1
resource: statefulsets
- group: apps
version: v1
resource: replicasets
- group: batch
version: v1
resource: cronjobs
- group: batch
version: v1
resource: jobs
validations:
- expression: >
allContainers.all(c, c.?securityContext.?readOnlyRootFilesystem.orValue(false) == true)
message: "Container is able to write to the root filesystem"
================================================
FILE: internal/builtins/nsa/M-300_read_only_root_filesystem_test.yml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
- name: "securityContext not specified"
pass: false
message: "Container is able to write to the root filesystem"
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
- name: "securityContext.readOnlyRootFilesystem not specified"
pass: false
message: "Container is able to write to the root filesystem"
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
securityContext:
runAsNonRoot: true
selector:
matchLabels:
app: nginx
- name: "securityContext.readOnlyRootFilesystem set to false"
pass: false
message: "Container is able to write to the root filesystem"
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
securityContext:
readOnlyRootFilesystem: false
selector:
matchLabels:
app: nginx
- name: "securityContext.readOnlyRootFilesystem set to true"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
securityContext:
readOnlyRootFilesystem: true
selector:
matchLabels:
app: nginx
================================================
FILE: internal/builtins/pss/baseline/M-100_host_process.yml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
# https://kubernetes.io/docs/concepts/security/pod-security-standards/#baseline
# https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/pod-security-admission/policy/check_windowsHostProcess.go
# https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/pod-security-admission/policy/check_windowsHostProcess_test.go
id: M-100
slug: host-process
severity: High
message: "Privileged access to the Windows node"
match:
resources:
- group: ""
version: v1
resource: pods
- group: apps
version: v1
resource: deployments
- group: apps
version: v1
resource: daemonsets
- group: apps
version: v1
resource: statefulsets
- group: apps
version: v1
resource: replicasets
- group: batch
version: v1
resource: cronjobs
- group: batch
version: v1
resource: jobs
validations:
- expression: >
podSpec.?securityContext.?windowsOptions.?hostProcess.orValue(false) == false
message: "Pod with privileged access to the Windows node"
- expression: >
allContainers.all(c, c.?securityContext.?windowsOptions.?hostProcess.orValue(false) == false)
message: "Container with privileged access to the Windows node"
================================================
FILE: internal/builtins/pss/baseline/M-100_host_process_test.yml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
- name: "securityContext not specified"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
- name: "securityContext.windowsOptions not specified"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
securityContext:
runAsNonRoot: true
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
- name: "securityContext.windowsOptions.hostProcess not specified"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
securityContext:
windowsOptions:
runAsUserName: user
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
- name: "securityContext.windowsOptions.hostProcess set to false"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
securityContext:
windowsOptions:
hostProcess: false
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
- name: "securityContext.windowsOptions.hostProcess set to true"
pass: false
message: "Pod with privileged access to the Windows node"
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
os:
name: windows
hostNetwork: true
securityContext:
windowsOptions:
hostProcess: true
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
- name: "second container with securityContext.windowsOptions.hostProcess set to true"
pass: false
message: "Container with privileged access to the Windows node"
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
os:
name: windows
hostNetwork: true
containers:
- name: proxy
image: proxy
securityContext:
windowsOptions:
hostProcess: true
- name: nginx
image: nginx
securityContext:
windowsOptions:
hostProcess: true
selector:
matchLabels:
app: nginx
================================================
FILE: internal/builtins/pss/baseline/M-101_host_namespaces.yml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
# https://kubernetes.io/docs/concepts/security/pod-security-standards/#baseline
# https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/pod-security-admission/policy/check_hostNamespaces.go
# https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/pod-security-admission/policy/check_hostNamespaces_test.go
id: M-101
slug: host-namespaces
severity: High
message: "Host namespaces"
match:
resources:
- group: ""
version: v1
resource: pods
- group: apps
version: v1
resource: deployments
- group: apps
version: v1
resource: daemonsets
- group: apps
version: v1
resource: statefulsets
- group: apps
version: v1
resource: replicasets
- group: batch
version: v1
resource: cronjobs
- group: batch
version: v1
resource: jobs
validations:
- expression: >
podSpec.?hostNetwork.orValue(false) == false &&
podSpec.?hostPID.orValue(false) == false &&
podSpec.?hostIPC.orValue(false) == false
message: "Pod sharing host namespace"
================================================
FILE: internal/builtins/pss/baseline/M-101_host_namespaces_test.yml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
- name: "host options not specified"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
- name: "hostNetwork set to true"
pass: false
message: "Pod sharing host namespace"
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
hostNetwork: true
hostIPC: false
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
- name: "hostPID set to true"
pass: false
message: "Pod sharing host namespace"
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
hostNetwork: false
hostPID: true
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
- name: "hostIPC set to true"
pass: false
message: "Pod sharing host namespace"
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
hostIPC: true
hostPID: false
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
- name: "all host options set to false"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
hostNetwork: false
hostIPC: false
hostPID: false
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
- name: "all host options set to true"
pass: false
message: "Pod sharing host namespace"
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
hostNetwork: true
hostIPC: true
hostPID: true
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
================================================
FILE: internal/builtins/pss/baseline/M-102_privileged_containers.yml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
# https://kubernetes.io/docs/concepts/security/pod-security-standards/#baseline
# https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/pod-security-admission/policy/check_privileged.go
# https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/pod-security-admission/policy/check_privileged_test.go
id: M-102
slug: privileged-containers
severity: High
message: "Privileged container"
match:
resources:
- group: ""
version: v1
resource: pods
- group: apps
version: v1
resource: deployments
- group: apps
version: v1
resource: daemonsets
- group: apps
version: v1
resource: statefulsets
- group: apps
version: v1
resource: replicasets
- group: batch
version: v1
resource: cronjobs
- group: batch
version: v1
resource: jobs
validations:
- expression: >
allContainers.all(c, c.?securityContext.?privileged.orValue(false) == false)
message: "Container running in privileged mode"
================================================
FILE: internal/builtins/pss/baseline/M-102_privileged_containers_test.yml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
- name: "securityContext not specified"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
- name: "securityContext.privileged not specified"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: proxy
image: proxy
- name: nginx
image: nginx
securityContext:
runAsNonRoot: true
selector:
matchLabels:
app: nginx
- name: "securityContext.privileged set to true"
pass: false
message: "Container running in privileged mode"
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: proxy
image: proxy
- name: nginx
image: nginx
securityContext:
privileged: true
selector:
matchLabels:
app: nginx
- name: "initContainer securityContext.privileged set to true"
pass: false
message: "Container running in privileged mode"
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
initContainers:
- name: init
image: busybox
securityContext:
privileged: true
containers:
- name: proxy
image: proxy
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
================================================
FILE: internal/builtins/pss/baseline/M-103_capabilities_baseline.yml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
# https://kubernetes.io/docs/concepts/security/pod-security-standards/#baseline
# https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/pod-security-admission/policy/check_capabilities_baseline.go
# https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/pod-security-admission/policy/check_capabilities_baseline_test.go
id: M-103
slug: capabilities-baseline
severity: High
message: "Insecure capabilities"
match:
resources:
- group: ""
version: v1
resource: pods
- group: apps
version: v1
resource: deployments
- group: apps
version: v1
resource: daemonsets
- group: apps
version: v1
resource: statefulsets
- group: apps
version: v1
resource: replicasets
- group: batch
version: v1
resource: cronjobs
- group: batch
version: v1
resource: jobs
params:
allowedCapabilities:
- AUDIT_WRITE
- CHOWN
- DAC_OVERRIDE
- FOWNER
- FSETID
- KILL
- MKNOD
- NET_BIND_SERVICE
- SETFCAP
- SETGID
- SETPCAP
- SETUID
- SYS_CHROOT
validations:
- expression: >
allContainers.all(c, c.?securityContext.?capabilities.?add.orValue([]).all(cap, cap in params.allowedCapabilities))
message: "Container running with not allowed capabilities"
================================================
FILE: internal/builtins/pss/baseline/M-103_capabilities_baseline_test.yml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
- name: "securityContext not specified"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
- name: "securityContext.capabilities not specified"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
securityContext:
runAsNonRoot: true
selector:
matchLabels:
app: nginx
- name: "securityContext.capabilities.add not specified"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
securityContext:
capabilities:
drop: [NET_BIND_SERVICE]
selector:
matchLabels:
app: nginx
- name: "securityContext.capabilities.add set with allowed capabilities"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
securityContext:
capabilities:
add: [CHOWN, NET_BIND_SERVICE, SETGID, SETUID]
selector:
matchLabels:
app: nginx
- name: "securityContext.capabilities.add set only with forbidden capabilities"
pass: false
message: "Container running with not allowed capabilities"
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
securityContext:
capabilities:
add: [NET_ADMIN, SYS_TIME]
selector:
matchLabels:
app: nginx
- name: "securityContext.capabilities.add set with one forbidden capability"
pass: false
message: "Container running with not allowed capabilities"
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
securityContext:
capabilities:
add: [NET_BIND_SERVICE, NET_ADMIN]
selector:
matchLabels:
app: nginx
================================================
FILE: internal/builtins/pss/baseline/M-104_host_path_volumes.yml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
# https://kubernetes.io/docs/concepts/security/pod-security-standards/#baseline
# https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/pod-security-admission/policy/check_hostPathVolumes.go
# https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/pod-security-admission/policy/check_hostPathVolumes_test.go
id: M-104
slug: host-path-volumes
severity: High
message: "HostPath volume"
match:
resources:
- group: ""
version: v1
resource: pods
- group: apps
version: v1
resource: deployments
- group: apps
version: v1
resource: daemonsets
- group: apps
version: v1
resource: statefulsets
- group: apps
version: v1
resource: replicasets
- group: batch
version: v1
resource: cronjobs
- group: batch
version: v1
resource: jobs
validations:
- expression: >
podSpec.?volumes.orValue([]).all(v, !has(v.hostPath))
message: "Pod with mounted host volume"
================================================
FILE: internal/builtins/pss/baseline/M-104_host_path_volumes_test.yml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
- name: "volumes not specified"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
- name: "hostPath volumes not specified"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
volumes:
- name: config
configMap:
name: nginx-config
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
- name: "hostPath set to null"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
volumes:
- name: config
hostPath: null
configMap:
name: nginx-config
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
- name: "hostPath volume specified"
pass: false
message: "Pod with mounted host volume"
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
volumes:
- name: cont1
hostPath:
path: path
containers:
- name: nginx
image: nginx
selector:
matchLabels:
app: nginx
================================================
FILE: internal/builtins/pss/baseline/M-105_host_ports.yml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
# https://kubernetes.io/docs/concepts/security/pod-security-standards/#baseline
# https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/pod-security-admission/policy/check_hostPorts.go
# https://github.com/kubernetes/kubernetes/blob/master/staging/src/k8s.io/pod-security-admission/policy/check_hostPorts_test.go
id: M-105
slug: host-ports
severity: High
message: "Not allowed hostPort"
match:
resources:
- group: ""
version: v1
resource: pods
- group: apps
version: v1
resource: deployments
- group: apps
version: v1
resource: daemonsets
- group: apps
version: v1
resource: statefulsets
- group: apps
version: v1
resource: replicasets
- group: batch
version: v1
resource: cronjobs
- group: batch
version: v1
resource: jobs
params:
allowedHostPorts: [0]
validations:
- expression: >
allContainers.all(c, c.?ports.orValue([]).all(p, p.?hostPort.orValue(0) in params.allowedHostPorts))
message: "Container exposing not allowed port on the host"
================================================
FILE: internal/builtins/pss/baseline/M-105_host_ports_test.yml
================================================
# Copyright 2023 Undistro Authors
#
# 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.
- name: "ports not specified"
pass: true
input: |
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
gitextract_roenwdf7/
├── .github/
│ ├── dependabot.yml
│ └── workflows/
│ ├── release.yml
│ └── test.yml
├── .gitignore
├── .goreleaser.yaml
├── .krew.yaml
├── CODE_OF_CONDUCT.md
├── CONTRIBUTING.md
├── Dockerfile
├── LICENSE
├── MAINTAINERS.md
├── Makefile
├── README.md
├── checks.md
├── cmd/
│ ├── root.go
│ ├── scan.go
│ └── version.go
├── examples/
│ ├── labels.yml
│ └── replicas.yml
├── go.mod
├── go.sum
├── install.sh
├── internal/
│ └── builtins/
│ ├── cis/
│ │ ├── M-500_workload_in_default_namespace.yaml
│ │ └── M-500_workload_in_default_namespace_test.yaml
│ ├── embed.go
│ ├── embed_test.go
│ ├── general/
│ │ ├── M-400_image_tagged_latest.yaml
│ │ ├── M-400_image_tagged_latest_test.yaml
│ │ ├── M-401_unmanaged_pod.yaml
│ │ ├── M-401_unmanaged_pod_test.yaml
│ │ ├── M-402_readiness_probe.yaml
│ │ ├── M-402_readiness_probe_test.yaml
│ │ ├── M-403_liveness_probe.yaml
│ │ ├── M-403_liveness_probe_test.yaml
│ │ ├── M-404_memory_requests.yaml
│ │ ├── M-404_memory_requests_test.yaml
│ │ ├── M-405_cpu_requests.yaml
│ │ ├── M-405_cpu_requests_test.yaml
│ │ ├── M-406_memory_limit.yaml
│ │ ├── M-406_memory_limit_test.yaml
│ │ ├── M-407_cpu_limit.yaml
│ │ ├── M-407_cpu_limit_test.yaml
│ │ ├── M-408_sudo_container_entrypoint.yaml
│ │ ├── M-408_sudo_container_entrypoint_test.yaml
│ │ ├── M-409_deprecated_image_registry.yaml
│ │ ├── M-409_deprecated_image_registry_test.yaml
│ │ ├── M-410_resource_using_invalid_restartpolicy.yaml
│ │ ├── M-410_resource_using_invalid_restartpolicy_test.yaml
│ │ ├── M-411_role_binding_referencing_anonymous_or_unauthenticated.yaml
│ │ └── M-411_role_binding_referencing_anonymous_or_unauthenticated_test.yaml
│ ├── mitre/
│ │ ├── M-200_allowed_registries.yml
│ │ ├── M-200_allowed_registries_test.yml
│ │ ├── M-201_app_credentials.yml
│ │ ├── M-201_app_credentials_test.yml
│ │ ├── M-202_auto_mount_service_account_token.yml
│ │ ├── M-202_auto_mount_service_account_token_test.yml
│ │ ├── M-203_ssh_server.yml
│ │ └── M-203_ssh_server_test.yml
│ ├── nsa/
│ │ ├── M-300_read_only_root_filesystem.yml
│ │ └── M-300_read_only_root_filesystem_test.yml
│ └── pss/
│ ├── baseline/
│ │ ├── M-100_host_process.yml
│ │ ├── M-100_host_process_test.yml
│ │ ├── M-101_host_namespaces.yml
│ │ ├── M-101_host_namespaces_test.yml
│ │ ├── M-102_privileged_containers.yml
│ │ ├── M-102_privileged_containers_test.yml
│ │ ├── M-103_capabilities_baseline.yml
│ │ ├── M-103_capabilities_baseline_test.yml
│ │ ├── M-104_host_path_volumes.yml
│ │ ├── M-104_host_path_volumes_test.yml
│ │ ├── M-105_host_ports.yml
│ │ ├── M-105_host_ports_test.yml
│ │ ├── M-106_apparmor.yml
│ │ ├── M-106_apparmor_test.yml
│ │ ├── M-107_selinux.yml
│ │ ├── M-107_selinux_test.yml
│ │ ├── M-108_proc_mount.yml
│ │ ├── M-108_proc_mount_test.yml
│ │ ├── M-109_seccomp_baseline.yml
│ │ ├── M-109_seccomp_baseline_test.yml
│ │ ├── M-110_sysctls.yml
│ │ └── M-110_sysctls_test.yml
│ └── restricted/
│ ├── M-111_volume_types.yml
│ ├── M-111_volume_types_test.yml
│ ├── M-112_privilege_escalation.yml
│ ├── M-112_privilege_escalation_test.yml
│ ├── M-113_run_as_non_root.yml
│ ├── M-113_run_as_non_root_test.yml
│ ├── M-114_run_as_user.yml
│ ├── M-114_run_as_user_test.yml
│ ├── M-115_seccomp_restricted.yml
│ ├── M-115_seccomp_restricted_test.yml
│ ├── M-116_capabilities_restricted.yml
│ └── M-116_capabilities_restricted_test.yml
├── main.go
├── pkg/
│ ├── cmd/
│ │ └── scan.go
│ ├── loader/
│ │ ├── builtin.go
│ │ ├── builtin_test.go
│ │ ├── loader.go
│ │ ├── loader_test.go
│ │ └── testdata/
│ │ ├── checks/
│ │ │ ├── svc_lb.json
│ │ │ └── workloads/
│ │ │ ├── replicas.yaml
│ │ │ ├── replicas_test.yaml
│ │ │ └── unsupported.txt
│ │ └── invalid/
│ │ └── invalid.yml
│ ├── printers/
│ │ ├── interface.go
│ │ ├── json.go
│ │ ├── md.go
│ │ ├── table.go
│ │ └── yaml.go
│ ├── types/
│ │ ├── check.go
│ │ ├── check_test.go
│ │ ├── report.go
│ │ ├── report_test.go
│ │ ├── severity.go
│ │ ├── severity_test.go
│ │ ├── status.go
│ │ └── status_test.go
│ ├── validator/
│ │ ├── activation.go
│ │ ├── compiler.go
│ │ ├── compiler_test.go
│ │ ├── interface.go
│ │ ├── podspec.go
│ │ ├── podspec_test.go
│ │ └── validator.go
│ └── version/
│ ├── version.go
│ └── version_test.go
└── test/
└── builtins_test.go
SYMBOL INDEX (138 symbols across 33 files)
FILE: cmd/root.go
function Execute (line 39) | func Execute() {
function isKubectlPlugin (line 46) | func isKubectlPlugin() bool {
function execName (line 50) | func execName() string {
function init (line 58) | func init() {
function initNoColor (line 76) | func initNoColor() {
FILE: cmd/scan.go
function init (line 69) | func init() {
FILE: cmd/version.go
function init (line 58) | func init() {
FILE: internal/builtins/embed_test.go
function TestEmbedChecks (line 23) | func TestEmbedChecks(t *testing.T) {
FILE: main.go
function main (line 19) | func main() {
FILE: pkg/cmd/scan.go
type ScanOptions (line 42) | type ScanOptions struct
method AddFlags (line 80) | func (o *ScanOptions) AddFlags(flags *pflag.FlagSet) {
method Init (line 106) | func (o *ScanOptions) Init(ctx context.Context) error {
method Validate (line 155) | func (o *ScanOptions) Validate() error {
method ToDynamicClient (line 163) | func (o *ScanOptions) ToDynamicClient() (*dynamic.DynamicClient, error) {
method Run (line 172) | func (o *ScanOptions) Run() (bool, error) {
method getChecks (line 192) | func (o *ScanOptions) getChecks() ([]types.Check, error) {
method runCheck (line 212) | func (o *ScanOptions) runCheck(check types.Check) *types.CheckResult {
method loadResources (line 253) | func (o *ScanOptions) loadResources(check types.Check) (map[string][]u...
method isSkipped (line 281) | func (o *ScanOptions) isSkipped(checkID string, annotations map[string...
method addGVR (line 302) | func (o *ScanOptions) addGVR(obj unstructured.Unstructured, gvr string) {
function NewScanOptions (line 65) | func NewScanOptions() *ScanOptions {
FILE: pkg/loader/builtin.go
function init (line 28) | func init() {
FILE: pkg/loader/builtin_test.go
function TestBuiltins (line 23) | func TestBuiltins(t *testing.T) {
FILE: pkg/loader/loader.go
type ChecksMap (line 31) | type ChecksMap
method toList (line 37) | func (cm ChecksMap) toList() []types.Check {
type TestsMap (line 32) | type TestsMap
type readFileFunc (line 33) | type readFileFunc
function LoadChecks (line 56) | func LoadChecks(root string) ([]types.Check, error) {
function LoadChecksAndTests (line 62) | func LoadChecksAndTests(root string) (ChecksMap, TestsMap, error) {
function load (line 66) | func load(root string) (ChecksMap, TestsMap, error) {
function walkDir (line 75) | func walkDir(readFileFn readFileFunc, builtin bool) (ChecksMap, TestsMap...
function parseCheck (line 117) | func parseCheck(ext string, bs []byte) (types.Check, error) {
function parseTests (line 122) | func parseTests(ext string, bs []byte) ([]types.Test, error) {
function parse (line 127) | func parse[T any](ext string, bs []byte, obj T) (T, error) {
FILE: pkg/loader/loader_test.go
function TestLoadChecks (line 23) | func TestLoadChecks(t *testing.T) {
function TestLoadChecksAndTests (line 88) | func TestLoadChecksAndTests(t *testing.T) {
FILE: pkg/printers/interface.go
type Printer (line 24) | type Printer interface
FILE: pkg/printers/json.go
type JSONPrinter (line 25) | type JSONPrinter struct
method PrintObj (line 27) | func (*JSONPrinter) PrintObj(report types.Report, w io.Writer) error {
FILE: pkg/printers/md.go
type MarkdownPrinter (line 26) | type MarkdownPrinter struct
method PrintObj (line 28) | func (*MarkdownPrinter) PrintObj(report types.Report, w io.Writer) err...
FILE: pkg/printers/table.go
type TablePrinter (line 38) | type TablePrinter struct
method PrintObj (line 41) | func (r *TablePrinter) PrintObj(report types.Report, w io.Writer) error {
function renderTable (line 59) | func renderTable(report types.Report, t *tablewriter.Table) {
function colorSeverity (line 87) | func colorSeverity(s types.Severity) string {
function colorStatus (line 101) | func colorStatus(s types.CheckStatus) string {
FILE: pkg/printers/yaml.go
type YAMLPrinter (line 27) | type YAMLPrinter struct
method PrintObj (line 29) | func (*YAMLPrinter) PrintObj(report types.Report, w io.Writer) error {
FILE: pkg/types/check.go
type Check (line 22) | type Check struct
type Match (line 36) | type Match struct
type ResourceRule (line 40) | type ResourceRule struct
method ToGVR (line 46) | func (r *ResourceRule) ToGVR() schema.GroupVersionResource {
type Validation (line 50) | type Validation struct
type Variable (line 55) | type Variable struct
type Test (line 60) | type Test struct
FILE: pkg/types/check_test.go
function TestResourceRule_ToGVR (line 26) | func TestResourceRule_ToGVR(t *testing.T) {
FILE: pkg/types/report.go
type Report (line 24) | type Report struct
method Add (line 34) | func (r *Report) Add(cr *CheckResult) {
method HasError (line 38) | func (r *Report) HasError() bool {
function NewReport (line 30) | func NewReport(kubeVersion *version.Info) *Report {
type CheckResult (line 47) | type CheckResult struct
method AddFailed (line 82) | func (r *CheckResult) AddFailed(obj unstructured.Unstructured) {
method AddPassed (line 87) | func (r *CheckResult) AddPassed(obj unstructured.Unstructured) {
method AddSkipped (line 92) | func (r *CheckResult) AddSkipped(obj unstructured.Unstructured) {
method AddError (line 97) | func (r *CheckResult) AddError(err error) {
method AddErrors (line 101) | func (r *CheckResult) AddErrors(errs ...error) {
method UpdateStatus (line 107) | func (r *CheckResult) UpdateStatus() {
function NewCheckResult (line 66) | func NewCheckResult(check Check) *CheckResult {
function GVK (line 125) | func GVK(obj unstructured.Unstructured) string {
function NamespacedName (line 131) | func NamespacedName(obj unstructured.Unstructured) string {
function addResource (line 138) | func addResource(obj unstructured.Unstructured, m map[string][]string) {
FILE: pkg/types/report_test.go
function TestReport (line 42) | func TestReport(t *testing.T) {
function obj (line 118) | func obj(apiVersion, kind, ns, name string) unstructured.Unstructured {
FILE: pkg/types/severity.go
type Severity (line 22) | type Severity
method String (line 32) | func (s Severity) String() string {
method UnmarshalJSON (line 62) | func (s *Severity) UnmarshalJSON(b []byte) error {
method MarshalJSON (line 67) | func (s Severity) MarshalJSON() ([]byte, error) {
constant SeverityUnknown (line 25) | SeverityUnknown Severity = iota
constant SeverityLow (line 26) | SeverityLow
constant SeverityMedium (line 27) | SeverityMedium
constant SeverityHigh (line 28) | SeverityHigh
constant SeverityCritical (line 29) | SeverityCritical
function ParseSeverity (line 47) | func ParseSeverity(s string) Severity {
FILE: pkg/types/severity_test.go
type severityHolder (line 24) | type severityHolder struct
function TestSeverityMarshalJSON (line 28) | func TestSeverityMarshalJSON(t *testing.T) {
function TestSeverityUnmarshalJSON (line 68) | func TestSeverityUnmarshalJSON(t *testing.T) {
FILE: pkg/types/status.go
type CheckStatus (line 22) | type CheckStatus
method String (line 32) | func (s CheckStatus) String() string {
method UnmarshalJSON (line 62) | func (s *CheckStatus) UnmarshalJSON(b []byte) error {
method MarshalJSON (line 67) | func (s CheckStatus) MarshalJSON() ([]byte, error) {
constant StatusUnknown (line 25) | StatusUnknown CheckStatus = iota
constant StatusPassed (line 26) | StatusPassed
constant StatusSkipped (line 27) | StatusSkipped
constant StatusFailed (line 28) | StatusFailed
constant StatusError (line 29) | StatusError
function ParseStatus (line 47) | func ParseStatus(s string) CheckStatus {
FILE: pkg/types/status_test.go
type statusHolder (line 24) | type statusHolder struct
function TestCheckStatusMarshalJSON (line 28) | func TestCheckStatusMarshalJSON(t *testing.T) {
function TestCheckStatusUnmarshalJSON (line 59) | func TestCheckStatusUnmarshalJSON(t *testing.T) {
FILE: pkg/validator/activation.go
constant ObjectVarName (line 22) | ObjectVarName = "object"
constant ParamsVarName (line 23) | ParamsVarName = "params"
constant PodMetaVarName (line 24) | PodMetaVarName = "podMeta"
constant PodSpecVarName (line 25) | PodSpecVarName = "podSpec"
constant AllContainersVarName (line 26) | AllContainersVarName = "allContainers"
constant APIVersionsVarName (line 27) | APIVersionsVarName = "apiVersions"
constant KubeVersionVarName (line 28) | KubeVersionVarName = "kubeVersion"
constant VariableVarName (line 29) | VariableVarName = "variables"
type activation (line 33) | type activation struct
method ResolveName (line 44) | func (a *activation) ResolveName(name string) (any, bool) {
method Parent (line 67) | func (a *activation) Parent() interpreter.Activation {
FILE: pkg/validator/compiler.go
function Compile (line 73) | func Compile(check types.Check, apiResources []*metav1.APIResourceList, ...
function newEnv (line 99) | func newEnv(check types.Check) (*cel.Env, error) {
function compileVariables (line 113) | func compileVariables(env *cel.Env, vars []types.Variable, costLimit uin...
function compileValidations (line 125) | func compileValidations(env *cel.Env, vals []types.Validation, costLimit...
function compileExpression (line 137) | func compileExpression(env *cel.Env, exp string, costLimit uint64, allow...
FILE: pkg/validator/compiler_test.go
function TestCompile (line 27) | func TestCompile(t *testing.T) {
FILE: pkg/validator/interface.go
type Validator (line 23) | type Validator interface
FILE: pkg/validator/podspec.go
function MatchesPodSpec (line 32) | func MatchesPodSpec(rules []types.ResourceRule) bool {
function HasPodSpec (line 55) | func HasPodSpec(u unstructured.Unstructured) bool {
function ExtractPodSpec (line 62) | func ExtractPodSpec(u unstructured.Unstructured) (*metav1.ObjectMeta, *c...
function extractPodSpecFromTemplate (line 108) | func extractPodSpecFromTemplate(template *corev1.PodTemplateSpec) (*meta...
function extractAllContainers (line 115) | func extractAllContainers(podSpec *corev1.PodSpec) []corev1.Container {
FILE: pkg/validator/podspec_test.go
function TestMatchesPodSpec (line 28) | func TestMatchesPodSpec(t *testing.T) {
function TestExtractPodSpec (line 104) | func TestExtractPodSpec(t *testing.T) {
function TestExtractAllContainers (line 237) | func TestExtractAllContainers(t *testing.T) {
FILE: pkg/validator/validator.go
type CELValidator (line 31) | type CELValidator struct
method SetAPIVersions (line 44) | func (r *CELValidator) SetAPIVersions(apiVersions []string) {
method SetKubeVersion (line 48) | func (r *CELValidator) SetKubeVersion(v *version.Info) {
method Validate (line 52) | func (r *CELValidator) Validate(obj unstructured.Unstructured, params ...
method setPodSpecParams (line 87) | func (r *CELValidator) setPodSpecParams(obj unstructured.Unstructured,...
type compiledVariable (line 39) | type compiledVariable struct
function callback (line 77) | func callback(v compiledVariable, activation any) lazy.GetFieldFunc {
FILE: pkg/version/version.go
type Info (line 27) | type Info struct
method String (line 35) | func (i Info) String() string {
function Get (line 39) | func Get() Info {
FILE: pkg/version/version_test.go
function TestGet (line 22) | func TestGet(t *testing.T) {
FILE: test/builtins_test.go
function TestBuiltinChecks (line 28) | func TestBuiltinChecks(t *testing.T) {
function parse (line 59) | func parse(i string) (unstructured.Unstructured, error) {
Condensed preview — 128 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (360K chars).
[
{
"path": ".github/dependabot.yml",
"chars": 195,
"preview": "version: 2\nupdates:\n - package-ecosystem: github-actions\n directory: /\n schedule:\n interval: weekly\n - pack"
},
{
"path": ".github/workflows/release.yml",
"chars": 2224,
"preview": "name: release\n\non:\n push:\n tags:\n - 'v*'\n\npermissions:\n contents: write\n packages: write\n\njobs:\n release:\n "
},
{
"path": ".github/workflows/test.yml",
"chars": 480,
"preview": "name: test\non:\n pull_request:\n branches: [main]\n push:\n branches: [main]\njobs:\n validate:\n runs-on: ubuntu-l"
},
{
"path": ".gitignore",
"chars": 287,
"preview": "# Binaries for programs and plugins\n*.exe\n*.exe~\n*.dll\n*.so\n*.dylib\nbin\n\n# Test binary, built with `go test -c`\n*.test\n\n"
},
{
"path": ".goreleaser.yaml",
"chars": 932,
"preview": "version: 2\nbefore:\n hooks:\n - go mod tidy\nbuilds:\n - env:\n - CGO_ENABLED=0\n goos:\n - linux\n - win"
},
{
"path": ".krew.yaml",
"chars": 1356,
"preview": "apiVersion: krew.googlecontainertools.github.com/v1alpha2\nkind: Plugin\nmetadata:\n name: marvin\nspec:\n homepage: https:"
},
{
"path": "CODE_OF_CONDUCT.md",
"chars": 5218,
"preview": "# Contributor Covenant Code of Conduct\n\n## Our Pledge\n\nWe as members, contributors, and leaders pledge to make participa"
},
{
"path": "CONTRIBUTING.md",
"chars": 1109,
"preview": "# Contributing to Marvin\n\n:+1::tada: Thanks for taking the time to contribute! :tada::+1:\n\nThe following is a set of gui"
},
{
"path": "Dockerfile",
"chars": 1384,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "LICENSE",
"chars": 11358,
"preview": "\n Apache License\n Version 2.0, January 2004\n "
},
{
"path": "MAINTAINERS.md",
"chars": 904,
"preview": "# Maintainers\n\nMaintainers are approvers who have shown good technical judgement in guiding feature design & development"
},
{
"path": "Makefile",
"chars": 2674,
"preview": "# Image URL to use all building/pushing image targets\nTAG ?= latest\nIMG ?= ghcr.io/undistro/marvin:${TAG}\n\n# Setting SHE"
},
{
"path": "README.md",
"chars": 11488,
"preview": "<div align=\"center\">\n\n<picture>\n <source media=\"(prefers-color-scheme: dark)\" srcset=\"assets/banner-dark.png\">\n <img a"
},
{
"path": "checks.md",
"chars": 7624,
"preview": "# Checks Overview \n\nIn the table below, you can view all checks present on Marvin. Click on the #ID column item for mor"
},
{
"path": "cmd/root.go",
"chars": 1904,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "cmd/scan.go",
"chars": 1929,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "cmd/version.go",
"chars": 1482,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "examples/labels.yml",
"chars": 943,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "examples/replicas.yml",
"chars": 838,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "go.mod",
"chars": 4085,
"preview": "module github.com/undistro/marvin\n\ngo 1.25.4\n\nrequire (\n\tgithub.com/Masterminds/semver/v3 v3.4.0\n\tgithub.com/fatih/color"
},
{
"path": "go.sum",
"chars": 23118,
"preview": "cel.dev/expr v0.24.0 h1:56OvJKSH3hDGL0ml5uSxZmz3/3Pq4tJ+fb1unVLAFcY=\ncel.dev/expr v0.24.0/go.mod h1:hLPLo1W4QUmuYdA72RBX"
},
{
"path": "install.sh",
"chars": 9552,
"preview": "#!/bin/sh\n\nset -e\n# Code generated by godownloader on 2023-02-28T17:14:26Z. DO NOT EDIT.\n#\n\nusage() {\n this=$1\n cat <<"
},
{
"path": "internal/builtins/cis/M-500_workload_in_default_namespace.yaml",
"chars": 1225,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/cis/M-500_workload_in_default_namespace_test.yaml",
"chars": 1844,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/embed.go",
"chars": 673,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "internal/builtins/embed_test.go",
"chars": 817,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "internal/builtins/general/M-400_image_tagged_latest.yaml",
"chars": 1414,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/general/M-400_image_tagged_latest_test.yaml",
"chars": 2703,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/general/M-401_unmanaged_pod.yaml",
"chars": 944,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/general/M-401_unmanaged_pod_test.yaml",
"chars": 2237,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/general/M-402_readiness_probe.yaml",
"chars": 1417,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/general/M-402_readiness_probe_test.yaml",
"chars": 3991,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/general/M-403_liveness_probe.yaml",
"chars": 1379,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/general/M-403_liveness_probe_test.yaml",
"chars": 2812,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/general/M-404_memory_requests.yaml",
"chars": 1230,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/general/M-404_memory_requests_test.yaml",
"chars": 1707,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/general/M-405_cpu_requests.yaml",
"chars": 1221,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/general/M-405_cpu_requests_test.yaml",
"chars": 1708,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/general/M-406_memory_limit.yaml",
"chars": 1214,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/general/M-406_memory_limit_test.yaml",
"chars": 1679,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/general/M-407_cpu_limit.yaml",
"chars": 1205,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/general/M-407_cpu_limit_test.yaml",
"chars": 1671,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/general/M-408_sudo_container_entrypoint.yaml",
"chars": 1260,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/general/M-408_sudo_container_entrypoint_test.yaml",
"chars": 1471,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/general/M-409_deprecated_image_registry.yaml",
"chars": 1219,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/general/M-409_deprecated_image_registry_test.yaml",
"chars": 2277,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/general/M-410_resource_using_invalid_restartpolicy.yaml",
"chars": 988,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/general/M-410_resource_using_invalid_restartpolicy_test.yaml",
"chars": 1462,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/general/M-411_role_binding_referencing_anonymous_or_unauthenticated.yaml",
"chars": 1206,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/general/M-411_role_binding_referencing_anonymous_or_unauthenticated_test.yaml",
"chars": 3248,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/mitre/M-200_allowed_registries.yml",
"chars": 1565,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/mitre/M-200_allowed_registries_test.yml",
"chars": 3311,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/mitre/M-201_app_credentials.yml",
"chars": 2545,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/mitre/M-201_app_credentials_test.yml",
"chars": 4019,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/mitre/M-202_auto_mount_service_account_token.yml",
"chars": 1306,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/mitre/M-202_auto_mount_service_account_token_test.yml",
"chars": 2029,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/mitre/M-203_ssh_server.yml",
"chars": 1744,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/mitre/M-203_ssh_server_test.yml",
"chars": 3822,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/nsa/M-300_read_only_root_filesystem.yml",
"chars": 1319,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/nsa/M-300_read_only_root_filesystem_test.yml",
"chars": 2641,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/baseline/M-100_host_process.yml",
"chars": 1837,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/baseline/M-100_host_process_test.yml",
"chars": 3933,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/baseline/M-101_host_namespaces.yml",
"chars": 1671,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/baseline/M-101_host_namespaces_test.yml",
"chars": 3400,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/baseline/M-102_privileged_containers.yml",
"chars": 1616,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/baseline/M-102_privileged_containers_test.yml",
"chars": 2742,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/baseline/M-103_capabilities_baseline.yml",
"chars": 1912,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/baseline/M-103_capabilities_baseline_test.yml",
"chars": 3736,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/baseline/M-104_host_path_volumes.yml",
"chars": 1586,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/baseline/M-104_host_path_volumes_test.yml",
"chars": 2524,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/baseline/M-105_host_ports.yml",
"chars": 1670,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/baseline/M-105_host_ports_test.yml",
"chars": 2462,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/baseline/M-106_apparmor.yml",
"chars": 1960,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/baseline/M-106_apparmor_test.yml",
"chars": 3008,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/baseline/M-107_selinux.yml",
"chars": 2501,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/baseline/M-107_selinux_test.yml",
"chars": 6561,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/baseline/M-108_proc_mount.yml",
"chars": 1622,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/baseline/M-108_proc_mount_test.yml",
"chars": 2924,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/baseline/M-109_seccomp_baseline.yml",
"chars": 1813,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/baseline/M-109_seccomp_baseline_test.yml",
"chars": 3735,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/baseline/M-110_sysctls.yml",
"chars": 1920,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/baseline/M-110_sysctls_test.yml",
"chars": 3111,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/restricted/M-111_volume_types.yml",
"chars": 1896,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/restricted/M-111_volume_types_test.yml",
"chars": 2391,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/restricted/M-112_privilege_escalation.yml",
"chars": 1729,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/restricted/M-112_privilege_escalation_test.yml",
"chars": 2462,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/restricted/M-113_run_as_non_root.yml",
"chars": 2787,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/restricted/M-113_run_as_non_root_test.yml",
"chars": 4065,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/restricted/M-114_run_as_user.yml",
"chars": 1664,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/restricted/M-114_run_as_user_test.yml",
"chars": 3096,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/restricted/M-115_seccomp_restricted.yml",
"chars": 2672,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/restricted/M-115_seccomp_restricted_test.yml",
"chars": 3870,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/restricted/M-116_capabilities_restricted.yml",
"chars": 2075,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "internal/builtins/pss/restricted/M-116_capabilities_restricted_test.yml",
"chars": 4114,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "main.go",
"chars": 680,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/cmd/scan.go",
"chars": 9717,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/loader/builtin.go",
"chars": 994,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/loader/builtin_test.go",
"chars": 809,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/loader/loader.go",
"chars": 3213,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/loader/loader_test.go",
"chars": 3592,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/loader/testdata/checks/svc_lb.json",
"chars": 403,
"preview": "{\n \"id\": \"TEST-002\",\n \"message\": \"Type Loadbalancer detected. Could be expensive\",\n \"severity\": \"Low\",\n \"match\": {\n "
},
{
"path": "pkg/loader/testdata/checks/workloads/replicas.yaml",
"chars": 865,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "pkg/loader/testdata/checks/workloads/replicas_test.yaml",
"chars": 1880,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "pkg/loader/testdata/checks/workloads/unsupported.txt",
"chars": 21,
"preview": "unsupported file type"
},
{
"path": "pkg/loader/testdata/invalid/invalid.yml",
"chars": 593,
"preview": "# Copyright 2023 Undistro Authors\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use "
},
{
"path": "pkg/printers/interface.go",
"chars": 826,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/printers/json.go",
"chars": 993,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/printers/md.go",
"chars": 1192,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/printers/table.go",
"chars": 3158,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/printers/yaml.go",
"chars": 991,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/types/check.go",
"chars": 2093,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/types/check_test.go",
"chars": 1617,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/types/report.go",
"chars": 3701,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/types/report_test.go",
"chars": 3258,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/types/severity.go",
"chars": 1470,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/types/severity_test.go",
"chars": 2259,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/types/status.go",
"chars": 1471,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/types/status_test.go",
"chars": 2006,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/validator/activation.go",
"chars": 1828,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/validator/compiler.go",
"chars": 5063,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/validator/compiler_test.go",
"chars": 2914,
"preview": "// Copyright 2024 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/validator/interface.go",
"chars": 981,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/validator/podspec.go",
"chars": 5709,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/validator/podspec_test.go",
"chars": 6742,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/validator/validator.go",
"chars": 3428,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/version/version.go",
"chars": 1150,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "pkg/version/version_test.go",
"chars": 2091,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
},
{
"path": "test/builtins_test.go",
"chars": 1899,
"preview": "// Copyright 2023 Undistro Authors\n//\n// Licensed under the Apache License, Version 2.0 (the \"License\");\n// you may not "
}
]
About this extraction
This page contains the full source code of the undistro/marvin GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 128 files (324.5 KB), approximately 93.9k tokens, and a symbol index with 138 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.