Skip to content

fix(security): scope trivy KSV-0037 to the infrastructure trees - #3054

Merged
devantler merged 2 commits into
mainfrom
claude/checkov-k8s-disposition-2787-2
Aug 10, 2026
Merged

fix(security): scope trivy KSV-0037 to the infrastructure trees#3054
devantler merged 2 commits into
mainfrom
claude/checkov-k8s-disposition-2787-2

Conversation

@devantler

@devantler devantler commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

🤖 Generated by the Agentic Engineer

Why

The security scanners on k8s/ still report on every pull request without failing the build, while
a backlog is worked off. The largest remaining group was one check firing 47 times — 30% of trivy's
findings on the tree — on cluster components that are exactly where they should be.

Left as noise, it buries the findings that matter. The residual on this tree still includes
HIGH/CRITICAL RBAC breadth, and that is much harder to see behind 47 reports about CoreDNS and the
CNI living in kube-system.

What

Scopes that one check to the infrastructure trees, with the reasoning recorded next to it, and
corrects the recorded scanner figures the config asks each slice to re-measure.

The check itself protects something real — an application does not belong in kube-system — so it
is scoped, not switched off. It stays live for application trees, and a user workload placed in
kube-system is still reported. That boundary was verified rather than assumed, with two copies of
one manifest: the copy under the apps tree fails the check, the copy under the infrastructure tree
is excepted. Same bytes, different path.

Measured with the repository's own counts script: trivy 157 → 110 across 27 targets. checkov is
unchanged at 9.

Two honesty notes, both carried into the config rather than left in this description:

  • The previously recorded figure was 163, measured on an older scanner version. 157 is the current
    version on unchanged manifests, so those 6 are scanner rule-set drift rather than progress. Only
    the 47 are this change's work.
  • Self-review caught a wrong claim in my own first draft, that tenant trees stay covered. They are
    not covered, and not because of this change: tenants are generated from ResourceGraphDefinition
    templates that no static scanner descends into, measured at zero findings with and without this
    entry. Filed separately as Workload templates inside ResourceGraphDefinitions are invisible to every static scanner #3055 and stated plainly in the comment instead of implied.

Part of #2787

All 47 KSV-0037 findings are cluster components that belong in kube-system by
construction — CNI, DNS, CSI, cloud-controller-manager, and their namespace-local
VerticalPodAutoscalers, PodDisruptionBudgets, Gateway and Certificate material. A
VPA targetRef and a PDB selector are namespace-local, so those cannot live
anywhere else; the one Deployment is CoreDNS.

Scoped to the infrastructure trees rather than skipped, so the check stays live
for application trees. Verified with a paired control: the same manifest FAILs
under k8s/bases/apps/ and is excepted under k8s/bases/infrastructure/.

trivy 157 -> 110 across 27 targets. The earlier recorded 163 was v0.72.0; 157 is
v0.73.0 on the same manifests, so that difference is scanner rule-set drift, not
backlog movement.

Part of #2787
Self-review found the claim that the tenant trees stay covered was wrong: there is
no separate tenant tree, and the KRO ResourceGraphDefinitions that generate tenants
sit inside the scoped path. Measured the actual reach instead — trivy reports zero
misconfigurations on both RGD files with or without this entry, because it does not
descend into the templates nested in an RGD, so tenant workloads are outside this
check either way. Filed as #3055 and stated here rather than implied.
@github-actions

Copy link
Copy Markdown
Contributor

⚠️MegaLinter analysis: Success with warnings

⚠️ BASH / bash-exec - 6 errors
Results of bash-exec linter (version 5.3.9)
See documentation on https://megalinter.io/9.6.0/descriptors/bash_bash_exec/
-----------------------------------------------

✅ [SUCCESS] scripts/check-megalinter-version-drift.sh
✅ [SUCCESS] scripts/dr-rebuild-supersession-guard.sh
❌ [ERROR] scripts/ghcr-auth-lib.sh
    Error: File:[scripts/ghcr-auth-lib.sh] is not executable

✅ [SUCCESS] scripts/guard-cilium-homogeneous-device-rollout.sh
✅ [SUCCESS] scripts/guard-shared-publish-workflow-pin.sh
✅ [SUCCESS] scripts/megalinter-scan-counts.sh
✅ [SUCCESS] scripts/normalize-sarif-paths.sh
❌ [ERROR] scripts/refresh-flux-ghcr-auth-safety.sh
    Error: File:[scripts/refresh-flux-ghcr-auth-safety.sh] is not executable

✅ [SUCCESS] scripts/refresh-flux-ghcr-auth.sh
✅ [SUCCESS] scripts/report-cilium-rollout-gate-suppression.sh
✅ [SUCCESS] scripts/run-ksail-prod-with-pull-auth.sh
✅ [SUCCESS] scripts/summarize-sarif-findings.sh
✅ [SUCCESS] scripts/tests/test-check-megalinter-version-drift.sh
✅ [SUCCESS] scripts/tests/test-cilium-bandwidth-manager-component.sh
✅ [SUCCESS] scripts/tests/test-cilium-homogeneous-devices-activation.sh
✅ [SUCCESS] scripts/tests/test-cilium-homogeneous-devices-autoscaler-gate.sh
✅ [SUCCESS] scripts/tests/test-cilium-homogeneous-devices-flux-wait.sh
✅ [SUCCESS] scripts/tests/test-cilium-mutual-auth-policy-regressions.sh
✅ [SUCCESS] scripts/tests/test-cilium-mutual-auth-policy.sh
✅ [SUCCESS] scripts/tests/test-cilium-rollout-gate-suppression-signal.sh
✅ [SUCCESS] scripts/tests/test-crossplane-sync-exporter.sh
✅ [SUCCESS] scripts/tests/test-dr-rebuild-supersession-guard.sh
✅ [SUCCESS] scripts/tests/test-github-config-role-activation-parity.sh
✅ [SUCCESS] scripts/tests/test-kyverno-admission-vpa.sh
❌ [ERROR] scripts/tests/test-megalinter-scan-counts-ignorefile.sh
    Error: File:[scripts/tests/test-megalinter-scan-counts-ignorefile.sh] is not executable

