├── .codebeatsettings
├── .dockerignore
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── dependabot.yml
└── workflows
│ ├── krew.yml
│ ├── lint.yml
│ └── test.yml
├── .gitignore
├── .golangci.yml
├── .goreleaser.yml
├── .krew.yaml
├── .travis.yml
├── CNAME
├── Dockerfile
├── LICENSE
├── Makefile
├── README.md
├── assets
├── imhotep_logo.png
├── popeye.png
├── popeye_bug.png
├── popeye_feature.png
├── popeye_logo.png
└── screens
│ ├── console.png
│ ├── html.png
│ ├── json.png
│ ├── pop-dash.png
│ ├── score-a.png
│ └── score-d.png
├── change_logs
├── release_v0.1.0.md
├── release_v0.1.1.md
├── release_v0.1.2.md
├── release_v0.1.3.md
├── release_v0.1.4.md
├── release_v0.10.0.md
├── release_v0.10.1.md
├── release_v0.11.0.md
├── release_v0.11.1.md
├── release_v0.11.2.md
├── release_v0.11.3.md
├── release_v0.12.0.md
├── release_v0.2.0.md
├── release_v0.20.0.md
├── release_v0.20.1.md
├── release_v0.20.2.md
├── release_v0.20.3.md
├── release_v0.20.4.md
├── release_v0.20.5.md
├── release_v0.21.0.md
├── release_v0.21.1.md
├── release_v0.21.2.md
├── release_v0.21.3.md
├── release_v0.21.4.md
├── release_v0.21.5.md
├── release_v0.21.6.md
├── release_v0.21.7.md
├── release_v0.22.0.md
├── release_v0.22.1.md
├── release_v0.3.0.md
├── release_v0.3.1.md
├── release_v0.3.10.md
├── release_v0.3.11.md
├── release_v0.3.12.md
├── release_v0.3.13.md
├── release_v0.3.2.md
├── release_v0.3.3.md
├── release_v0.3.4.md
├── release_v0.3.5.md
├── release_v0.3.6.md
├── release_v0.3.7.md
├── release_v0.3.8.md
├── release_v0.3.9.md
├── release_v0.4.0.md
├── release_v0.4.1.md
├── release_v0.4.2.md
├── release_v0.4.3.md
├── release_v0.5.0.md
├── release_v0.6.0.md
├── release_v0.6.1.md
├── release_v0.6.2.md
├── release_v0.7.0.md
├── release_v0.7.1.md
├── release_v0.8.0.md
├── release_v0.8.1.md
├── release_v0.8.10.md
├── release_v0.8.2.md
├── release_v0.8.3.md
├── release_v0.8.4.md
├── release_v0.8.5.md
├── release_v0.8.6.md
├── release_v0.8.7.md
├── release_v0.8.8.md
├── release_v0.8.9.md
├── release_v0.9.0.md
├── release_v0.9.1.md
├── release_v0.9.2.md
├── release_v0.9.3.md
├── release_v0.9.4.md
├── release_v0.9.5.md
├── release_v0.9.6.md
├── release_v0.9.7.md
└── release_v0.9.8.md
├── cmd
├── info.go
├── root.go
└── version.go
├── docs
└── codes.md
├── go.mod
├── go.sum
├── grafana
└── popeye-dashboard.json
├── internal
├── alias.go
├── cache
│ ├── cluster.go
│ ├── cluster_test.go
│ ├── cr.go
│ ├── cr_test.go
│ ├── crb.go
│ ├── crb_test.go
│ ├── helper.go
│ ├── helper_test.go
│ ├── ing.go
│ ├── ing_test.go
│ ├── no_mx.go
│ ├── no_mx_test.go
│ ├── pod.go
│ ├── pod_test.go
│ ├── rb.go
│ ├── rb_test.go
│ ├── sa.go
│ ├── sa_test.go
│ ├── testdata
│ │ ├── auth
│ │ │ ├── cr
│ │ │ │ └── 1.yaml
│ │ │ ├── crb
│ │ │ │ └── 1.yaml
│ │ │ └── rob
│ │ │ │ └── 1.yaml
│ │ ├── core
│ │ │ ├── node
│ │ │ │ └── 1.yaml
│ │ │ ├── pod
│ │ │ │ ├── 1.yaml
│ │ │ │ └── 2.yaml
│ │ │ └── sa
│ │ │ │ └── 1.yaml
│ │ ├── mx
│ │ │ └── node
│ │ │ │ └── 1.yaml
│ │ └── net
│ │ │ └── ingress
│ │ │ └── 1.yaml
│ └── types.go
├── cilium
│ ├── cache
│ │ └── cep.go
│ ├── cilium.go
│ ├── lint
│ │ ├── ccnp.go
│ │ ├── ccnp_test.go
│ │ ├── cep.go
│ │ ├── cep_test.go
│ │ ├── cid.go
│ │ ├── cid_test.go
│ │ ├── cnp.go
│ │ ├── cnp_test.go
│ │ └── testdata
│ │ │ ├── ccnp
│ │ │ └── 1.yaml
│ │ │ ├── cep
│ │ │ └── 1.yaml
│ │ │ ├── cid
│ │ │ └── 1.yaml
│ │ │ └── cnp
│ │ │ └── 1.yaml
│ └── scrub
│ │ ├── ccnp.go
│ │ ├── cep.go
│ │ ├── cid.go
│ │ ├── cnp.go
│ │ └── scrubers.go
├── client
│ ├── client.go
│ ├── client_test.go
│ ├── config.go
│ ├── config_test.go
│ ├── factory.go
│ ├── helper_test.go
│ ├── helpers.go
│ ├── metrics.go
│ ├── metrics_test.go
│ ├── revision.go
│ ├── revision_test.go
│ ├── testdata
│ │ ├── config
│ │ └── config.1
│ └── types.go
├── context.go
├── dag
│ ├── cluster.go
│ ├── helper_test.go
│ └── helpers.go
├── dao
│ ├── ev.go
│ ├── generic.go
│ ├── non_resource.go
│ ├── resource.go
│ ├── table.go
│ └── types.go
├── db
│ ├── db.go
│ ├── loader.go
│ ├── schema
│ │ ├── indexer.go
│ │ └── k8s.go
│ └── types.go
├── glossary.go
├── issues
│ ├── assets
│ │ └── codes.yaml
│ ├── codes.go
│ ├── codes_test.go
│ ├── collector.go
│ ├── collector_test.go
│ ├── issue.go
│ ├── issue_test.go
│ ├── issues.go
│ ├── issues_test.go
│ └── tally
│ │ ├── code.go
│ │ ├── code_test.go
│ │ ├── linter.go
│ │ ├── linter_test.go
│ │ ├── ns.go
│ │ └── ns_test.go
├── keys.go
├── lint
│ ├── cluster.go
│ ├── cluster_test.go
│ ├── cm.go
│ ├── cm_test.go
│ ├── container.go
│ ├── container_bench_test.go
│ ├── container_status.go
│ ├── container_status_test.go
│ ├── container_test.go
│ ├── cr.go
│ ├── cr_test.go
│ ├── crb.go
│ ├── crb_test.go
│ ├── cronjob.go
│ ├── cronjob_test.go
│ ├── dp.go
│ ├── dp_test.go
│ ├── ds.go
│ ├── ds_test.go
│ ├── gw.go
│ ├── gw_test.go
│ ├── gwc.go
│ ├── gwc_test.go
│ ├── gwr.go
│ ├── gwr_test.go
│ ├── helper.go
│ ├── helper_test.go
│ ├── hpa.go
│ ├── hpa_test.go
│ ├── ing.go
│ ├── ing_test.go
│ ├── job.go
│ ├── job_test.go
│ ├── metrics_helpers.go
│ ├── metrics_helpers_test.go
│ ├── node.go
│ ├── node_bench_test.go
│ ├── node_test.go
│ ├── np.go
│ ├── np_helpers.go
│ ├── np_test.go
│ ├── ns.go
│ ├── ns_test.go
│ ├── pdb.go
│ ├── pdb_test.go
│ ├── pod.go
│ ├── pod_test.go
│ ├── pv.go
│ ├── pv_test.go
│ ├── pvc.go
│ ├── pvc_test.go
│ ├── rb.go
│ ├── rb_test.go
│ ├── ro.go
│ ├── ro_test.go
│ ├── rs.go
│ ├── rs_test.go
│ ├── sa.go
│ ├── sa_test.go
│ ├── sec.go
│ ├── sec_test.go
│ ├── sts.go
│ ├── sts_test.go
│ ├── svc.go
│ ├── svc_test.go
│ ├── testdata
│ │ ├── apps
│ │ │ ├── dp
│ │ │ │ └── 1.yaml
│ │ │ ├── ds
│ │ │ │ └── 1.yaml
│ │ │ ├── rs
│ │ │ │ └── 1.yaml
│ │ │ └── sts
│ │ │ │ └── 1.yaml
│ │ ├── auth
│ │ │ ├── cr
│ │ │ │ ├── 1.yaml
│ │ │ │ └── 2.yaml
│ │ │ ├── crb
│ │ │ │ ├── 1.yaml
│ │ │ │ └── 2.yaml
│ │ │ ├── ro
│ │ │ │ └── 1.yaml
│ │ │ └── rob
│ │ │ │ ├── 1.yaml
│ │ │ │ └── 2.yaml
│ │ ├── autoscaling
│ │ │ └── hpa
│ │ │ │ └── 1.yaml
│ │ ├── batch
│ │ │ ├── cjob
│ │ │ │ └── 1.yaml
│ │ │ └── job
│ │ │ │ └── 1.yaml
│ │ ├── config
│ │ │ └── 1.yaml
│ │ ├── core
│ │ │ ├── cm
│ │ │ │ └── 1.yaml
│ │ │ ├── ep
│ │ │ │ └── 1.yaml
│ │ │ ├── node
│ │ │ │ └── 1.yaml
│ │ │ ├── ns
│ │ │ │ └── 1.yaml
│ │ │ ├── pod
│ │ │ │ ├── 1.yaml
│ │ │ │ ├── 2.yaml
│ │ │ │ ├── 3.yaml
│ │ │ │ └── 4.yaml
│ │ │ ├── pv
│ │ │ │ └── 1.yaml
│ │ │ ├── pvc
│ │ │ │ └── 1.yaml
│ │ │ ├── sa
│ │ │ │ ├── 1.yaml
│ │ │ │ └── 2.yaml
│ │ │ ├── secret
│ │ │ │ └── 1.yaml
│ │ │ └── svc
│ │ │ │ ├── 1.yaml
│ │ │ │ └── 2.yaml
│ │ ├── mx
│ │ │ ├── node
│ │ │ │ └── 1.yaml
│ │ │ └── pod
│ │ │ │ └── 1.yaml
│ │ ├── net
│ │ │ ├── gw
│ │ │ │ └── 1.yaml
│ │ │ ├── gwc
│ │ │ │ └── 1.yaml
│ │ │ ├── gwr
│ │ │ │ └── 1.yaml
│ │ │ ├── ingress
│ │ │ │ └── 1.yaml
│ │ │ └── np
│ │ │ │ ├── 1.yaml
│ │ │ │ ├── 2.yaml
│ │ │ │ ├── 3.yaml
│ │ │ │ ├── a.yaml
│ │ │ │ ├── allow-all-egr.yaml
│ │ │ │ ├── allow-all-ing.yaml
│ │ │ │ ├── b.yaml
│ │ │ │ ├── blee.yml
│ │ │ │ ├── c.yaml
│ │ │ │ ├── d.yaml
│ │ │ │ ├── deny-all-egr.yaml
│ │ │ │ ├── deny-all-ing.yaml
│ │ │ │ └── deny-all.yaml
│ │ └── pol
│ │ │ └── pdb
│ │ │ └── 1.yaml
│ └── types.go
├── report
│ ├── assets
│ │ └── report.html
│ ├── builder.go
│ ├── builder_test.go
│ ├── color.go
│ ├── color_test.go
│ ├── delta_score.go
│ ├── delta_score_test.go
│ ├── emoji.go
│ ├── emoji_test.go
│ ├── grade.go
│ ├── grade_test.go
│ ├── junit.go
│ ├── logo.go
│ ├── prometheus.go
│ ├── report.go
│ ├── tally.go
│ ├── tally_test.go
│ ├── test_assets
│ │ ├── empty.yml
│ │ ├── r1.yml
│ │ └── r2.yml
│ ├── types.go
│ ├── writer.go
│ └── writer_test.go
├── rules
│ ├── code.go
│ ├── code_test.go
│ ├── exclude.go
│ ├── exclude_test.go
│ ├── exclusions.go
│ ├── expression.go
│ ├── expression_test.go
│ ├── helpers.go
│ ├── helpers_int_test.go
│ ├── keyvals.go
│ ├── level.go
│ ├── level_test.go
│ ├── linters.go
│ ├── linters_test.go
│ ├── spec.go
│ └── types.go
├── scrub
│ ├── cache.go
│ ├── cjob.go
│ ├── cluster.go
│ ├── cm.go
│ ├── cr.go
│ ├── crb.go
│ ├── dp.go
│ ├── ds.go
│ ├── gw-route.go
│ ├── gw.go
│ ├── gwc.go
│ ├── hpa.go
│ ├── ing.go
│ ├── job.go
│ ├── no.go
│ ├── np.go
│ ├── ns.go
│ ├── pdb.go
│ ├── pod.go
│ ├── preload.go
│ ├── pv.go
│ ├── pvc.go
│ ├── rb.go
│ ├── ro.go
│ ├── rs.go
│ ├── sa.go
│ ├── sec.go
│ ├── sts.go
│ ├── svc.go
│ └── types.go
├── stringset.go
├── stringset_test.go
├── test
│ └── helpers.go
└── types.go
├── k8s
└── popeye
│ ├── cm.yml
│ ├── cronjob.yml
│ ├── ns.yml
│ └── rbac.yml
├── main.go
├── pkg
├── config
│ ├── config.go
│ ├── config_test.go
│ ├── flags.go
│ ├── flags_test.go
│ ├── helpers.go
│ ├── helpers_test.go
│ ├── json
│ │ ├── schemas
│ │ │ └── spinach.json
│ │ ├── testdata
│ │ │ ├── 1.yaml
│ │ │ └── toast.yaml
│ │ ├── validator.go
│ │ └── validator_test.go
│ ├── no.go
│ ├── po.go
│ ├── popeye.go
│ ├── popeye_test.go
│ ├── prom.go
│ ├── s3.go
│ ├── s3_test.go
│ ├── testdata
│ │ ├── sp-toast.yml
│ │ ├── sp1.yml
│ │ ├── sp2.yml
│ │ └── sp3.yml
│ └── types.go
├── helpers.go
└── popeye.go
├── spinach-examples
├── spinach_aks.yml
└── spinach_eks.yml
└── types
├── gvr.go
├── gvr_test.go
└── types.go
/.codebeatsettings:
--------------------------------------------------------------------------------
1 | {
2 | "GOLANG": {
3 | "TOO_MANY_IVARS": [
4 | 15,
5 | 18,
6 | 20,
7 | 22
8 | ],
9 | "LOC": [
10 | 45,
11 | 55,
12 | 90,
13 | 110
14 | ],
15 | "TOTAL_LOC": [
16 | 300,
17 | 500,
18 | 600,
19 | 700
20 | ],
21 | "TOO_MANY_FUNCTIONS": [
22 | 30,
23 | 40,
24 | 45,
25 | 46
26 | ]
27 | }
28 | }
--------------------------------------------------------------------------------
/.dockerignore:
--------------------------------------------------------------------------------
1 | .git
2 | README.md
3 | /execs
4 | *_test.go
5 | *.yml
6 | /krew
7 | /notes
8 | /junit
9 | /dist
10 | /change_logs
11 | /assets
12 | /.github
13 | /.idea
14 | /.vscode
15 | /aa_dead
16 | /k8s
17 | /k8s1
--------------------------------------------------------------------------------
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: [derailed]
4 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | **Describe the bug**
19 | A clear and concise description of what the bug is.
20 |
21 | **To Reproduce**
22 | Steps to reproduce the behavior:
23 | 1. Go to '...'
24 | 2. Click on '....'
25 | 3. Scroll down to '....'
26 | 4. See error
27 |
28 | **Expected behavior**
29 | A clear and concise description of what you expected to happen.
30 |
31 | **Screenshots**
32 | If applicable, add screenshots to help explain your problem.
33 |
34 | **Versions (please complete the following information):**
35 | - OS: [e.g. OSX]
36 | - Popeye [e.g. 0.1.0]
37 | - K8s [e.g. 1.11.0]
38 |
39 | **Additional context**
40 | Add any other context about the problem here.
41 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 | **Is your feature request related to a problem? Please describe.**
18 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
19 |
20 | **Describe the solution you'd like**
21 | A clear and concise description of what you want to happen.
22 |
23 | **Describe alternatives you've considered**
24 | A clear and concise description of any alternative solutions or features you've considered.
25 |
26 | **Additional context**
27 | Add any other context or screenshots about the feature request here.
28 |
--------------------------------------------------------------------------------
/.github/dependabot.yml:
--------------------------------------------------------------------------------
1 | ---
2 | version: 2
3 | updates:
4 | - package-ecosystem: "gomod"
5 | directory: "/"
6 | schedule:
7 | interval: "weekly"
8 |
9 | # Maintain dependencies for GitHub Actions
10 | - package-ecosystem: "github-actions"
11 | directory: "/"
12 | schedule:
13 | interval: weekly
14 |
15 | # Maintain dependencies for docker
16 | - package-ecosystem: "docker"
17 | directory: "/"
18 | schedule:
19 | interval: weekly
20 |
--------------------------------------------------------------------------------
/.github/workflows/krew.yml:
--------------------------------------------------------------------------------
1 | name: Krew
2 | on:
3 | release:
4 |
5 | jobs:
6 | krew:
7 | runs-on: ubuntu-latest
8 | steps:
9 | - name: Checkout
10 | uses: actions/checkout@v4.2.2
11 |
12 | - name: Update new version in krew-index
13 | uses: rajatjindal/krew-release-bot@v0.0.47
14 |
--------------------------------------------------------------------------------
/.github/workflows/lint.yml:
--------------------------------------------------------------------------------
1 | name: lint
2 | on:
3 | push:
4 | branches:
5 | - main
6 | pull_request: {}
7 |
8 | permissions: read-all
9 |
10 | jobs:
11 | lint:
12 | name: lint
13 | runs-on: ubuntu-latest
14 | steps:
15 | - name: Checkout Code
16 | uses: actions/checkout@v4.2.2
17 |
18 | - name: Install Go
19 | uses: actions/setup-go@v5.4.0
20 | with:
21 | go-version-file: go.mod
22 | cache-dependency-path: go.sum
23 |
24 | - name: Setup GO env
25 | run: go env -w CGO_ENABLED=0
26 |
27 | - name: golangci-lint
28 | uses: golangci/golangci-lint-action@9665fb5353a2e4cc60d570d956ab6db7d9949f06
29 | with:
30 | version: v1.60.3
31 | args: --config=.golangci.yml --verbose --out-${NO_FUTURE}format colored-line-number
32 | skip-cache: true
--------------------------------------------------------------------------------
/.github/workflows/test.yml:
--------------------------------------------------------------------------------
1 | name: Tests
2 |
3 | on:
4 | workflow_dispatch:
5 | push:
6 | branches:
7 | - master
8 | tags:
9 | - rc*
10 | - v*
11 | pull_request:
12 | branches:
13 | - master
14 | jobs:
15 | tests:
16 | runs-on: ubuntu-latest
17 | steps:
18 | - name: Checkout Code
19 | uses: actions/checkout@v4.2.2
20 |
21 | - name: Install Go
22 | uses: actions/setup-go@v5.4.0
23 | with:
24 | go-version-file: go.mod
25 | cache-dependency-path: go.sum
26 |
27 | - name: Setup GO env
28 | run: go env -w CGO_ENABLED=0
29 |
30 | - name: Run Tests
31 | run: make test
32 | env:
33 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
34 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /k8s/*
2 | !/k8s/popeye/
3 | /k8s1
4 | krew
5 | *.out
6 | /execs
7 | *.test
8 | notes
9 | eugen1
10 | *.txt
11 | /dist
12 | .envrc
13 | gen.sh
14 | aa_dead
15 | popeye
16 | /junit
17 | .vscode
18 | .idea
19 | spinach.yml
20 | /kind
21 | /spinach-me
22 | __debug_bin*
23 | .act-evt
24 | /Dockerfile.cross
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: go
2 | go_import_path: github.com/derailed/popeye
3 | go:
4 | - "1.13"
5 | # - master
6 |
7 | os:
8 | - linux
9 | - osx
10 |
11 | dist: trusty
12 | sudo: false
13 |
14 | install: true
15 |
16 | env:
17 | - GO111MODULE=on
18 |
19 | script:
20 | - go build
21 | - go test ./...
22 |
--------------------------------------------------------------------------------
/CNAME:
--------------------------------------------------------------------------------
1 | popeyecli.io
--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------
1 | # -----------------------------------------------------------------------------
2 | # Build...
3 | FROM golang:1.24.2-alpine3.21 AS build
4 | ARG TARGETOS
5 | ARG TARGETARCH
6 |
7 | WORKDIR /popeye
8 |
9 | COPY go.mod go.sum main.go Makefile ./
10 | COPY internal internal
11 | COPY cmd cmd
12 | COPY types types
13 | COPY pkg pkg
14 | RUN apk --no-cache add make git gcc libc-dev curl ca-certificates binutils-gold && \
15 | CGO_ENABLED=0 GOOS=${TARGETOS:-linux} GOARCH=${TARGETARCH} make build
16 |
17 | # -----------------------------------------------------------------------------
18 | # Image...
19 | FROM alpine:3.21.3
20 |
21 | COPY --from=build /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/ca-certificates.crt
22 | COPY --from=build /popeye/execs/popeye /bin/popeye
23 |
24 | RUN adduser -u 5000 -D nonroot
25 | USER 5000
26 |
27 | ENTRYPOINT [ "/bin/popeye" ]
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright © 2020, Imhotep Software LLC
2 | All rights reserved.
3 |
4 | Licensed under the Apache License, Version 2.0 (the "License");
5 | you may not use this file except in compliance with the License.
6 | You may obtain a copy of the License at
7 |
8 | http://www.apache.org/licenses/LICENSE-2.0
9 |
10 | Unless required by applicable law or agreed to in writing, software
11 | distributed under the License is distributed on an "AS IS" BASIS,
12 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | See the License for the specific language governing permissions and
--------------------------------------------------------------------------------
/assets/imhotep_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derailed/popeye/5d07838165bb64fa70c594f2b46ef14a9080782f/assets/imhotep_logo.png
--------------------------------------------------------------------------------
/assets/popeye.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derailed/popeye/5d07838165bb64fa70c594f2b46ef14a9080782f/assets/popeye.png
--------------------------------------------------------------------------------
/assets/popeye_bug.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derailed/popeye/5d07838165bb64fa70c594f2b46ef14a9080782f/assets/popeye_bug.png
--------------------------------------------------------------------------------
/assets/popeye_feature.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derailed/popeye/5d07838165bb64fa70c594f2b46ef14a9080782f/assets/popeye_feature.png
--------------------------------------------------------------------------------
/assets/popeye_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derailed/popeye/5d07838165bb64fa70c594f2b46ef14a9080782f/assets/popeye_logo.png
--------------------------------------------------------------------------------
/assets/screens/console.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derailed/popeye/5d07838165bb64fa70c594f2b46ef14a9080782f/assets/screens/console.png
--------------------------------------------------------------------------------
/assets/screens/html.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derailed/popeye/5d07838165bb64fa70c594f2b46ef14a9080782f/assets/screens/html.png
--------------------------------------------------------------------------------
/assets/screens/json.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derailed/popeye/5d07838165bb64fa70c594f2b46ef14a9080782f/assets/screens/json.png
--------------------------------------------------------------------------------
/assets/screens/pop-dash.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derailed/popeye/5d07838165bb64fa70c594f2b46ef14a9080782f/assets/screens/pop-dash.png
--------------------------------------------------------------------------------
/assets/screens/score-a.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derailed/popeye/5d07838165bb64fa70c594f2b46ef14a9080782f/assets/screens/score-a.png
--------------------------------------------------------------------------------
/assets/screens/score-d.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derailed/popeye/5d07838165bb64fa70c594f2b46ef14a9080782f/assets/screens/score-d.png
--------------------------------------------------------------------------------
/change_logs/release_v0.1.0.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.1.0
4 |
5 | ## Notes
6 |
7 | Thank you so much for your support and suggestions to make Popeye better!!
8 |
9 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
10 |
11 | ---
12 |
13 | ## Change Logs
14 |
15 |
16 | ### Initial Release
17 |
18 | Popeye is now in town! What's your cluster score?
19 |
20 | ---
21 |
22 | ## Resolved Bugs
23 |
24 |
25 | ---
26 |
27 |
© 2019 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
28 |
--------------------------------------------------------------------------------
/change_logs/release_v0.1.1.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.1.1
4 |
5 | ## Notes
6 |
7 | Thank you so much for your support and suggestions to make Popeye better!!
8 |
9 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
10 |
11 | ---
12 |
13 | ## Change Logs
14 |
15 |
16 | ### Initial Release
17 |
18 | Popeye is now in town! What's your cluster score?
19 |
20 | ---
21 |
22 | ## Resolved Bugs
23 |
24 | + Ensure nodes can see all pods in the cluster.
25 |
26 | ---
27 |
28 |
© 2019 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
29 |
--------------------------------------------------------------------------------
/change_logs/release_v0.1.2.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.1.2
4 |
5 | ## Notes
6 |
7 | Thank you so much for your support and suggestions to make Popeye better!!
8 |
9 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
10 |
11 | ---
12 |
13 | ## Change Logs
14 |
15 | ### ServiceAccount
16 |
17 | Added preliminary support for ServiceAcount checks. Popeye will scan ClusterRoleBinding and RoleBinding and
18 | report any ServiceAccount that are not actually used by any pods on the cluster.
19 |
20 | ---
21 |
22 | ## Resolved Bugs
23 |
24 |
25 | ---
26 |
27 |
© 2019 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
28 |
--------------------------------------------------------------------------------
/change_logs/release_v0.1.3.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.1.3
4 |
5 | ## Notes
6 |
7 | Thank you so much for your support and suggestions to make Popeye better!!
8 |
9 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
10 |
11 | ---
12 |
13 | ## Change Logs
14 |
15 | ---
16 |
17 | ## Resolved Bugs
18 |
19 | + [Issue #2](https://github.com/derailed/popeye/issues/2)
20 |
21 | ---
22 |
23 |
© 2019 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
24 |
--------------------------------------------------------------------------------
/change_logs/release_v0.1.4.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.1.4
4 |
5 | ## Notes
6 |
7 | Thank you so much for your support and suggestions to make Popeye better!!
8 |
9 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
10 |
11 | ---
12 |
13 | ## Change Logs
14 |
15 | ---
16 |
17 | ## Resolved Bugs
18 |
19 | + [Issue #4](https://github.com/derailed/popeye/issues/4)
20 |
21 | ---
22 |
23 |
© 2019 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
24 |
--------------------------------------------------------------------------------
/change_logs/release_v0.10.1.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.10.1
4 |
5 | ## Notes
6 |
7 | Thank you to all that contributed with flushing out issues and enhancements for Popeye! I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev and see if we're happier with some of the fixes! If you've filed an issue please help me verify and close. Your support, kindness and awesome suggestions to make Popeye better is as ever very much noticed and appreciated!
8 |
9 | This project offers a GitHub Sponsor button (over here 👆). As you well know this is not pimped out by big corps with deep pockets. If you feel `Popeye` is saving you cycles diagnosing potential cluster issues please consider sponsoring this project!! It does go a long way in keeping our servers lights on and beers in our fridge.
10 |
11 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
12 |
13 | ---
14 |
15 | ## Maintenance Release!
16 |
17 | Fix issue with pod disruption budget appearing twice
18 |
19 | ---
20 |
21 |
© 2022 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
22 |
--------------------------------------------------------------------------------
/change_logs/release_v0.11.3.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.11.3
4 |
5 | ## Notes
6 |
7 | Thank you to all that contributed with flushing out issues and enhancements for Popeye! I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev and see if we're happier with some of the fixes! If you've filed an issue please help me verify and close. Your support, kindness and awesome suggestions to make Popeye better is as ever very much noticed and appreciated!
8 |
9 | This project offers a GitHub Sponsor button (over here 👆). As you well know this is not pimped out by big corps with deep pockets. If you feel `Popeye` is saving you cycles diagnosing potential cluster issues please consider sponsoring this project!! It does go a long way in keeping our servers lights on and beers in our fridge.
10 |
11 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
12 |
13 | ---
14 |
15 | ## Maintenance Release!
16 |
17 | Fix docker build issues
18 |
19 | ---
20 |
21 |
© 2023 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
22 |
--------------------------------------------------------------------------------
/change_logs/release_v0.20.1.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.20.1
4 |
5 | ## Notes
6 |
7 | Thank you to all that contributed with flushing out issues and enhancements for Popeye! I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev and see if we're happier with some of the fixes! If you've filed an issue please help me verify and close. Your support, kindness and awesome suggestions to make Popeye better is as ever very much noticed and appreciated!
8 |
9 | This project offers a GitHub Sponsor button (over here 👆). As you well know this is not pimped out by big corps with deep pockets. If you feel `Popeye` is saving you cycles diagnosing potential cluster issues please consider sponsoring this project!! It does go a long way in keeping our servers lights on and beers in our fridge.
10 |
11 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
12 |
13 | ---
14 |
15 | ## Patch Release
16 |
17 | ---
18 |
19 |
© 2024 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
20 |
--------------------------------------------------------------------------------
/change_logs/release_v0.20.2.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.20.2
4 |
5 | ## Notes
6 |
7 | Thank you to all that contributed with flushing out issues and enhancements for Popeye! I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev and see if we're happier with some of the fixes! If you've filed an issue please help me verify and close. Your support, kindness and awesome suggestions to make Popeye better is as ever very much noticed and appreciated!
8 |
9 | This project offers a GitHub Sponsor button (over here 👆). As you well know this is not pimped out by big corps with deep pockets. If you feel `Popeye` is saving you cycles diagnosing potential cluster issues please consider sponsoring this project!! It does go a long way in keeping our servers lights on and beers in our fridge.
10 |
11 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
12 |
13 | ---
14 |
15 | ## Maintenance Release
16 |
17 | ---
18 |
19 | ## Resolved Issues
20 |
21 | . [#280](https://github.com/derailed/popeye/issues/280) No RunInfo in context
22 |
23 | ---
24 |
25 |
© 2024 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
26 |
--------------------------------------------------------------------------------
/change_logs/release_v0.20.3.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.20.3
4 |
5 | ## Notes
6 |
7 | Thank you to all that contributed with flushing out issues and enhancements for Popeye! I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev and see if we're happier with some of the fixes! If you've filed an issue please help me verify and close. Your support, kindness and awesome suggestions to make Popeye better is as ever very much noticed and appreciated!
8 |
9 | This project offers a GitHub Sponsor button (over here 👆). As you well know this is not pimped out by big corps with deep pockets. If you feel `Popeye` is saving you cycles diagnosing potential cluster issues please consider sponsoring this project!! It does go a long way in keeping our servers lights on and beers in our fridge.
10 |
11 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
12 |
13 | ---
14 |
15 | ## Maintenance Release
16 |
17 | ---
18 |
19 | ## Resolved Issues
20 |
21 | . [#284](https://github.com/derailed/popeye/issues/284) Db get failed for ""
22 |
23 | ---
24 |
25 |
© 2024 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
26 |
--------------------------------------------------------------------------------
/change_logs/release_v0.22.0.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.22.0
4 |
5 | ## Notes
6 |
7 | Thank you to all that contributed with flushing out issues and enhancements for Popeye! I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev and see if we're happier with some of the fixes! If you've filed an issue please help me verify and close. Your support, kindness and awesome suggestions to make Popeye better is as ever very much noticed and appreciated!
8 |
9 | This project offers a GitHub Sponsor button (over here 👆). As you well know this is not pimped out by big corps with deep pockets. If you feel `Popeye` is saving you cycles diagnosing potential cluster issues please consider sponsoring this project!! It does go a long way in keeping our servers lights on and beers in our fridge.
10 |
11 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
12 |
13 | ---
14 |
15 | ## Feature Release
16 |
17 | * Update AWS S3 SDK to V2
18 | * Add support for Minio object storage
19 |
20 | ---
21 |
22 |
© 2025 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
23 |
--------------------------------------------------------------------------------
/change_logs/release_v0.22.1.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.22.1
4 |
5 | ## Notes
6 |
7 | Thank you to all that contributed with flushing out issues and enhancements for Popeye! I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev and see if we're happier with some of the fixes! If you've filed an issue please help me verify and close. Your support, kindness and awesome suggestions to make Popeye better is as ever very much noticed and appreciated!
8 |
9 | This project offers a GitHub Sponsor button (over here 👆). As you well know this is not pimped out by big corps with deep pockets. If you feel `Popeye` is saving you cycles diagnosing potential cluster issues please consider sponsoring this project!! It does go a long way in keeping our servers lights on and beers in our fridge.
10 |
11 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
12 |
13 | ---
14 |
15 | ## Maintenance Release
16 |
17 | ---
18 |
19 | ## Resolved Issues
20 |
21 | * [#425](https://github.com/derailed/popeye/issues/425) Upload to s3 failing in v0.22.0
22 |
23 |
© 2025 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
24 |
--------------------------------------------------------------------------------
/change_logs/release_v0.3.10.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.3.10
4 |
5 | ## Notes
6 |
7 | Thank you so much for your support and suggestions to make Popeye better!!
8 |
9 | If you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
10 |
11 | ---
12 |
13 | ## Change Logs
14 |
15 | ### PodDisruptionBugdet
16 |
17 | Added check for pbs. The sanitizer will report usage and possible misconfiguration if PodDiscruptionBudgets are available on the cluster.
18 |
19 | ---
20 |
21 | ## Resolved Bugs
22 |
23 | * [Issue #34](https://github.com/derailed/popeye/issues/34)
24 | * [Issue #21](https://github.com/derailed/popeye/issues/21)
25 |
26 | ---
27 |
28 |
© 2019 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
29 |
--------------------------------------------------------------------------------
/change_logs/release_v0.3.11.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.3.11
4 |
5 | ## Notes
6 |
7 | Thank you so much for your support and suggestions to make Popeye better!!
8 |
9 | If you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
10 |
11 | ---
12 |
13 | ## Change Logs
14 |
15 | ---
16 |
17 | ## Resolved Bugs
18 |
19 | * [Issue #37](https://github.com/derailed/popeye/issues/37)
20 |
21 | ---
22 |
23 |
© 2019 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
24 |
--------------------------------------------------------------------------------
/change_logs/release_v0.3.12.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.3.12
4 |
5 | ## Notes
6 |
7 | Thank you so much for your support and suggestions to make Popeye better!!
8 |
9 | If you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
10 |
11 | ---
12 |
13 | ## Change Logs
14 |
15 | Bug and Maintenance release.
16 |
17 | ---
18 |
19 | ## Resolved Bugs
20 |
21 | * [Issue #38](https://github.com/derailed/popeye/issues/38)
22 |
23 | ---
24 |
25 |
© 2019 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
26 |
--------------------------------------------------------------------------------
/change_logs/release_v0.3.13.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.3.13
4 |
5 | ## Notes
6 |
7 | Thank you so much for your support and suggestions to make Popeye better!!
8 |
9 | If you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
10 |
11 | ---
12 |
13 | ## Change Logs
14 |
15 | ### Add over-allocs flag
16 |
17 | Popeye is designed to report sanitization on a live cluster. As such when a cluster is mainly idle, the over allocation report may yield false positives. To this end, we've added a `--over-allocs` option to the CLI to opt-in over allocations reports. By default this option will be off, hence no over cpu/memory allocations will be reported. This now gives you an option to report allocation based on cluster load.
18 |
19 | ---
20 |
21 | ## Resolved Bugs
22 |
23 | * [Issue #39](https://github.com/derailed/popeye/issues/39)
24 |
25 | ---
26 |
27 |
© 2019 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
28 |
--------------------------------------------------------------------------------
/change_logs/release_v0.3.2.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.3.2
4 |
5 | ## Notes
6 |
7 | Thank you so much for your support and suggestions to make Popeye better!!
8 |
9 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
10 |
11 | ---
12 |
13 | ## Change Logs
14 |
15 |
16 | ## Cleaning up
17 |
18 | Fixed up a few sanitizer messages.
19 |
20 | ---
21 |
22 | ## Resolved Bugs
23 |
24 | ---
25 |
26 |
© 2019 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
27 |
--------------------------------------------------------------------------------
/change_logs/release_v0.3.3.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.3.3
4 |
5 | ## Notes
6 |
7 | Thank you so much for your support and suggestions to make Popeye better!!
8 |
9 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
10 |
11 | ---
12 |
13 | ## Change Logs
14 |
15 | Bugs and cleanup!
16 |
17 | ---
18 |
19 | ## Resolved Bugs
20 |
21 | + [Issue #24](https://github.com/derailed/popeye/issues/24)
22 |
23 | ---
24 |
25 |
© 2019 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
26 |
--------------------------------------------------------------------------------
/change_logs/release_v0.3.4.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.3.4
4 |
5 | ## Notes
6 |
7 | Thank you so much for your support and suggestions to make Popeye better!!
8 |
9 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
10 |
11 | ---
12 |
13 | ## Change Logs
14 |
15 | ### Spring Cleaning!
16 |
17 | Lost of work happened under the hood in this release. Mainly refactoring, bugs and cleanup items. If you notice any breakage from the previous release, please file an issue so we can improve Popeye. Thank you!
18 |
19 | ---
20 |
21 | ## Resolved Bugs
22 |
23 | + [Issue #25](https://github.com/derailed/popeye/issues/25)
24 |
25 | ---
26 |
27 |
© 2019 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
28 |
--------------------------------------------------------------------------------
/change_logs/release_v0.3.5.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.3.5
4 |
5 | ## Notes
6 |
7 | Thank you so much for your support and suggestions to make Popeye better!!
8 |
9 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
10 |
11 | ---
12 |
13 | ## Change Logs
14 |
15 | ### Perfomance Pass
16 |
17 | Added a caching layer to improve sanitization report generation. This is a first pass of many but looks like 2X improvement over previous release. Yeah!
18 |
19 | ---
20 |
21 | ## Resolved Bugs
22 |
23 | ---
24 |
25 |
© 2019 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
26 |
--------------------------------------------------------------------------------
/change_logs/release_v0.3.8.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.3.8
4 |
5 | ## Notes
6 |
7 | Thank you so much for your support and suggestions to make Popeye better!!
8 |
9 | If you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
10 |
11 | ---
12 |
13 | ## Change Logs
14 |
15 | Bugs and clean up...
16 |
17 | ---
18 |
19 | ## Resolved Bugs
20 |
21 | + [Issue #33](https://github.com/derailed/popeye/issues/33)
22 |
23 | ---
24 |
25 |
© 2019 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
26 |
--------------------------------------------------------------------------------
/change_logs/release_v0.3.9.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.3.9
4 |
5 | ## Notes
6 |
7 | Thank you so much for your support and suggestions to make Popeye better!!
8 |
9 | If you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
10 |
11 | ---
12 |
13 | ## Change Logs
14 |
15 | Snap release attempt. No new features or fixes.
16 |
17 | ---
18 |
19 | ## Resolved Bugs
20 |
21 |
22 | ---
23 |
24 |
© 2019 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
25 |
--------------------------------------------------------------------------------
/change_logs/release_v0.4.1.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.4.0
4 |
5 | ## Notes
6 |
7 | Thank you so much for your support and suggestions to make Popeye better!!
8 |
9 | If you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
10 |
11 | ---
12 |
13 | ## Change Logs
14 |
15 | Oops! Broke the scorer ;(
16 |
17 | ---
18 |
19 | ## Resolved Bugs
20 |
21 | ---
22 |
23 |
© 2019 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
24 |
--------------------------------------------------------------------------------
/change_logs/release_v0.4.2.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.4.2
4 |
5 | ## Notes
6 |
7 | Thank you so much for your support and suggestions to make Popeye better!!
8 |
9 | If you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
10 |
11 | ---
12 |
13 | ## Change Logs
14 |
15 | Maintenance release bugs and cleanup.
16 |
17 | ---
18 |
19 | ## Resolved Bugs
20 |
21 | * [Issue #44](https://github.com/derailed/popeye/issues/44)
22 |
23 | ---
24 |
25 |
© 2019 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
26 |
--------------------------------------------------------------------------------
/change_logs/release_v0.4.3.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.4.3
4 |
5 | ## Notes
6 |
7 | Thank you so much for your support and suggestions to make Popeye better!!
8 |
9 | If you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
10 |
11 | ---
12 |
13 | ## Change Logs
14 |
15 | Maintenance release bugs and cleanup.
16 |
17 | ---
18 |
19 | ## Resolved Bugs
20 |
21 | * Wrong Popeye version in Docker builds [Issue #48](https://github.com/derailed/popeye/issues/48)
22 | * Incorrect ServiceAccount reporting [Issue #49](https://github.com/derailed/popeye/issues/49)
23 |
24 | ---
25 |
26 |
© 2019 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
27 |
--------------------------------------------------------------------------------
/change_logs/release_v0.5.0.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.5.0
4 |
5 | ## Notes
6 |
7 | Thank you so much for your support and suggestions to make Popeye better!!
8 |
9 | If you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
10 |
11 | ---
12 |
13 | ## Change Logs
14 |
15 | In this drop, we've cleaned up a few code duds and addressed a bit of debt.
16 |
17 | ### Prometheus Report
18 |
19 | Thanks to an awesome contribution by [dardanel](https://github.com/eminugurkenar), Popeye can now report sanitization issues as Prometheus metrics. Thus, you will have the ability to run Popeye in cluster as a job and push sanitization metrics back to the prometheus mothership. How cool is that? As it stands these will just be reported as raw counts and thus you won't have sanitization details but you can leverage Prometheus AlertManager to trigger your clusters investigation based on these reports.
20 |
21 | ---
22 |
23 | ## Resolved Bugs
24 |
25 | * [Issue #58](https://github.com/derailed/popeye/issues/58) Thank you @renan!!
26 |
27 | ---
28 |
29 |
© 2019 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
30 |
--------------------------------------------------------------------------------
/change_logs/release_v0.6.1.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.6.1
4 |
5 | ## Notes
6 |
7 | Thank you so much for your support and suggestions to make Popeye better!!
8 |
9 | If you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
10 |
11 | ---
12 |
13 | ## Change Logs
14 |
15 | Maintenance release!
16 |
17 | ---
18 |
19 | ## Resolved Bugs
20 |
21 | * [Issue #53](https://github.com/derailed/popeye/issues/53)
22 |
23 | ---
24 |
25 |
© 2019 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
26 |
--------------------------------------------------------------------------------
/change_logs/release_v0.6.2.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.6.2
4 |
5 | ## Notes
6 |
7 | Thank you so much for your support and suggestions to make Popeye better!!
8 |
9 | If you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
10 |
11 | ---
12 |
13 | ## Change Logs
14 |
15 | Maintenance release!
16 |
17 | # GitHub Sponsorships
18 |
19 | As you may have noticed this project now offers a GitHub Sponsor button (over there 👆).
20 | If you feel `Popeye` sanitizers are helping you diagnose potential cluster issues and his saving you some cycles, you may consider sponsorizing this project. Thank you for your gesture of kindness and for supporting Popeye!! (not to mention helping replainish my liquids during oh-dark-thirty hours 🍺🍹🍸)
21 |
22 | ---
23 |
24 | ## Resolved Bugs
25 |
26 | * [Issue #77](https://github.com/derailed/popeye/issues/77)
27 |
28 | ---
29 |
30 |
© 2019 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
31 |
--------------------------------------------------------------------------------
/change_logs/release_v0.7.1.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.7.1
4 |
5 | ## Notes
6 |
7 | Thank you to all that contributed with flushing out issues and enhancements for Popeye! I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev and see if we're happier with some of the fixes! If you've filed an issue please help me verify and close. Your support, kindness and awesome suggestions to make Popeye better is as ever very much noticed and appreciated!
8 |
9 | This project offers a GitHub Sponsor button (over here 👆). If you feel `Popeye` sanitizers are helping you diagnose potential cluster issues and it's saving you some cycles, please consider sponsoring this project.
10 |
11 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
12 |
13 | ---
14 |
15 | ## Change Logs
16 |
17 | Maintenance Release!
18 |
19 | ---
20 |
21 | ## Resolved Bugs/PRs
22 |
23 | * [Issue #85](https://github.com/derailed/popeye/issues/85)
24 |
25 | ---
26 |
27 |
© 2020 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
28 |
--------------------------------------------------------------------------------
/change_logs/release_v0.8.1.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.8.1
4 |
5 | ## Notes
6 |
7 | Thank you to all that contributed with flushing out issues and enhancements for Popeye! I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev and see if we're happier with some of the fixes! If you've filed an issue please help me verify and close. Your support, kindness and awesome suggestions to make Popeye better is as ever very much noticed and appreciated!
8 |
9 | This project offers a GitHub Sponsor button (over here 👆). If you feel `Popeye` sanitizers are helping you diagnose potential cluster issues and it's saving you some cycles, please consider sponsoring this project.
10 |
11 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
12 |
13 | ---
14 |
15 | ## Change Logs
16 |
17 | Maintenance Release!
18 |
19 | ---
20 |
21 | ## Resolved Bugs/PRs
22 |
23 | ---
24 |
25 |
© 2020 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
26 |
--------------------------------------------------------------------------------
/change_logs/release_v0.8.2.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.8.2
4 |
5 | ## Notes
6 |
7 | Thank you to all that contributed with flushing out issues and enhancements for Popeye! I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev and see if we're happier with some of the fixes! If you've filed an issue please help me verify and close. Your support, kindness and awesome suggestions to make Popeye better is as ever very much noticed and appreciated!
8 |
9 | This project offers a GitHub Sponsor button (over here 👆). If you feel `Popeye` sanitizers are helping you diagnose potential cluster issues and it's saving you some cycles, please consider sponsoring this project.
10 |
11 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
12 |
13 | ---
14 |
15 | ## Change Logs
16 |
17 | Maintenance Release!
18 |
19 | ---
20 |
21 | ## Resolved Bugs/PRs
22 |
23 | - Fix concurrent map access issue
24 | - [Issue #100](https://github.com/derailed/popeye/issues/100)
25 | - [Issue #94](https://github.com/derailed/popeye/issues/94)
26 |
27 | ---
28 |
29 |
© 2020 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
30 |
--------------------------------------------------------------------------------
/change_logs/release_v0.8.3.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.8.3
4 |
5 | ## Notes
6 |
7 | Thank you to all that contributed with flushing out issues and enhancements for Popeye! I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev and see if we're happier with some of the fixes! If you've filed an issue please help me verify and close. Your support, kindness and awesome suggestions to make Popeye better is as ever very much noticed and appreciated!
8 |
9 | This project offers a GitHub Sponsor button (over here 👆). If you feel `Popeye` sanitizers are helping you diagnose potential cluster issues and it's saving you some cycles, please consider sponsoring this project.
10 |
11 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
12 |
13 | ---
14 |
15 | ## Change Logs
16 |
17 | Maintenance Release!
18 |
19 | ---
20 |
21 | ## Resolved Bugs/PRs
22 |
23 | - Removed collision flag check for deployment, statefulset and daemonset
24 |
25 | ---
26 |
27 |
© 2020 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
28 |
--------------------------------------------------------------------------------
/change_logs/release_v0.8.4.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.8.4
4 |
5 | ## Notes
6 |
7 | Thank you to all that contributed with flushing out issues and enhancements for Popeye! I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev and see if we're happier with some of the fixes! If you've filed an issue please help me verify and close. Your support, kindness and awesome suggestions to make Popeye better is as ever very much noticed and appreciated!
8 |
9 | This project offers a GitHub Sponsor button (over here 👆). If you feel `Popeye` sanitizers are helping you diagnose potential cluster issues and it's saving you some cycles, please consider sponsoring this project.
10 |
11 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
12 |
13 | ---
14 |
15 | ## Change Logs
16 |
17 | Maintenance Release!
18 |
19 | ---
20 |
21 | ## Resolved Bugs/PRs
22 |
23 | - Add checks for missing serviceaccount
24 | - Rework APIServer connection logic
25 |
26 | ---
27 |
28 |
© 2020 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
29 |
--------------------------------------------------------------------------------
/change_logs/release_v0.8.5.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.8.5
4 |
5 | ## Notes
6 |
7 | Thank you to all that contributed with flushing out issues and enhancements for Popeye! I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev and see if we're happier with some of the fixes! If you've filed an issue please help me verify and close. Your support, kindness and awesome suggestions to make Popeye better is as ever very much noticed and appreciated!
8 |
9 | This project offers a GitHub Sponsor button (over here 👆). If you feel `Popeye` sanitizers are helping you diagnose potential cluster issues and it's saving you some cycles, please consider sponsoring this project.
10 |
11 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
12 |
13 | ---
14 |
15 | ## Change Logs
16 |
17 | Maintenance Release!
18 |
19 | ---
20 |
21 | ## Resolved Bugs/PRs
22 |
23 | - [Issue #105](https://github.com/derailed/popeye/issues/105)
24 | - [PR #100](https://github.com/derailed/popeye/pull/104) Big Thanks!! [Paul Cantea](https://github.com/pcantea)
25 |
26 | ---
27 |
28 |
© 2020 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
29 |
--------------------------------------------------------------------------------
/change_logs/release_v0.8.6.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.8.6
4 |
5 | ## Notes
6 |
7 | Thank you to all that contributed with flushing out issues and enhancements for Popeye! I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev and see if we're happier with some of the fixes! If you've filed an issue please help me verify and close. Your support, kindness and awesome suggestions to make Popeye better is as ever very much noticed and appreciated!
8 |
9 | This project offers a GitHub Sponsor button (over here 👆). If you feel `Popeye` sanitizers are helping you diagnose potential cluster issues and it's saving you some cycles, please consider sponsoring this project!!
10 |
11 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
12 |
13 | ---
14 |
15 | ## Change Logs
16 |
17 | Maintenance Release!
18 |
19 | ---
20 |
21 | ## Resolved Bugs/PRs
22 |
23 | - [Issue #106](https://github.com/derailed/popeye/issues/106) All credits goes to [Paul Cantea](https://github.com/pcantea)
24 |
25 | ---
26 |
27 |
© 2020 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
28 |
--------------------------------------------------------------------------------
/change_logs/release_v0.8.7.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.8.7
4 |
5 | ## Notes
6 |
7 | Thank you to all that contributed with flushing out issues and enhancements for Popeye! I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev and see if we're happier with some of the fixes! If you've filed an issue please help me verify and close. Your support, kindness and awesome suggestions to make Popeye better is as ever very much noticed and appreciated!
8 |
9 | This project offers a GitHub Sponsor button (over here 👆). If you feel `Popeye` sanitizers are helping you diagnose potential cluster issues and it's saving you some cycles, please consider sponsoring this project!!
10 |
11 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
12 |
13 | ---
14 |
15 | ## Change Logs
16 |
17 | Maintenance Release!
18 |
19 | ---
20 |
21 | ## Resolved Bugs/PRs
22 |
23 | - [Issue #112](https://github.com/derailed/popeye/issues/112)
24 | - [Issue #111](https://github.com/derailed/popeye/issues/111)
25 |
26 | ---
27 |
28 |
© 2020 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
29 |
--------------------------------------------------------------------------------
/change_logs/release_v0.8.8.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.8.8
4 |
5 | ## Notes
6 |
7 | Thank you to all that contributed with flushing out issues and enhancements for Popeye! I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev and see if we're happier with some of the fixes! If you've filed an issue please help me verify and close. Your support, kindness and awesome suggestions to make Popeye better is as ever very much noticed and appreciated!
8 |
9 | This project offers a GitHub Sponsor button (over here 👆). If you feel `Popeye` sanitizers are helping you diagnose potential cluster issues and it's saving you some cycles, please consider sponsoring this project!!
10 |
11 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
12 |
13 | ---
14 |
15 | ## Change Logs
16 |
17 | Maintenance Release!
18 |
19 | ---
20 |
21 | ## Resolved Bugs/PRs
22 |
23 | - [Issue #115](https://github.com/derailed/popeye/issues/115)
24 |
25 | ---
26 |
27 |
© 2020 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
28 |
--------------------------------------------------------------------------------
/change_logs/release_v0.9.8.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # Release v0.9.8
4 |
5 | ## Notes
6 |
7 | Thank you to all that contributed with flushing out issues and enhancements for Popeye! I'll try to mark some of these issues as fixed. But if you don't mind grab the latest rev and see if we're happier with some of the fixes! If you've filed an issue please help me verify and close. Your support, kindness and awesome suggestions to make Popeye better is as ever very much noticed and appreciated!
8 |
9 | This project offers a GitHub Sponsor button (over here 👆). As you well know this is not pimped out by big corps with deep pockets. If you feel `Popeye` is saving you cycles diagnosing potential cluster issues please consider sponsoring this project!! It does go a long way in keeping our servers lights on and beers in our fridge.
10 |
11 | Also if you dig this tool, please make some noise on social! [@kitesurfer](https://twitter.com/kitesurfer)
12 |
13 | ---
14 |
15 | ## Maintenance Release!
16 |
17 | NOTE: Fix'n brew deprecation warnings
18 |
19 | ## Resolved Bugs/PRs
20 |
21 | ---
22 |
23 |
© 2020 Imhotep Software LLC. All materials licensed under [Apache v2.0](http://www.apache.org/licenses/LICENSE-2.0)
24 |
--------------------------------------------------------------------------------
/cmd/info.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package cmd
5 |
6 | import (
7 | "fmt"
8 |
9 | "github.com/derailed/popeye/internal/report"
10 | "github.com/derailed/popeye/pkg"
11 | "github.com/spf13/cobra"
12 | )
13 |
14 | func init() {
15 | rootCmd.AddCommand(infoCmd())
16 | }
17 |
18 | func infoCmd() *cobra.Command {
19 | return &cobra.Command{
20 | Use: "info",
21 | Short: "Prints Popeye info",
22 | Long: "Prints Popeye information",
23 | Run: func(cmd *cobra.Command, args []string) {
24 | printInfo()
25 | },
26 | }
27 | }
28 |
29 | func printInfo() {
30 | printLogo(report.ColorAqua, report.ColorLighSlate)
31 | fmt.Println()
32 | printTuple("Logs", pkg.LogFile)
33 | }
34 |
--------------------------------------------------------------------------------
/internal/cache/cluster.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package cache
5 |
6 | import (
7 | "errors"
8 |
9 | "github.com/blang/semver/v4"
10 | )
11 |
12 | // ClusterKey tracks Cluster resource references
13 | const ClusterKey = "cl"
14 |
15 | // Cluster represents Cluster cache.
16 | type Cluster struct {
17 | rev *semver.Version
18 | }
19 |
20 | // NewCluster returns a new Cluster cache.
21 | func NewCluster(v *semver.Version) *Cluster {
22 | return &Cluster{rev: v}
23 | }
24 |
25 | // ListVersion returns cluster server version.
26 | func (c *Cluster) ListVersion() (*semver.Version, error) {
27 | if c.rev == nil {
28 | return nil, errors.New("unable to assert cluster version")
29 | }
30 |
31 | return c.rev, nil
32 | }
33 |
--------------------------------------------------------------------------------
/internal/cache/cluster_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package cache_test
5 |
6 | import (
7 | "testing"
8 |
9 | "github.com/blang/semver/v4"
10 | "github.com/derailed/popeye/internal/cache"
11 | "github.com/rs/zerolog"
12 | "github.com/stretchr/testify/assert"
13 | )
14 |
15 | func init() {
16 | zerolog.SetGlobalLevel(zerolog.FatalLevel)
17 | }
18 |
19 | func TestCluster(t *testing.T) {
20 | v, err := semver.ParseTolerant("1.9")
21 | assert.NoError(t, err)
22 |
23 | c := cache.NewCluster(&v)
24 | v1, err := c.ListVersion()
25 | assert.NoError(t, err)
26 | assert.Equal(t, &v, v1)
27 | }
28 |
--------------------------------------------------------------------------------
/internal/cache/cr.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package cache
5 |
6 | import (
7 | "sync"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | rbacv1 "k8s.io/api/rbac/v1"
12 | )
13 |
14 | // ClusterRole represents ClusterRole cache.
15 | type ClusterRole struct {
16 | db *db.DB
17 | }
18 |
19 | // NewClusterRole returns a new ClusterRole cache.
20 | func NewClusterRole(db *db.DB) *ClusterRole {
21 | return &ClusterRole{db: db}
22 | }
23 |
24 | // RoleRefs computes all role external references.
25 | func (r *ClusterRole) AggregationMatchers(refs *sync.Map) {
26 | txn, it := r.db.MustITFor(internal.Glossary[internal.CR])
27 | defer txn.Abort()
28 | for o := it.Next(); o != nil; o = it.Next() {
29 | cr := o.(*rbacv1.ClusterRole)
30 | if cr.AggregationRule != nil {
31 | for _, lbs := range cr.AggregationRule.ClusterRoleSelectors {
32 | for k, v := range lbs.MatchLabels {
33 | refs.Store(k, v)
34 | }
35 | }
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/internal/cache/cr_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package cache_test
5 |
6 | import (
7 | "sync"
8 | "testing"
9 |
10 | "github.com/derailed/popeye/internal"
11 | "github.com/derailed/popeye/internal/cache"
12 | "github.com/derailed/popeye/internal/db"
13 | "github.com/derailed/popeye/internal/test"
14 | "github.com/stretchr/testify/assert"
15 | rbacv1 "k8s.io/api/rbac/v1"
16 | )
17 |
18 | func TestClusterRoleAggregation(t *testing.T) {
19 | dba, err := test.NewTestDB()
20 | assert.NoError(t, err)
21 | l := db.NewLoader(dba)
22 |
23 | ctx := test.MakeCtx(t)
24 | assert.NoError(t, test.LoadDB[*rbacv1.ClusterRole](ctx, l.DB, "auth/cr/1.yaml", internal.Glossary[internal.CR]))
25 |
26 | cr := cache.NewClusterRole(dba)
27 | var aRefs sync.Map
28 | cr.AggregationMatchers(&aRefs)
29 |
30 | value, ok := aRefs.Load("rbac.authorization.k8s.io/aggregate-to-cr4")
31 | assert.True(t, ok)
32 | assert.Equal(t, "true", value)
33 | }
34 |
--------------------------------------------------------------------------------
/internal/cache/crb.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package cache
5 |
6 | import (
7 | "strings"
8 | "sync"
9 |
10 | "github.com/derailed/popeye/internal"
11 | "github.com/derailed/popeye/internal/client"
12 | "github.com/derailed/popeye/internal/db"
13 | rbacv1 "k8s.io/api/rbac/v1"
14 | )
15 |
16 | // ClusterRoleBinding represents ClusterRoleBinding cache.
17 | type ClusterRoleBinding struct {
18 | db *db.DB
19 | }
20 |
21 | // NewClusterRoleBinding returns a new ClusterRoleBinding cache.
22 | func NewClusterRoleBinding(db *db.DB) *ClusterRoleBinding {
23 | return &ClusterRoleBinding{db: db}
24 | }
25 |
26 | // ClusterRoleRefs computes all clusterrole external references.
27 | func (c *ClusterRoleBinding) ClusterRoleRefs(refs *sync.Map) {
28 | txn, it := c.db.MustITFor(internal.Glossary[internal.CRB])
29 | defer txn.Abort()
30 | for o := it.Next(); o != nil; o = it.Next() {
31 | crb := o.(*rbacv1.ClusterRoleBinding)
32 | fqn := client.FQN(crb.Namespace, crb.Name)
33 | key := ResFqn(strings.ToLower(crb.RoleRef.Kind), FQN(crb.Namespace, crb.RoleRef.Name))
34 | if c, ok := refs.Load(key); ok {
35 | c.(internal.StringSet).Add(fqn)
36 | } else {
37 | refs.Store(key, internal.StringSet{fqn: internal.Blank})
38 | }
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/internal/cache/crb_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package cache_test
5 |
6 | import (
7 | "sync"
8 | "testing"
9 |
10 | "github.com/derailed/popeye/internal"
11 | "github.com/derailed/popeye/internal/cache"
12 | "github.com/derailed/popeye/internal/db"
13 | "github.com/derailed/popeye/internal/test"
14 | "github.com/stretchr/testify/assert"
15 | rbacv1 "k8s.io/api/rbac/v1"
16 | )
17 |
18 | func TestClusterRoleRef(t *testing.T) {
19 | dba, err := test.NewTestDB()
20 | assert.NoError(t, err)
21 | l := db.NewLoader(dba)
22 |
23 | ctx := test.MakeCtx(t)
24 | assert.NoError(t, test.LoadDB[*rbacv1.ClusterRoleBinding](ctx, l.DB, "auth/crb/1.yaml", internal.Glossary[internal.CRB]))
25 |
26 | cr := cache.NewClusterRoleBinding(dba)
27 | var refs sync.Map
28 | cr.ClusterRoleRefs(&refs)
29 |
30 | m, ok := refs.Load("clusterrole:cr1")
31 | assert.True(t, ok)
32 | _, ok = m.(internal.StringSet)["crb1"]
33 | assert.True(t, ok)
34 |
35 | m, ok = refs.Load("role:r1")
36 | assert.True(t, ok)
37 |
38 | _, ok = m.(internal.StringSet)["crb3"]
39 | assert.True(t, ok)
40 | }
41 |
--------------------------------------------------------------------------------
/internal/cache/helper.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package cache
5 |
6 | import (
7 | "strings"
8 |
9 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
10 | )
11 |
12 | // FQN returns a fully qualified resource identifier.
13 | func FQN(ns, n string) string {
14 | if ns == "" {
15 | return n
16 | }
17 | return ns + "/" + n
18 | }
19 |
20 | // MetaFQN returns a fully qualified resource identifier based on object meta.
21 | func MetaFQN(m metav1.ObjectMeta) string {
22 | return FQN(m.Namespace, m.Name)
23 | }
24 |
25 | // ResFqn returns a resource specific fqn.
26 | func ResFqn(k, s string) string {
27 | return k + ":" + s
28 | }
29 |
30 | // Namespaced return ns and name contained in given fqn.
31 | func namespaced(fqn string) (string, string) {
32 | tokens := strings.Split(fqn, "/")
33 | if len(tokens) == 2 {
34 | return tokens[0], tokens[1]
35 | }
36 | return "", tokens[0]
37 | }
38 |
39 | // MatchLabels check if pod labels match a selector.
40 | func MatchLabels(labels, sel map[string]string) bool {
41 | if len(sel) == 0 {
42 | return false
43 | }
44 |
45 | for k, v := range sel {
46 | if v1, ok := labels[k]; !ok || v1 != v {
47 | return false
48 | }
49 | }
50 |
51 | return true
52 | }
53 |
--------------------------------------------------------------------------------
/internal/cache/ing.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package cache
5 |
6 | import (
7 | "errors"
8 | "sync"
9 |
10 | "github.com/derailed/popeye/internal"
11 | "github.com/derailed/popeye/internal/db"
12 | netv1 "k8s.io/api/networking/v1"
13 | )
14 |
15 | // IngressKey tracks Ingress resource references
16 | const IngressKey = "ing"
17 |
18 | // Ingress represents Ingress cache.
19 | type Ingress struct {
20 | db *db.DB
21 | }
22 |
23 | // NewIngress returns a new Ingress cache.
24 | func NewIngress(db *db.DB) *Ingress {
25 | return &Ingress{db: db}
26 | }
27 |
28 | // IngressRefs computes all ingress external references.
29 | func (d *Ingress) IngressRefs(refs *sync.Map) error {
30 | txn, it := d.db.MustITFor(internal.Glossary[internal.ING])
31 | defer txn.Abort()
32 | for o := it.Next(); o != nil; o = it.Next() {
33 | ing, ok := o.(*netv1.Ingress)
34 | if !ok {
35 | return errors.New("expected ing")
36 | }
37 | for _, tls := range ing.Spec.TLS {
38 | d.trackReference(refs, ResFqn(SecretKey, FQN(ing.Namespace, tls.SecretName)))
39 | }
40 | }
41 |
42 | return nil
43 | }
44 |
45 | func (d *Ingress) trackReference(refs *sync.Map, key string) {
46 | refs.Store(key, internal.AllKeys)
47 | }
48 |
--------------------------------------------------------------------------------
/internal/cache/ing_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package cache
5 |
6 | import (
7 | "sync"
8 | "testing"
9 |
10 | "github.com/derailed/popeye/internal"
11 | "github.com/derailed/popeye/internal/db"
12 | "github.com/derailed/popeye/internal/test"
13 | "github.com/stretchr/testify/assert"
14 | netv1 "k8s.io/api/networking/v1"
15 | )
16 |
17 | func TestIngressRefs(t *testing.T) {
18 | dba, err := test.NewTestDB()
19 | assert.NoError(t, err)
20 | l := db.NewLoader(dba)
21 |
22 | ctx := test.MakeCtx(t)
23 | assert.NoError(t, test.LoadDB[*netv1.Ingress](ctx, l.DB, "net/ingress/1.yaml", internal.Glossary[internal.ING]))
24 |
25 | var refs sync.Map
26 | ing := NewIngress(dba)
27 | assert.NoError(t, ing.IngressRefs(&refs))
28 |
29 | _, ok := refs.Load("sec:default/foo")
30 | assert.Equal(t, ok, true)
31 | }
32 |
--------------------------------------------------------------------------------
/internal/cache/no_mx.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package cache
5 |
6 | import (
7 | "github.com/derailed/popeye/internal/db"
8 | v1 "k8s.io/api/core/v1"
9 | "k8s.io/apimachinery/pkg/api/resource"
10 | )
11 |
12 | // ListAllocatedMetrics collects total used cpu and mem on the cluster.
13 | func listAllocatedMetrics(db *db.DB) (v1.ResourceList, error) {
14 | cpu, mem := new(resource.Quantity), new(resource.Quantity)
15 | mm, err := db.ListNMX()
16 | if err != nil {
17 | return nil, err
18 | }
19 | for _, mx := range mm {
20 | cpu.Add(*mx.Usage.Cpu())
21 | mem.Add(*mx.Usage.Memory())
22 | }
23 |
24 | return v1.ResourceList{v1.ResourceCPU: *cpu, v1.ResourceMemory: *mem}, nil
25 | }
26 |
27 | // ListAvailableMetrics return the total cluster available cpu/mem.
28 | func ListAvailableMetrics(db *db.DB) (v1.ResourceList, error) {
29 | cpu, mem := new(resource.Quantity), new(resource.Quantity)
30 | nn, err := db.ListNodes()
31 | if err != nil {
32 | return nil, err
33 | }
34 | for _, n := range nn {
35 | cpu.Add(*n.Status.Allocatable.Cpu())
36 | mem.Add(*n.Status.Allocatable.Memory())
37 | }
38 | used, err := listAllocatedMetrics(db)
39 | if err != nil {
40 | return nil, err
41 | }
42 | cpu.Sub(*used.Cpu())
43 | mem.Sub(*used.Memory())
44 |
45 | return v1.ResourceList{
46 | v1.ResourceCPU: *cpu,
47 | v1.ResourceMemory: *mem,
48 | }, nil
49 | }
50 |
--------------------------------------------------------------------------------
/internal/cache/rb.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package cache
5 |
6 | import (
7 | "strings"
8 | "sync"
9 |
10 | "github.com/derailed/popeye/internal"
11 | "github.com/derailed/popeye/internal/client"
12 | "github.com/derailed/popeye/internal/db"
13 | rbacv1 "k8s.io/api/rbac/v1"
14 | )
15 |
16 | // RoleKey represents a role identifier.
17 | const RoleKey = "role"
18 |
19 | // RoleBinding represents RoleBinding cache.
20 | type RoleBinding struct {
21 | db *db.DB
22 | }
23 |
24 | // NewRoleBinding returns a new RoleBinding cache.
25 | func NewRoleBinding(db *db.DB) *RoleBinding {
26 | return &RoleBinding{db: db}
27 | }
28 |
29 | // RoleRefs computes all role external references.
30 | func (r *RoleBinding) RoleRefs(refs *sync.Map) {
31 | txn, it := r.db.MustITFor(internal.Glossary[internal.ROB])
32 | defer txn.Abort()
33 | for o := it.Next(); o != nil; o = it.Next() {
34 | rb := o.(*rbacv1.RoleBinding)
35 | fqn := client.FQN(rb.Namespace, rb.Name)
36 | cfqn := FQN(rb.Namespace, rb.RoleRef.Name)
37 | if rb.RoleRef.Kind == "ClusterRole" {
38 | cfqn = client.FQN("", rb.RoleRef.Name)
39 | }
40 | key := ResFqn(strings.ToLower(rb.RoleRef.Kind), cfqn)
41 | if c, ok := refs.LoadOrStore(key, internal.StringSet{fqn: internal.Blank}); ok {
42 | c.(internal.StringSet).Add(fqn)
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/internal/cache/rb_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package cache_test
5 |
6 | import (
7 | "sync"
8 | "testing"
9 |
10 | "github.com/derailed/popeye/internal"
11 | "github.com/derailed/popeye/internal/cache"
12 | "github.com/derailed/popeye/internal/db"
13 | "github.com/derailed/popeye/internal/test"
14 | "github.com/stretchr/testify/assert"
15 | rbacv1 "k8s.io/api/rbac/v1"
16 | )
17 |
18 | func TestRoleRef(t *testing.T) {
19 | dba, err := test.NewTestDB()
20 | assert.NoError(t, err)
21 | l := db.NewLoader(dba)
22 |
23 | ctx := test.MakeCtx(t)
24 | assert.NoError(t, test.LoadDB[*rbacv1.RoleBinding](ctx, l.DB, "auth/rob/1.yaml", internal.Glossary[internal.ROB]))
25 |
26 | cr := cache.NewRoleBinding(dba)
27 | var refs sync.Map
28 | cr.RoleRefs(&refs)
29 |
30 | m, ok := refs.Load("clusterrole:cr-bozo")
31 | assert.True(t, ok)
32 | _, ok = m.(internal.StringSet)["default/rb3"]
33 | assert.True(t, ok)
34 |
35 | m, ok = refs.Load("role:default/r1")
36 | assert.True(t, ok)
37 | _, ok = m.(internal.StringSet)["default/rb1"]
38 | assert.True(t, ok)
39 | }
40 |
--------------------------------------------------------------------------------
/internal/cache/sa.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package cache
5 |
6 | import (
7 | "errors"
8 | "sync"
9 |
10 | "github.com/derailed/popeye/internal"
11 | "github.com/derailed/popeye/internal/db"
12 | v1 "k8s.io/api/core/v1"
13 | )
14 |
15 | // ServiceAccount tracks serviceaccounts.
16 | type ServiceAccount struct {
17 | db *db.DB
18 | }
19 |
20 | // NewServiceAccount returns a new serviceaccount loader.
21 | func NewServiceAccount(db *db.DB) *ServiceAccount {
22 | return &ServiceAccount{db: db}
23 | }
24 |
25 | // ServiceAccountRefs computes all serviceaccount external references.
26 | func (s *ServiceAccount) ServiceAccountRefs(refs *sync.Map) error {
27 | txn, it := s.db.MustITFor(internal.Glossary[internal.SA])
28 | defer txn.Abort()
29 | for o := it.Next(); o != nil; o = it.Next() {
30 | sa, ok := o.(*v1.ServiceAccount)
31 | if !ok {
32 | return errors.New("expected sa")
33 | }
34 | namespaceRefs(sa.Namespace, refs)
35 | for _, s := range sa.Secrets {
36 | key := ResFqn(SecretKey, FQN(s.Namespace, s.Name))
37 | refs.Store(key, internal.AllKeys)
38 | }
39 | for _, s := range sa.ImagePullSecrets {
40 | key := ResFqn(SecretKey, FQN(sa.Namespace, s.Name))
41 | refs.Store(key, internal.AllKeys)
42 | }
43 |
44 | }
45 |
46 | return nil
47 | }
48 |
--------------------------------------------------------------------------------
/internal/cache/sa_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package cache
5 |
6 | import (
7 | "sync"
8 | "testing"
9 |
10 | "github.com/derailed/popeye/internal"
11 | "github.com/derailed/popeye/internal/db"
12 | "github.com/derailed/popeye/internal/test"
13 | "github.com/stretchr/testify/assert"
14 | v1 "k8s.io/api/core/v1"
15 | )
16 |
17 | func TestServiceAccountRefs(t *testing.T) {
18 | dba, err := test.NewTestDB()
19 | assert.NoError(t, err)
20 | l := db.NewLoader(dba)
21 |
22 | ctx := test.MakeCtx(t)
23 | assert.NoError(t, test.LoadDB[*v1.ServiceAccount](ctx, l.DB, "core/sa/1.yaml", internal.Glossary[internal.SA]))
24 |
25 | uu := []struct {
26 | keys []string
27 | }{
28 | {
29 | []string{
30 | "sec:default/s1",
31 | "sec:default/bozo",
32 | },
33 | },
34 | }
35 |
36 | var refs sync.Map
37 | sa := NewServiceAccount(dba)
38 | assert.NoError(t, sa.ServiceAccountRefs(&refs))
39 | for _, u := range uu {
40 | for _, k := range u.keys {
41 | v, ok := refs.Load(k)
42 | assert.True(t, ok)
43 | assert.Equal(t, internal.AllKeys, v.(internal.StringSet))
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/internal/cache/testdata/auth/cr/1.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: List
4 | items:
5 | - apiVersion: rbac.authorization.k8s.io/v1
6 | kind: ClusterRole
7 | metadata:
8 | annotations:
9 | rbac.authorization.kubernetes.io/autoupdate: "true"
10 | name: cr4
11 | aggregationRule:
12 | clusterRoleSelectors:
13 | - matchLabels:
14 | rbac.authorization.k8s.io/aggregate-to-cr4: "true"
15 | - apiVersion: rbac.authorization.k8s.io/v1
16 | kind: ClusterRole
17 | metadata:
18 | labels:
19 | rbac.authorization.k8s.io/aggregate-to-cr4: "true"
20 | name: cr5
21 | rules:
22 | - apiGroups:
23 | - ""
24 | resources:
25 | - pods
26 | verbs:
27 | - list
--------------------------------------------------------------------------------
/internal/cache/testdata/auth/crb/1.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: List
4 | items:
5 | - apiVersion: rbac.authorization.k8s.io/v1
6 | kind: ClusterRoleBinding
7 | metadata:
8 | name: crb1
9 | subjects:
10 | - kind: User
11 | name: fred
12 | apiGroup: rbac.authorization.k8s.io
13 | roleRef:
14 | kind: ClusterRole
15 | name: cr1
16 | apiGroup: rbac.authorization.k8s.io
17 | - apiVersion: rbac.authorization.k8s.io/v1
18 | kind: ClusterRoleBinding
19 | metadata:
20 | name: crb2
21 | subjects:
22 | - kind: ServiceAccount
23 | name: sa2
24 | namespace: default
25 | apiGroup: rbac.authorization.k8s.io
26 | roleRef:
27 | kind: ClusterRole
28 | name: cr-bozo
29 | apiGroup: rbac.authorization.k8s.io
30 | - apiVersion: rbac.authorization.k8s.io/v1
31 | kind: ClusterRoleBinding
32 | metadata:
33 | name: crb3
34 | subjects:
35 | - kind: ServiceAccount
36 | name: sa-bozo
37 | namespace: default
38 | apiGroup: rbac.authorization.k8s.io
39 | roleRef:
40 | kind: Role
41 | name: r1
42 | namespace: blee
43 | apiGroup: rbac.authorization.k8s.io
--------------------------------------------------------------------------------
/internal/cache/testdata/auth/rob/1.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: List
4 | items:
5 | - apiVersion: rbac.authorization.k8s.io/v1
6 | kind: RoleBinding
7 | metadata:
8 | name: rb1
9 | namespace: default
10 | subjects:
11 | - kind: User
12 | name: fred
13 | apiGroup: rbac.authorization.k8s.io
14 | roleRef:
15 | kind: Role
16 | name: r1
17 | apiGroup: rbac.authorization.k8s.io
18 | - apiVersion: rbac.authorization.k8s.io/v1
19 | kind: RoleBinding
20 | metadata:
21 | name: rb2
22 | namespace: default
23 | subjects:
24 | - kind: ServiceAccount
25 | name: sa-bozo
26 | apiGroup: rbac.authorization.k8s.io
27 | roleRef:
28 | kind: Role
29 | name: r-bozo
30 | apiGroup: rbac.authorization.k8s.io
31 | - apiVersion: rbac.authorization.k8s.io/v1
32 | kind: RoleBinding
33 | metadata:
34 | name: rb3
35 | namespace: default
36 | subjects:
37 | - kind: ServiceAccount
38 | name: sa-bozo
39 | apiGroup: rbac.authorization.k8s.io
40 | roleRef:
41 | kind: ClusterRole
42 | name: cr-bozo
43 | apiGroup: rbac.authorization.k8s.io
--------------------------------------------------------------------------------
/internal/cache/testdata/core/sa/1.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: List
4 | items:
5 | - apiVersion: v1
6 | kind: ServiceAccount
7 | metadata:
8 | name: default
9 | namespace: default
10 | - apiVersion: v1
11 | kind: ServiceAccount
12 | metadata:
13 | name: sa1
14 | namespace: default
15 | automountServiceAccountToken: false
16 | - apiVersion: v1
17 | kind: ServiceAccount
18 | metadata:
19 | name: sa2
20 | namespace: default
21 | automountServiceAccountToken: true
22 | - apiVersion: v1
23 | kind: ServiceAccount
24 | metadata:
25 | name: sa3
26 | namespace: default
27 | automountServiceAccountToken: true
28 | - apiVersion: v1
29 | kind: ServiceAccount
30 | metadata:
31 | name: sa4
32 | namespace: default
33 | automountServiceAccountToken: false
34 | secrets:
35 | - kind: Secret
36 | namespace: default
37 | name: bozo
38 | apiVersion: v1
39 | imagePullSecrets:
40 | - name: s1
41 | namespace: fred
42 | - apiVersion: v1
43 | kind: ServiceAccount
44 | metadata:
45 | name: sa5
46 | namespace: default
47 | automountServiceAccountToken: false
48 | secrets:
49 | - kind: Secret
50 | namespace: default
51 | name: s1
52 | apiVersion: v1
53 | imagePullSecrets:
54 | - name: bozo
55 |
--------------------------------------------------------------------------------
/internal/cache/testdata/mx/node/1.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: List
3 | items:
4 | - apiVersion: metrics.k8s.io/v1beta1
5 | kind: NodeMetrics
6 | metadata:
7 | name: n1
8 | usage:
9 | cpu: 2
10 | memory: 200Mi
11 |
--------------------------------------------------------------------------------
/internal/cache/types.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package cache
5 |
6 | const (
7 | // SecretKey tracks Secret resource references
8 | SecretKey = "sec"
9 |
10 | // ClusterRoleKey tracks ClusterRole resource references
11 | ClusterRoleKey = "clusterrole"
12 |
13 | // ConfigMapKey tracks ConfigMap resource references
14 | ConfigMapKey = "cm"
15 | )
16 |
--------------------------------------------------------------------------------
/internal/cilium/cache/cep.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package cache
5 |
6 | import (
7 | "fmt"
8 | "strconv"
9 | "sync"
10 |
11 | v2 "github.com/cilium/cilium/pkg/k8s/apis/cilium.io/v2"
12 | "github.com/derailed/popeye/internal"
13 | icache "github.com/derailed/popeye/internal/cache"
14 | "github.com/derailed/popeye/internal/cilium"
15 | "github.com/derailed/popeye/internal/db"
16 | )
17 |
18 | const CIDKey = "cid"
19 |
20 | // CiliumEndpoint represents a CiliumEndpoint cache.
21 | type CiliumEndpoint struct {
22 | db *db.DB
23 | }
24 |
25 | // NewCiliumEndpoint returns a CiliumEndpoint cache.
26 | func NewCiliumEndpoint(dba *db.DB) *CiliumEndpoint {
27 | return &CiliumEndpoint{db: dba}
28 | }
29 |
30 | // CEPRefs computes all CiliumEndpoints external references.
31 | func (p *CiliumEndpoint) CEPRefs(refs *sync.Map) error {
32 | txn, it := p.db.MustITFor(internal.Glossary[cilium.CEP])
33 | defer txn.Abort()
34 | for o := it.Next(); o != nil; o = it.Next() {
35 | cep, ok := o.(*v2.CiliumEndpoint)
36 | if !ok {
37 | return fmt.Errorf("expected a CiliumEndpoint but got %T", o)
38 | }
39 | if cep.Status.Identity != nil {
40 | key := icache.ResFqn(CIDKey, icache.FQN("", strconv.Itoa(int(cep.Status.Identity.ID))))
41 | refs.Store(key, internal.AllKeys)
42 | }
43 | }
44 |
45 | return nil
46 | }
47 |
--------------------------------------------------------------------------------
/internal/cilium/cilium.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package cilium
5 |
6 | import (
7 | "github.com/derailed/popeye/internal"
8 | "github.com/derailed/popeye/types"
9 | )
10 |
11 | func init() {
12 | for _, r := range CiliumRS {
13 | internal.Glossary[r] = types.BlankGVR
14 | }
15 | }
16 |
17 | const (
18 | CEP internal.R = "ciliumendpoints"
19 | CID internal.R = "ciliumidentities"
20 | CNP internal.R = "ciliumnetworkpolicies"
21 | CCNP internal.R = "ciliumclusterwidenetworkpolicies"
22 | )
23 |
24 | var CiliumRS = []internal.R{CEP, CID, CNP, CCNP}
25 |
26 | var Aliases = internal.ShortNames{
27 | CEP: {"cep"},
28 | CID: {"cid"},
29 | }
30 |
--------------------------------------------------------------------------------
/internal/cilium/scrub/scrubers.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "github.com/derailed/popeye/internal"
8 | "github.com/derailed/popeye/internal/cilium"
9 | iscrub "github.com/derailed/popeye/internal/scrub"
10 | )
11 |
12 | func Inject(ss map[internal.R]iscrub.ScrubFn) {
13 | ss[cilium.CEP] = NewCiliumEndpoint
14 | ss[cilium.CID] = NewCiliumIdentity
15 | ss[cilium.CNP] = NewCiliumNetworkPolicy
16 | ss[cilium.CCNP] = NewCiliumClusterwideNetworkPolicy
17 | }
18 |
--------------------------------------------------------------------------------
/internal/client/client_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package client
5 |
6 | import (
7 | "testing"
8 |
9 | "github.com/stretchr/testify/assert"
10 | )
11 |
12 | func TestIsSet(t *testing.T) {
13 | s1, s2 := "fred", ""
14 |
15 | uu := []struct {
16 | s *string
17 | e bool
18 | }{
19 | {&s1, true},
20 | {&s2, false},
21 | {nil, false},
22 | }
23 |
24 | for _, u := range uu {
25 | assert.Equal(t, u.e, isSet(u.s))
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/internal/client/helper_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package client_test
5 |
6 | import (
7 | "testing"
8 |
9 | "github.com/derailed/popeye/internal/client"
10 | "github.com/stretchr/testify/assert"
11 | )
12 |
13 | func TestNamespaced(t *testing.T) {
14 | uu := []struct {
15 | p, ns, n string
16 | }{
17 | {"fred/blee", "fred", "blee"},
18 | {"blee", "", "blee"},
19 | }
20 |
21 | for _, u := range uu {
22 | ns, n := client.Namespaced(u.p)
23 | assert.Equal(t, u.ns, ns)
24 | assert.Equal(t, u.n, n)
25 | }
26 | }
27 |
28 | func TestFQN(t *testing.T) {
29 | uu := []struct {
30 | ns, n string
31 | e string
32 | }{
33 | {"fred", "blee", "fred/blee"},
34 | {"", "blee", "blee"},
35 | }
36 |
37 | for _, u := range uu {
38 | assert.Equal(t, u.e, client.FQN(u.ns, u.n))
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/internal/client/metrics.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package client
5 |
6 | import (
7 | "k8s.io/apimachinery/pkg/api/resource"
8 | )
9 |
10 | type (
11 | // Metrics represent an aggregation of all pod containers metrics.
12 | Metrics struct {
13 | CurrentCPU resource.Quantity
14 | CurrentMEM resource.Quantity
15 | }
16 |
17 | // NodeMetrics describes raw node metrics.
18 | NodeMetrics struct {
19 | CurrentCPU resource.Quantity
20 | CurrentMEM resource.Quantity
21 | AvailableCPU resource.Quantity
22 | AvailableMEM resource.Quantity
23 | TotalCPU resource.Quantity
24 | TotalMEM resource.Quantity
25 | }
26 |
27 | // NodesMetrics tracks usage metrics per nodes.
28 | NodesMetrics map[string]NodeMetrics
29 |
30 | // PodsMetrics tracks usage metrics per pods.
31 | PodsMetrics map[string]ContainerMetrics
32 |
33 | // ContainerMetrics tracks container metrics
34 | ContainerMetrics map[string]Metrics
35 | )
36 |
37 | // Empty checks if we have any metrics.
38 | func (n NodeMetrics) Empty() bool {
39 | return n == NodeMetrics{}
40 | }
41 |
42 | // Empty checks if we have any metrics.
43 | func (m Metrics) Empty() bool {
44 | return m == Metrics{}
45 | }
46 |
--------------------------------------------------------------------------------
/internal/client/metrics_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package client
5 |
6 | import (
7 | "testing"
8 |
9 | "github.com/stretchr/testify/assert"
10 | "k8s.io/apimachinery/pkg/api/resource"
11 | )
12 |
13 | func TestNodeMetricsEmpty(t *testing.T) {
14 | uu := []struct {
15 | m NodeMetrics
16 | e bool
17 | }{
18 | {NodeMetrics{}, true},
19 | {NodeMetrics{CurrentCPU: toQty("100m")}, false},
20 | }
21 |
22 | for _, u := range uu {
23 | assert.Equal(t, u.e, u.m.Empty())
24 | }
25 | }
26 |
27 | func TestMetricsEmpty(t *testing.T) {
28 | uu := []struct {
29 | m Metrics
30 | e bool
31 | }{
32 | {Metrics{}, true},
33 | {Metrics{CurrentCPU: toQty("100m")}, false},
34 | }
35 |
36 | for _, u := range uu {
37 | assert.Equal(t, u.e, u.m.Empty())
38 | }
39 | }
40 |
41 | // Helpers...
42 |
43 | func toQty(s string) resource.Quantity {
44 | q, _ := resource.ParseQuantity(s)
45 |
46 | return q
47 | }
48 |
--------------------------------------------------------------------------------
/internal/client/revision.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package client
5 |
6 | import (
7 | "fmt"
8 | "regexp"
9 | "strconv"
10 |
11 | "k8s.io/apimachinery/pkg/version"
12 | )
13 |
14 | // Revision tracks server version.
15 | type Revision struct {
16 | Info *version.Info
17 | Major, Minor int
18 | }
19 |
20 | var minorRX = regexp.MustCompile(`(\d+)\+?`)
21 |
22 | // NewRevision returns a new instance.
23 | func NewRevision(info *version.Info) (*Revision, error) {
24 | major, err := strconv.Atoi(info.Major)
25 | if err != nil {
26 | return nil, fmt.Errorf("unable to extract major %q", info.Major)
27 | }
28 | minors := minorRX.FindStringSubmatch(info.Minor)
29 | if len(minors) < 2 {
30 | return nil, fmt.Errorf("unable to extract minor %q", info.Minor)
31 | }
32 | minor, err := strconv.Atoi(minors[1])
33 | if err != nil {
34 | return nil, err
35 | }
36 | return &Revision{Info: info, Major: major, Minor: minor}, nil
37 | }
38 |
--------------------------------------------------------------------------------
/internal/client/revision_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package client_test
5 |
6 | import (
7 | "testing"
8 |
9 | "github.com/derailed/popeye/internal/client"
10 | "github.com/stretchr/testify/assert"
11 | "k8s.io/apimachinery/pkg/version"
12 | )
13 |
14 | func TestNewRevision(t *testing.T) {
15 | uu := map[string]struct {
16 | info *version.Info
17 | major, minor int
18 | }{
19 | "plain": {
20 | info: &version.Info{Major: "1", Minor: "18+"},
21 | major: 1,
22 | minor: 18,
23 | },
24 | "no-plus": {
25 | info: &version.Info{Major: "1", Minor: "18"},
26 | major: 1,
27 | minor: 18,
28 | },
29 | }
30 |
31 | for k := range uu {
32 | u := uu[k]
33 | t.Run(k, func(t *testing.T) {
34 | r, err := client.NewRevision(u.info)
35 | assert.Nil(t, err)
36 | assert.Equal(t, u.major, r.Major)
37 | assert.Equal(t, u.minor, r.Minor)
38 | })
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/internal/client/testdata/config:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: Config
3 | preferences: {}
4 | clusters:
5 | - cluster:
6 | insecure-skip-tls-verify: true
7 | server: https://localhost:3000
8 | name: fred
9 | - cluster:
10 | insecure-skip-tls-verify: true
11 | server: https://localhost:3001
12 | name: blee
13 | - cluster:
14 | insecure-skip-tls-verify: true
15 | server: https://localhost:3002
16 | name: duh
17 | contexts:
18 | - context:
19 | cluster: fred
20 | user: fred
21 | name: fred
22 | - context:
23 | cluster: blee
24 | user: blee
25 | name: blee
26 | - context:
27 | cluster: duh
28 | user: duh
29 | name: duh
30 | current-context: fred
31 | users:
32 | - name: fred
33 | user:
34 | client-certificate-data: ZnJlZA==
35 | client-key-data: ZnJlZA==
36 | - name: blee
37 | user:
38 | client-certificate-data: ZnJlZA==
39 | client-key-data: ZnJlZA==
40 | - name: duh
41 | user:
42 | client-certificate-data: ZnJlZA==
43 | client-key-data: ZnJlZA==
44 |
--------------------------------------------------------------------------------
/internal/client/testdata/config.1:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | clusters:
3 | - cluster:
4 | insecure-skip-tls-verify: true
5 | server: https://localhost:3001
6 | name: blee
7 | - cluster:
8 | insecure-skip-tls-verify: true
9 | server: https://localhost:3002
10 | name: duh
11 | - cluster:
12 | insecure-skip-tls-verify: true
13 | server: https://localhost:3000
14 | name: fred
15 | contexts:
16 | - context:
17 | cluster: blee
18 | user: blee
19 | name: blee
20 | - context:
21 | cluster: duh
22 | user: duh
23 | name: duh
24 | current-context: fred
25 | kind: Config
26 | preferences: {}
27 | users:
28 | - name: blee
29 | user:
30 | client-certificate-data: ZnJlZA==
31 | client-key-data: ZnJlZA==
32 | - name: duh
33 | user:
34 | client-certificate-data: ZnJlZA==
35 | client-key-data: ZnJlZA==
36 | - name: fred
37 | user:
38 | client-certificate-data: ZnJlZA==
39 | client-key-data: ZnJlZA==
40 |
--------------------------------------------------------------------------------
/internal/client/types.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package client
5 |
6 | const (
7 | // NA Not available
8 | NA = "n/a"
9 |
10 | // NamespaceAll designates the fictional all namespace.
11 | NamespaceAll = "all"
12 |
13 | // AllNamespaces designates all namespaces.
14 | AllNamespaces = ""
15 |
16 | // ClusterScope designates a resource is not namespaced.
17 | ClusterScope = "-"
18 |
19 | // NotNamespaced designates a non resource namespace.
20 | NotNamespaced = "*"
21 |
22 | // BlankNamespace tracks an unspecified namespace.
23 | BlankNamespace = ""
24 |
25 | // DefaultNamespace tracks the default namespace.
26 | DefaultNamespace = "default"
27 | )
28 |
--------------------------------------------------------------------------------
/internal/dag/cluster.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package dag
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/blang/semver/v4"
10 | )
11 |
12 | // ListVersion return server api version.
13 | func ListVersion(ctx context.Context) (*semver.Version, error) {
14 | f := mustExtractFactory(ctx)
15 | dial, err := f.Client().Dial()
16 | if err != nil {
17 | return nil, err
18 | }
19 | info, err := dial.Discovery().ServerVersion()
20 | if err != nil {
21 | return nil, err
22 | }
23 |
24 | return ParseVersion(info)
25 | }
26 |
--------------------------------------------------------------------------------
/internal/dag/helpers.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package dag
5 |
6 | import (
7 | "context"
8 | "fmt"
9 | "strings"
10 |
11 | "github.com/blang/semver/v4"
12 | "github.com/derailed/popeye/internal"
13 | "github.com/derailed/popeye/types"
14 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
15 | "k8s.io/apimachinery/pkg/version"
16 | )
17 |
18 | // ParseVersion renders cluster info version into semver rev.
19 | func ParseVersion(info *version.Info) (*semver.Version, error) {
20 | if info == nil {
21 | return nil, fmt.Errorf("no cluster version available")
22 | }
23 | v := strings.TrimSuffix(info.Major+"."+info.Minor, "+")
24 | rev, err := semver.ParseTolerant(v)
25 | if err != nil {
26 | err = fmt.Errorf("semver parse failed for %q (%q|%q): %w", v, info.Major, info.Minor, err)
27 | }
28 |
29 | return &rev, err
30 | }
31 |
32 | func mustExtractFactory(ctx context.Context) types.Factory {
33 | f, ok := ctx.Value(internal.KeyFactory).(types.Factory)
34 | if !ok {
35 | panic("expecting factory in context")
36 | }
37 | return f
38 | }
39 |
40 | // MetaFQN returns a full qualified ns/name string.
41 | func metaFQN(m metav1.ObjectMeta) string {
42 | if m.Namespace == "" {
43 | return m.Name
44 | }
45 |
46 | return m.Namespace + "/" + m.Name
47 | }
48 |
--------------------------------------------------------------------------------
/internal/dao/non_resource.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package dao
5 |
6 | import (
7 | "context"
8 | "fmt"
9 |
10 | "github.com/derailed/popeye/types"
11 | "k8s.io/apimachinery/pkg/runtime"
12 | )
13 |
14 | // NonResource represents a non k8s resource.
15 | type NonResource struct {
16 | types.Factory
17 |
18 | gvr types.GVR
19 | }
20 |
21 | // Init initializes the resource.
22 | func (n *NonResource) Init(f types.Factory, gvr types.GVR) {
23 | n.Factory, n.gvr = f, gvr
24 | }
25 |
26 | // GVR returns a gvr.
27 | func (n *NonResource) GVR() string {
28 | return n.gvr.String()
29 | }
30 |
31 | // Get returns the given resource.
32 | func (n *NonResource) Get(context.Context, string) (runtime.Object, error) {
33 | return nil, fmt.Errorf("NYI!")
34 | }
35 |
--------------------------------------------------------------------------------
/internal/dao/resource.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package dao
5 |
6 | import (
7 | "context"
8 | "fmt"
9 |
10 | "github.com/derailed/popeye/internal"
11 | "github.com/derailed/popeye/internal/client"
12 | "k8s.io/apimachinery/pkg/labels"
13 | "k8s.io/apimachinery/pkg/runtime"
14 | )
15 |
16 | var _ Accessor = (*Resource)(nil)
17 |
18 | // Resource represents an informer based resource.
19 | type Resource struct {
20 | Generic
21 | }
22 |
23 | // List returns a collection of resources.
24 | func (r *Resource) List(ctx context.Context) ([]runtime.Object, error) {
25 | strLabel, ok := ctx.Value(internal.KeyLabels).(string)
26 | lsel := labels.Everything()
27 | if sel, err := labels.ConvertSelectorToLabelsMap(strLabel); ok && err == nil {
28 | lsel = sel.AsSelector()
29 | }
30 | ns, ok := ctx.Value(internal.KeyNamespace).(string)
31 | if !ok {
32 | return nil, fmt.Errorf("BOOM!! no namespace found in context %s", r.gvr)
33 | }
34 | if r.gvr == internal.Glossary[internal.NS] {
35 | ns = client.AllNamespaces
36 | }
37 |
38 | return r.Factory.List(r.gvr, ns, true, lsel)
39 | }
40 |
41 | // Get returns a resource instance if found, else an error.
42 | func (r *Resource) Get(_ context.Context, path string) (runtime.Object, error) {
43 | return r.Factory.Get(r.gvr, path, true, labels.Everything())
44 | }
45 |
--------------------------------------------------------------------------------
/internal/dao/types.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package dao
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/types"
10 | metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
11 | "k8s.io/apimachinery/pkg/runtime"
12 | )
13 |
14 | // ResourceMetas represents a collection of resource metadata.
15 | type ResourceMetas map[types.GVR]metav1.APIResource
16 |
17 | // Getter represents a resource getter.
18 | type Getter interface {
19 | // Get return a given resource.
20 | Get(ctx context.Context, path string) (runtime.Object, error)
21 | }
22 |
23 | // Lister represents a resource lister.
24 | type Lister interface {
25 | // List returns a resource collection.
26 | List(ctx context.Context) ([]runtime.Object, error)
27 | }
28 |
29 | // Accessor represents an accessible k8s resource.
30 | type Accessor interface {
31 | Lister
32 | Getter
33 |
34 | // Init the resource with a factory object.
35 | Init(types.Factory, types.GVR)
36 |
37 | // GVR returns a gvr a string.
38 | GVR() string
39 | }
40 |
--------------------------------------------------------------------------------
/internal/db/schema/k8s.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package schema
5 |
6 | import (
7 | "github.com/derailed/popeye/internal"
8 | "github.com/derailed/popeye/types"
9 | "github.com/hashicorp/go-memdb"
10 | )
11 |
12 | // Init initializes db tables.
13 | func Init() *memdb.DBSchema {
14 | var sc memdb.DBSchema
15 | sc.Tables = make(map[string]*memdb.TableSchema)
16 | for _, gvr := range internal.Glossary {
17 | if gvr == types.BlankGVR {
18 | continue
19 | }
20 | sc.Tables[gvr.String()] = indexFor(gvr.String())
21 | }
22 |
23 | return &sc
24 | }
25 |
--------------------------------------------------------------------------------
/internal/db/types.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package db
5 |
6 | import "k8s.io/apimachinery/pkg/runtime"
7 |
8 | type ConvertFn func(o runtime.Object) (any, error)
9 |
--------------------------------------------------------------------------------
/internal/issues/codes.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package issues
5 |
6 | import (
7 | _ "embed"
8 |
9 | "github.com/derailed/popeye/internal/rules"
10 | "gopkg.in/yaml.v2"
11 | )
12 |
13 | //go:embed assets/codes.yaml
14 | var codes string
15 |
16 | // Codes represents a collection of linter codes.
17 | type Codes struct {
18 | Glossary rules.Glossary `yaml:"codes"`
19 | }
20 |
21 | // LoadCodes retrieves linters codes from yaml file.
22 | func LoadCodes() (*Codes, error) {
23 | var cc Codes
24 | if err := yaml.Unmarshal([]byte(codes), &cc); err != nil {
25 | return &cc, err
26 | }
27 |
28 | return &cc, nil
29 | }
30 |
31 | // Refine overrides code severity based on user input.
32 | func (c *Codes) Refine(oo rules.Overrides) {
33 | for _, ov := range oo {
34 | c, ok := c.Glossary[ov.ID]
35 | if !ok {
36 | continue
37 | }
38 | if validSeverity(ov.Severity) {
39 | c.Severity = ov.Severity
40 | }
41 | if ov.Message != "" {
42 | c.Message = ov.Message
43 | }
44 | }
45 | }
46 |
47 | // Helpers...
48 |
49 | func validSeverity(l rules.Level) bool {
50 | return l > 0 && l < 4
51 | }
52 |
--------------------------------------------------------------------------------
/internal/issues/codes_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package issues_test
5 |
6 | import (
7 | "testing"
8 |
9 | "github.com/derailed/popeye/internal/issues"
10 | "github.com/derailed/popeye/internal/rules"
11 | "github.com/stretchr/testify/assert"
12 | )
13 |
14 | func TestCodesLoad(t *testing.T) {
15 | cc, err := issues.LoadCodes()
16 |
17 | assert.Nil(t, err)
18 | assert.Equal(t, 117, len(cc.Glossary))
19 | assert.Equal(t, "No liveness probe", cc.Glossary[103].Message)
20 | assert.Equal(t, rules.WarnLevel, cc.Glossary[103].Severity)
21 | }
22 |
23 | func TestRefine(t *testing.T) {
24 | cc, err := issues.LoadCodes()
25 | assert.Nil(t, err)
26 |
27 | ov := rules.Overrides{
28 | rules.CodeOverride{
29 | ID: 0,
30 | Message: "blah",
31 | Severity: rules.InfoLevel,
32 | },
33 |
34 | rules.CodeOverride{
35 | ID: 100,
36 | Message: "blah",
37 | Severity: rules.InfoLevel,
38 | },
39 |
40 | rules.CodeOverride{
41 | ID: 101,
42 | Message: "blah",
43 | Severity: 1000,
44 | },
45 | }
46 | cc.Refine(ov)
47 |
48 | assert.Equal(t, rules.InfoLevel, cc.Glossary[100].Severity)
49 | assert.Equal(t, rules.WarnLevel, cc.Glossary[101].Severity)
50 | }
51 |
--------------------------------------------------------------------------------
/internal/issues/issue_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package issues
5 |
6 | import (
7 | "testing"
8 |
9 | "github.com/derailed/popeye/internal/rules"
10 | "github.com/derailed/popeye/types"
11 | "github.com/stretchr/testify/assert"
12 | )
13 |
14 | func TestIsSubIssues(t *testing.T) {
15 | uu := map[string]struct {
16 | i Issue
17 | e bool
18 | }{
19 | "root": {New(types.NewGVR("fred"), Root, rules.WarnLevel, "blah"), false},
20 | "rootf": {Newf(types.NewGVR("fred"), Root, rules.WarnLevel, "blah %s", "blee"), false},
21 | "sub": {New(types.NewGVR("fred"), "sub1", rules.WarnLevel, "blah"), true},
22 | "subf": {Newf(types.NewGVR("fred"), "sub1", rules.WarnLevel, "blah %s", "blee"), true},
23 | }
24 |
25 | for k := range uu {
26 | u := uu[k]
27 | t.Run(k, func(t *testing.T) {
28 | assert.Equal(t, u.e, u.i.IsSubIssue())
29 | })
30 | }
31 | }
32 |
33 | func TestBlank(t *testing.T) {
34 | uu := map[string]struct {
35 | i Issue
36 | e bool
37 | }{
38 | "blank": {Issue{}, true},
39 | "notBlank": {New(types.NewGVR("fred"), Root, rules.WarnLevel, "blah"), false},
40 | }
41 |
42 | for k := range uu {
43 | u := uu[k]
44 | t.Run(k, func(t *testing.T) {
45 | assert.Equal(t, u.e, u.i.Blank())
46 | })
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/internal/issues/tally/code.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package tally
5 |
6 | import (
7 | "slices"
8 | "strconv"
9 |
10 | "github.com/derailed/popeye/internal/rules"
11 | "github.com/rs/zerolog/log"
12 | )
13 |
14 | // SevScore tracks per level total score.
15 | type SevScore map[rules.Level]int
16 |
17 | // Code tracks code issue counts.
18 | type Code map[string]int
19 |
20 | // Compact removes zero entries.
21 | func (cc Code) Compact() {
22 | for c, v := range cc {
23 | if v == 0 {
24 | delete(cc, c)
25 | }
26 | }
27 | }
28 |
29 | // Rollup rollups code scores per severity.
30 | func (cc Code) Rollup(gg rules.Glossary) SevScore {
31 | if len(cc) == 0 {
32 | return nil
33 | }
34 | ss := make(SevScore, len(cc))
35 | for sid, count := range cc {
36 | id, _ := strconv.Atoi(sid)
37 | c := gg[rules.ID(id)]
38 | ss[c.Severity] += count
39 | }
40 |
41 | return ss
42 | }
43 |
44 | // Merge merges two sets.
45 | func (cc Code) Merge(cc1 Code) {
46 | for code, count := range cc1 {
47 | cc[code] += count
48 | }
49 | }
50 |
51 | // Dump for debugging.
52 | func (cc Code) Dump(indent string) {
53 | kk := make([]string, 0, len(cc))
54 | for k := range cc {
55 | kk = append(kk, k)
56 | }
57 | slices.Sort(kk)
58 | for _, k := range kk {
59 | log.Debug().Msgf("%s%s: %d", indent, k, cc[k])
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/internal/issues/tally/linter.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package tally
5 |
6 | import (
7 | "slices"
8 |
9 | "github.com/rs/zerolog/log"
10 | )
11 |
12 | // Linter tracks linters namespace tallies.
13 | type Linter map[string]Namespace
14 |
15 | func (l Linter) Compact() {
16 | for linter, v := range l {
17 | v.Compact()
18 | if len(v) == 0 {
19 | delete(l, linter)
20 | }
21 | }
22 | }
23 |
24 | func (s Linter) Dump() {
25 | kk := make([]string, 0, len(s))
26 | for k := range s {
27 | kk = append(kk, k)
28 | }
29 | slices.Sort(kk)
30 | for _, k := range kk {
31 | log.Debug().Msgf("%s", k)
32 | s[k].Dump(" ")
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/internal/issues/tally/ns.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package tally
5 |
6 | import (
7 | "slices"
8 | "strings"
9 |
10 | "github.com/rs/zerolog/log"
11 | )
12 |
13 | // Namespace tracks each namespace code tally.
14 | type Namespace map[string]Code
15 |
16 | // Compact compacts set by removing zero entries.
17 | func (nn Namespace) Compact() {
18 | for ns, v := range nn {
19 | v.Compact()
20 | if len(v) == 0 {
21 | delete(nn, ns)
22 | }
23 | }
24 | }
25 |
26 | // Merge merges 2 sets.
27 | func (nn Namespace) Merge(t Namespace) {
28 | for k, v := range t {
29 | if v1, ok := nn[k]; ok {
30 | nn[k].Merge(v1)
31 | } else {
32 | nn[k] = v
33 | }
34 | }
35 | }
36 |
37 | // Dump for debugging.
38 | func (s Namespace) Dump(indent string) {
39 | kk := make([]string, 0, len(s))
40 | for k := range s {
41 | kk = append(kk, k)
42 | }
43 | slices.Sort(kk)
44 | for _, k := range kk {
45 | log.Debug().Msgf("%s%s", indent, k)
46 | s[k].Dump(strings.Repeat(indent, 2))
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/internal/keys.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package internal
5 |
6 | // ContextKey represents context key.
7 | type ContextKey string
8 |
9 | // A collection of context keys.
10 | const (
11 | KeyFactory ContextKey = "factory"
12 | KeyLabels ContextKey = "labels"
13 | KeyFields ContextKey = "fields"
14 | KeyOverAllocs ContextKey = "overAllocs"
15 | KeyRunInfo ContextKey = "runInfo"
16 | KeyConfig ContextKey = "config"
17 | KeyNamespace ContextKey = "namespace"
18 | KeyVersion ContextKey = "version"
19 | KeyDB ContextKey = "db"
20 | KeyNamespaceName ContextKey = "namespaceName"
21 | )
22 |
--------------------------------------------------------------------------------
/internal/lint/cluster.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package lint
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/blang/semver/v4"
10 | "github.com/derailed/popeye/internal"
11 | "github.com/derailed/popeye/internal/issues"
12 | )
13 |
14 | const (
15 | tolerableMajor = 1
16 | tolerableMinor = 21
17 | )
18 |
19 | type (
20 | // Cluster tracks cluster sanitization.
21 | Cluster struct {
22 | *issues.Collector
23 | ClusterLister
24 | }
25 |
26 | // ClusterLister list available Clusters on a cluster.
27 | ClusterLister interface {
28 | ListVersion() (*semver.Version, error)
29 | HasMetrics() bool
30 | }
31 | )
32 |
33 | // NewCluster returns a new instance.
34 | func NewCluster(co *issues.Collector, lister ClusterLister) *Cluster {
35 | return &Cluster{
36 | Collector: co,
37 | ClusterLister: lister,
38 | }
39 | }
40 |
41 | // Lint cleanse the resource.
42 | func (c *Cluster) Lint(ctx context.Context) error {
43 | return c.checkVersion(ctx)
44 | }
45 |
46 | func (c *Cluster) checkVersion(ctx context.Context) error {
47 | rev, err := c.ListVersion()
48 | if err != nil {
49 | return err
50 | }
51 |
52 | ctx = internal.WithSpec(ctx, SpecFor("Version", nil))
53 | if rev.Major != tolerableMajor || rev.Minor < tolerableMinor {
54 | c.AddCode(ctx, 405)
55 | } else {
56 | c.AddCode(ctx, 406)
57 | }
58 |
59 | return nil
60 | }
61 |
--------------------------------------------------------------------------------
/internal/lint/container_bench_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package lint
5 |
6 | import (
7 | "context"
8 | "testing"
9 |
10 | v1 "k8s.io/api/core/v1"
11 | )
12 |
13 | func BenchmarkContainerCheckImageTag(b *testing.B) {
14 | co := v1.Container{
15 | Name: "c1",
16 | Image: "blee",
17 | }
18 | l := NewContainer("", nil)
19 |
20 | b.ResetTimer()
21 | b.ReportAllocs()
22 | ctx := context.Background()
23 | for i := 0; i < b.N; i++ {
24 | l.checkImageTags(ctx, co.Image)
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/internal/lint/gwc_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package lint
5 |
6 | import (
7 | "testing"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/rules"
12 | "github.com/derailed/popeye/internal/test"
13 | "github.com/stretchr/testify/assert"
14 | gwv1 "sigs.k8s.io/gateway-api/apis/v1"
15 | )
16 |
17 | func TestGatewayClassLint(t *testing.T) {
18 | dba, err := test.NewTestDB()
19 | assert.NoError(t, err)
20 | l := db.NewLoader(dba)
21 |
22 | ctx := test.MakeCtx(t)
23 | assert.NoError(t, test.LoadDB[*gwv1.GatewayClass](ctx, l.DB, "net/gwc/1.yaml", internal.Glossary[internal.GWC]))
24 | assert.NoError(t, test.LoadDB[*gwv1.Gateway](ctx, l.DB, "net/gw/1.yaml", internal.Glossary[internal.GW]))
25 |
26 | gwc := NewGatewayClass(test.MakeCollector(t), dba)
27 | assert.Nil(t, gwc.Lint(test.MakeContext("gateway.networking.k8s.io/v1/gatewayclasses", "gatewayclasses")))
28 | assert.Equal(t, 2, len(gwc.Outcome()))
29 |
30 | ii := gwc.Outcome()["gwc1"]
31 | assert.Equal(t, 0, len(ii))
32 |
33 | ii = gwc.Outcome()["gwc2"]
34 | assert.Equal(t, 1, len(ii))
35 | assert.Equal(t, `[POP-400] Used? Unable to locate resource reference`, ii[0].Message)
36 | assert.Equal(t, rules.InfoLevel, ii[0].Level)
37 | }
38 |
--------------------------------------------------------------------------------
/internal/lint/node_bench_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package lint
5 |
6 | // import (
7 | // "testing"
8 |
9 | // "github.com/derailed/popeye/internal/client"
10 | // v1 "k8s.io/api/core/v1"
11 | // )
12 |
13 | // func BenchmarkNodeTaints(b *testing.B) {
14 | // no := makeTaintedNode("n1")
15 | // tt := tolerations{
16 | // "duh:f1": struct{}{},
17 | // "blee:f2": struct{}{},
18 | // }
19 |
20 | // l := NewNode(nil, nil)
21 | // b.ResetTimer()
22 | // b.ReportAllocs()
23 | // for n := 0; n < b.N; n++ {
24 | // l.checkTaints(no, tt)
25 | // }
26 | // }
27 |
28 | // func BenchmarkNodeLint(b *testing.B) {
29 | // no := makeCondNode("n1", v1.NodeReady, v1.ConditionFalse)
30 | // tt := tolerations{
31 | // "duh:f1": struct{}{},
32 | // "blee:f2": struct{}{},
33 | // }
34 |
35 | // l := NewNode(nil, nil)
36 | // b.ResetTimer()
37 | // b.ReportAllocs()
38 | // for n := 0; n < b.N; n++ {
39 | // l.lint(no, k8s.NodeMetrics{}, tt)
40 | // }
41 | // }
42 |
--------------------------------------------------------------------------------
/internal/lint/ns_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package lint
5 |
6 | import (
7 | "testing"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/rules"
12 | "github.com/derailed/popeye/internal/test"
13 | "github.com/stretchr/testify/assert"
14 | v1 "k8s.io/api/core/v1"
15 | )
16 |
17 | func TestNSSanitizer(t *testing.T) {
18 | dba, err := test.NewTestDB()
19 | assert.NoError(t, err)
20 | l := db.NewLoader(dba)
21 | ctx := test.MakeCtx(t)
22 | assert.NoError(t, test.LoadDB[*v1.Namespace](ctx, l.DB, "core/ns/1.yaml", internal.Glossary[internal.NS]))
23 | assert.NoError(t, test.LoadDB[*v1.Pod](ctx, l.DB, "core/pod/1.yaml", internal.Glossary[internal.PO]))
24 |
25 | ns := NewNamespace(test.MakeCollector(t), dba)
26 | assert.Nil(t, ns.Lint(test.MakeContext("v1/namespaces", "ns")))
27 | assert.Equal(t, 3, len(ns.Outcome()))
28 |
29 | ii := ns.Outcome()["default"]
30 | assert.Equal(t, 0, len(ii))
31 |
32 | ii = ns.Outcome()["ns1"]
33 | assert.Equal(t, 1, len(ii))
34 | assert.Equal(t, "[POP-400] Used? Unable to locate resource reference", ii[0].Message)
35 | assert.Equal(t, rules.InfoLevel, ii[0].Level)
36 |
37 | ii = ns.Outcome()["ns2"]
38 | assert.Equal(t, 1, len(ii))
39 | assert.Equal(t, "[POP-800] Namespace is inactive", ii[0].Message)
40 | assert.Equal(t, rules.ErrorLevel, ii[0].Level)
41 | }
42 |
--------------------------------------------------------------------------------
/internal/lint/rs.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package lint
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/client"
11 | "github.com/derailed/popeye/internal/db"
12 | "github.com/derailed/popeye/internal/issues"
13 | appsv1 "k8s.io/api/apps/v1"
14 | )
15 |
16 | // ReplicaSet tracks ReplicaSet sanitization.
17 | type ReplicaSet struct {
18 | *issues.Collector
19 |
20 | db *db.DB
21 | }
22 |
23 | // NewReplicaSet returns a new instance.
24 | func NewReplicaSet(co *issues.Collector, db *db.DB) *ReplicaSet {
25 | return &ReplicaSet{
26 | Collector: co,
27 | db: db,
28 | }
29 | }
30 |
31 | // Lint cleanse the resource.
32 | func (s *ReplicaSet) Lint(ctx context.Context) error {
33 | txn, it := s.db.MustITFor(internal.Glossary[internal.RS])
34 | defer txn.Abort()
35 | for o := it.Next(); o != nil; o = it.Next() {
36 | rs := o.(*appsv1.ReplicaSet)
37 | fqn := client.FQN(rs.Namespace, rs.Name)
38 | s.InitOutcome(fqn)
39 | ctx = internal.WithSpec(ctx, coSpecFor(fqn, rs, rs.Spec.Template.Spec))
40 |
41 | s.checkHealth(ctx, rs)
42 | }
43 |
44 | return nil
45 | }
46 |
47 | func (s *ReplicaSet) checkHealth(ctx context.Context, rs *appsv1.ReplicaSet) {
48 | if rs.Spec.Replicas != nil && *rs.Spec.Replicas != rs.Status.ReadyReplicas {
49 | s.AddCode(ctx, 1120, *rs.Spec.Replicas, rs.Status.ReadyReplicas)
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/internal/lint/rs_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package lint
5 |
6 | import (
7 | "testing"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/rules"
12 | "github.com/derailed/popeye/internal/test"
13 | "github.com/stretchr/testify/assert"
14 | appsv1 "k8s.io/api/apps/v1"
15 | v1 "k8s.io/api/core/v1"
16 | )
17 |
18 | func TestRSLint(t *testing.T) {
19 | dba, err := test.NewTestDB()
20 | assert.NoError(t, err)
21 | l := db.NewLoader(dba)
22 |
23 | ctx := test.MakeCtx(t)
24 | assert.NoError(t, test.LoadDB[*appsv1.ReplicaSet](ctx, l.DB, "apps/rs/1.yaml", internal.Glossary[internal.RS]))
25 | assert.NoError(t, test.LoadDB[*v1.Pod](ctx, l.DB, "core/pod/1.yaml", internal.Glossary[internal.PO]))
26 |
27 | rs := NewReplicaSet(test.MakeCollector(t), dba)
28 | assert.Nil(t, rs.Lint(test.MakeContext("apps/v1/replicasets", "replicasets")))
29 | assert.Equal(t, 2, len(rs.Outcome()))
30 |
31 | ii := rs.Outcome()["default/rs1"]
32 | assert.Equal(t, 0, len(ii))
33 |
34 | ii = rs.Outcome()["default/rs2"]
35 | assert.Equal(t, 1, len(ii))
36 | assert.Equal(t, `[POP-1120] Unhealthy ReplicaSet 2 desired but have 0 ready`, ii[0].Message)
37 | assert.Equal(t, rules.ErrorLevel, ii[0].Level)
38 | }
39 |
--------------------------------------------------------------------------------
/internal/lint/testdata/auth/cr/1.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: List
4 | items:
5 | - apiVersion: rbac.authorization.k8s.io/v1
6 | kind: ClusterRole
7 | metadata:
8 | name: cr1
9 | rules:
10 | - apiGroups: [""]
11 | resources: ["pods"]
12 | verbs: ["get", "watch", "list"]
13 | - apiVersion: rbac.authorization.k8s.io/v1
14 | kind: ClusterRole
15 | metadata:
16 | name: cr2
17 | rules:
18 | - apiGroups: [""]
19 | resources: ["configmaps"]
20 | verbs: ["get", "watch", "list"]
21 | - apiVersion: rbac.authorization.k8s.io/v1
22 | kind: ClusterRole
23 | metadata:
24 | name: cr3
25 | rules:
26 | - apiGroups: [""]
27 | resources: ["secrets"]
28 | verbs: ["get", "watch", "list"]
--------------------------------------------------------------------------------
/internal/lint/testdata/auth/cr/2.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: List
4 | items:
5 | - apiVersion: rbac.authorization.k8s.io/v1
6 | kind: ClusterRole
7 | metadata:
8 | annotations:
9 | rbac.authorization.kubernetes.io/autoupdate: "true"
10 | name: cr4
11 | aggregationRule:
12 | clusterRoleSelectors:
13 | - matchLabels:
14 | rbac.authorization.k8s.io/aggregate-to-cr4: "true"
15 | - apiVersion: rbac.authorization.k8s.io/v1
16 | kind: ClusterRole
17 | metadata:
18 | labels:
19 | rbac.authorization.k8s.io/aggregate-to-cr4: "true"
20 | name: cr5
21 | rules:
22 | - apiGroups:
23 | - ""
24 | resources:
25 | - pods
26 | verbs:
27 | - list
--------------------------------------------------------------------------------
/internal/lint/testdata/auth/crb/1.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: List
4 | items:
5 | - apiVersion: rbac.authorization.k8s.io/v1
6 | kind: ClusterRoleBinding
7 | metadata:
8 | name: crb1
9 | subjects:
10 | - kind: User
11 | name: fred
12 | apiGroup: rbac.authorization.k8s.io
13 | roleRef:
14 | kind: ClusterRole
15 | name: cr1
16 | apiGroup: rbac.authorization.k8s.io
17 | - apiVersion: rbac.authorization.k8s.io/v1
18 | kind: ClusterRoleBinding
19 | metadata:
20 | name: crb2
21 | subjects:
22 | - kind: ServiceAccount
23 | name: sa2
24 | namespace: default
25 | apiGroup: rbac.authorization.k8s.io
26 | roleRef:
27 | kind: ClusterRole
28 | name: cr-bozo
29 | apiGroup: rbac.authorization.k8s.io
30 | - apiVersion: rbac.authorization.k8s.io/v1
31 | kind: ClusterRoleBinding
32 | metadata:
33 | name: crb3
34 | subjects:
35 | - kind: ServiceAccount
36 | name: sa-bozo
37 | namespace: default
38 | apiGroup: rbac.authorization.k8s.io
39 | roleRef:
40 | kind: Role
41 | name: r-bozo
42 | apiGroup: rbac.authorization.k8s.io
--------------------------------------------------------------------------------
/internal/lint/testdata/auth/crb/2.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: List
4 | items:
5 | - apiVersion: rbac.authorization.k8s.io/v1
6 | kind: ClusterRoleBinding
7 | metadata:
8 | name: crb1
9 | subjects:
10 | - kind: ServiceAccount
11 | name: default
12 | namespace: default
13 | apiGroup: rbac.authorization.k8s.io
14 | roleRef:
15 | kind: ClusterRole
16 | name: cr1
17 | apiGroup: rbac.authorization.k8s.io
18 | - apiVersion: rbac.authorization.k8s.io/v1
19 | kind: ClusterRoleBinding
20 | metadata:
21 | name: crb2
22 | subjects:
23 | - kind: ServiceAccount
24 | name: sa2
25 | namespace: default
26 | apiGroup: rbac.authorization.k8s.io
27 | roleRef:
28 | kind: ClusterRole
29 | name: cr-bozo
30 | apiGroup: rbac.authorization.k8s.io
31 | - apiVersion: rbac.authorization.k8s.io/v1
32 | kind: ClusterRoleBinding
33 | metadata:
34 | name: crb3
35 | subjects:
36 | - kind: ServiceAccount
37 | name: sa-bozo
38 | namespace: default
39 | apiGroup: rbac.authorization.k8s.io
40 | roleRef:
41 | kind: Role
42 | name: r-bozo
43 | apiGroup: rbac.authorization.k8s.io
--------------------------------------------------------------------------------
/internal/lint/testdata/auth/ro/1.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: List
4 | items:
5 | - apiVersion: rbac.authorization.k8s.io/v1
6 | kind: Role
7 | metadata:
8 | name: r1
9 | namespace: default
10 | rules:
11 | - apiGroups: [""]
12 | resources: ["pods"]
13 | verbs: ["get", "watch", "list"]
14 | - apiVersion: rbac.authorization.k8s.io/v1
15 | kind: Role
16 | metadata:
17 | name: r2
18 | namespace: default
19 | rules:
20 | - apiGroups: [""]
21 | resources: ["configmaps"]
22 | verbs: ["get", "watch", "list"]
23 | - apiVersion: rbac.authorization.k8s.io/v1
24 | kind: Role
25 | metadata:
26 | name: r3
27 | namespace: default
28 | rules:
29 | - apiGroups: [""]
30 | resources: ["secrets"]
31 | verbs: ["get", "watch", "list"]
--------------------------------------------------------------------------------
/internal/lint/testdata/auth/rob/1.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: List
4 | items:
5 | - apiVersion: rbac.authorization.k8s.io/v1
6 | kind: RoleBinding
7 | metadata:
8 | name: rb1
9 | namespace: default
10 | subjects:
11 | - kind: User
12 | name: fred
13 | apiGroup: rbac.authorization.k8s.io
14 | roleRef:
15 | kind: Role
16 | name: r1
17 | apiGroup: rbac.authorization.k8s.io
18 | - apiVersion: rbac.authorization.k8s.io/v1
19 | kind: RoleBinding
20 | metadata:
21 | name: rb2
22 | namespace: default
23 | subjects:
24 | - kind: ServiceAccount
25 | name: sa-bozo
26 | apiGroup: rbac.authorization.k8s.io
27 | roleRef:
28 | kind: Role
29 | name: r-bozo
30 | apiGroup: rbac.authorization.k8s.io
31 | - apiVersion: rbac.authorization.k8s.io/v1
32 | kind: RoleBinding
33 | metadata:
34 | name: rb3
35 | namespace: default
36 | subjects:
37 | - kind: ServiceAccount
38 | name: sa-bozo
39 | apiGroup: rbac.authorization.k8s.io
40 | roleRef:
41 | kind: ClusterRole
42 | name: cr-bozo
43 | apiGroup: rbac.authorization.k8s.io
--------------------------------------------------------------------------------
/internal/lint/testdata/auth/rob/2.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: List
4 | items:
5 | - apiVersion: rbac.authorization.k8s.io/v1
6 | kind: RoleBinding
7 | metadata:
8 | name: rb1
9 | namespace: default
10 | subjects:
11 | - kind: ServiceAccount
12 | name: default
13 | apiGroup: rbac.authorization.k8s.io
14 | roleRef:
15 | kind: Role
16 | name: r1
17 | apiGroup: rbac.authorization.k8s.io
18 |
19 | - apiVersion: rbac.authorization.k8s.io/v1
20 | kind: RoleBinding
21 | metadata:
22 | name: rb2
23 | namespace: default
24 | subjects:
25 | - kind: ServiceAccount
26 | name: sa-bozo
27 | apiGroup: rbac.authorization.k8s.io
28 | roleRef:
29 | kind: Role
30 | name: r-bozo
31 | apiGroup: rbac.authorization.k8s.io
32 |
33 | - apiVersion: rbac.authorization.k8s.io/v1
34 | kind: RoleBinding
35 | metadata:
36 | name: rb3
37 | namespace: default
38 | subjects:
39 | - kind: ServiceAccount
40 | name: sa-bozo
41 | apiGroup: rbac.authorization.k8s.io
42 | roleRef:
43 | kind: ClusterRole
44 | name: cr-bozo
45 | apiGroup: rbac.authorization.k8s.io
--------------------------------------------------------------------------------
/internal/lint/testdata/config/1.yaml:
--------------------------------------------------------------------------------
1 | popeye:
2 | excludes:
3 | linters:
4 | pods:
5 | instances:
6 | - codes:
7 | - 100
8 | - 106
9 | - 113
10 | - 204
11 | containers:
12 | - "rx:c2*"
--------------------------------------------------------------------------------
/internal/lint/testdata/core/cm/1.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: List
4 | items:
5 | - apiVersion: v1
6 | kind: ConfigMap
7 | metadata:
8 | name: cm1
9 | namespace: default
10 | data:
11 | fred.yaml: |
12 | k1: 1
13 | k2: blee
14 | - apiVersion: v1
15 | kind: ConfigMap
16 | metadata:
17 | name: cm2
18 | namespace: default
19 | data:
20 | k1: apple
21 | k2: bee
22 | - apiVersion: v1
23 | kind: ConfigMap
24 | metadata:
25 | name: cm3
26 | namespace: default
27 | data:
28 | k1: apple
29 | k2: bee
30 | - apiVersion: v1
31 | kind: ConfigMap
32 | metadata:
33 | name: cm4
34 | namespace: default
35 | data:
36 | k1: apple
37 | k2: bee
38 |
--------------------------------------------------------------------------------
/internal/lint/testdata/core/ep/1.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: List
3 | items:
4 | - apiVersion: v1
5 | kind: Endpoints
6 | metadata:
7 | name: svc1
8 | namespace: default
9 | labels:
10 | app: p1
11 | subsets:
12 | - addresses:
13 | - ip: 10.244.1.27
14 | nodeName: n1
15 | targetRef:
16 | kind: Pod
17 | name: p1
18 | namespace: default
19 | ports:
20 | - name: http
21 | port: 4000
22 | protocol: TCP
23 | - apiVersion: v1
24 | kind: Endpoints
25 | metadata:
26 | name: svc2
27 | namespace: default
28 | subsets:
29 | - addresses:
30 | - ip: 10.244.1.19
31 | nodeName: n1
32 | targetRef:
33 | kind: Pod
34 | name: p2
35 | namespace: default
36 | ports:
37 | - name: service
38 | port: 3000
39 | protocol: TCP
40 | - apiVersion: v1
41 | kind: Endpoints
42 | metadata:
43 | name: svc-none
44 | namespace: default
45 | subsets:
46 | - addresses:
47 | - ip: 10.244.1.19
48 | nodeName: n1
49 | targetRef:
50 | kind: Pod
51 | name: p5
52 | namespace: default
53 | - ip: 10.244.1.19
54 | nodeName: n1
55 | targetRef:
56 | kind: Pod
57 | name: p4
58 | namespace: default
59 | ports:
60 | - name: service
61 | port: 3000
62 | protocol: TCP
63 | - apiVersion: v1
64 | kind: Endpoints
65 | metadata:
66 | name: svc4
67 | namespace: default
68 | subsets:
--------------------------------------------------------------------------------
/internal/lint/testdata/core/ns/1.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: List
3 | items:
4 | - apiVersion: v1
5 | kind: Namespace
6 | metadata:
7 | name: default
8 | labels:
9 | ns: default
10 | spec:
11 | finalizers:
12 | - kubernetes
13 | status:
14 | phase: Active
15 | - apiVersion: v1
16 | kind: Namespace
17 | metadata:
18 | name: ns1
19 | labels:
20 | app: ns1
21 | spec:
22 | finalizers:
23 | - kubernetes
24 | status:
25 | phase: Active
26 | - apiVersion: v1
27 | kind: Namespace
28 | metadata:
29 | name: ns2
30 | labels:
31 | app: ns2
32 | spec:
33 | finalizers:
34 | - kubernetes
--------------------------------------------------------------------------------
/internal/lint/testdata/core/sa/1.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: List
4 | items:
5 | - apiVersion: v1
6 | kind: ServiceAccount
7 | metadata:
8 | name: default
9 | namespace: default
10 | - apiVersion: v1
11 | kind: ServiceAccount
12 | metadata:
13 | name: sa1
14 | namespace: default
15 | automountServiceAccountToken: false
16 | - apiVersion: v1
17 | kind: ServiceAccount
18 | metadata:
19 | name: sa2
20 | namespace: default
21 | automountServiceAccountToken: true
22 | - apiVersion: v1
23 | kind: ServiceAccount
24 | metadata:
25 | name: sa3
26 | namespace: default
27 | automountServiceAccountToken: true
28 | - apiVersion: v1
29 | kind: ServiceAccount
30 | metadata:
31 | name: sa4
32 | namespace: default
33 | automountServiceAccountToken: false
34 | secrets:
35 | - kind: Secret
36 | namespace: default
37 | name: bozo
38 | apiVersion: v1
39 | imagePullSecrets:
40 | - name: s1
41 | - apiVersion: v1
42 | kind: ServiceAccount
43 | metadata:
44 | name: sa5
45 | namespace: default
46 | automountServiceAccountToken: false
47 | secrets:
48 | - kind: Secret
49 | namespace: default
50 | name: s1
51 | apiVersion: v1
52 | imagePullSecrets:
53 | - name: bozo
54 |
--------------------------------------------------------------------------------
/internal/lint/testdata/core/sa/2.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: List
4 | items:
5 | - apiVersion: v1
6 | kind: ServiceAccount
7 | metadata:
8 | name: sa1
9 | namespace: ns1
10 | - apiVersion: v1
11 | kind: ServiceAccount
12 | metadata:
13 | name: sa2
14 | namespace: ns2
15 | automountServiceAccountToken: false
--------------------------------------------------------------------------------
/internal/lint/testdata/core/secret/1.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: List
3 | items:
4 | - apiVersion: v1
5 | data:
6 | ca.crt: blee
7 | ns: zorg
8 | kind: Secret
9 | metadata:
10 | annotations:
11 | kubernetes.io/service-account.name: default
12 | name: sec1
13 | namespace: default
14 | type: kubernetes.io/service-account-token
15 | - apiVersion: v1
16 | data:
17 | admin-password: zorg
18 | admin-user: blee
19 | kind: Secret
20 | metadata:
21 | labels:
22 | name: sec2
23 | namespace: default
24 | type: Opaque
25 | - apiVersion: v1
26 | data:
27 | ca.crt: crap
28 | namespace: zorg
29 | kind: Secret
30 | metadata:
31 | annotations:
32 | name: sec3
33 | namespace: default
34 | type: kubernetes.io/service-account-token
35 |
--------------------------------------------------------------------------------
/internal/lint/testdata/core/svc/2.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: List
3 | items:
4 | - apiVersion: v1
5 | kind: Service
6 | metadata:
7 | labels:
8 | app: p1
9 | name: svc1
10 | namespace: default
11 | spec:
12 | ports:
13 | - name: http
14 | port: 9090
15 | protocol: TCP
16 | targetPort: bbb
17 | selector:
18 | app: p1
19 | instance: bbb
20 | sessionAffinity: None
21 | status:
22 | loadBalancer: {}
23 |
--------------------------------------------------------------------------------
/internal/lint/testdata/mx/node/1.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: List
3 | items:
4 | - apiVersion: metrics.k8s.io/v1beta1
5 | kind: NodeMetrics
6 | metadata:
7 | name: n1
8 | usage:
9 | cpu: 144965184n
10 | memory: 770776Ki
11 | - apiVersion: metrics.k8s.io/v1beta1
12 | kind: NodeMetrics
13 | metadata:
14 | name: n5
15 | usage:
16 | cpu: 20
17 | memory: 40Mi
18 | window: 20.101s
19 |
--------------------------------------------------------------------------------
/internal/lint/testdata/mx/pod/1.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: List
3 | items:
4 | - apiVersion: metrics.k8s.io/v1beta1
5 | kind: PodMetrics
6 | metadata:
7 | labels:
8 | app: p1
9 | name: p1
10 | namespace: default
11 | containers:
12 | - name: c1
13 | usage:
14 | cpu: 20
15 | memory: 20Mi
16 | - apiVersion: metrics.k8s.io/v1beta1
17 | kind: PodMetrics
18 | metadata:
19 | labels:
20 | app: p3
21 | name: p3
22 | namespace: default
23 | containers:
24 | - name: c1
25 | usage:
26 | cpu: 2000m
27 | memory: 20Mi
28 | - apiVersion: metrics.k8s.io/v1beta1
29 | kind: PodMetrics
30 | metadata:
31 | labels:
32 | app: j1
33 | name: j1
34 | namespace: default
35 | containers:
36 | - name: c1
37 | usage:
38 | cpu: 2000m
39 | memory: 20Mi
--------------------------------------------------------------------------------
/internal/lint/testdata/net/gw/1.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: List
3 | items:
4 | - apiVersion: gateway.networking.k8s.io/v1
5 | kind: Gateway
6 | metadata:
7 | name: gw1
8 | namespace: default
9 | spec:
10 | gatewayClassName: gwc1
11 | listeners:
12 | - name: http
13 | protocol: HTTP
14 | port: 80
15 | - apiVersion: gateway.networking.k8s.io/v1
16 | kind: Gateway
17 | metadata:
18 | name: gw2
19 | namespace: default
20 | spec:
21 | gatewayClassName: gwc-bozo
22 | listeners:
23 | - name: http
24 | protocol: HTTP
25 | port: 80
--------------------------------------------------------------------------------
/internal/lint/testdata/net/gwc/1.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: List
3 | items:
4 | - apiVersion: gateway.networking.k8s.io/v1
5 | kind: GatewayClass
6 | metadata:
7 | name: gwc1
8 | spec:
9 | controllerName: example.com/gateway-controller
10 | - apiVersion: gateway.networking.k8s.io/v1
11 | kind: GatewayClass
12 | metadata:
13 | name: gwc2
14 | spec:
15 | controllerName: example.com/gateway-controller
--------------------------------------------------------------------------------
/internal/lint/testdata/net/gwr/1.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: v1
2 | kind: List
3 | items:
4 | - apiVersion: gateway.networking.k8s.io/v1
5 | kind: HTTPRoute
6 | metadata:
7 | name: r1
8 | namespace: default
9 | spec:
10 | parentRefs:
11 | - name: gw1
12 | hostnames:
13 | - fred
14 | rules:
15 | - matches:
16 | - path:
17 | type: PathPrefix
18 | value: /blee
19 | backendRefs:
20 | - name: svc1
21 | port: 9090
22 | - apiVersion: gateway.networking.k8s.io/v1
23 | kind: HTTPRoute
24 | metadata:
25 | name: r2
26 | namespace: default
27 | spec:
28 | parentRefs:
29 | - name: gw-bozo
30 | hostnames:
31 | - bozo
32 | rules:
33 | - matches:
34 | - path:
35 | type: PathPrefix
36 | value: /zorg
37 | backendRefs:
38 | - name: svc2
39 | port: 8080
40 | - apiVersion: gateway.networking.k8s.io/v1
41 | kind: HTTPRoute
42 | metadata:
43 | name: r3
44 | namespace: default
45 | spec:
46 | parentRefs:
47 | - kind: Service
48 | name: svc-bozo
49 | hostnames:
50 | - bozo
51 | rules:
52 | - matches:
53 | - path:
54 | type: PathPrefix
55 | value: /zorg
56 | backendRefs:
57 | - name: svc2
58 | port: 9090
--------------------------------------------------------------------------------
/internal/lint/testdata/net/np/3.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.k8s.io/v1
2 | kind: NetworkPolicyList
3 | items:
4 |
5 | - apiVersion: networking.k8s.io/v1
6 | kind: NetworkPolicy
7 | metadata:
8 | name: deny-all-ing
9 | namespace: ns1
10 | spec:
11 | podSelector: {}
12 | policyTypes:
13 | - Ingress
14 |
15 | - apiVersion: networking.k8s.io/v1
16 | kind: NetworkPolicy
17 | metadata:
18 | name: allow-all-egress
19 | namespace: ns2
20 | spec:
21 | podSelector: {}
22 | ingress:
23 | - from:
24 | - namespaceSelector:
25 | matchLabels:
26 | app: ns2
27 | podSelector:
28 | matchLabels:
29 | app: p2
30 | - podSelector:
31 | matchLabels:
32 | app: p2
33 | egress:
34 | - {}
35 | policyTypes:
36 | - Ingress
37 | - Egress
--------------------------------------------------------------------------------
/internal/lint/testdata/net/np/a.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.k8s.io/v1
2 | kind: NetworkPolicy
3 | metadata:
4 | name: test-network-policy
5 | namespace: default
6 | spec:
7 | podSelector:
8 | matchLabels:
9 | role: db
10 | policyTypes:
11 | - Ingress
12 | - Egress
13 | ingress:
14 | - from:
15 | - ipBlock:
16 | cidr: 172.17.0.0/16
17 | except:
18 | - 172.17.1.0/24
19 | - namespaceSelector:
20 | matchLabels:
21 | project: myproject
22 | - podSelector:
23 | matchLabels:
24 | role: frontend
25 | ports:
26 | - protocol: TCP
27 | port: 6379
28 | egress:
29 | - to:
30 | - ipBlock:
31 | cidr: 10.0.0.0/24
32 | ports:
33 | - protocol: TCP
34 | port: 5978
--------------------------------------------------------------------------------
/internal/lint/testdata/net/np/allow-all-egr.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.k8s.io/v1
2 | kind: NetworkPolicy
3 | metadata:
4 | name: allow-all-egress
5 | spec:
6 | podSelector: {}
7 | egress:
8 | - {}
9 | policyTypes:
10 | - Egress
--------------------------------------------------------------------------------
/internal/lint/testdata/net/np/allow-all-ing.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.k8s.io/v1
2 | kind: NetworkPolicy
3 | metadata:
4 | name: allow-all-egress
5 | spec:
6 | podSelector: {}
7 | egress:
8 | - {}
9 | policyTypes:
10 | - Ingress
--------------------------------------------------------------------------------
/internal/lint/testdata/net/np/b.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.k8s.io/v1
2 | kind: NetworkPolicy
3 | metadata:
4 | name: np-b
5 | namespace: default
6 | spec:
7 | ingress:
8 | - from:
9 | - ipBlock:
10 | cidr: 172.17.0.0/16
11 | except:
12 | - 172.17.1.0/24
13 | - namespaceSelector:
14 | matchLabels:
15 | ns: ns1
16 | - podSelector:
17 | matchLabels:
18 | po: po1
19 | ports:
20 | - protocol: TCP
21 | port: 6379
22 | egress:
23 | - to:
24 | - namespaceSelector:
25 | matchLabels:
26 | ns: ns1
27 | - podSelector:
28 | matchLabels:
29 | po: po1
30 | - ipBlock:
31 | cidr: 10.0.0.0/24
32 | ports:
33 | - protocol: TCP
34 | port: 5978
--------------------------------------------------------------------------------
/internal/lint/testdata/net/np/blee.yml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.k8s.io/v1
2 | kind: NetworkPolicy
3 | metadata:
4 | name: np1
5 | namespace: default
6 | spec:
7 | podSelector:
8 | matchLabels:
9 | app: p1
10 | policyTypes:
11 | - Ingress
12 | - Egress
13 | ingress:
14 | - from:
15 | - ipBlock:
16 | cidr: 172.1.0.0/16
17 | except:
18 | - 172.1.0.0/24
19 | - namespaceSelector:
20 | matchLabels:
21 | ns: default
22 | podSelector:
23 | matchLabels:
24 | app: p1
25 | ports:
26 | - protocol: TCP
27 | port: 6379
28 | egress:
29 | - to:
30 | - ipBlock:
31 | cidr: 172.1.0.0/16
32 | ports:
33 | - protocol: TCP
34 | port: 5978
35 |
--------------------------------------------------------------------------------
/internal/lint/testdata/net/np/c.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.k8s.io/v1
2 | kind: NetworkPolicy
3 | metadata:
4 | name: np-c
5 | namespace: default
6 | spec:
7 | ingress:
8 | - from:
9 | - ipBlock:
10 | cidr: 172.17.0.0/16
11 | except:
12 | - 172.17.1.0/24
13 | - namespaceSelector:
14 | matchLabels:
15 | ns: ns1
16 | - podSelector:
17 | matchLabels:
18 | po: p1-missing
19 | ports:
20 | - protocol: TCP
21 | port: 6379
22 | egress:
23 | - to:
24 | - namespaceSelector:
25 | matchLabels:
26 | ns: ns1
27 | - podSelector:
28 | matchLabels:
29 | po: p1-missing
30 | - ipBlock:
31 | cidr: 10.0.0.0/24
32 | ports:
33 | - protocol: TCP
34 | port: 5978
--------------------------------------------------------------------------------
/internal/lint/testdata/net/np/d.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.k8s.io/v1
2 | kind: NetworkPolicy
3 | metadata:
4 | name: np-d
5 | namespace: default
6 | spec:
7 | podSelector:
8 | podSelector:
9 | matchLabels:
10 | role: db
11 | policyTypes:
12 | - Ingress
13 | - Egress
--------------------------------------------------------------------------------
/internal/lint/testdata/net/np/deny-all-egr.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.k8s.io/v1
2 | kind: NetworkPolicy
3 | metadata:
4 | name: deny-all-eg
5 | spec:
6 | podSelector: {}
7 | policyTypes:
8 | - Egress
--------------------------------------------------------------------------------
/internal/lint/testdata/net/np/deny-all-ing.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.k8s.io/v1
2 | kind: NetworkPolicy
3 | metadata:
4 | name: deny-all-ing
5 | spec:
6 | podSelector: {}
7 | policyTypes:
8 | - Ingress
--------------------------------------------------------------------------------
/internal/lint/testdata/net/np/deny-all.yaml:
--------------------------------------------------------------------------------
1 | apiVersion: networking.k8s.io/v1
2 | kind: NetworkPolicy
3 | metadata:
4 | name: deny-all
5 | spec:
6 | podSelector: {}
7 | policyTypes:
8 | - Ingress
9 | - Egress
--------------------------------------------------------------------------------
/internal/lint/testdata/pol/pdb/1.yaml:
--------------------------------------------------------------------------------
1 | ---
2 | apiVersion: v1
3 | kind: List
4 | items:
5 | - apiVersion: policy/v1
6 | kind: PodDisruptionBudget
7 | metadata:
8 | name: pdb1
9 | namespace: default
10 | spec:
11 | minAvailable: 2
12 | selector:
13 | matchLabels:
14 | app: p1
15 | - apiVersion: policy/v1
16 | kind: PodDisruptionBudget
17 | metadata:
18 | name: pdb2
19 | namespace: default
20 | spec:
21 | minAvailable: 1
22 | selector:
23 | matchLabels:
24 | app: p2
25 | - apiVersion: policy/v1
26 | kind: PodDisruptionBudget
27 | metadata:
28 | name: pdb3
29 | namespace: default
30 | spec:
31 | minAvailable: 1
32 | selector:
33 | matchLabels:
34 | app: test4
35 | - apiVersion: policy/v1
36 | kind: PodDisruptionBudget
37 | metadata:
38 | name: pdb4
39 | namespace: default
40 | spec:
41 | minAvailable: 1
42 | selector:
43 | matchLabels:
44 | app: test5
45 | - apiVersion: policy/v1
46 | kind: PodDisruptionBudget
47 | metadata:
48 | name: pdb4-1
49 | namespace: default
50 | spec:
51 | minAvailable: 1
52 | selector:
53 | matchLabels:
54 | app: test5
55 |
--------------------------------------------------------------------------------
/internal/report/color_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package report
5 |
6 | import (
7 | "testing"
8 |
9 | "github.com/derailed/popeye/internal/rules"
10 | "github.com/stretchr/testify/assert"
11 | )
12 |
13 | func TestColorForLevel(t *testing.T) {
14 | colors := map[int]Color{
15 | 0: ColorDarkOlive,
16 | 1: ColorAqua,
17 | 2: ColorOrangish,
18 | 3: ColorRed,
19 | 4: ColorLighSlate,
20 | }
21 |
22 | for k, v := range colors {
23 | assert.Equal(t, v, colorForLevel(rules.Level(k)))
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/internal/report/delta_score.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package report
5 |
6 | import "github.com/derailed/popeye/internal/rules"
7 |
8 | const (
9 | noChange = "not changed"
10 | better = "improved"
11 | worst = "worsened"
12 | )
13 |
14 | // DeltaScore tracks delta between 2 tally scores.
15 | type DeltaScore struct {
16 | level rules.Level
17 | s1, s2 int
18 | inverse bool
19 | }
20 |
21 | // NewDeltaScore returns a new delta score.
22 | func NewDeltaScore(level rules.Level, s1, s2 int, inverse bool) DeltaScore {
23 | return DeltaScore{
24 | s1: s1,
25 | s2: s2,
26 | level: level,
27 | inverse: inverse,
28 | }
29 | }
30 |
31 | func (s DeltaScore) changed() bool {
32 | return s.s1 != s.s2
33 | }
34 |
35 | func (s DeltaScore) worst() bool {
36 | if s.s1 == s.s2 {
37 | return false
38 | }
39 |
40 | return !s.better()
41 | }
42 |
43 | func (s DeltaScore) better() bool {
44 | if s.s1 == s.s2 {
45 | return false
46 | }
47 |
48 | if s.s2 > s.s1 {
49 | return !s.inverse
50 | }
51 |
52 | return s.inverse
53 | }
54 |
55 | func (s DeltaScore) summarize() string {
56 | if s.s1 == s.s2 {
57 | return noChange
58 | }
59 |
60 | if s.s1 > s.s2 {
61 | if s.inverse {
62 | return better
63 | }
64 | return worst
65 | }
66 |
67 | if s.inverse {
68 | return worst
69 | }
70 |
71 | return better
72 | }
73 |
--------------------------------------------------------------------------------
/internal/report/emoji.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package report
5 |
6 | import (
7 | "github.com/derailed/popeye/internal/rules"
8 | )
9 |
10 | const (
11 | containerLevel rules.Level = 100
12 | )
13 |
14 | var emojis = map[string]string{
15 | "peachy": "✅",
16 | "farfromfok": "💥",
17 | "warn": "😱",
18 | "fyi": "🔊",
19 | "container": "🐳",
20 | }
21 |
22 | var emojisUgry = map[string]string{
23 | "peachy": "OK",
24 | "farfromfok": "E",
25 | "warn": "W",
26 | "fyi": "I",
27 | "container": "C",
28 | }
29 |
30 | // EmojiForLevel maps lint levels to emojis.
31 | func EmojiForLevel(l rules.Level, jurassic bool) string {
32 | var key string
33 | // nolint:exhaustive
34 | switch l {
35 | case containerLevel:
36 | key = "container"
37 | case rules.ErrorLevel:
38 | key = "farfromfok"
39 | case rules.WarnLevel:
40 | key = "warn"
41 | case rules.InfoLevel:
42 | key = "fyi"
43 | default:
44 | key = "peachy"
45 | }
46 |
47 | if jurassic {
48 | return emojisUgry[key]
49 | }
50 |
51 | return emojis[key]
52 | }
53 |
--------------------------------------------------------------------------------
/internal/report/emoji_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package report
5 |
6 | import (
7 | "testing"
8 | "unicode/utf8"
9 |
10 | "github.com/derailed/popeye/internal/rules"
11 | "github.com/stretchr/testify/assert"
12 | )
13 |
14 | func TestEmojiForLevel(t *testing.T) {
15 | for k, v := range map[int]int{0: 1, 1: 1, 2: 1, 3: 1, 4: 1, 100: 1} {
16 | assert.Equal(t, v, utf8.RuneCountInString(EmojiForLevel(rules.Level(k), false)))
17 | }
18 | }
19 |
20 | func TestEmojiUgry(t *testing.T) {
21 | for k, v := range map[int]string{0: "OK", 1: "I", 2: "W", 3: "E", 100: "C"} {
22 | assert.Equal(t, v, EmojiForLevel(rules.Level(k), true))
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/internal/report/grade.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package report
5 |
6 | import "strings"
7 |
8 | // Grade returns a run report grade based on score.
9 | func Grade(score int) string {
10 | switch {
11 | case score >= 90:
12 | return "A"
13 | case score >= 80:
14 | return "B"
15 | case score >= 70:
16 | return "C"
17 | case score >= 60:
18 | return "D"
19 | case score >= 50:
20 | return "E"
21 | default:
22 | return "F"
23 | }
24 | }
25 |
26 | // Badge returns a popeye grade.
27 | func (s *ScanReport) Badge(score int) []string {
28 | ic := make([]string, len(GraderLogo))
29 | for i, l := range GraderLogo {
30 | switch i {
31 | case 0, 2:
32 | if score < 70 {
33 | l = strings.Replace(l, "o", "S", 1)
34 | }
35 | case 1:
36 | l = strings.Replace(l, "K", Grade(score), 1)
37 | case 3:
38 | if score < 70 {
39 | l = strings.Replace(l, "a", "O", 1)
40 | }
41 | }
42 | ic[i] = s.Color(l, colorForScore(score))
43 | }
44 |
45 | return ic
46 | }
47 |
48 | // GraderLogo affords for replacing logo parts.
49 | var GraderLogo = []string{
50 | "o .-'-. ",
51 | " o __| K `\\ ",
52 | " o `-,-`--._ `\\",
53 | " [] .->' a `|-'",
54 | " `=/ (__/_ / ",
55 | " \\_, ` _) ",
56 | " `----; | ",
57 | }
58 |
--------------------------------------------------------------------------------
/internal/report/logo.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package report
5 |
6 | // Logo popeye
7 | var Logo = []string{
8 | "K .-'-. ",
9 | " 8 __| `\\ ",
10 | " s `-,-`--._ `\\",
11 | " [] .->' a `|-'",
12 | " `=/ (__/_ / ",
13 | " \\_, ` _) ",
14 | " `----; | ",
15 | }
16 |
17 | // Popeye title
18 | var Popeye = []string{
19 | ` ___ ___ _____ _____ `,
20 | `| _ \___| _ \ __\ \ / / __|`,
21 | `| _/ _ \ _/ _| \ V /| _| `,
22 | `|_| \___/_| |___| |_| |___|`,
23 | }
24 |
--------------------------------------------------------------------------------
/internal/report/test_assets/empty.yml:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/derailed/popeye/5d07838165bb64fa70c594f2b46ef14a9080782f/internal/report/test_assets/empty.yml
--------------------------------------------------------------------------------
/internal/report/test_assets/r1.yml:
--------------------------------------------------------------------------------
1 | popeye:
2 | score: 50
3 | grade: F
4 | sanitizers:
5 | - sanitizer: po
6 | tally:
7 | ok: 0
8 | info: 0
9 | warning: 1
10 | error: 0
11 | score: 0
12 | issues:
13 | default/nginx:
14 | - group: nginx
15 | level: 2
16 | message: "[POP-106] No resources requests/limits defined"
17 | - group: nginx
18 | level: 2
19 | message: "[POP-102] No probes defined"
20 | - group: __root__
21 | level: 1
22 | message: "[POP-206] No DisruptionBudget in effect"
23 | - group: __root__
24 | level: 2
25 | message: "[POP-300] Pod uses the `default` ServiceAccount"
26 | - group: __root__
27 | level: 2
28 | message: "[POP-301] Connects to API Server? ServiceAccount token is mounted"
29 | - group: __root__
30 | level: 2
31 | message: "[POP-302] Containers are possibly running as root"
32 |
--------------------------------------------------------------------------------
/internal/report/test_assets/r2.yml:
--------------------------------------------------------------------------------
1 | popeye:
2 | score: 0
3 | grade: F
4 | sanitizers:
5 | - sanitizer: po
6 | tally:
7 | ok: 0
8 | info: 0
9 | warning: 1
10 | error: 0
11 | score: 0
12 | issues:
13 | default/nginx:
14 | - group: nginx
15 | level: 2
16 | message: "[POP-106] No resources requests/limits defined"
17 | - group: nginx
18 | level: 2
19 | message: "[POP-102] No probes defined"
20 | - group: __root__
21 | level: 1
22 | message: "[POP-206] No DisruptionBudget in effect"
23 | - group: __root__
24 | level: 2
25 | message: "[POP-300] Pod uses the `default` ServiceAccount"
26 | - group: __root__
27 | level: 2
28 | message: "[POP-301] Connects to API Server? ServiceAccount token is mounted"
29 | - group: __root__
30 | level: 2
31 | message: "[POP-302] Containers are possibly running as root"
32 |
--------------------------------------------------------------------------------
/internal/report/types.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package report
5 |
6 | import _ "embed"
7 |
8 | const (
9 | // DefaultFormat dumps report with color, emojis, the works.
10 | DefaultFormat = "standard"
11 |
12 | // JurassicFormat dumps report with dud fancy-ness.
13 | JurassicFormat = "jurassic"
14 |
15 | // YAMLFormat dumps report as YAML.
16 | YAMLFormat = "yaml"
17 |
18 | // JSONFormat dumps report as JSON.
19 | JSONFormat = "json"
20 |
21 | // HTMLFormat dumps report as HTML
22 | HTMLFormat = "html"
23 |
24 | // JunitFormat renders report as JUnit.
25 | JunitFormat = "junit"
26 |
27 | // ScoreFormat renders report as the value of the Score.
28 | ScoreFormat = "score"
29 |
30 | // PromFormat renders report to prom metrics.
31 | PromFormat = "prometheus"
32 | )
33 |
34 | //go:embed assets/report.html
35 | var htmlReport string
36 |
--------------------------------------------------------------------------------
/internal/rules/code.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package rules
5 |
6 | import (
7 | "fmt"
8 | "strconv"
9 | "strings"
10 | )
11 |
12 | // Code represents an issue code.
13 | type Code struct {
14 | Message string `yaml:"message"`
15 | Severity Level `yaml:"severity"`
16 | }
17 |
18 | // Format hydrates a message with arguments.
19 | func (c *Code) Format(code ID, args ...any) string {
20 | msg := "[POP-" + strconv.Itoa(int(code)) + "] "
21 | if len(args) == 0 {
22 | msg += c.Message
23 | } else {
24 | msg += fmt.Sprintf(c.Message, args...)
25 | }
26 |
27 | return strings.TrimSpace(msg)
28 | }
29 |
--------------------------------------------------------------------------------
/internal/rules/code_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package rules_test
5 |
6 | import (
7 | "testing"
8 |
9 | "github.com/derailed/popeye/internal/rules"
10 | "github.com/stretchr/testify/assert"
11 | )
12 |
13 | func TestCodeFormat(t *testing.T) {
14 | uu := map[string]struct {
15 | c rules.Code
16 | aa []any
17 | e string
18 | }{
19 | "empty": {
20 | e: "[POP-100]",
21 | },
22 | "no-args": {
23 | c: rules.Code{Message: "bla"},
24 | e: "[POP-100] bla",
25 | },
26 | "args": {
27 | c: rules.Code{Message: "bla %s %d"},
28 | aa: []any{"yo", 10},
29 | e: "[POP-100] bla yo 10",
30 | },
31 | }
32 |
33 | for k := range uu {
34 | u := uu[k]
35 | t.Run(k, func(t *testing.T) {
36 | assert.Equal(t, u.e, u.c.Format(100, u.aa...))
37 | })
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/internal/rules/exclusions.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package rules
5 |
6 | import (
7 | "fmt"
8 |
9 | "github.com/rs/zerolog/log"
10 | )
11 |
12 | type Exclusions struct {
13 | // Excludes tracks exclusions
14 | Global Exclude `yaml:"global"`
15 |
16 | // Linters tracks exclusions
17 | Linters Linters `yaml:"linters"`
18 | }
19 |
20 | func NewExclusions() Exclusions {
21 | return Exclusions{
22 | Global: NewExclude(),
23 | Linters: make(Linters),
24 | }
25 | }
26 |
27 | func (e Exclusions) Match(spec Spec) bool {
28 | if e.Global.Match(spec, true) {
29 | log.Debug().Msgf("Global exclude matched: %q::%q", spec.GVR, spec.FQN)
30 | return true
31 | }
32 |
33 | return e.Linters.Match(spec, false)
34 | }
35 |
36 | func (e Exclusions) Dump() {
37 | fmt.Println("Globals")
38 | e.Global.Dump(" ")
39 |
40 | fmt.Println("Linters")
41 | e.Linters.Dump(" ")
42 | }
43 |
--------------------------------------------------------------------------------
/internal/rules/expression.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package rules
5 |
6 | import (
7 | "fmt"
8 | "regexp"
9 | "strings"
10 | )
11 |
12 | type Expression string
13 |
14 | func (e Expression) dump(indent string) {
15 | fmt.Printf("%s%q\n", indent, e)
16 | }
17 |
18 | func (e Expression) IsRX() bool {
19 | return strings.HasPrefix(string(e), rxMarker)
20 | }
21 |
22 | func (e Expression) MatchRX(s string) bool {
23 | rx := regexp.MustCompile(strings.Replace(string(e), rxMarker, "", 1))
24 |
25 | return rx.MatchString(s)
26 | }
27 |
28 | func (e Expression) match(s string) bool {
29 | if e == "" {
30 | return true
31 | }
32 | if e.IsRX() {
33 | return e.MatchRX(s)
34 | }
35 |
36 | return s == string(e)
37 | }
38 |
39 | type expressions []Expression
40 |
41 | func (ee expressions) dump(indent string) {
42 | for _, e := range ee {
43 | e.dump(indent)
44 | }
45 | }
46 |
47 | func (ee expressions) isEmpty() bool {
48 | return len(ee) == 0
49 | }
50 |
51 | func (ee expressions) matches(ss []string) bool {
52 | if len(ee) == 0 {
53 | return true
54 | }
55 |
56 | for _, s := range ss {
57 | if ee.match(s) {
58 | return true
59 | }
60 | }
61 |
62 | return false
63 | }
64 |
65 | func (ee expressions) match(exp string) bool {
66 | if len(ee) == 0 || exp == "" {
67 | return true
68 | }
69 | for _, e := range ee {
70 | if e.match(exp) {
71 | return true
72 | }
73 | }
74 |
75 | return false
76 | }
77 |
--------------------------------------------------------------------------------
/internal/rules/expression_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package rules
5 |
6 | import (
7 | "testing"
8 |
9 | "github.com/stretchr/testify/assert"
10 | )
11 |
12 | func Test_expressionMatch(t *testing.T) {
13 | uu := map[string]struct {
14 | exp Expression
15 | s string
16 | e bool
17 | }{
18 | "empty": {
19 | e: true,
20 | },
21 | "empty-rule": {
22 | s: "fred",
23 | e: true,
24 | },
25 | "happy": {
26 | exp: "fred",
27 | s: "fred",
28 | e: true,
29 | },
30 | "happy-rx": {
31 | exp: "rx:^fred",
32 | s: "fred",
33 | e: true,
34 | },
35 | "toast": {
36 | exp: "freddy",
37 | s: "fred",
38 | },
39 | "toast-rx": {
40 | exp: "rx:freddy",
41 | s: "fred",
42 | },
43 | }
44 |
45 | for k := range uu {
46 | u := uu[k]
47 | t.Run(k, func(t *testing.T) {
48 | ok := u.exp.match(u.s)
49 | assert.Equal(t, u.e, ok)
50 | })
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/internal/rules/helpers.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package rules
5 |
6 | import (
7 | "regexp"
8 | "strings"
9 | )
10 |
11 | const rxMarker = "rx:"
12 |
13 | func rxMatch(exp, name string) (bool, error) {
14 | if !isRegex(exp) {
15 | return false, nil
16 | }
17 | rx, err := regexp.Compile(strings.Replace(exp, rxMarker, "", 1))
18 | if err != nil {
19 | return false, err
20 | }
21 |
22 | return rx.MatchString(name), nil
23 | }
24 |
25 | func isRegex(s string) bool {
26 | return strings.HasPrefix(s, rxMarker)
27 | }
28 |
--------------------------------------------------------------------------------
/internal/rules/keyvals.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package rules
5 |
6 | import (
7 | "fmt"
8 | "strings"
9 | )
10 |
11 | type Labels map[string]string
12 |
13 | func (l Labels) String() string {
14 | if len(l) == 0 {
15 | return "n/a"
16 | }
17 |
18 | kk := make([]string, 0, len(l))
19 | for k := range l {
20 | kk = append(kk, k)
21 | }
22 |
23 | return strings.Join(kk, ",")
24 | }
25 |
26 | type keyVals map[string]expressions
27 |
28 | func (kv keyVals) dump(indent string) {
29 | for k, v := range kv {
30 | fmt.Printf("%s%s: %s\n", indent, k, v)
31 | }
32 | }
33 |
34 | func (kv keyVals) isEmpty() bool {
35 | return len(kv) == 0
36 | }
37 |
38 | func (kv keyVals) match(ll Labels) bool {
39 | if len(kv) == 0 {
40 | return true
41 | }
42 |
43 | var matches int
44 | for k, ee := range kv {
45 | v, ok := ll[k]
46 | if !ok {
47 | continue
48 | }
49 | if ee.match(v) {
50 | matches++
51 | }
52 | }
53 |
54 | return matches > 0
55 | }
56 |
--------------------------------------------------------------------------------
/internal/rules/level.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package rules
5 |
6 | // Level tracks lint check level.
7 | type Level int
8 |
9 | const (
10 | // OkLevel denotes no linting issues.
11 | OkLevel Level = iota
12 | // InfoLevel denotes FIY linting issues.
13 | InfoLevel
14 | // WarnLevel denotes a warning issue.
15 | WarnLevel
16 | // ErrorLevel denotes a serious issue.
17 | ErrorLevel
18 | )
19 |
20 | // ToIssueLevel convert a string to a issue level.
21 | func ToIssueLevel(level *string) Level {
22 | if level == nil || *level == "" {
23 | return OkLevel
24 | }
25 |
26 | switch *level {
27 | case "ok":
28 | return OkLevel
29 | case "info":
30 | return InfoLevel
31 | case "warn":
32 | return WarnLevel
33 | case "error":
34 | return ErrorLevel
35 | default:
36 | return OkLevel
37 | }
38 | }
39 |
40 | func (l Level) ToHumanLevel() string {
41 | switch l {
42 | case OkLevel:
43 | return "ok"
44 | case InfoLevel:
45 | return "info"
46 | case WarnLevel:
47 | return "warn"
48 | case ErrorLevel:
49 | return "error"
50 | default:
51 | return "n/a"
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/internal/rules/level_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package rules
5 |
6 | import (
7 | "testing"
8 |
9 | "github.com/stretchr/testify/assert"
10 | )
11 |
12 | func TestLintLevel(t *testing.T) {
13 | uu := map[string]Level{
14 | "ok": OkLevel,
15 | "info": InfoLevel,
16 | "warn": WarnLevel,
17 | "error": ErrorLevel,
18 | "blee": OkLevel,
19 | "": OkLevel,
20 | }
21 |
22 | for k := range uu {
23 | u, key := uu[k], k
24 | t.Run(k, func(t *testing.T) {
25 | assert.Equal(t, u, ToIssueLevel(&key))
26 | })
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/internal/rules/linters.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package rules
5 |
6 | import (
7 | "fmt"
8 | "strings"
9 |
10 | "github.com/rs/zerolog/log"
11 | )
12 |
13 | type LinterExcludes struct {
14 | Codes expressions `yaml:"codes"`
15 | Instances Excludes `yaml:"instances"`
16 | }
17 |
18 | func (l LinterExcludes) Dump(indent string) {
19 | l.Codes.dump(indent)
20 | l.Instances.Dump(indent)
21 | }
22 |
23 | func (l LinterExcludes) Match(spec Spec, global bool) bool {
24 | if l.Instances.Match(spec, global) {
25 | return true
26 | }
27 |
28 | if spec.Code == ZeroCode || len(l.Codes) == 0 {
29 | return false
30 | }
31 |
32 | return l.Codes.match(spec.Code.String())
33 | }
34 |
35 | type Linters map[string]LinterExcludes
36 |
37 | func (l Linters) Dump(indent string) {
38 | for k, v := range l {
39 | fmt.Printf("%s%s\n", indent, k)
40 | v.Dump(strings.Repeat(indent, 2))
41 | }
42 | }
43 |
44 | func (l Linters) isEmpty() bool {
45 | return len(l) == 0
46 | }
47 |
48 | func (l Linters) Match(spec Spec, global bool) bool {
49 | if l.isEmpty() {
50 | return false
51 | }
52 |
53 | linter, ok := l[spec.GVR.R()]
54 | if !ok {
55 | log.Debug().Msgf("No exclusions found for linter: %q", spec.GVR.R())
56 | return false
57 | }
58 |
59 | return linter.Match(spec, global)
60 | }
61 |
--------------------------------------------------------------------------------
/internal/rules/linters_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package rules
5 |
6 | import (
7 | "testing"
8 |
9 | "github.com/derailed/popeye/types"
10 | "github.com/stretchr/testify/assert"
11 | )
12 |
13 | func Test_lintersMatch(t *testing.T) {
14 | uu := map[string]struct {
15 | linters Linters
16 | spec Spec
17 | glob bool
18 | e bool
19 | }{
20 | "empty": {},
21 | "empty-rule": {
22 | spec: Spec{
23 | GVR: types.NewGVR("v1/pods"),
24 | FQN: "ns1/p1",
25 | Code: 100,
26 | },
27 | },
28 | "missing": {
29 | linters: Linters{
30 | "pods": LinterExcludes{
31 | Instances: Excludes{
32 | {
33 | FQNs: expressions{"ns1", "ns2"},
34 | },
35 | },
36 | },
37 | },
38 | spec: Spec{
39 | GVR: types.NewGVR("v1/configmaps"),
40 | FQN: "ns1/p1",
41 | Code: 100,
42 | },
43 | },
44 |
45 | "happy": {
46 | linters: Linters{
47 | "pods": LinterExcludes{
48 | Instances: Excludes{
49 | {
50 | FQNs: expressions{"rx:^ns1", "ns2"},
51 | },
52 | },
53 | },
54 | },
55 | spec: Spec{
56 | GVR: types.NewGVR("v1/pods"),
57 | FQN: "ns1/p1",
58 | Code: 100,
59 | },
60 | e: true,
61 | },
62 | }
63 |
64 | for k := range uu {
65 | u := uu[k]
66 | t.Run(k, func(t *testing.T) {
67 | assert.Equal(t, u.e, u.linters.Match(u.spec, u.glob))
68 | })
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/internal/rules/spec.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package rules
5 |
6 | import (
7 | "fmt"
8 | "strings"
9 |
10 | "github.com/derailed/popeye/types"
11 | )
12 |
13 | // Spec tracks an issue spec
14 | type Spec struct {
15 | GVR types.GVR
16 | FQN string
17 | Labels Labels
18 | Annotations Labels
19 | Containers []string
20 | Code ID
21 | }
22 |
23 | func (s Spec) isEmpty() bool {
24 | return s.GVR == types.BlankGVR &&
25 | s.FQN == "" &&
26 | len(s.Labels) == 0 &&
27 | len(s.Annotations) == 0 &&
28 | len(s.Containers) == 0 &&
29 | s.Code == ZeroCode
30 | }
31 |
32 | func (s Spec) String() string {
33 | ss := fmt.Sprintf("[%s] %s", s.GVR, s.FQN)
34 | if len(s.Containers) != 0 {
35 | ss += fmt.Sprintf("::%s", strings.Join(s.Containers, ","))
36 | }
37 | if s.Code != ZeroCode {
38 | ss += fmt.Sprintf("(%q)", s.Code)
39 | }
40 | ss += fmt.Sprintf("-- %s::%s", s.Labels, s.Annotations)
41 |
42 | return ss
43 | }
44 |
--------------------------------------------------------------------------------
/internal/rules/types.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package rules
5 |
6 | import "strconv"
7 |
8 | const ZeroCode ID = 0
9 |
10 | // ID represents a issue code identifier.
11 | type ID int
12 |
13 | func (i ID) String() string {
14 | return strconv.Itoa(int(i))
15 | }
16 |
17 | // IDS tracks a collection of ids.
18 | type IDS map[Code]struct{}
19 |
20 | type CodeOverride struct {
21 | ID ID `yaml:"code"`
22 | Message string `yaml:"message"`
23 | Severity Level `yaml:"severity"`
24 | }
25 |
26 | // Glossary represents a collection of codes.
27 | type Overrides []CodeOverride
28 |
29 | // Glossary represents a collection of codes.
30 | type Glossary map[ID]*Code
31 |
--------------------------------------------------------------------------------
/internal/scrub/cjob.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/issues"
12 | "github.com/derailed/popeye/internal/lint"
13 | batchv1 "k8s.io/api/batch/v1"
14 | v1 "k8s.io/api/core/v1"
15 | mv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
16 | )
17 |
18 | // CronJob represents a CronJob scruber.
19 | type CronJob struct {
20 | *issues.Collector
21 | *Cache
22 | }
23 |
24 | // NewCronJob return a new instance.
25 | func NewCronJob(_ context.Context, c *Cache, codes *issues.Codes) Linter {
26 | return &CronJob{
27 | Collector: issues.NewCollector(codes, c.Config),
28 | Cache: c,
29 | }
30 | }
31 |
32 | func (s *CronJob) Preloads() Preloads {
33 | return Preloads{
34 | internal.CJOB: db.LoadResource[*batchv1.CronJob],
35 | internal.JOB: db.LoadResource[*batchv1.Job],
36 | internal.PO: db.LoadResource[*v1.Pod],
37 | internal.SA: db.LoadResource[*v1.ServiceAccount],
38 | internal.PMX: db.LoadResource[*mv1beta1.PodMetrics],
39 | }
40 | }
41 |
42 | // Lint all available CronJobs.
43 | func (s *CronJob) Lint(ctx context.Context) error {
44 | for k, f := range s.Preloads() {
45 | if err := f(ctx, s.Loader, internal.Glossary[k]); err != nil {
46 | return err
47 | }
48 | }
49 |
50 | return lint.NewCronJob(s.Collector, s.DB).Lint(ctx)
51 | }
52 |
--------------------------------------------------------------------------------
/internal/scrub/cluster.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal/cache"
10 | "github.com/derailed/popeye/internal/issues"
11 | "github.com/derailed/popeye/internal/lint"
12 | "github.com/derailed/popeye/pkg/config"
13 | "github.com/derailed/popeye/types"
14 | "github.com/rs/zerolog/log"
15 | )
16 |
17 | // Cluster represents a Cluster scruber.
18 | type Cluster struct {
19 | *issues.Collector
20 | *cache.Cluster
21 | *config.Config
22 |
23 | client types.Connection
24 | }
25 |
26 | // NewCluster returns a new instance.
27 | func NewCluster(ctx context.Context, c *Cache, codes *issues.Codes) Linter {
28 | cl := Cluster{
29 | client: c.factory.Client(),
30 | Config: c.Config,
31 | Collector: issues.NewCollector(codes, c.Config),
32 | }
33 |
34 | var err error
35 | cl.Cluster, err = c.cluster(ctx)
36 | if err != nil {
37 | log.Error().Err(err).Msgf("Unable to gather cluster info")
38 | }
39 |
40 | return &cl
41 | }
42 |
43 | func (d *Cluster) Preloads() Preloads {
44 | return nil
45 | }
46 |
47 | // Lint all available Clusters.
48 | func (d *Cluster) Lint(ctx context.Context) error {
49 | return lint.NewCluster(d.Collector, d).Lint(ctx)
50 | }
51 |
52 | func (d *Cluster) HasMetrics() bool {
53 | return d.client.HasMetrics()
54 | }
55 |
--------------------------------------------------------------------------------
/internal/scrub/cm.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/issues"
12 | "github.com/derailed/popeye/internal/lint"
13 | v1 "k8s.io/api/core/v1"
14 | )
15 |
16 | // ConfigMap represents a configMap scruber.
17 | type ConfigMap struct {
18 | *issues.Collector
19 | *Cache
20 | }
21 |
22 | // NewConfigMap returns a new instance.
23 | func NewConfigMap(_ context.Context, c *Cache, codes *issues.Codes) Linter {
24 | return &ConfigMap{
25 | Collector: issues.NewCollector(codes, c.Config),
26 | Cache: c,
27 | }
28 | }
29 |
30 | func (s *ConfigMap) Preloads() Preloads {
31 | return Preloads{
32 | internal.CM: db.LoadResource[*v1.ConfigMap],
33 | internal.PO: db.LoadResource[*v1.Pod],
34 | }
35 | }
36 |
37 | // Lint all available ConfigMaps.
38 | func (s *ConfigMap) Lint(ctx context.Context) error {
39 | for k, f := range s.Preloads() {
40 | if err := f(ctx, s.Loader, internal.Glossary[k]); err != nil {
41 | return err
42 | }
43 | }
44 |
45 | return lint.NewConfigMap(s.Collector, s.DB).Lint(ctx)
46 | }
47 |
--------------------------------------------------------------------------------
/internal/scrub/cr.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/issues"
12 | "github.com/derailed/popeye/internal/lint"
13 | v1 "k8s.io/api/core/v1"
14 | rbacv1 "k8s.io/api/rbac/v1"
15 | )
16 |
17 | // ClusterRole represents a ClusterRole scruber.
18 | type ClusterRole struct {
19 | *issues.Collector
20 | *Cache
21 | }
22 |
23 | // NewClusterRole returns a new instance.
24 | func NewClusterRole(_ context.Context, c *Cache, codes *issues.Codes) Linter {
25 | return &ClusterRole{
26 | Collector: issues.NewCollector(codes, c.Config),
27 | Cache: c,
28 | }
29 | }
30 |
31 | func (s *ClusterRole) Preloads() Preloads {
32 | return Preloads{
33 | internal.CR: db.LoadResource[*rbacv1.ClusterRole],
34 | internal.CRB: db.LoadResource[*rbacv1.ClusterRoleBinding],
35 | internal.RO: db.LoadResource[*rbacv1.Role],
36 | internal.SA: db.LoadResource[*v1.ServiceAccount],
37 | }
38 | }
39 |
40 | // Lint all available ClusterRoles.
41 | func (s *ClusterRole) Lint(ctx context.Context) error {
42 | for k, f := range s.Preloads() {
43 | if err := f(ctx, s.Loader, internal.Glossary[k]); err != nil {
44 | return err
45 | }
46 | }
47 |
48 | return lint.NewClusterRole(s.Collector, s.DB).Lint(ctx)
49 | }
50 |
--------------------------------------------------------------------------------
/internal/scrub/crb.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/issues"
12 | "github.com/derailed/popeye/internal/lint"
13 | v1 "k8s.io/api/core/v1"
14 | rbacv1 "k8s.io/api/rbac/v1"
15 | )
16 |
17 | // ClusterRoleBinding represents a ClusterRoleBinding scruber.
18 | type ClusterRoleBinding struct {
19 | *issues.Collector
20 | *Cache
21 | }
22 |
23 | // NewClusterRoleBinding returns a new instance.
24 | func NewClusterRoleBinding(_ context.Context, c *Cache, codes *issues.Codes) Linter {
25 | return &ClusterRoleBinding{
26 | Collector: issues.NewCollector(codes, c.Config),
27 | Cache: c,
28 | }
29 | }
30 |
31 | func (s *ClusterRoleBinding) Preloads() Preloads {
32 | return Preloads{
33 | internal.CRB: db.LoadResource[*rbacv1.ClusterRoleBinding],
34 | internal.CR: db.LoadResource[*rbacv1.ClusterRole],
35 | internal.RO: db.LoadResource[*rbacv1.Role],
36 | internal.SA: db.LoadResource[*v1.ServiceAccount],
37 | }
38 | }
39 |
40 | // Lint all available ClusterRoleBindings.
41 | func (s *ClusterRoleBinding) Lint(ctx context.Context) error {
42 | for k, f := range s.Preloads() {
43 | if err := f(ctx, s.Loader, internal.Glossary[k]); err != nil {
44 | return err
45 | }
46 | }
47 |
48 | return lint.NewClusterRoleBinding(s.Collector, s.DB).Lint(ctx)
49 | }
50 |
--------------------------------------------------------------------------------
/internal/scrub/dp.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/issues"
12 | "github.com/derailed/popeye/internal/lint"
13 | appsv1 "k8s.io/api/apps/v1"
14 | v1 "k8s.io/api/core/v1"
15 | mv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
16 | )
17 |
18 | // Deployment represents a Deployment scruber.
19 | type Deployment struct {
20 | *issues.Collector
21 | *Cache
22 | }
23 |
24 | // NewDeployment returns a new instance.
25 | func NewDeployment(_ context.Context, c *Cache, codes *issues.Codes) Linter {
26 | return &Deployment{
27 | Collector: issues.NewCollector(codes, c.Config),
28 | Cache: c,
29 | }
30 | }
31 |
32 | func (s *Deployment) Preloads() Preloads {
33 | return Preloads{
34 | internal.DP: db.LoadResource[*appsv1.Deployment],
35 | internal.PO: db.LoadResource[*v1.Pod],
36 | internal.SA: db.LoadResource[*v1.ServiceAccount],
37 | internal.PMX: db.LoadResource[*mv1beta1.PodMetrics],
38 | }
39 | }
40 |
41 | // Lint all available Deployments.
42 | func (s *Deployment) Lint(ctx context.Context) error {
43 | for k, f := range s.Preloads() {
44 | if err := f(ctx, s.Loader, internal.Glossary[k]); err != nil {
45 | return err
46 | }
47 | }
48 |
49 | return lint.NewDeployment(s.Collector, s.DB).Lint(ctx)
50 | }
51 |
--------------------------------------------------------------------------------
/internal/scrub/ds.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/issues"
12 | "github.com/derailed/popeye/internal/lint"
13 | appsv1 "k8s.io/api/apps/v1"
14 | v1 "k8s.io/api/core/v1"
15 | mv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
16 | )
17 |
18 | // DaemonSet represents a DaemonSet scruber.
19 | type DaemonSet struct {
20 | *issues.Collector
21 | *Cache
22 | }
23 |
24 | // NewDaemonSet return a new instance.
25 | func NewDaemonSet(_ context.Context, c *Cache, codes *issues.Codes) Linter {
26 | return &DaemonSet{
27 | Collector: issues.NewCollector(codes, c.Config),
28 | Cache: c,
29 | }
30 |
31 | }
32 |
33 | func (s *DaemonSet) Preloads() Preloads {
34 | return Preloads{
35 | internal.DS: db.LoadResource[*appsv1.DaemonSet],
36 | internal.PO: db.LoadResource[*v1.Pod],
37 | internal.SA: db.LoadResource[*v1.ServiceAccount],
38 | internal.PMX: db.LoadResource[*mv1beta1.PodMetrics],
39 | }
40 | }
41 |
42 | // Lint all available DaemonSets.
43 | func (s *DaemonSet) Lint(ctx context.Context) error {
44 | for k, f := range s.Preloads() {
45 | if err := f(ctx, s.Loader, internal.Glossary[k]); err != nil {
46 | return err
47 | }
48 | }
49 |
50 | return lint.NewDaemonSet(s.Collector, s.DB).Lint(ctx)
51 | }
52 |
--------------------------------------------------------------------------------
/internal/scrub/gw-route.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/issues"
12 | "github.com/derailed/popeye/internal/lint"
13 | gwv1 "sigs.k8s.io/gateway-api/apis/v1"
14 | )
15 |
16 | // HTTPRoute represents a HTTPRoute scruber.
17 | type HTTPRoute struct {
18 | *issues.Collector
19 | *Cache
20 | }
21 |
22 | // NewHTTPRoute return a new instance.
23 | func NewHTTPRoute(_ context.Context, c *Cache, codes *issues.Codes) Linter {
24 | return &HTTPRoute{
25 | Collector: issues.NewCollector(codes, c.Config),
26 | Cache: c,
27 | }
28 | }
29 |
30 | func (s *HTTPRoute) Preloads() Preloads {
31 | return Preloads{
32 | internal.GW: db.LoadResource[*gwv1.Gateway],
33 | internal.GWC: db.LoadResource[*gwv1.GatewayClass],
34 | internal.GWR: db.LoadResource[*gwv1.HTTPRoute],
35 | }
36 | }
37 |
38 | // Lint all available HTTPRoute.
39 | func (s *HTTPRoute) Lint(ctx context.Context) error {
40 | for k, f := range s.Preloads() {
41 | if err := f(ctx, s.Loader, internal.Glossary[k]); err != nil {
42 | return err
43 | }
44 | }
45 |
46 | return lint.NewHTTPRoute(s.Collector, s.DB).Lint(ctx)
47 | }
48 |
--------------------------------------------------------------------------------
/internal/scrub/gw.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/issues"
12 | "github.com/derailed/popeye/internal/lint"
13 | gwv1 "sigs.k8s.io/gateway-api/apis/v1"
14 | )
15 |
16 | // Gateway represents a Gateway scruber.
17 | type Gateway struct {
18 | *issues.Collector
19 | *Cache
20 | }
21 |
22 | // NewGateway return a new instance.
23 | func NewGateway(_ context.Context, c *Cache, codes *issues.Codes) Linter {
24 | return &Gateway{
25 | Collector: issues.NewCollector(codes, c.Config),
26 | Cache: c,
27 | }
28 | }
29 |
30 | func (s *Gateway) Preloads() Preloads {
31 | return Preloads{
32 | internal.GW: db.LoadResource[*gwv1.Gateway],
33 | internal.GWC: db.LoadResource[*gwv1.GatewayClass],
34 | }
35 | }
36 |
37 | // Lint all available Gateway.
38 | func (s *Gateway) Lint(ctx context.Context) error {
39 | for k, f := range s.Preloads() {
40 | if err := f(ctx, s.Loader, internal.Glossary[k]); err != nil {
41 | return err
42 | }
43 | }
44 |
45 | return lint.NewGateway(s.Collector, s.DB).Lint(ctx)
46 | }
47 |
--------------------------------------------------------------------------------
/internal/scrub/gwc.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/issues"
12 | "github.com/derailed/popeye/internal/lint"
13 | gwv1 "sigs.k8s.io/gateway-api/apis/v1"
14 | )
15 |
16 | // GatewayClass represents a GatewayClass scruber.
17 | type GatewayClass struct {
18 | *issues.Collector
19 | *Cache
20 | }
21 |
22 | // NewGatewayClass return a new instance.
23 | func NewGatewayClass(_ context.Context, c *Cache, codes *issues.Codes) Linter {
24 | return &GatewayClass{
25 | Collector: issues.NewCollector(codes, c.Config),
26 | Cache: c,
27 | }
28 | }
29 |
30 | func (s *GatewayClass) Preloads() Preloads {
31 | return Preloads{
32 | internal.GW: db.LoadResource[*gwv1.Gateway],
33 | internal.GWC: db.LoadResource[*gwv1.GatewayClass],
34 | }
35 | }
36 |
37 | // Lint all available GatewayClass.
38 | func (s *GatewayClass) Lint(ctx context.Context) error {
39 | for k, f := range s.Preloads() {
40 | if err := f(ctx, s.Loader, internal.Glossary[k]); err != nil {
41 | return err
42 | }
43 | }
44 |
45 | return lint.NewGatewayClass(s.Collector, s.DB).Lint(ctx)
46 | }
47 |
--------------------------------------------------------------------------------
/internal/scrub/ing.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/issues"
12 | "github.com/derailed/popeye/internal/lint"
13 | v1 "k8s.io/api/core/v1"
14 | netv1 "k8s.io/api/networking/v1"
15 | )
16 |
17 | // Ingress represents a Ingress scruber.
18 | type Ingress struct {
19 | *issues.Collector
20 | *Cache
21 | }
22 |
23 | // NewIngress return a new instance.
24 | func NewIngress(_ context.Context, c *Cache, codes *issues.Codes) Linter {
25 | return &Ingress{
26 | Collector: issues.NewCollector(codes, c.Config),
27 | Cache: c,
28 | }
29 | }
30 |
31 | func (s *Ingress) Preloads() Preloads {
32 | return Preloads{
33 | internal.ING: db.LoadResource[*netv1.Ingress],
34 | internal.SVC: db.LoadResource[*v1.Service],
35 | }
36 | }
37 |
38 | // Lint all available Ingress.
39 | func (s *Ingress) Lint(ctx context.Context) error {
40 | for k, f := range s.Preloads() {
41 | if err := f(ctx, s.Loader, internal.Glossary[k]); err != nil {
42 | return err
43 | }
44 | }
45 |
46 | return lint.NewIngress(s.Collector, s.DB).Lint(ctx)
47 | }
48 |
--------------------------------------------------------------------------------
/internal/scrub/job.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/issues"
12 | "github.com/derailed/popeye/internal/lint"
13 | batchv1 "k8s.io/api/batch/v1"
14 | v1 "k8s.io/api/core/v1"
15 | mv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
16 | )
17 |
18 | // Job represents a Job scruber.
19 | type Job struct {
20 | *issues.Collector
21 | *Cache
22 | }
23 |
24 | // NewJob return a new instance.
25 | func NewJob(_ context.Context, c *Cache, codes *issues.Codes) Linter {
26 | return &Job{
27 | Collector: issues.NewCollector(codes, c.Config),
28 | Cache: c,
29 | }
30 | }
31 |
32 | func (s *Job) Preloads() Preloads {
33 | return Preloads{
34 | internal.CJOB: db.LoadResource[*batchv1.CronJob],
35 | internal.JOB: db.LoadResource[*batchv1.Job],
36 | internal.PO: db.LoadResource[*v1.Pod],
37 | internal.SA: db.LoadResource[*v1.ServiceAccount],
38 | internal.PMX: db.LoadResource[*mv1beta1.PodMetrics],
39 | }
40 | }
41 |
42 | // Lint all available Jobs.
43 | func (s *Job) Lint(ctx context.Context) error {
44 | for k, f := range s.Preloads() {
45 | if err := f(ctx, s.Loader, internal.Glossary[k]); err != nil {
46 | return err
47 | }
48 | }
49 |
50 | return lint.NewJob(s.Collector, s.DB).Lint(ctx)
51 | }
52 |
--------------------------------------------------------------------------------
/internal/scrub/no.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/issues"
12 | "github.com/derailed/popeye/internal/lint"
13 | v1 "k8s.io/api/core/v1"
14 | mv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
15 | )
16 |
17 | // Node represents a Node scruber.
18 | type Node struct {
19 | *issues.Collector
20 | *Cache
21 | }
22 |
23 | // NewNode return a new instance.
24 | func NewNode(_ context.Context, c *Cache, codes *issues.Codes) Linter {
25 | return &Node{
26 | Collector: issues.NewCollector(codes, c.Config),
27 | Cache: c,
28 | }
29 | }
30 |
31 | func (s *Node) Preloads() Preloads {
32 | return Preloads{
33 | internal.NO: db.LoadResource[*v1.Node],
34 | internal.PO: db.LoadResource[*v1.Pod],
35 | internal.NMX: db.LoadResource[*mv1beta1.NodeMetrics],
36 | }
37 | }
38 |
39 | // Lint all available Nodes.
40 | func (s *Node) Lint(ctx context.Context) error {
41 | for k, f := range s.Preloads() {
42 | if err := f(ctx, s.Loader, internal.Glossary[k]); err != nil {
43 | return err
44 | }
45 | }
46 |
47 | return lint.NewNode(s.Collector, s.DB).Lint(ctx)
48 | }
49 |
--------------------------------------------------------------------------------
/internal/scrub/np.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/issues"
12 | "github.com/derailed/popeye/internal/lint"
13 | v1 "k8s.io/api/core/v1"
14 | netv1 "k8s.io/api/networking/v1"
15 | )
16 |
17 | // NetworkPolicy represents a NetworkPolicy scruber.
18 | type NetworkPolicy struct {
19 | *issues.Collector
20 | *Cache
21 | }
22 |
23 | // NewNetworkPolicy return a new instance.
24 | func NewNetworkPolicy(_ context.Context, c *Cache, codes *issues.Codes) Linter {
25 | return &NetworkPolicy{
26 | Collector: issues.NewCollector(codes, c.Config),
27 | Cache: c,
28 | }
29 | }
30 |
31 | func (s *NetworkPolicy) Preloads() Preloads {
32 | return Preloads{
33 | internal.NP: db.LoadResource[*netv1.NetworkPolicy],
34 | internal.NS: db.LoadResource[*v1.Namespace],
35 | internal.PO: db.LoadResource[*v1.Pod],
36 | }
37 | }
38 |
39 | // Lint all available NetworkPolicies.
40 | func (s *NetworkPolicy) Lint(ctx context.Context) error {
41 | for k, f := range s.Preloads() {
42 | if err := f(ctx, s.Loader, internal.Glossary[k]); err != nil {
43 | return err
44 | }
45 | }
46 |
47 | return lint.NewNetworkPolicy(s.Collector, s.DB).Lint(ctx)
48 | }
49 |
--------------------------------------------------------------------------------
/internal/scrub/ns.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/issues"
12 | "github.com/derailed/popeye/internal/lint"
13 | v1 "k8s.io/api/core/v1"
14 | )
15 |
16 | // Namespace represents a Namespace scruber.
17 | type Namespace struct {
18 | *issues.Collector
19 | *Cache
20 | }
21 |
22 | // NewNamespace returns a new instance.
23 | func NewNamespace(_ context.Context, c *Cache, codes *issues.Codes) Linter {
24 | return &Namespace{
25 | Collector: issues.NewCollector(codes, c.Config),
26 | Cache: c,
27 | }
28 | }
29 |
30 | func (s *Namespace) Preloads() Preloads {
31 | return Preloads{
32 | internal.NS: db.LoadResource[*v1.Namespace],
33 | internal.PO: db.LoadResource[*v1.Pod],
34 | internal.SA: db.LoadResource[*v1.ServiceAccount],
35 | }
36 | }
37 |
38 | // Lint all available Namespaces.
39 | func (s *Namespace) Lint(ctx context.Context) error {
40 | for k, f := range s.Preloads() {
41 | if err := f(ctx, s.Loader, internal.Glossary[k]); err != nil {
42 | return err
43 | }
44 | }
45 |
46 | return lint.NewNamespace(s.Collector, s.DB).Lint(ctx)
47 | }
48 |
--------------------------------------------------------------------------------
/internal/scrub/pdb.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/issues"
12 | "github.com/derailed/popeye/internal/lint"
13 | v1 "k8s.io/api/core/v1"
14 | polv1 "k8s.io/api/policy/v1"
15 | )
16 |
17 | // PodDisruptionBudget represents a pdb scruber.
18 | type PodDisruptionBudget struct {
19 | *issues.Collector
20 | *Cache
21 | }
22 |
23 | // NewPodDisruptionBudget return a new PodDisruptionBudget scruber.
24 | func NewPodDisruptionBudget(_ context.Context, c *Cache, codes *issues.Codes) Linter {
25 | return &PodDisruptionBudget{
26 | Collector: issues.NewCollector(codes, c.Config),
27 | Cache: c,
28 | }
29 | }
30 |
31 | func (s *PodDisruptionBudget) Preloads() Preloads {
32 | return Preloads{
33 | internal.PDB: db.LoadResource[*polv1.PodDisruptionBudget],
34 | internal.PO: db.LoadResource[*v1.Pod],
35 | }
36 | }
37 |
38 | // Lint all available PodDisruptionBudgets.
39 | func (s *PodDisruptionBudget) Lint(ctx context.Context) error {
40 | for k, f := range s.Preloads() {
41 | if err := f(ctx, s.Loader, internal.Glossary[k]); err != nil {
42 | return err
43 | }
44 | }
45 |
46 | return lint.NewPodDisruptionBudget(s.Collector, s.DB).Lint(ctx)
47 | }
48 |
--------------------------------------------------------------------------------
/internal/scrub/pod.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/issues"
12 | "github.com/derailed/popeye/internal/lint"
13 | v1 "k8s.io/api/core/v1"
14 | netv1 "k8s.io/api/networking/v1"
15 | polv1 "k8s.io/api/policy/v1"
16 | mv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
17 | )
18 |
19 | // Pod represents a Pod scruber.
20 | type Pod struct {
21 | *issues.Collector
22 | *Cache
23 | }
24 |
25 | // NewPod return a new instance.
26 | func NewPod(_ context.Context, c *Cache, codes *issues.Codes) Linter {
27 | return &Pod{
28 | Collector: issues.NewCollector(codes, c.Config),
29 | Cache: c,
30 | }
31 | }
32 |
33 | func (s *Pod) Preloads() Preloads {
34 | return Preloads{
35 | internal.PO: db.LoadResource[*v1.Pod],
36 | internal.SA: db.LoadResource[*v1.ServiceAccount],
37 | internal.PDB: db.LoadResource[*polv1.PodDisruptionBudget],
38 | internal.NP: db.LoadResource[*netv1.NetworkPolicy],
39 | internal.PMX: db.LoadResource[*mv1beta1.PodMetrics],
40 | }
41 | }
42 |
43 | // Lint all available Pods.
44 | func (s *Pod) Lint(ctx context.Context) error {
45 | for k, f := range s.Preloads() {
46 | if err := f(ctx, s.Loader, internal.Glossary[k]); err != nil {
47 | return err
48 | }
49 | }
50 |
51 | return lint.NewPod(s.Collector, s.DB).Lint(ctx)
52 | }
53 |
--------------------------------------------------------------------------------
/internal/scrub/preload.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import "github.com/derailed/popeye/internal"
7 |
8 | type Preloads map[internal.R]LoaderFn
9 |
10 | func (p Preloads) Merge(ll Preloads) {
11 | for k, v := range ll {
12 | if _, ok := p[k]; ok {
13 | continue
14 | }
15 | p[k] = v
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/internal/scrub/pv.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/issues"
12 | "github.com/derailed/popeye/internal/lint"
13 | v1 "k8s.io/api/core/v1"
14 | )
15 |
16 | // PersistentVolume represents a PersistentVolume scruber.
17 | type PersistentVolume struct {
18 | *issues.Collector
19 | *Cache
20 | }
21 |
22 | // NewPersistentVolume return a new instance.
23 | func NewPersistentVolume(_ context.Context, c *Cache, codes *issues.Codes) Linter {
24 | return &PersistentVolume{
25 | Collector: issues.NewCollector(codes, c.Config),
26 | Cache: c,
27 | }
28 | }
29 |
30 | func (s *PersistentVolume) Preloads() Preloads {
31 | return Preloads{
32 | internal.PV: db.LoadResource[*v1.PersistentVolume],
33 | internal.PO: db.LoadResource[*v1.Pod],
34 | }
35 | }
36 |
37 | // Lint all available PersistentVolumes.
38 | func (s *PersistentVolume) Lint(ctx context.Context) error {
39 | for k, f := range s.Preloads() {
40 | if err := f(ctx, s.Loader, internal.Glossary[k]); err != nil {
41 | return err
42 | }
43 | }
44 |
45 | return lint.NewPersistentVolume(s.Collector, s.DB).Lint(ctx)
46 | }
47 |
--------------------------------------------------------------------------------
/internal/scrub/pvc.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/issues"
12 | "github.com/derailed/popeye/internal/lint"
13 | v1 "k8s.io/api/core/v1"
14 | )
15 |
16 | // PersistentVolumeClaim represents a PersistentVolumeClaim scruber.
17 | type PersistentVolumeClaim struct {
18 | *issues.Collector
19 | *Cache
20 | }
21 |
22 | // NewPersistentVolumeClaim returns a new instance.
23 | func NewPersistentVolumeClaim(_ context.Context, c *Cache, codes *issues.Codes) Linter {
24 | return &PersistentVolumeClaim{
25 | Collector: issues.NewCollector(codes, c.Config),
26 | Cache: c,
27 | }
28 | }
29 |
30 | func (s *PersistentVolumeClaim) Preloads() Preloads {
31 | return Preloads{
32 | internal.PVC: db.LoadResource[*v1.PersistentVolumeClaim],
33 | internal.PO: db.LoadResource[*v1.Pod],
34 | }
35 | }
36 |
37 | // Lint all available PersistentVolumeClaims.
38 | func (s *PersistentVolumeClaim) Lint(ctx context.Context) error {
39 | for k, f := range s.Preloads() {
40 | if err := f(ctx, s.Loader, internal.Glossary[k]); err != nil {
41 | return err
42 | }
43 | }
44 |
45 | return lint.NewPersistentVolumeClaim(s.Collector, s.DB).Lint(ctx)
46 | }
47 |
--------------------------------------------------------------------------------
/internal/scrub/rb.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/issues"
12 | "github.com/derailed/popeye/internal/lint"
13 | v1 "k8s.io/api/core/v1"
14 | rbacv1 "k8s.io/api/rbac/v1"
15 | )
16 |
17 | // RoleBinding represents a RoleBinding scruber.
18 | type RoleBinding struct {
19 | *issues.Collector
20 | *Cache
21 | }
22 |
23 | // NewRoleBinding returns a new instance.
24 | func NewRoleBinding(_ context.Context, c *Cache, codes *issues.Codes) Linter {
25 | return &RoleBinding{
26 | Collector: issues.NewCollector(codes, c.Config),
27 | Cache: c,
28 | }
29 | }
30 |
31 | func (s *RoleBinding) Preloads() Preloads {
32 | return Preloads{
33 | internal.ROB: db.LoadResource[*rbacv1.RoleBinding],
34 | internal.RO: db.LoadResource[*rbacv1.Role],
35 | internal.CR: db.LoadResource[*rbacv1.ClusterRole],
36 | internal.CRB: db.LoadResource[*rbacv1.ClusterRoleBinding],
37 | internal.SA: db.LoadResource[*v1.ServiceAccount],
38 | }
39 | }
40 |
41 | // Lint all available RoleBindings.
42 | func (s *RoleBinding) Lint(ctx context.Context) error {
43 | for k, f := range s.Preloads() {
44 | if err := f(ctx, s.Loader, internal.Glossary[k]); err != nil {
45 | return err
46 | }
47 | }
48 |
49 | return lint.NewRoleBinding(s.Collector, s.DB).Lint(ctx)
50 | }
51 |
--------------------------------------------------------------------------------
/internal/scrub/ro.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/issues"
12 | "github.com/derailed/popeye/internal/lint"
13 | rbacv1 "k8s.io/api/rbac/v1"
14 | )
15 |
16 | // Role represents a Role scruber.
17 | type Role struct {
18 | *issues.Collector
19 | *Cache
20 | }
21 |
22 | // NewRole returns a new instance.
23 | func NewRole(_ context.Context, c *Cache, codes *issues.Codes) Linter {
24 | return &Role{
25 | Collector: issues.NewCollector(codes, c.Config),
26 | Cache: c,
27 | }
28 | }
29 |
30 | func (s *Role) Preloads() Preloads {
31 | return Preloads{
32 | internal.RO: db.LoadResource[*rbacv1.Role],
33 | internal.ROB: db.LoadResource[*rbacv1.RoleBinding],
34 | internal.CRB: db.LoadResource[*rbacv1.ClusterRoleBinding],
35 | }
36 | }
37 |
38 | // Lint all available Roles.
39 | func (s *Role) Lint(ctx context.Context) error {
40 | for k, f := range s.Preloads() {
41 | if err := f(ctx, s.Loader, internal.Glossary[k]); err != nil {
42 | return err
43 | }
44 | }
45 |
46 | return lint.NewRole(s.Collector, s.DB).Lint(ctx)
47 | }
48 |
--------------------------------------------------------------------------------
/internal/scrub/rs.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/issues"
12 | "github.com/derailed/popeye/internal/lint"
13 | appsv1 "k8s.io/api/apps/v1"
14 | v1 "k8s.io/api/core/v1"
15 | )
16 |
17 | // ReplicaSet represents a ReplicaSet scruber.
18 | type ReplicaSet struct {
19 | *issues.Collector
20 | *Cache
21 | }
22 |
23 | // NewReplicaSet returns a new instance.
24 | func NewReplicaSet(_ context.Context, c *Cache, codes *issues.Codes) Linter {
25 | return &ReplicaSet{
26 | Collector: issues.NewCollector(codes, c.Config),
27 | Cache: c,
28 | }
29 | }
30 |
31 | func (s *ReplicaSet) Preloads() Preloads {
32 | return Preloads{
33 | internal.RS: db.LoadResource[*appsv1.ReplicaSet],
34 | internal.PO: db.LoadResource[*v1.Pod],
35 | }
36 | }
37 |
38 | // Lint all available ReplicaSets.
39 | func (s *ReplicaSet) Lint(ctx context.Context) error {
40 | for k, f := range s.Preloads() {
41 | if err := f(ctx, s.Loader, internal.Glossary[k]); err != nil {
42 | return err
43 | }
44 | }
45 |
46 | return lint.NewReplicaSet(s.Collector, s.DB).Lint(ctx)
47 | }
48 |
--------------------------------------------------------------------------------
/internal/scrub/sec.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/issues"
12 | "github.com/derailed/popeye/internal/lint"
13 | v1 "k8s.io/api/core/v1"
14 | netv1 "k8s.io/api/networking/v1"
15 | )
16 |
17 | // Secret represents a Secret scruber.
18 | type Secret struct {
19 | *issues.Collector
20 | *Cache
21 | }
22 |
23 | // NewSecret return a new Secret scruber.
24 | func NewSecret(_ context.Context, c *Cache, codes *issues.Codes) Linter {
25 | return &Secret{
26 | Collector: issues.NewCollector(codes, c.Config),
27 | Cache: c,
28 | }
29 | }
30 |
31 | func (s *Secret) Preloads() Preloads {
32 | return Preloads{
33 | internal.SEC: db.LoadResource[*v1.Secret],
34 | internal.PO: db.LoadResource[*v1.Pod],
35 | internal.SA: db.LoadResource[*v1.ServiceAccount],
36 | internal.ING: db.LoadResource[*netv1.Ingress],
37 | }
38 | }
39 |
40 | // Lint all available Secrets.
41 | func (s *Secret) Lint(ctx context.Context) error {
42 | for k, f := range s.Preloads() {
43 | if err := f(ctx, s.Loader, internal.Glossary[k]); err != nil {
44 | return err
45 | }
46 | }
47 |
48 | return lint.NewSecret(s.Collector, s.DB).Lint(ctx)
49 | }
50 |
--------------------------------------------------------------------------------
/internal/scrub/sts.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/issues"
12 | "github.com/derailed/popeye/internal/lint"
13 | appsv1 "k8s.io/api/apps/v1"
14 | v1 "k8s.io/api/core/v1"
15 | mv1beta1 "k8s.io/metrics/pkg/apis/metrics/v1beta1"
16 | )
17 |
18 | // StatefulSet represents a StatefulSet scruber.
19 | type StatefulSet struct {
20 | *issues.Collector
21 | *Cache
22 | }
23 |
24 | // NewStatefulSet return a new StatefulSet scruber.
25 | func NewStatefulSet(_ context.Context, c *Cache, codes *issues.Codes) Linter {
26 | return &StatefulSet{
27 | Collector: issues.NewCollector(codes, c.Config),
28 | Cache: c,
29 | }
30 | }
31 |
32 | func (s *StatefulSet) Preloads() Preloads {
33 | return Preloads{
34 | internal.STS: db.LoadResource[*appsv1.StatefulSet],
35 | internal.PO: db.LoadResource[*v1.Pod],
36 | internal.SA: db.LoadResource[*v1.ServiceAccount],
37 | internal.PMX: db.LoadResource[*mv1beta1.PodMetrics],
38 | }
39 | }
40 |
41 | // Lint all available StatefulSets.
42 | func (s *StatefulSet) Lint(ctx context.Context) error {
43 | for k, f := range s.Preloads() {
44 | if err := f(ctx, s.Loader, internal.Glossary[k]); err != nil {
45 | return err
46 | }
47 | }
48 |
49 | return lint.NewStatefulSet(s.Collector, s.DB).Lint(ctx)
50 | }
51 |
--------------------------------------------------------------------------------
/internal/scrub/svc.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/issues"
12 | "github.com/derailed/popeye/internal/lint"
13 | v1 "k8s.io/api/core/v1"
14 | )
15 |
16 | // Service represents a Service scruber.
17 | type Service struct {
18 | *issues.Collector
19 | *Cache
20 | }
21 |
22 | // NewService return a new instance.
23 | func NewService(_ context.Context, c *Cache, codes *issues.Codes) Linter {
24 | return &Service{
25 | Collector: issues.NewCollector(codes, c.Config),
26 | Cache: c,
27 | }
28 | }
29 |
30 | func (s *Service) Preloads() Preloads {
31 | return Preloads{
32 | internal.SVC: db.LoadResource[*v1.Service],
33 | internal.PO: db.LoadResource[*v1.Pod],
34 | internal.EP: db.LoadResource[*v1.Endpoints],
35 | }
36 | }
37 |
38 | // Lint all available Services.
39 | func (s *Service) Lint(ctx context.Context) error {
40 | for k, f := range s.Preloads() {
41 | if err := f(ctx, s.Loader, internal.Glossary[k]); err != nil {
42 | return err
43 | }
44 | }
45 |
46 | return lint.NewService(s.Collector, s.DB).Lint(ctx)
47 | }
48 |
--------------------------------------------------------------------------------
/internal/scrub/types.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package scrub
5 |
6 | import (
7 | "context"
8 |
9 | "github.com/derailed/popeye/internal"
10 | "github.com/derailed/popeye/internal/db"
11 | "github.com/derailed/popeye/internal/issues"
12 | "github.com/derailed/popeye/internal/rules"
13 | "github.com/derailed/popeye/types"
14 | )
15 |
16 | type Scrubs map[internal.R]ScrubFn
17 |
18 | // ScrubFn represents a resource scruber.
19 | type ScrubFn func(context.Context, *Cache, *issues.Codes) Linter
20 |
21 | // LoaderFn represents a resource loader.
22 | type LoaderFn func(context.Context, *db.Loader, types.GVR) error
23 |
24 | // Collector collects sanitization issues.
25 | type Collector interface {
26 | MaxSeverity(res string) rules.Level
27 | Outcome() issues.Outcome
28 | }
29 |
30 | // Linter represents a resource linter.
31 | type Linter interface {
32 | // Collector tracks issues.
33 | Collector
34 |
35 | // Lint runs checks on a resource.
36 | Lint(context.Context) error
37 |
38 | // Preloads Preloads resource requirements.
39 | Preloads() Preloads
40 | }
41 |
--------------------------------------------------------------------------------
/internal/stringset.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package internal
5 |
6 | // All indicates all data keys are being used when referencing a cm or secret.
7 | const All = "all"
8 |
9 | // Empty denotes an empty value.
10 | type Empty struct{}
11 |
12 | // Blank represents an empty value.
13 | var Blank = Empty{}
14 |
15 | // StringSet represents a set of strings.
16 | type StringSet map[string]Empty
17 |
18 | // AllKeys indicates all keys are present.
19 | var AllKeys = StringSet{All: Blank}
20 |
21 | // AddAll merges two sets.
22 | func (ss StringSet) AddAll(s StringSet) {
23 | for k := range s {
24 | ss[k] = Blank
25 | }
26 | }
27 |
28 | // Add a collection of elements to the set.
29 | func (ss StringSet) Add(strs ...string) {
30 | for _, s := range strs {
31 | ss[s] = Blank
32 | }
33 | }
34 |
35 | // Clone returns a new copy.
36 | func (ss StringSet) Clone() StringSet {
37 | clone := make(StringSet, len(ss))
38 | for k, v := range ss {
39 | clone[k] = v
40 | }
41 | return clone
42 | }
43 |
44 | // Has checks if an item is in the set.
45 | func (ss StringSet) Has(s string) bool {
46 | _, ok := ss[s]
47 |
48 | return ok
49 | }
50 |
51 | // Diff computes B-A.
52 | func (ss StringSet) Diff(set StringSet) StringSet {
53 | delta := make(StringSet)
54 | for k := range set {
55 | if _, ok := ss[k]; !ok {
56 | delta.Add(k)
57 | }
58 | }
59 |
60 | return delta
61 | }
62 |
--------------------------------------------------------------------------------
/internal/types.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package internal
5 |
6 | // !!BOZO!!
7 | // type (
8 | // Linter int
9 | // Linters map[Linter]types.GVR
10 | // )
11 |
12 | // const (
13 | // LR Linter = iota
14 | // SVC
15 | // EP
16 | // NO
17 | // NS
18 | // PO
19 | // CM
20 | // SEC
21 | // SA
22 | // PV
23 | // PVC
24 | // DP
25 | // RS
26 | // DS
27 | // STS
28 | // NP
29 | // CR
30 | // CRB
31 | // RO
32 | // ROB
33 | // ING
34 | // PDB
35 | // PSP
36 | // HPA
37 | // )
38 |
--------------------------------------------------------------------------------
/k8s/popeye/cm.yml:
--------------------------------------------------------------------------------
1 | ---
2 | # Load Popeye spinach.yml as configmap
3 | apiVersion: v1
4 | kind: ConfigMap
5 | metadata:
6 | name: popeye
7 | namespace: popeye
8 | data:
9 | spinach: |-
10 | popeye:
11 | allocations:
12 | cpu:
13 | over: 100
14 | under: 50
15 | memory:
16 | over: 100
17 | under: 50
18 | node:
19 | limits:
20 | cpu: 90
21 | memory: 80
22 | pod:
23 | limits:
24 | cpu: 80
25 | memory: 75
26 | restarts:
27 | 5
--------------------------------------------------------------------------------
/k8s/popeye/cronjob.yml:
--------------------------------------------------------------------------------
1 | # Sample Popeye CronJob. Runs Popeye as a cron every hours
2 | ---
3 | apiVersion: batch/v1
4 | kind: CronJob
5 | metadata:
6 | name: popeye
7 | namespace: popeye
8 | spec:
9 | schedule: "59 23 * * *"
10 | concurrencyPolicy: Forbid
11 | jobTemplate:
12 | spec:
13 | template:
14 | spec:
15 | serviceAccountName: popeye
16 | restartPolicy: OnFailure
17 | containers:
18 | - name: popeye
19 | image: derailed/popeye:latest
20 | imagePullPolicy: IfNotPresent
21 | command: ["/bin/popeye"]
22 | args:
23 | - -f
24 | - /etc/config/popeye/spinach.yml
25 | - -o
26 | - yaml
27 | resources:
28 | limits:
29 | cpu: 500m
30 | memory: 100Mi
31 | volumeMounts:
32 | - name: spinach
33 | mountPath: /etc/config/popeye
34 | volumes:
35 | - name: spinach
36 | configMap:
37 | name: popeye
38 | items:
39 | - key: spinach
40 | path: spinach.yml
41 |
--------------------------------------------------------------------------------
/k8s/popeye/ns.yml:
--------------------------------------------------------------------------------
1 | # Create Namespace
2 | ---
3 | apiVersion: v1
4 | kind: Namespace
5 | metadata:
6 | name: popeye
--------------------------------------------------------------------------------
/main.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package main
5 |
6 | import (
7 | "github.com/derailed/popeye/cmd"
8 | _ "k8s.io/client-go/plugin/pkg/client/auth"
9 | )
10 |
11 | func main() {
12 | cmd.Execute()
13 | }
14 |
--------------------------------------------------------------------------------
/pkg/config/helpers.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package config
5 |
6 | import "regexp"
7 |
8 | var invalidPathCharsRX = regexp.MustCompile(`[:/]+`)
9 |
10 | func in(oo []string, p *string) bool {
11 | if p == nil {
12 | return true
13 | }
14 | for _, o := range oo {
15 | if o == *p {
16 | return true
17 | }
18 | }
19 |
20 | return false
21 | }
22 |
23 | // SanitizeFileName ensure file spec is valid.
24 | func SanitizeFileName(name string) string {
25 | return invalidPathCharsRX.ReplaceAllString(name, "-")
26 | }
27 |
28 | // IsStrSet checks string option is set.
29 | func IsStrSet(s *string) bool {
30 | return s != nil && *s != ""
31 | }
32 |
33 | // IsBoolSet checks bool option is set
34 | func IsBoolSet(s *bool) bool {
35 | return s != nil && *s
36 | }
37 |
38 | func boolPtr(b bool) *bool {
39 | return &b
40 | }
41 |
42 | func strPtr(s string) *string {
43 | return &s
44 | }
45 |
46 | func intPtr(i int) *int {
47 | return &i
48 | }
49 |
--------------------------------------------------------------------------------
/pkg/config/json/testdata/1.yaml:
--------------------------------------------------------------------------------
1 | # A Sample AKS Popeye configuration.
2 | popeye:
3 | allocations:
4 | cpu:
5 | underPercUtilization: 200
6 | overPercUtilization: 50
7 | memory:
8 | underPercUtilization: 200
9 | overPercUtilization: 50
10 |
11 | excludes:
12 | # all linters
13 | global:
14 | fqns: [ns1, ns2, rx:bozo]
15 | labels:
16 | l1: [lv1, lv2]
17 | l2: [lv1, lv2]
18 | annotations:
19 | a1: [av1, av2]
20 | a2: [bv1, bv2]
21 | containers: [c1, c2, rx:c3]
22 | codes: ["100", "200", "rx:^3"]
23 |
24 | # Specific linters
25 | linters:
26 | pods:
27 | - labels:
28 | l1: [v1,v2]
29 | containers: [c1, c2]
30 | codes: ["101", "200"]
31 | - fqns: [n1, n2, n3]
32 |
33 | configmaps:
34 | - labels:
35 | l1: [v1,v2]
36 | containers: [c1, c2]
37 | codes: ["101", "200"]
38 |
39 | resources:
40 | node:
41 | limits:
42 | cpu: 90
43 | memory: 80
44 |
45 | pod:
46 | restarts: 3
47 | limits:
48 | cpu: 80
49 | memory: 75
50 |
51 | overrides:
52 | - code: 206
53 | message: blee
54 | severity: 1
55 | - code: 210
56 | message: fred
57 | severity: 2
58 |
59 | registries:
60 | - docker.io
61 | - pocker.io
--------------------------------------------------------------------------------
/pkg/config/json/validator_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package json_test
5 |
6 | import (
7 | "os"
8 | "testing"
9 |
10 | "github.com/derailed/popeye/pkg/config/json"
11 | "github.com/stretchr/testify/assert"
12 | )
13 |
14 | func TestValidateSpinach(t *testing.T) {
15 | uu := map[string]struct {
16 | f string
17 | err string
18 | }{
19 | "happy": {
20 | f: "testdata/1.yaml",
21 | },
22 | "toast": {
23 | f: "testdata/toast.yaml",
24 | err: "Additional property rbac.authorization.k8s.io/v1/clusterroles is not allowed",
25 | },
26 | }
27 |
28 | v := json.NewValidator()
29 | for k := range uu {
30 | u := uu[k]
31 | t.Run(k, func(t *testing.T) {
32 | bb, err := os.ReadFile(u.f)
33 | assert.NoError(t, err)
34 | if err := v.Validate(json.SpinachSchema, bb); err != nil {
35 | assert.Equal(t, u.err, err.Error())
36 | }
37 | })
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/pkg/config/no.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package config
5 |
6 | const (
7 | defaultCPULimit = 80 // percentage
8 | defaultMEMLimit = 80 // percentage
9 | )
10 |
11 | // Limits tracks cpu and mem limits.
12 | type Limits struct {
13 | CPU float64 `yaml:"cpu"`
14 | Memory float64 `yam:"memory"`
15 | }
16 |
17 | // Node tracks node configurations.
18 | type Node struct {
19 | Limits Limits `yaml:"limits"`
20 | }
21 |
22 | // NewNode create a new node configuration.
23 | func newNode() Node {
24 | return Node{
25 | Limits: Limits{
26 | CPU: defaultCPULimit,
27 | Memory: defaultMEMLimit,
28 | },
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/pkg/config/po.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package config
5 |
6 | const defaultRestarts = 5
7 |
8 | // Pod tracks pod configurations.
9 | type Pod struct {
10 | Restarts int `yaml:"restarts"`
11 | Limits Limits `yaml:"limits"`
12 | }
13 |
14 | // NewPod create a new pod configuration.
15 | func newPod() Pod {
16 | return Pod{
17 | Restarts: defaultRestarts,
18 | Limits: Limits{
19 | CPU: defaultCPULimit,
20 | Memory: defaultMEMLimit,
21 | },
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/pkg/config/popeye_test.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package config
5 |
6 | import (
7 | "testing"
8 |
9 | "github.com/derailed/popeye/internal/rules"
10 | "github.com/derailed/popeye/types"
11 | "github.com/stretchr/testify/assert"
12 | )
13 |
14 | func TestNewPopeye(t *testing.T) {
15 | p := NewPopeye()
16 |
17 | assert.Equal(t, 5, p.Resources.Pod.Restarts)
18 |
19 | ok := p.Match(rules.Spec{
20 | GVR: types.NewGVR("v1/nodes"),
21 | FQN: "-/n1",
22 | Code: 600,
23 | })
24 | assert.False(t, ok)
25 |
26 | ok = p.Match(rules.Spec{
27 | GVR: types.NewGVR("v1/namespaces"),
28 | FQN: "kube-public",
29 | Code: 100,
30 | })
31 | assert.False(t, ok)
32 | }
33 |
--------------------------------------------------------------------------------
/pkg/config/prom.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package config
5 |
6 | // BasicAuth tracks basic authentication.
7 | type BasicAuth struct {
8 | User *string
9 | Password *string
10 | }
11 |
12 | func newBasicAuth() BasicAuth {
13 | return BasicAuth{
14 | User: strPtr(""),
15 | Password: strPtr(""),
16 | }
17 | }
18 |
19 | // PushGateway tracks prometheus gateway representations.
20 | type PushGateway struct {
21 | URL *string
22 | BasicAuth BasicAuth
23 | }
24 |
25 | func newPushGateway() *PushGateway {
26 | return &PushGateway{
27 | URL: strPtr(""),
28 | BasicAuth: newBasicAuth(),
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/pkg/config/testdata/sp-toast.yml:
--------------------------------------------------------------------------------
1 | # A Sample Popeye configuration.
2 | popeye1:
3 | # Allocations ratios current to resources.
4 | allocations:
5 | cpu:
6 | over: 200
7 | under: 50
8 | memory:
9 | over: 200
10 | under: 50
11 |
12 | # Excludes
13 | excludes:
14 | node:
15 | - n1
16 | namespace:
17 | - kube-system
18 | - kube-node-lease
19 | - kube-public
20 | - istio-system
21 | service:
22 | - default/dictionary
23 |
24 | # Node...
25 | node:
26 | limits:
27 | cpu: 90
28 | memory: 80
29 |
30 | # Pod...
31 | pod:
32 | limits:
33 | cpu: 80
34 | memory: 75
35 | restarts: 3
36 |
--------------------------------------------------------------------------------
/pkg/config/testdata/sp1.yml:
--------------------------------------------------------------------------------
1 | popeye:
2 | allocations:
3 | cpu:
4 | overPercUtilization: 200
5 | underPercUtilization: 50
6 | memory:
7 | overPercUtilization: 200
8 | underPercUtilization: 50
9 |
10 | excludes:
11 | global:
12 | fqns: [rx:^ns1, rx:^ns2]
13 |
14 | linters:
15 | nodes:
16 | instances:
17 | - labels:
18 | k8s-app: [app1]
19 | codes: ["100"]
20 |
21 | namespaces:
22 | instances:
23 | - labels:
24 | group: [ns1]
25 | codes: ["100"]
26 |
27 | services:
28 | instances:
29 | - labels:
30 | group: [ns1]
31 | codes: ["100"]
32 |
33 | resources:
34 | node:
35 | limits:
36 | cpu: 90
37 | memory: 80
38 | pod:
39 | restarts: 3
40 | limits:
41 | cpu: 80
42 | memory: 75
43 |
44 | registries:
45 | - docker.io
--------------------------------------------------------------------------------
/pkg/config/testdata/sp2.yml:
--------------------------------------------------------------------------------
1 | # A Sample Popeye configuration.
2 | popeye:
3 | # Allocations ratios current to resources.
4 | allocations:
5 | cpu:
6 | overPercUtilization: 200
7 | underPercUtilization: 50
8 | memory:
9 | overPercUtilization: 200
10 | underPercUtilization: 50
--------------------------------------------------------------------------------
/pkg/config/testdata/sp3.yml:
--------------------------------------------------------------------------------
1 | popeye:
2 | allocations:
3 | cpu:
4 | overPercUtilization: 200
5 | underPercUtilization: 50
6 | memory:
7 | overPercUtilization: 200
8 | underPercUtilization: 50
9 |
10 | excludes:
11 | global:
12 | fqns: [rx:^gns1, rx:^gns2]
13 | labels:
14 | l1: [a, aa, aaa]
15 | l2: [f, ff, fff]
16 | annotations:
17 | a1: [a, b,c]
18 | a2: [a1, b1, c1]
19 |
20 | linters:
21 | configmaps:
22 |
23 | secrets:
24 | instances:
25 | - fqns: [rx:fred]
26 |
27 | nodes:
28 | instances:
29 | - annotations:
30 | a1: [b1]
31 | codes: ["100"]
32 |
33 | pods:
34 | instances:
35 | - fqns: [rx:^istio]
36 | - labels:
37 | kube-system: [fred]
38 | codes: ["300"]
39 | - fqns: [rx:^ns1]
40 | containers: [c1, c2, c3]
41 |
42 | services:
43 | instances:
44 | - labels:
45 | default: [dictionary]
46 | codes: ["100"]
47 |
48 | resources:
49 | node:
50 | limits:
51 | cpu: 90
52 | memory: 80
53 | pod:
54 | restarts: 3
55 | limits:
56 | cpu: 80
57 | memory: 75
58 |
59 | registries:
60 | - docker.io
--------------------------------------------------------------------------------
/pkg/config/types.go:
--------------------------------------------------------------------------------
1 | // SPDX-License-Identifier: Apache-2.0
2 | // Copyright Authors of Popeye
3 |
4 | package config
5 |
--------------------------------------------------------------------------------
/spinach-examples/spinach_eks.yml:
--------------------------------------------------------------------------------
1 | # A Sample EKS Popeye configuration.
2 | popeye:
3 | allocations:
4 | cpu:
5 | # Checks if cpu is under allocated by more than 200% at current load.
6 | underPercUtilization: 200
7 | # Checks if cpu is over allocated by more than 50% at current load.
8 | overPercUtilization: 50
9 | memory:
10 | # Checks if mem is under allocated by more than 200% at current load.
11 | underPercUtilization: 200
12 | # Checks if mem is over allocated by more than 50% at current load.
13 | overPercUtilization: 50
14 |
15 | # Excludes define rules to exempt resources from sanitization
16 | excludes:
17 | global:
18 | fqns: [rx:^kube-system,rx:^local-path-storage]
19 |
20 | linters:
21 | clusterroles:
22 | instances:
23 | - fqns: [rx:^eks,rx:^aws-node,rx:^system,admin,edit,view,cluster-admin]
24 | codes: [400]
25 |
26 | resources:
27 | # Nodes specific sanitization
28 | node:
29 | limits:
30 | cpu: 90
31 | memory: 80
32 |
33 | # Pods specific sanitization
34 | pod:
35 | limits:
36 | # Fail if cpu is over 80%
37 | cpu: 80
38 | # Fail if pod mem is over 75%
39 | memory: 75
40 | # Fail if more than 3 restarts on any pods
41 | restarts: 3
42 |
43 |
44 | # Code specifies a custom severity level ie critical=3, warn=2, info=1
45 | overrides:
46 | - codes: 206
47 | severity: 1
48 |
--------------------------------------------------------------------------------