❌ [ERROR] scripts/tests/test-normalize-sarif-paths.sh
    Error: File:[scripts/tests/test-normalize-sarif-paths.sh] is not executable

✅ [SUCCESS] scripts/tests/test-openbao-oidc-role.sh
❌ [ERROR] scripts/tests/test-opencost-usage-scraper.sh
    Error: File:[scripts/tests/test-opencost-usage-scraper.sh] is not executable

❌ [ERROR] scripts/tests/test-refresh-flux-ghcr-auth-safety.sh
    Error: File:[scripts/tests/test-refresh-flux-ghcr-auth-safety.sh] is not executable

✅ [SUCCESS] scripts/tests/test-restrict-tenant-secret-stores.sh
✅ [SUCCESS] scripts/tests/test-shared-publish-workflow-pin-guard.sh
✅ [SUCCESS] scripts/tests/test-summarize-sarif-findings.sh
✅ [SUCCESS] scripts/tests/test-verify-published-evidence.sh
✅ [SUCCESS] scripts/update-vendored-operators.sh
✅ [SUCCESS] scripts/validate-alert-coverage.sh
✅ [SUCCESS] scripts/verify-published-evidence.sh
✅ [SUCCESS] scripts/wait-for-platform-flux-revision.sh
⚠️ REPOSITORY / checkov - 9 errors
2026-08-10 11:18:41,516 [MainThread  ] [ERROR]  YAML error parsing k8s/bases/infrastructure/controllers/kubevirt/kubevirt-operator.yaml: expected a single document in the stream
  in "<unicode string>", line 2, column 1
but found another document
  in "<unicode string>", line 9, column 1
cloudformation scan results:

Passed checks: 0, Failed checks: 0, Skipped checks: 0, Parsing errors: 1

kubernetes scan results:

Passed checks: 1973, Failed checks: 9, Skipped checks: 32

Check: CKV_K8S_35: "Prefer using secrets as files over secrets as environment variables"
	FAILED for resource: Deployment.minio.minio
	File: /k8s/providers/docker/infrastructure/controllers/minio/deployment.yaml:12-104
	Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/kubernetes-policies/kubernetes-policy-index/bc-k8s-33

		Code lines for this resource are too many. Please use IDE of your choice to review the file.
Check: CKV_K8S_35: "Prefer using secrets as files over secrets as environment variables"
	FAILED for resource: Job.minio.minio-create-bucket
	File: /k8s/providers/docker/infrastructure/controllers/minio/job.yaml:4-76
	Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/kubernetes-policies/kubernetes-policy-index/bc-k8s-33

		Code lines for this resource are too many. Please use IDE of your choice to review the file.
Check: CKV_K8S_25: "Minimize the admission of containers with added capability"
	FAILED for resource: Deployment.kube-system.coredns
	File: /k8s/providers/docker/infrastructure/controllers/coredns/deployment.yaml:2-146
	Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/kubernetes-policies/kubernetes-policy-index/bc-k8s-24

		Code lines for this resource are too many. Please use IDE of your choice to review the file.
Check: CKV_K8S_11: "CPU limits should be set"
	FAILED for resource: Deployment.kube-system.coredns
	File: /k8s/providers/docker/infrastructure/controllers/coredns/deployment.yaml:2-146
	Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/kubernetes-policies/kubernetes-policy-index/bc-k8s-10

		Code lines for this resource are too many. Please use IDE of your choice to review the file.
Check: CKV_K8S_35: "Prefer using secrets as files over secrets as environment variables"
	FAILED for resource: CronJob.umami.umami-provision-tenants
	File: /k8s/bases/apps/umami/cron-job.yaml:44-318
	Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/kubernetes-policies/kubernetes-policy-index/bc-k8s-33

		Code lines for this resource are too many. Please use IDE of your choice to review the file.
Check: CKV_K8S_22: "Use read-only filesystem for containers where possible"
	FAILED for resource: CronJob.umami.umami-provision-tenants
	File: /k8s/bases/apps/umami/cron-job.yaml:44-318
	Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/kubernetes-policies/kubernetes-policy-index/bc-k8s-21

		Code lines for this resource are too many. Please use IDE of your choice to review the file.
Check: CKV_K8S_40: "Containers should run as a high UID to avoid host conflict"
	FAILED for resource: CronJob.openbao.vault-snapshot
	File: /k8s/bases/infrastructure/vault-backup/cron-job.yaml:23-197
	Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/kubernetes-policies/kubernetes-policy-index/bc-k8s-37

		Code lines for this resource are too many. Please use IDE of your choice to review the file.
Check: CKV_K8S_40: "Containers should run as a high UID to avoid host conflict"
	FAILED for resource: Job.openbao.vault-snapshot-init
	File: /k8s/bases/infrastructure/vault-backup/job.yaml:23-191
	Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/kubernetes-policies/kubernetes-policy-index/bc-k8s-37

		Code lines for this resource are too many. Please use IDE of your choice to review the file.
Check: CKV_K8S_35: "Prefer using secrets as files over secrets as environment variables"
	FAILED for resource: CronJob.observability.cnpg-degraded-alert
	File: /k8s/bases/infrastructure/controllers/coroot/cron-job-cnpg-degraded-alert.yaml:56-204
	Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/kubernetes-policies/kubernetes-policy-index/bc-k8s-33

		Code lines for this resource are too many. Please use IDE of your choice to review the file.
github_actions scan results:

Passed checks: 124, Failed checks: 0, Skipped checks: 0
⚠️ SPELL / cspell - 3156 errors
ed",
        "distroless",
        "dockerconfigjson",
        "docstrings",
        "dorny",
        "dpkg",
        "drainable",
        "emptydir",
        "endgroup",
        "entrys",
        "envsubst",
        "esac",
        "etcdctl",
        "evictable",
        "extensionless",
        "externalsecret",
        "externalsecrets",
        "fakerepo",
        "fanout",
        "featureflagsource",
        "fleetdm",
        "fluxinstance",
        "fromdateiso",
        "gatewayapi",
        "generatable",
        "generatingpolicies",
        "genkey",
        "gethomepage",
        "gitops",
        "gocritic's",
        "golangci",
        "gosec",
        "grjtvs",
        "growfs",
        "growpart",
        "healthchecks",
        "healthz",
        "helmrelease",
        "helmreleases",
        "helmv",
        "homelab",
        "hostnames",
        "httproute",
        "idempotently",
        "ignorefile",
        "imagetools",
        "imagevalidatingpolicy",
        "imranismail",
        "injective",
        "inspectable",
        "iscsi",
        "italicise",
        "ivpol",
        "jobif",
        "keylessly",
        "keypair",
        "kprobes",
        "kptr",
        "krew",
        "ksail",
        "ksail's",
        "ksailcd",
        "kubeconfig",
        "kubeconform",
        "kubeconform's",
        "kubelet",
        "kubelet's",
        "kubelets",
        "kubelogin",
        "kubescape",
        "kubespan",
        "kubevirt",
        "kubevuln",
        "kustomization",
        "kustomizations",
        "kyverno",
        "letsencrypt",
        "libc",
        "libgnutls",
        "lintable",
        "livez",
        "loadtester",
        "locationless",
        "logfile",
        "luks",
        "lycheeignore",
        "machineconfig",
        "materialise",
        "materialised",
        "materialises",
        "maxage",
        "maxbackup",
        "maxsize",
        "maxx",
        "microtime",
        "misconfig",
        "misconfigs",
        "misordered",
        "mistargeted",
        "mktemp",
        "mlock",
        "mutatingpolicies",
        "mutatingwebhookconfigurations",
        "myapp",
        "najsk",
        "neighbour",
        "nenv",
        "netlink",
        "netpol",
        "netpols",
        "neutralises",
        "neutralising",
        "nextjs",
        "nftables",
        "nilnil",
        "nobuckets",
        "nodepod",
        "nodeport",
        "nolint",
        "nonroot",
        "normalisation",
        "normalised",
        "normalises",
        "normalising",
        "nosec",
        "nullglob",
        "ocirepository",
        "openbao",
        "opencost",
        "openfeature",
        "oras",
        "overprovisioning",
        "parallelised",
        "partialgroup",
        "pasteable",
        "permissioning",
        "pipefail",
        "policyignore",
        "policyreports",
        "portforward",
        "preemptible",
        "preservingly",
        "prioritisable",
        "prioritisation",
        "prioritised",
        "privesc",
        "providerconfigs",
        "pseudonymization",
        "pseudonymized",
        "pseudonymizes",
        "publishapp",
        "publishprovider",
        "pushsecret",
        "pushsecrets",
        "pycache",
        "randomises",
        "rdqwpktr",
        "readyz",
        "reassertions",
        "recognisable",
        "recognisably",
        "recognise",
        "recognised",
        "recolour",
        "reconverges",
        "refreshfluxghcrauth",
        "regenerable",
        "releaserc",
        "rematerialise",
        "rematerialised",
        "replicaset",
        "repoint",
        "repointed",
        "repoints",
        "repositoryrulesets",
        "resizer",
        "restrictor",
        "retabbed",
        "retarget",
        "rmem",
        "rolebindings",
        "rollouts",
        "rshared",
        "sanitised",
        "sanitiser",
        "sanitising",
        "sarif",
        "scheckov",
        "schedulability",
        "schedulable",
        "scopeable",
        "scopeless",
        "seccomp",
        "secretbox",
        "secretstore",
        "seedable",
        "serialised",
        "serverside",
        "serviceaccount",
        "serviceaccounts",
        "sgdisk",
        "shellcheck",
        "shfmt",
        "shopt",
        "shortsha",
        "siderolabs",
        "siderolink",
        "sigstore",
        "skmde",
        "slurpfile",
        "sngle",
        "specnull",
        "spiffe",
        "srole",
        "startswith",
        "statefulset",
        "statemanager",
        "stdlib",
        "stepif",
        "storageclass",
        "subtest",
        "summarised",
        "surfaceless",
        "syft",
        "syscall",
        "sysctls",
        "tagliteral",
        "tagonly",
        "talosconfig",
        "talosctl",
        "tanzu",
        "templatesyncignore",
        "thresholded",
        "tlsv",
        "tmpl",
        "tostring",
        "tracepoints",
        "trixie",
        "trueish",
        "trustd",
        "ture",
        "uids",
        "umami",
        "umami's",
        "unablated",
        "unclickable",
        "uncompilable",
        "uncordon",
        "uncordoned",
        "undecoded",
        "undercounts",
        "undispositioned",
        "unevidenced",
        "unexcepted",
        "unfiled",
        "ungated",
        "ungenerated",
        "unifi",
        "uninvoked",
        "unmarshalling",
        "unmarshals",
        "unmodelled",
        "unparseable",
        "unprovisioned",
        "unrecognisable",
        "unrecognised",
        "unrepresentable",
        "unreviewed",
        "unroutable",
        "unrun",
        "unshippable",
        "unskipped",
        "untrackable",
        "unvalidated",
        "unwired",
        "upbound",
        "updatekeys",
        "upjet",
        "upstreaming",
        "urlencode",
        "userinfo",
        "userns",
        "ushfn",
        "validatable",
        "validatealertcoverage",
        "validatingwebhookconfigurations",
        "vcunav",
        "velero",
        "virt",
        "volumesnapshot",
        "vpas",
        "vulnerabilitymanifests",
        "vulnerabilitymanifestsummary",
        "vulns",
        "vxlan",
        "wffc",
        "wgpolicyk",
        "wildcarded",
        "wlid",
        "wmem",
        "workloadconfigurationscans",
        "workloadconfigurationscansummary",
        "worktrees",
        "yannh",
        "yubikey",
        "yzwvjjmcyfnl",
        "zizmor"
    ]
}


You can also copy-paste megalinter-reports/.cspell.json at the root of your repository

(Truncated to last 6666 characters out of 561660)
⚠️ COPYPASTE / jscpd - 185 errors
ens)
   scripts/tests/refresh-flux-ghcr-auth/rollout_safety_test.go [468:57 - 485:5]
Clone found (go)
 - scripts/tests/refresh-flux-ghcr-auth/rollout_safety_test.go [492:77 - 508:11] (17 lines, 118 tokens)
   scripts/tests/refresh-flux-ghcr-auth/rollout_safety_test.go [519:110 - 535:11]
Clone found (bash)
 - scripts/tests/test-cilium-bandwidth-manager-component.sh [9:1 - 54:2] (46 lines, 202 tokens)
   scripts/tests/test-cilium-homogeneous-devices-activation.sh [9:1 - 54:2]
Clone found (bash)
 - scripts/tests/test-cilium-bandwidth-manager-component.sh [52:5 - 72:2] (21 lines, 67 tokens)
   scripts/tests/test-cilium-homogeneous-devices-activation.sh [80:23 - 100:2]
Clone found (bash)
 - scripts/tests/test-cilium-bandwidth-manager-component.sh [54:1 - 72:2] (19 lines, 65 tokens)
   scripts/tests/test-opencost-usage-scraper.sh [15:1 - 33:2]
Clone found (bash)
 - scripts/tests/test-cilium-mutual-auth-policy.sh [28:29 - 41:10] (14 lines, 78 tokens)
   scripts/tests/test-cilium-mutual-auth-policy.sh [79:33 - 92:10]
Clone found (bash)
 - scripts/tests/test-cilium-mutual-auth-policy.sh [98:33 - 107:54] (10 lines, 57 tokens)
   scripts/tests/test-cilium-mutual-auth-policy.sh [118:32 - 127:54]
Clone found (bash)
 - scripts/tests/test-crossplane-sync-exporter.sh [56:3 - 118:11] (63 lines, 338 tokens)
   scripts/tests/test-opencost-usage-scraper.sh [22:45 - 84:11]
Clone found (bash)
 - scripts/tests/test-refresh-flux-ghcr-auth-safety.sh [177:5 - 185:51] (9 lines, 76 tokens)
   scripts/tests/test-refresh-flux-ghcr-auth-safety.sh [186:5 - 194:51]
Clone found (python)
 - scripts/tests/test_validate_homepage_bookmarks.py [46:57 - 54:54] (9 lines, 58 tokens)
   scripts/tests/test_validate_homepage_bookmarks.py [100:53 - 109:54]
Clone found (go)
 - scripts/validate-dr-signing/main_test.go [1007:13 - 1015:2] (9 lines, 51 tokens)
   scripts/validate-dr-signing/main_test.go [1075:12 - 1083:2]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [244:50 - 249:24] (6 lines, 103 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [756:31 - 761:24]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [276:14 - 282:4] (7 lines, 115 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [603:43 - 609:4]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [302:13 - 311:7] (10 lines, 158 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [828:18 - 837:7]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [311:1 - 316:8] (6 lines, 93 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [838:1 - 843:8]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [388:5 - 393:2] (6 lines, 82 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [574:8 - 579:9]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [389:1 - 399:23] (11 lines, 220 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [666:60 - 677:3]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [393:15 - 404:2] (12 lines, 185 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [494:17 - 505:2]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [440:15 - 451:12] (12 lines, 264 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [649:1 - 662:3]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [503:2 - 509:19] (7 lines, 89 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [688:7 - 694:19]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [503:2 - 509:33] (7 lines, 103 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [1013:58 - 1019:33]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [503:2 - 509:4] (7 lines, 74 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [1126:5 - 1132:4]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [596:30 - 601:8] (6 lines, 50 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [623:44 - 628:8]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [710:22 - 716:2] (7 lines, 135 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [1212:22 - 1218:2]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [951:33 - 959:11] (9 lines, 118 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [963:130 - 971:11]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [1158:47 - 1163:2] (6 lines, 166 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [1238:46 - 1243:2]
Clone found (go)
 - scripts/validate-flux-verify/instance_test.go [109:62 - 126:31] (18 lines, 57 tokens)
   scripts/validate-flux-verify/instance_test.go [161:57 - 178:31]
Clone found (go)
 - scripts/validate-flux-verify/instance_test.go [109:62 - 128:35] (20 lines, 62 tokens)
   scripts/validate-flux-verify/instance_test.go [198:55 - 217:26]
Clone found (python)
 - scripts/validate-naming.py [126:52 - 132:25] (7 lines, 53 tokens)
   scripts/validate-naming.py [171:82 - 177:29]
┌────────┬────────────────┬─────────────┬──────────────┬──────────────┬──────────────────┬───────────────────┐
│ Format │ Files analyzed │ Total lines │ Total tokens │ Clones found │ Duplicated lines │ Duplicated tokens │
├────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ bash   │ 40             │ 12255       │ 47004        │ 20           │ 295 (2.41%)      │ 1797 (3.82%)      │
├────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ go     │ 36             │ 29911       │ 180577       │ 99           │ 804 (2.69%)      │ 7637 (4.23%)      │
├────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ python │ 4              │ 807         │ 5606         │ 2            │ 14 (1.73%)       │ 111 (1.98%)       │
├────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ txt    │ 57             │ 3378        │ 109125       │ 64           │ 2417 (71.55%)    │ 80219 (73.51%)    │
├────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ Total: │ 137            │ 46351       │ 342312       │ 185          │ 3530 (7.62%)     │ 89764 (26.22%)    │
└────────┴────────────────┴─────────────┴──────────────┴──────────────┴──────────────────┴───────────────────┘
Found 185 clones.
HTML report saved to megalinter-reports/copy-paste/jscpd-report.html
ERROR: jscpd found too many duplicates (7.6%) over threshold (0.0%)
time: 803.947ms

(Truncated to last 6666 characters out of 39337)
⚠️ MARKDOWN / markdownlint - 62 errors
; Actual: 838]
AGENTS.md:24 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
AGENTS.md:101:401 error MD013/line-length Line length [Expected: 400; Actual: 1769]
AGENTS.md:105:401 error MD013/line-length Line length [Expected: 400; Actual: 1126]
AGENTS.md:106:401 error MD013/line-length Line length [Expected: 400; Actual: 1447]
AGENTS.md:159:401 error MD013/line-length Line length [Expected: 400; Actual: 649]
AGENTS.md:161:401 error MD013/line-length Line length [Expected: 400; Actual: 971]
AGENTS.md:188:401 error MD013/line-length Line length [Expected: 400; Actual: 970]
AGENTS.md:210:401 error MD013/line-length Line length [Expected: 400; Actual: 1510]
AGENTS.md:278:401 error MD013/line-length Line length [Expected: 400; Actual: 1016]
AGENTS.md:279:401 error MD013/line-length Line length [Expected: 400; Actual: 491]
AGENTS.md:280:401 error MD013/line-length Line length [Expected: 400; Actual: 468]
AGENTS.md:286:401 error MD013/line-length Line length [Expected: 400; Actual: 532]
AGENTS.md:288:401 error MD013/line-length Line length [Expected: 400; Actual: 523]
AGENTS.md:291:401 error MD013/line-length Line length [Expected: 400; Actual: 613]
AGENTS.md:292:401 error MD013/line-length Line length [Expected: 400; Actual: 714]
AGENTS.md:296:401 error MD013/line-length Line length [Expected: 400; Actual: 502]
AGENTS.md:300:401 error MD013/line-length Line length [Expected: 400; Actual: 441]
AGENTS.md:305:401 error MD013/line-length Line length [Expected: 400; Actual: 427]
AGENTS.md:408:401 error MD013/line-length Line length [Expected: 400; Actual: 1139]
AGENTS.md:410:401 error MD013/line-length Line length [Expected: 400; Actual: 1240]
AGENTS.md:426:401 error MD013/line-length Line length [Expected: 400; Actual: 1137]
AGENTS.md:437:401 error MD013/line-length Line length [Expected: 400; Actual: 790]
AGENTS.md:442:401 error MD013/line-length Line length [Expected: 400; Actual: 515]
CLAUDE.md:1 error MD041/first-line-heading/first-line-h1 First line in a file should be a top-level heading [Context: "@AGENTS.md"]
docs/dr/alerting.md:226:28 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/crypto-custody.md:22:389 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/crypto-custody.md:23:264 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/crypto-custody.md:27:35 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/crypto-custody.md:27:161 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/crypto-custody.md:27:239 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/crypto-custody.md:114 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Custody recommendations"]
docs/dr/crypto-custody.md:245 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "Custody recommendations"]
docs/dr/crypto-custody.md:251 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "What to do if it leaks"]
docs/dr/crypto-custody.md:258 error MD024/no-duplicate-heading Multiple headings with the same content [Context: "What to do if it is *lost* (no..."]
docs/dr/restore-drill.md:42 error MD028/no-blanks-blockquote Blank line inside blockquote
docs/dr/runbook.md:23:102 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/runbook.md:23:487 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/runbook.md:34 error MD028/no-blanks-blockquote Blank line inside blockquote
docs/dr/runbook.md:41 error MD028/no-blanks-blockquote Blank line inside blockquote
docs/dr/runbook.md:50 error MD028/no-blanks-blockquote Blank line inside blockquote
docs/dr/runbook.md:489:92 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/spire-server-ha.md:93 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/dr/velero-cnpg.md:11 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/dr/velero-cnpg.md:56:78 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/velero-cnpg.md:56:166 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/velero-cnpg.md:57:78 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/velero-cnpg.md:57:227 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/velero-cnpg.md:58:78 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/dr/velero-cnpg.md:58:166 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
docs/github-management.md:38:401 error MD013/line-length Line length [Expected: 400; Actual: 419]
docs/github-management.md:40:401 error MD013/line-length Line length [Expected: 400; Actual: 522]
docs/node-autoscaling.md:14 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/oidc-kubectl.md:95 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/runtime-security.md:114 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/rwx-storage.md:9 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/unifi-management.md:14 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
docs/unifi-management.md:62 error MD040/fenced-code-language Fenced code blocks should have a language specified [Context: "```"]
README.md:116:401 error MD013/line-length Line length [Expected: 400; Actual: 540]
README.md:237:32 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]
README.md:237:36 error MD060/table-column-style Table column style [Table pipe does not align with header for style "aligned"]

(Truncated to last 6666 characters out of 6911)
⚠️ REPOSITORY / trivy - 1 error
rn-smoke/job.yaml (kubernetes)
======================================================================
Tests: 118 (SUCCESSES: 116, FAILURES: 2)
Failures: 2 (UNKNOWN: 0, LOW: 0, MEDIUM: 2, HIGH: 0, CRITICAL: 0)

KSV-0125 (MEDIUM): Container verify-round-trip in job userns-longhorn-smoke (namespace: userns-longhorn-smoke) uses an image from an untrusted registry.
════════════════════════════════════════
Ensure that all containers use images only from trusted registry domains.

See https://avd.aquasec.com/misconfig/ksv-0125
────────────────────────────────────────
 k8s/providers/hetzner/apps/userns-longhorn-smoke/job.yaml:102-157
────────────────────────────────────────
 102 ┌         - name: verify-round-trip
 103 │           image: docker.io/library/busybox:1.38.0@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d
 104 │           imagePullPolicy: IfNotPresent
 105 │           command:
 106 │             - /bin/sh
 107 │             - -ec
 108 │           args:
 109 │             - |
 110 └               set -eu
 ...   
────────────────────────────────────────


KSV-0125 (MEDIUM): Container write-sentinel in job userns-longhorn-smoke (namespace: userns-longhorn-smoke) uses an image from an untrusted registry.
════════════════════════════════════════
Ensure that all containers use images only from trusted registry domains.

See https://avd.aquasec.com/misconfig/ksv-0125
────────────────────────────────────────
 k8s/providers/hetzner/apps/userns-longhorn-smoke/job.yaml:54-100
────────────────────────────────────────
  54 ┌         - name: write-sentinel
  55 │           image: docker.io/library/busybox:1.38.0@sha256:fd8d9aa63ba2f0982b5304e1ee8d3b90a210bc1ffb5314d980eb6962f1a9715d
  56 │           imagePullPolicy: IfNotPresent
  57 │           command:
  58 │             - /bin/sh
  59 │             - -ec
  60 │           args:
  61 │             - |
  62 └               set -eu
  ..   
────────────────────────────────────────



k8s/providers/hetzner/infrastructure/controllers/longhorn/cron-job-stale-node-cleanup.yaml (kubernetes)
=======================================================================================================
Tests: 116 (SUCCESSES: 115, FAILURES: 1)
Failures: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)

KSV-0125 (MEDIUM): Container cleanup in cronjob longhorn-stale-node-cleanup (namespace: longhorn-system) uses an image from an untrusted registry.
════════════════════════════════════════
Ensure that all containers use images only from trusted registry domains.

See https://avd.aquasec.com/misconfig/ksv-0125
────────────────────────────────────────
 k8s/providers/hetzner/infrastructure/controllers/longhorn/cron-job-stale-node-cleanup.yaml:73-112
────────────────────────────────────────
  73 ┌             - name: cleanup
  74 │               # NOT registry.k8s.io/kubectl: that image is distroless (kubectl
  75 │               # binary only, no /bin/sh), so the shell script below could never
  76 │               # start — every run since the CronJob shipped failed with
  77 │               # StartError exit 128 "stat /bin/sh: no such file or directory"
  78 │               # (observed live 2026-07-02). alpine/k8s ships kubectl + a POSIX
  79 │               # shell; the tag tracks the kubectl minor, matching the cluster.
  80 │               image: docker.io/alpine/k8s:1.36.2@sha256:44ef4942e171939b9c665a4a84beb80e2dcdb9a24330d4651cfdfd2e9deecc47
  81 └               securityContext:
  ..   
────────────────────────────────────────



k8s/providers/hetzner/infrastructure/coroot/cron-job-alert-autosuppressor.yaml (kubernetes)
===========================================================================================
Tests: 116 (SUCCESSES: 115, FAILURES: 1)
Failures: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)

KSV-0125 (MEDIUM): Container autosuppressor in cronjob coroot-alert-autosuppressor (namespace: observability) uses an image from an untrusted registry.
════════════════════════════════════════
Ensure that all containers use images only from trusted registry domains.

See https://avd.aquasec.com/misconfig/ksv-0125
────────────────────────────────────────
 k8s/providers/hetzner/infrastructure/coroot/cron-job-alert-autosuppressor.yaml:93-116
────────────────────────────────────────
  93 ┌             - name: autosuppressor
  94 │               # curl + jq, digest-pinned (same image as custom-cloud-pricing).
  95 │               # observability is exempt from disallow-latest-tag.
  96 │               image: docker.io/badouralix/curl-jq:latest@sha256:1e7c0284e24572ace7170df9fc91f15fd3b79ebf056d4dde17244d5d74bbfabc
  97 │               securityContext:
  98 │                 allowPrivilegeEscalation: false
  99 │                 readOnlyRootFilesystem: true
 100 │                 runAsNonRoot: true
 101 └                 runAsUser: 65532
 ...   
────────────────────────────────────────



k8s/providers/hetzner/infrastructure/coroot/cron-job-custom-cloud-pricing.yaml (kubernetes)
===========================================================================================
Tests: 116 (SUCCESSES: 115, FAILURES: 1)
Failures: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)

KSV-0125 (MEDIUM): Container set-pricing in cronjob coroot-custom-cloud-pricing (namespace: observability) uses an image from an untrusted registry.
════════════════════════════════════════
Ensure that all containers use images only from trusted registry domains.

See https://avd.aquasec.com/misconfig/ksv-0125
────────────────────────────────────────
 k8s/providers/hetzner/infrastructure/coroot/cron-job-custom-cloud-pricing.yaml:77-114
────────────────────────────────────────
  77 ┌             - name: set-pricing
  78 │               # curl + jq, pinned by digest. jq replaces the former grep/sed/awk
  79 │               # JSON parsing + awk float compare with a robust, structure-tolerant
  80 │               # parse (the heartbeat CronJob still uses curlimages/curl — it has no
  81 │               # JSON to parse). No official curl+jq image exists, so this is the
  82 │               # de-facto community one, digest-pinned; observability is exempt from
  83 │               # disallow-latest-tag. Swappable for any curl+jq image.
  84 │               image: docker.io/badouralix/curl-jq:latest@sha256:1e7c0284e24572ace7170df9fc91f15fd3b79ebf056d4dde17244d5d74bbfabc
  85 └               securityContext:
  ..   
────────────────────────────────────────



📣 Notices:
  - Version 0.73.0 of Trivy is now available, current version is 0.71.2

To suppress version checks, run Trivy scans with the --skip-version-check flag

(Truncated to last 6666 characters out of 289419)

✅ Linters with no issues

actionlint, betterleaks, git_diff, golangci-lint, grype, jsonlint, lychee, osv-scanner, prettier, prettier, revive, secretlint, shellcheck, shfmt, syft, trivy-sbom, trufflehog, v8r, v8r, yamllint, zizmor

Notices

📣 MegaLinter 9.5.0 is out! Discover the new features and security recommendations in the release announcement. (Skip this info by defining SECURITY_SUGGESTIONS: false)

See detailed reports in MegaLinter artifacts

MegaLinter is graciously provided by OX Security
Show us your support by starring ⭐ the repository

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

What I verified locally, and the one thing only CI can settle

Verified locally (trivy v0.73.0, the exact CI invocation trivy fs --scanners misconfig --ignorefile .trivyignore.yaml --skip-dirs tests . from the repository root):

  • trivy 157 → 110 across 27 targets; KSV-0037 goes to 0. Reproduced through the repository's
    own scripts/megalinter-scan-counts.sh, which reports the same pair.
  • checkov unchanged at 9 — this change does not touch it.
  • Paired control for the scope boundary: two copies of one manifest, one under k8s/bases/apps/ and
    one under k8s/bases/infrastructure/. The apps copy FAILS KSV-0037 with this entry in place;
    the infrastructure copy is excepted. Identical bytes, so the path is what decides.
  • All 47 findings enumerated by kind and they sum exactly: 17 VPA + 12 HelmRelease + 5 PDB +
    5 HelmRepository + 2 HTTPRoute + 2 Gateway + 1 LimitRange + 1 Deployment + 1 CiliumNetworkPolicy +
    1 Certificate.

The open question this PR's own 🧹 Lint - mega-linter job answers: this is the first entry in
.trivyignore.yaml to use a glob
in paths: — every existing entry (KSV-0109 ×2) names a literal
file. Local trivy is v0.73.0; CI runs v0.71.2 inside MegaLinter 9.6.0. If glob support in the
ignore file's paths: differs between those versions, the exception would apply locally and silently
not apply in CI — the change would look done and do nothing.

That is checkable rather than arguable, and it is checked by the job on this PR: MegaLinter's trivy run
uses --ignorefile .trivyignore.yaml (set in REPOSITORY_TRIVY_ARGUMENTS), so its reported count is
the CI-side answer. I am holding the review request until that job reports, and will record the CI
number here. If the glob does not carry to v0.71.2, the fix is to enumerate the two literal directory
prefixes instead of globbing — not to widen the entry.

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

CI answered the glob question — it carries to trivy v0.71.2

Read from this PR's own 🧹 Lint - mega-linter job log (run 31382727407, job 93436402506), whose
trivy invocation the log states verbatim:

Command: [trivy fs --scanners vuln,misconfig --exit-code 1 --ignorefile .trivyignore.yaml --skip-dirs tests .]
Signal CI (trivy v0.71.2) Local (trivy v0.73.0)
total failures 110 110
KSV-0037 occurrences 0 0

The two independently agree on the exact total, so the paths: glob applies on the older scanner CI
actually runs. The version risk I raised above is settled empirically rather than argued.

The zero is attributable, because its neighbours are not zero. Every other check from the
pre-change grouping appears in the CI log at exactly the count measured locally — KSV-0125 25,
KSV-0048 14, KSV-0021 11, KSV-0020 9, KSV-0056 8, KSV-0049 8, KSV-0113 7, KSV-0114 5,
KSV-0046 5, KSV-0041 4. So the log does contain trivy's findings, and KSV-0037 being absent
from it is the exception working rather than the report being missing.

One pre-existing defect noticed in the same log, NOT fixed here

bash-exec reports an error on every pull request:

[ERROR] scripts/tests/test-megalinter-scan-counts-ignorefile.sh is not executable

It is mode 644 on main (added by #3016), as are test-normalize-sarif-paths.sh,
test-opencost-usage-scraper.sh and test-refresh-flux-ghcr-auth-safety.sh, while every other
script in scripts/tests/ is 755. They still run — CI invokes each as bash scripts/tests/…,
so nothing is silently skipped; the cost is a recurring error line in the very report this backlog is
trying to empty. Out of scope for this PR, which is one concern; filed separately rather than mixed in.

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

Requesting a review at f59ed548, with every check green. Noting for the record that the head's
CodeRabbit status has read pending | Review queued for ~50 minutes with no review object and no
comment, and no @coderabbitai request exists anywhere on this PR from me or anyone else — so this
is the first actual request at this head, not a duplicate of one in flight.

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

@devantler I will review pull request #3054 at f59ed548.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The change adds a path-scoped KSV-0037 exception for Kubernetes infrastructure manifests that run in kube-system. Application paths remain scanned. MegaLinter documentation now reports 110 Trivy findings across 27 targets on v0.73.0. It also explains the reduction from 157 findings after scoping and the earlier scanner rule-set drift.

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Title check ✅ Passed The title clearly summarizes the main change: scoping Trivy KSV-0037 to infrastructure trees.
Description check ✅ Passed The description directly explains the Trivy scope change, measured results, rationale, verification, and related limitation.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

Readiness at f59ed548 — promoting

Green review: cr@f59ed548, and it is the SUMMARY comment, not the command reply. Worth stating
which artifact carries it, because the two are easy to conflate here:

  • CodeRabbit posted zero review objects on this PR, so there is nothing to identify as a review
    by its **Actionable comments posted: opening.
  • Its command-invocation reply reads I will review pull request #3054 at f59ed548 plus a
    ✅ Action performed / Review finished shell. That is an acknowledgement, not a verdict — it
    carries neither Reviewed pull request #N at <sha> nor I found no actionable issues, so it does
    not satisfy the gate on its own. (This is exactly the discrimination monorepo#2759 landed
    earlier today; applying it against my own PR rather than taking the convenient reading.)
  • The auto-generated summary comment is the satisfier: updated after the request, naming the full
    head f59ed548348ed3aab782a9491dabaefa86691882, carrying no rate-limit/quota/did-not-run marker,
    and its only collapsed section is 🔇 Additional comments (2) — CodeRabbit's non-actionable
    informational section, which is excluded from the finding count.
  • Corroborated by the head's CodeRabbit commit status, read by description rather than state:
    Review completed (not the Review skipped: automatic reviews are disabled default this head
    carried an hour ago).

Pentad at head: checks green · unresolved threads 0 · non-thread findings 0 (no review
objects, no inline comments, no actionable summary section) · mergeStateStatus CLEAN · green
review cr@f59ed548.

Exercised as a user — recorded in the two comments above rather than repeated here: the
disposition was measured locally (trivy 157 → 110, KSV-0037 → 0, reproduced through the repository's
own counts script), the scope boundary was proven with a paired control from the repository root, and
the version risk I raised was closed against CI's own job log, where trivy v0.71.2 independently sums
to the same 110 with KSV-0037 absent and every neighbouring check at its expected count.

@devantler
devantler marked this pull request as ready for review August 10, 2026 11:42
@devantler
devantler added this pull request to the merge queue Aug 10, 2026
Merged via the queue into main with commit 68fe3fb Aug 10, 2026
33 checks passed
@devantler
devantler deleted the claude/checkov-k8s-disposition-2787-2 branch August 10, 2026 12:20
@github-project-automation github-project-automation Bot moved this from 🫴 Ready to ✅ Done in 🌊 Project Board Aug 10, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: ✅ Done

Development

Successfully merging this pull request may close these issues.

1 participant