Skip to content

fix(apps): pin tenant OCI manifest tags - #2737

Merged
devantler merged 11 commits into
mainfrom
codex/fix-tenant-oci-semver-selection-vulnerability
Aug 18, 2026
Merged

fix(apps): pin tenant OCI manifest tags#2737
devantler merged 11 commits into
mainfrom
codex/fix-tenant-oci-semver-selection-vulnerability

Conversation

@devantler

@devantler devantler commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

🤖 Generated by the Agentic Engineer

Why

Both tenant apps tracked their manifests with an open-ended >=1.0.0 range, so Flux automatically selected and deployed any newer tag pushed to that registry path. Whoever can publish a tag chose what production runs, with no review in between.

What

Pins each tenant to the exact manifest revision production is already reconciling, so tenant deployments become a reviewed step rather than an unattended one. Nothing that is running changes.

Security/DevEx: the floor gains removal of unattended tag selection for both tenants; the everyday path is unchanged for app development — only a tenant manifest rollout now needs a pin bump.

⚠️ Operational note: future tenant releases no longer roll out on their own. Each one needs a PR bumping the pin in k8s/bases/apps/<app>/oci-repository.yaml.

@devantler

Copy link
Copy Markdown
Contributor Author

Requested by the 🤖 Daily AI Engineer — CI is green at the current head and this draft carries no qualifying review, so requesting the lane-priority reviewer. Hygiene only: this is a sibling lane's draft and its owner promotes it.

@devantler

Copy link
Copy Markdown
Contributor Author

@cursor review

@cursor

cursor Bot commented Jul 21, 2026

Copy link
Copy Markdown
Contributor

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_13fcb2f8-74cf-44f3-8e7a-036bcfbb9d9f)

@devantler devantler left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤖 Generated by the Agentic Engineer

Static exact-head review of 34665f7d3c28803b186fa34df53e0c516f5a255e; the branch was not checked out or executed.

Comment thread k8s/bases/apps/ascoachingogvaner/oci-repository.yaml Outdated
@github-actions

github-actions Bot commented Aug 14, 2026

Copy link
Copy Markdown
Contributor

⚠️MegaLinter analysis: Success with warnings

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

✅ [SUCCESS] .github/scripts/setup-ksail.sh
✅ [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-kubescape-gate-frameworks.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-actual-budget-auth-route.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-cnpg-degraded-alert.sh
✅ [SUCCESS] scripts/tests/test-coroot-postgres-scrape-policy.sh
✅ [SUCCESS] scripts/tests/test-crossplane-egress-policy.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
❌ [ERROR] scripts/tests/test-headlamp-plugin-removal.sh
    Error: File:[scripts/tests/test-headlamp-plugin-removal.sh] is not executable

✅ [SUCCESS] scripts/tests/test-kubescape-gate-frameworks-guard.sh
✅ [SUCCESS] scripts/tests/test-kyverno-admission-vpa.sh
❌ [ERROR] scripts/tests/test-kyverno-umami-mutation-rbac.sh
    Error: File:[scripts/tests/test-kyverno-umami-mutation-rbac.sh] is not executable

✅ [SUCCESS] scripts/tests/test-megalinter-scan-counts-ignorefile.sh
✅ [SUCCESS] scripts/tests/test-normalize-sarif-paths.sh
✅ [SUCCESS] scripts/tests/test-openbao-oidc-role.sh
✅ [SUCCESS] scripts/tests/test-opencost-usage-scraper.sh
✅ [SUCCESS] scripts/tests/test-pvc-prune-safety.sh
✅ [SUCCESS] scripts/tests/test-refresh-flux-ghcr-auth-safety.sh
✅ [SUCCESS] scripts/tests/test-restrict-homepage-service-groups.sh
✅ [SUCCESS] scripts/tests/test-restrict-tenant-secret-stores.sh
✅ [SUCCESS] scripts/tests/test-setup-ksail.sh
✅ [SUCCESS] scripts/tests/test-shared-publish-workflow-pin-guard.sh
✅ [SUCCESS] scripts/tests/test-summarize-sarif-findings.sh
✅ [SUCCESS] scripts/tests/test-tenant-route-hostname-boundary.sh
✅ [SUCCESS] scripts/tests/test-umami-provisioning-bootstrap.sh
✅ [SUCCESS] scripts/tests/test-use-prod-stable-api-endpoint.sh
✅ [SUCCESS] scripts/tests/test-validate-image-verifier-liveness.sh
✅ [SUCCESS] scripts/tests/test-verify-published-evidence.sh
✅ [SUCCESS] scripts/update-vendored-operators.sh
✅ [SUCCESS] scripts/use-prod-stable-api-endpoint.sh
✅ [SUCCESS] scripts/validate-alert-coverage.sh
✅ [SUCCESS] scripts/validate-image-verifier-liveness.sh
✅ [SUCCESS] scripts/verify-published-evidence.sh
✅ [SUCCESS] scripts/wait-for-platform-flux-revision.sh
⚠️ REPOSITORY / checkov - 2 errors
2026-08-18 00:22:35,917 [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: 2167, Failed checks: 2, Skipped checks: 36

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.
github_actions scan results:

Passed checks: 156, Failed checks: 0, Skipped checks: 0
⚠️ SPELL / cspell - 3566 errors
edocs",
        "homelab",
        "hostnames",
        "httproute",
        "httproutes",
        "idempotently",
        "ignorefile",
        "imagevalidatingpolicy",
        "imranismail",
        "injective",
        "inspectable",
        "iscsi",
        "italicise",
        "ivpol",
        "jobif",
        "journalled",
        "keylessly",
        "keypair",
        "kprobes",
        "kptr",
        "krew",
        "ksail",
        "ksail's",
        "ksailcd",
        "kubeconfig",
        "kubeconfig's",
        "kubeconform",
        "kubeconform's",
        "kubelet",
        "kubelet's",
        "kubelets",
        "kubescape",
        "kubescape's",
        "kubespan",
        "kubevirt",
        "kubevuln",
        "kustomization",
        "kustomizations",
        "letsencrypt",
        "libc",
        "libgnutls",
        "lintable",
        "livez",
        "loadtester",
        "locationless",
        "logfile",
        "lookarounds",
        "lrwxrwxrwx",
        "lserror",
        "lsfail",
        "luks",
        "lycheeignore",
        "machineconfig",
        "materialise",
        "materialised",
        "materialises",
        "maxage",
        "maxbackup",
        "maxsize",
        "maxx",
        "microtime",
        "mikefarah",
        "misconfig",
        "misconfigs",
        "misordered",
        "mistargeted",
        "mitrelike",
        "mktemp",
        "mlock",
        "mutatingpolicies",
        "mutatingwebhookconfigurations",
        "myapp",
        "najsk",
        "neighbour",
        "nenv",
        "netlink",
        "netpol",
        "netpols",
        "neutralises",
        "neutralising",
        "nextjs",
        "nftables",
        "nilnil",
        "nobuckets",
        "nodepod",
        "nodeport",
        "nolabel",
        "nolint",
        "nonexec",
        "nonroot",
        "normalisation",
        "normalise",
        "normalised",
        "normalises",
        "normalising",
        "nosec",
        "nsalike",
        "nullglob",
        "ocirepository",
        "onlycri",
        "onlysystem",
        "openbao",
        "opencost",
        "openfeature",
        "oras",
        "otherplugin",
        "overclaimed",
        "overprovisioning",
        "parallelised",
        "partialgroup",
        "pasteable",
        "permissioning",
        "persistentvolumeclaims",
        "phaseless",
        "pipefail",
        "policyreports",
        "portforward",
        "preemptible",
        "preservingly",
        "prioritisable",
        "prioritisation",
        "prioritised",
        "privesc",
        "probeerror",
        "providerconfigs",
        "pseudonymization",
        "pseudonymized",
        "pseudonymizes",
        "publishapp",
        "publishprovider",
        "pushsecret",
        "pushsecrets",
        "qrbvrml",
        "randomises",
        "rdqwpktr",
        "readyz",
        "reassertions",
        "recognisable",
        "recognisably",
        "recognise",
        "recognised",
        "recolour",
        "reconverges",
        "referencegrants",
        "refreshfluxghcrauth",
        "regenerable",
        "releaserc",
        "rematerialise",
        "rematerialised",
        "replicaset",
        "repoint",
        "repointed",
        "repoints",
        "repositoryrulesets",
        "resizer",
        "restrictor",
        "retabbed",
        "retarget",
        "rmem",
        "rolebindings",
        "rollouts",
        "rshared",
        "rwxr",
        "sanitised",
        "sanitiser",
        "sanitising",
        "sarif",
        "scheckov",
        "schedulability",
        "schedulable",
        "scopeable",
        "scopeless",
        "seccomp",
        "secretbox",
        "secretstore",
        "seedable",
        "serialise",
        "serialised",
        "serverside",
        "serviceaccount",
        "serviceaccounts",
        "sgdisk",
        "shellcheck",
        "shfmt",
        "shopt",
        "shortsha",
        "siderolabs",
        "siderolink",
        "sigstore",
        "skmde",
        "slurpfile",
        "sngle",
        "specnull",
        "spiffe",
        "sprintf",
        "srole",
        "stakater",
        "startswith",
        "statefulset",
        "statemanager",
        "stdlib",
        "stepif",
        "storageclass",
        "strenv",
        "subshell",
        "subtest",
        "summarised",
        "surfaceless",
        "syft",
        "syscall",
        "sysctls",
        "syste",
        "systembare",
        "tagliteral",
        "tagonly",
        "talosconfig",
        "talosctl",
        "tanzu",
        "tcproutes",
        "templatesyncignore",
        "thresholded",
        "tlsroutes",
        "tlsv",
        "tmpl",
        "toplevel",
        "tostring",
        "tracepoints",
        "travelled",
        "trixie",
        "trueish",
        "trustd",
        "ture",
        "udproutes",
        "uids",
        "umami",
        "umami's",
        "unablated",
        "unclickable",
        "uncompilable",
        "unconfigured",
        "uncordon",
        "uncordoned",
        "uncordoning",
        "uncordons",
        "undecoded",
        "undercounts",
        "undispositioned",
        "unenforcing",
        "unevidenced",
        "unexcepted",
        "unfiled",
        "ungated",
        "ungenerated",
        "unifi",
        "uninspected",
        "uninvoked",
        "unioned",
        "unmarshalling",
        "unmarshals",
        "unmodelled",
        "unparseable",
        "unprovisioned",
        "unrecognisable",
        "unrecognised",
        "unrepresentable",
        "unreviewed",
        "unroutable",
        "unrun",
        "unshippable",
        "unskipped",
        "untrackable",
        "unvalidated",
        "unwaited",
        "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",
        "xpkg",
        "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 643090)
⚠️ COPYPASTE / jscpd - 147 errors
est-crossplane-egress-policy.sh [260:25 - 268:19] (9 lines, 52 tokens)
   scripts/tests/test-crossplane-egress-policy.sh [280:24 - 288:19]
Clone found (bash)
 - scripts/tests/test-crossplane-egress-policy.sh [260:25 - 268:18] (9 lines, 51 tokens)
   scripts/tests/test-crossplane-egress-policy.sh [305:31 - 313:18]
Clone found (bash)
 - scripts/tests/test-crossplane-egress-policy.sh [291:13 - 299:8] (9 lines, 52 tokens)
   scripts/tests/test-crossplane-egress-policy.sh [370:18 - 378:14]
Clone found (bash)
 - scripts/tests/test-crossplane-egress-policy.sh [369:22 - 378:15] (10 lines, 63 tokens)
   scripts/tests/test-crossplane-egress-policy.sh [379:33 - 388:15]
Clone found (bash)
 - scripts/tests/test-crossplane-sync-exporter.sh [186:1 - 235:2] (50 lines, 299 tokens)
   scripts/tests/test-kyverno-umami-mutation-rbac.sh [16:1 - 63:2]
Clone found (bash)
 - scripts/tests/test-crossplane-sync-exporter.sh [186:1 - 237:11] (52 lines, 303 tokens)
   scripts/tests/test-opencost-usage-scraper.sh [33:1 - 84:11]
Clone found (bash)
 - scripts/tests/test-crossplane-sync-exporter.sh [221:27 - 238:53] (18 lines, 53 tokens)
   scripts/tests/test-opencost-usage-scraper.sh [68:27 - 85:51]
Clone found (bash)
 - scripts/tests/test-headlamp-plugin-removal.sh [121:89 - 126:22] (6 lines, 65 tokens)
   scripts/tests/test-headlamp-plugin-removal.sh [165:84 - 170:22]
Clone found (bash)
 - scripts/tests/test-refresh-flux-ghcr-auth-safety.sh [348:5 - 356:51] (9 lines, 76 tokens)
   scripts/tests/test-refresh-flux-ghcr-auth-safety.sh [357:5 - 365: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 [564:50 - 569:24] (6 lines, 103 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [1076:31 - 1081:24]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [596:14 - 602:4] (7 lines, 115 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [923:43 - 929:4]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [622:13 - 631:7] (10 lines, 158 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [1205:18 - 1214:7]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [631:1 - 636:8] (6 lines, 93 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [1215:1 - 1220:8]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [708:5 - 713:2] (6 lines, 82 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [894:8 - 899:9]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [709:1 - 719:23] (11 lines, 220 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [986:60 - 997:3]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [713:15 - 724:2] (12 lines, 185 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [814:17 - 825:2]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [760:15 - 771:12] (12 lines, 264 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [969:1 - 982:3]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [823:2 - 829:19] (7 lines, 89 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [1008:7 - 1014:19]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [823:2 - 829:33] (7 lines, 103 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [1390:58 - 1396:33]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [823:2 - 829:4] (7 lines, 74 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [1503:5 - 1509:4]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [916:30 - 921:8] (6 lines, 50 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [943:44 - 948:8]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [1030:22 - 1036:2] (7 lines, 135 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [1589:22 - 1595:2]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [1328:33 - 1336:11] (9 lines, 118 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [1340:130 - 1348:11]
Clone found (go)
 - scripts/validate-eks-ci-role-policy/main_test.go [1535:47 - 1540:2] (6 lines, 166 tokens)
   scripts/validate-eks-ci-role-policy/main_test.go [1615:46 - 1620: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   │ 55             │ 18446       │ 72425        │ 36           │ 490 (2.66%)      │ 3377 (4.66%)      │
├────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ go     │ 38             │ 33040       │ 195679       │ 109          │ 890 (2.69%)      │ 8272 (4.23%)      │
├────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ python │ 4              │ 807         │ 5606         │ 2            │ 14 (1.73%)       │ 111 (1.98%)       │
├────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ txt    │ 1              │ 212         │ 1172         │ 0            │ 0 (0.00%)        │ 0 (0.00%)         │
├────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ Total: │ 98             │ 52505       │ 274882       │ 147          │ 1394 (2.65%)     │ 11760 (4.28%)     │
└────────┴────────────────┴─────────────┴──────────────┴──────────────┴──────────────────┴───────────────────┘
Found 147 clones.
HTML report saved to megalinter-reports/copy-paste/jscpd-report.html
ERROR: jscpd found too many duplicates (2.7%) over threshold (0.0%)
time: 913.527ms

(Truncated to last 6666 characters out of 28065)
⚠️ MARKDOWN / markdownlint - 65 errors
length Line length [Expected: 400; Actual: 439]
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: 628]
AGENTS.md:107:401 error MD013/line-length Line length [Expected: 400; Actual: 1774]
AGENTS.md:160:401 error MD013/line-length Line length [Expected: 400; Actual: 649]
AGENTS.md:162:401 error MD013/line-length Line length [Expected: 400; Actual: 971]
AGENTS.md:189:401 error MD013/line-length Line length [Expected: 400; Actual: 970]
AGENTS.md:193:401 error MD013/line-length Line length [Expected: 400; Actual: 660]
AGENTS.md:211:401 error MD013/line-length Line length [Expected: 400; Actual: 1510]
AGENTS.md:279:401 error MD013/line-length Line length [Expected: 400; Actual: 1016]
AGENTS.md:280:401 error MD013/line-length Line length [Expected: 400; Actual: 491]
AGENTS.md:281:401 error MD013/line-length Line length [Expected: 400; Actual: 468]
AGENTS.md:287:401 error MD013/line-length Line length [Expected: 400; Actual: 532]
AGENTS.md:289:401 error MD013/line-length Line length [Expected: 400; Actual: 523]
AGENTS.md:292:401 error MD013/line-length Line length [Expected: 400; Actual: 613]
AGENTS.md:293:401 error MD013/line-length Line length [Expected: 400; Actual: 714]
AGENTS.md:297:401 error MD013/line-length Line length [Expected: 400; Actual: 502]
AGENTS.md:301:401 error MD013/line-length Line length [Expected: 400; Actual: 441]
AGENTS.md:306:401 error MD013/line-length Line length [Expected: 400; Actual: 427]
AGENTS.md:409:401 error MD013/line-length Line length [Expected: 400; Actual: 1139]
AGENTS.md:411:401 error MD013/line-length Line length [Expected: 400; Actual: 1240]
AGENTS.md:427:401 error MD013/line-length Line length [Expected: 400; Actual: 1137]
AGENTS.md:824:401 error MD013/line-length Line length [Expected: 400; Actual: 790]
AGENTS.md:829: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:589: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 7160)
⚠️ REPOSITORY / trivy - 1 error
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-crossplane-sync-alerter.yaml (kubernetes)
==============================================================================================
Tests: 116 (SUCCESSES: 115, FAILURES: 1)
Failures: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)

KSV-0125 (MEDIUM): Container alerter in cronjob crossplane-sync-alerter (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-crossplane-sync-alerter.yaml:71-94
────────────────────────────────────────
  71 ┌             - name: alerter
  72 │               # curl + jq, digest-pinned (same image as the autosuppressor).
  73 │               # observability is exempt from disallow-latest-tag.
  74 │               image: docker.io/badouralix/curl-jq:latest@sha256:1e7c0284e24572ace7170df9fc91f15fd3b79ebf056d4dde17244d5d74bbfabc
  75 │               securityContext:
  76 │                 allowPrivilegeEscalation: false
  77 │                 readOnlyRootFilesystem: true
  78 │                 runAsNonRoot: true
  79 └                 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.74.0 of Trivy is now available, current version is 0.73.0

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

(Truncated to last 6666 characters out of 300470)

✅ Linters with no issues

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

Notices

⚠️ Your configuration references items that have been removed from MegaLinter and are ignored: REPOSITORY_GITLEAKS. See Removed linters to find their replacements.

See detailed reports in MegaLinter artifacts

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

Pinning the ascoachingogvaner and wedding-app OCIRepository refs moves the
aggregate authorization-surface fingerprint, because Flux source resources are
authorization-capable and their projected text is covered by it.

Membership is unchanged and no per-resource hash moved; the delta is two
spec.ref fields swapping a floating semver range for a fixed tag, which narrows
what may be reconciled. Fingerprint read from the required job on the approved
renderer, measured after updating onto current main.
@github-code-quality

github-code-quality Bot commented Aug 16, 2026

Copy link
Copy Markdown

Code Coverage Overview

Languages: Go

Go / code-coverage/go

The overall coverage in commit 977478b in the codex/fix-tenant-oci... branch is 81%. Coverage data for the main branch is not yet available.

Show a code coverage summary of the most covered files.
File main codex/fix-tenant-oci... 977478b +/-
scripts/kubesca...ridge/issues.go 99%
scripts/validat...-verify/main.go 97%
scripts/kubesca...e/exceptions.go 96%
scripts/kubesca...-bridge/main.go 93%
scripts/validat...ify/instance.go 87%
scripts/validat...signing/main.go 85%
scripts/validat...-policy/main.go 80%
scripts/generat...eptions/main.go 79%
scripts/kubesca...ridge/client.go 74%
scripts/annotat...checkov/main.go 54%

Updated August 18, 2026 00:25 UTC

…e tags

Merge main and correct both pins. The branch pinned ascoachingogvaner to
1.1.0 and wedding-app to 1.5.9 while production reconciles 1.13.4 and
1.15.10, so merging it would have rolled both tenants backward by many
releases. Read-only prod evidence confirms the deployed revisions; both
match each repository's latest release.

The rendered-surface fingerprint is reset to main's approved value. The
tag change moves the selected authorization surface, so CI's approved
renderer must supply the new value — the local toolchain is kubectl
v1.36.1 against the approved v1.36.2 and is refused.
@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

CI is green at the current head and no review has been requested on this PR yet. Requesting one.

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

@devantler: I will review the current pull request head.


🧠 Learnings used
Learnt from: devantler
Repo: devantler-tech/platform PR: 0
File: :0-0
Timestamp: 2026-08-15T21:24:53.679Z
Learning: In `devantler-tech/platform`, a disclosed `coderabbitai review` request can be parsed as chat and return the `initiate chat on the files` prompt instead of starting a review. A bare `coderabbitai review` trigger is the known workaround. This behavior is tracked in GitHub issue `monorepo#2818`.

Learnt from: devantler
Repo: devantler-tech/platform PR: 0
File: :0-0
Timestamp: 2026-08-03T08:32:31.421Z
Learning: For GitHub pull request `#2917`, empty-body `coderabbitai[bot]` review objects can be generated by thread resolution. They are wrappers, not completed CodeRabbit reviews. Treat a CodeRabbit review as delivered only when it has a non-empty review body and applies to the current commit head.
⚠️ Action not completed

Review rate limited.

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 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository YAML (base), Organization UI (inherited)

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 05ff97e5-42e8-4b8e-975d-8e06e9e927ab

📥 Commits

Reviewing files that changed from the base of the PR and between c4fb7f2 and 977478b.

📒 Files selected for processing (3)
  • k8s/bases/apps/ascoachingogvaner/oci-repository.yaml
  • k8s/bases/apps/wedding-app/oci-repository.yaml
  • scripts/validate-eks-ci-role-policy/main.go

Included review availability: Your plan includes up to 1 review per rolling hour; 0 remain after this review.

📜 Recent review details
🧰 Additional context used
📓 Path-based instructions (1)
**/*.{yaml,yml}

📄 CodeRabbit inference engine (AGENTS.md)

**/*.{yaml,yml}: Never run a cluster
Put a change in the layer that matches its scope

Files:

  • k8s/bases/apps/ascoachingogvaner/oci-repository.yaml
  • k8s/bases/apps/wedding-app/oci-repository.yaml
🧠 Learnings (6)
📚 Learning: 2026-07-01T21:13:36.950Z
Learnt from: devantler
Repo: devantler-tech/platform PR: 2359
File: k8s/bases/apps/actual-budget/helm-release.yaml:62-111
Timestamp: 2026-07-01T21:13:36.950Z
Learning: When reviewing Kustomize/Helm YAML in this repo, keep the base vs provider overlay split: `k8s/bases/apps/**` and `k8s/bases/infrastructure/**` should contain each app’s full, environment-agnostic configuration (including base-level postRenderer Kustomize patches such as deployment strategy, topology spread, probes, and env injection). `k8s/providers/{docker,hetzner}/**` should only add small provider-specific deltas (e.g., `interval`, `persistence.size`) via patch files (like `k8s/providers/<provider>/apps/<app>/patches/helm-release-patch.yaml`). If configuration is identical across providers (e.g., OIDC/OAuth env vars where `${domain}` is resolved per cluster via envsubst), it belongs in the base and must not be duplicated into provider overlays.

Applied to files:

  • k8s/bases/apps/ascoachingogvaner/oci-repository.yaml
  • k8s/bases/apps/wedding-app/oci-repository.yaml
📚 Learning: 2026-07-03T03:44:11.507Z
Learnt from: devantler
Repo: devantler-tech/platform PR: 2399
File: k8s/bases/apps/ascoachingogvaner/oci-repository.yaml:25-26
Timestamp: 2026-07-03T03:44:11.507Z
Learning: In Flux `OCIRepository` manifests under `k8s/bases/**/oci-repository.yaml`, keep the existing house convention for `spec.serviceAccountRef.verify.matchOIDCIdentity` subject regexes to use an `@.+` ref suffix (i.e., match any ref) rather than tightening it to a specific SHA/tag pattern.

If a PR adds a transitional dual-subject entry for an ongoing migration (e.g., moving from `devantler-tech/reusable-workflows` to `devantler-tech/actions`), do not request tightening the ref matcher in that PR. Defer any ref-matcher tightening to a separate, focused follow-up PR that consistently tightens `matchOIDCIdentity` subject rules once each file returns to a single subject after migration cleanup.

Applied to files:

  • k8s/bases/apps/ascoachingogvaner/oci-repository.yaml
  • k8s/bases/apps/wedding-app/oci-repository.yaml
📚 Learning: 2026-08-08T15:10:00.349Z
Learnt from: devantler
Repo: devantler-tech/platform PR: 3017
File: k8s/bases/infrastructure/coroot/components/crossplane-sync-exporter/deployment.yaml:13-21
Timestamp: 2026-08-08T15:10:00.349Z
Learning: In the devantler-tech/platform repository, Checkov CI scans source manifests with `--skip-framework kustomize` rather than rendered Kustomize overlays. To suppress a Checkov finding on a base manifest, place the appropriate `checkov.io/skip*` annotation directly in that base YAML file; an overlay patch will not suppress findings reported for the source file.

Applied to files:

  • k8s/bases/apps/ascoachingogvaner/oci-repository.yaml
  • k8s/bases/apps/wedding-app/oci-repository.yaml
📚 Learning: 2026-08-08T15:10:00.350Z
Learnt from: devantler
Repo: devantler-tech/platform PR: 3017
File: k8s/bases/infrastructure/coroot/components/crossplane-sync-exporter/deployment.yaml:13-21
Timestamp: 2026-08-08T15:10:00.350Z
Learning: For Kubernetes manifests under k8s/bases/, keep workload-related Checkov exception annotations (checkov.io/skip*) in the base manifest when the checked condition is defined there and CI scans that source manifest directly. Do not move these annotations to overlays solely because the base is immutable; keeping them with the workload ensures the disposition applies consistently to every consumer of the base.

Applied to files:

  • k8s/bases/apps/ascoachingogvaner/oci-repository.yaml
  • k8s/bases/apps/wedding-app/oci-repository.yaml
📚 Learning: 2026-08-08T21:23:32.529Z
Learnt from: devantler
Repo: devantler-tech/platform PR: 3025
File: k8s/bases/infrastructure/controllers/kubescape/helm-release.yaml:97-133
Timestamp: 2026-08-08T21:23:32.529Z
Learning: In the devantler-tech/platform repository, modify Kubernetes manifests directly under k8s/bases/ when a configuration change should apply to all Kustomize overlays. Use provider- or cluster-specific overlay patches only for changes that are intentionally limited to those overlays.

Applied to files:

  • k8s/bases/apps/ascoachingogvaner/oci-repository.yaml
  • k8s/bases/apps/wedding-app/oci-repository.yaml
📚 Learning: 2026-08-11T12:41:28.242Z
Learnt from: devantler
Repo: devantler-tech/platform PR: 3082
File: k8s/bases/infrastructure/controllers/coroot/cron-job-cnpg-degraded-alert.yaml:113-120
Timestamp: 2026-08-11T12:41:28.242Z
Learning: When changing behavior in Kubernetes manifests or related documentation, review comments and documentation in YAML/YML and Markdown files for statements describing the previous behavior. Update every stale statement in the same change so the repository’s explanatory text remains consistent with the implementation.

Applied to files:

  • k8s/bases/apps/ascoachingogvaner/oci-repository.yaml
  • k8s/bases/apps/wedding-app/oci-repository.yaml
🔇 Additional comments (3)
k8s/bases/apps/ascoachingogvaner/oci-repository.yaml (1)

12-12: LGTM!

k8s/bases/apps/wedding-app/oci-repository.yaml (1)

12-12: LGTM!

scripts/validate-eks-ci-role-policy/main.go (1)

1011-1055: LGTM!


📝 Walkthrough

Walkthrough

The ascoachingogvaner OCIRepository now uses tag 1.13.4. The wedding-app OCIRepository now uses tag 1.15.10. The authorization-surface approval record stores the resulting aggregate fingerprint. No identity, binding, permission, URL, or AWS service-account grant changed.

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 and concisely summarizes the main change: pinning tenant OCI manifest tags.
Description check ✅ Passed The description accurately explains the security rationale, exact changes, deployment impact, and required process for future tenant releases.

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

@codex review

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.
To continue using code reviews, add credits to your account and enable them for code reviews in your settings.

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

CodeRabbit returned Review rate limited at this head and Codex replied with an account usage
limit (measured 2026-08-17T00:03:29Z). Advancing to Bugbot per lane order.

@devantler

Copy link
Copy Markdown
Contributor Author

@cursor review

@cursor

cursor Bot commented Aug 17, 2026

Copy link
Copy Markdown
Contributor

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_570b60eb-975d-4fd0-a0da-56e028c0f03a)

# Conflicts:
#	scripts/validate-eks-ci-role-policy/main.go
@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

Blocker: this PR's conflict is an authorization-surface re-measurement, not a mergeable conflict. Diagnosed, not resolved — recording it so the next pass starts from evidence.

main has advanced to 9a84e92b, and the only conflicting file is scripts/validate-eks-ci-role-policy/main.go. Both conflict hunks land on the same thing:

side expectedRenderedSurfaceSHA
this branch 3fda5879259ea82207cf38faf32a30ed1603f77985fb4e2d61b61a4172792538
main b5b394181a8f2bc325bd427a90990fbc3872fb1f41f3d938f1e28f0aac1075f4

Neither value is correct for the merge result, which is why this cannot be hand-merged. That constant is the aggregate fingerprint of the rendered RBAC surface; the branch's value was measured against an older main, and main's value describes main without this branch. Picking either side commits a fingerprint that describes a tree nobody rendered — and this validator is the gate protecting the aws/aws service account, so a wrong value here either fails the build or, worse, passes while describing the wrong surface.

The rest of the state is healthy: 28 checks green, 5 skipped, 0 failing, and the change itself (pinning tenant OCI manifest tags away from a >=1.0.0 semver range) is unaffected by the merge.

What this needs

The two-renderer re-measurement on the merge result, with matched controls:

  1. Render with the required job's own approved toolchain (kubectl v1.36.2, checksum-verified into a scratch dir — never replacing the shared binary, which carries prod access).
  2. Render independently via TestValidateAuthorizationAcceptsCommittedPolicy, which bypasses the version gate.
  3. Both must first pass on clean main — that control is what makes their agreement evidence rather than two guesses.
  4. Rewrite the audit comment to describe this merge's delta, and state the conservation counts.

I stopped rather than hurry it: a hasty pass on a prod authorization fingerprint is worse than none. The branch is untouched and no partial merge was pushed.

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 18, 2026

Copy link
Copy Markdown
Contributor

@devantler: I will review pull request #2737 at the current head.

🧠 Learnings used
  • In this repository, a bare review trigger avoids the known chat-parsing behavior.

🧠 Learnings used
Learnt from: devantler
Repo: devantler-tech/platform PR: 0
File: :0-0
Timestamp: 2026-08-15T21:24:53.679Z
Learning: In `devantler-tech/platform`, a disclosed `coderabbitai review` request can be parsed as chat and return the `initiate chat on the files` prompt instead of starting a review. A bare `coderabbitai review` trigger is the known workaround. This behavior is tracked in GitHub issue `monorepo#2818`.

Learnt from: devantler
Repo: devantler-tech/platform PR: 0
File: :0-0
Timestamp: 2026-08-03T08:32:31.421Z
Learning: For GitHub pull request `#2917`, empty-body `coderabbitai[bot]` review objects can be generated by thread resolution. They are wrappers, not completed CodeRabbit reviews. Treat a CodeRabbit review as delivered only when it has a non-empty review body and applies to the current commit head.
✅ 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.

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

Readiness evaluation @ 977478bd78a72c76c2a4da28da740955936fd954

  1. Programmatically tested — 26 checks pass, 5 skipped, none failing; mergeStateStatus CLEAN; 0 unresolved threads; 0 non-thread review findings. The required 🔐 Validate EKS Authorization job re-approved the surface fingerprint on the merge with exact main c4fb7f2d, reporting 0 per-identity mismatches, 0 missing resources, 0 duplicates — the aggregate was the only control that moved, which is what the two pinned OCIRepository documents should do and nothing more.

  2. Reviewed — CodeRabbit at this head: auto-generated summary refreshed after the request naming this commit, Review completed, 0 inline comments, 0 review findings.

  3. Tried and evaluated as a user — checked the running cluster rather than inferring from the manifests. Both tenants are already reconciling the exact revisions this PR pins, while still selecting them through the floating range:

    Tenant Live revision now Pinned to Live selector today
    ascoachingogvaner 1.13.4 1.13.4 >=1.0.0
    wedding-app 1.15.10 1.15.10 >=1.0.0

    So the deployed state does not move: what changes is that a newly published tag can no longer be selected and reconciled without a review. That was the point of the change, and it is the part worth confirming against reality — had either pin disagreed with the live revision, this would have been a silent rollback rather than a pin.

Promoting and enqueuing.

@devantler
devantler marked this pull request as ready for review August 18, 2026 00:44
@devantler
devantler added this pull request to the merge queue Aug 18, 2026
Merged via the queue into main with commit 76ad7f7 Aug 18, 2026
33 checks passed
@devantler
devantler deleted the codex/fix-tenant-oci-semver-selection-vulnerability branch August 18, 2026 00:52
@github-project-automation github-project-automation Bot moved this from 🫴 Ready to ✅ Done in 🌊 Project Board Aug 18, 2026
devantler added a commit to devantler-tech/platform-tenant-template that referenced this pull request Aug 18, 2026
* fix(tests): track the Platform tenant OCI pinned-tag change

Platform pinned the manual tenant apps' OCI manifests to an exact tag in
devantler-tech/platform#2737, replacing the floating ">=1.0.0" semver range.
The envelope contract still asserted the semver form, so the whole conjunction
matched nothing and CI failed with "no matches found".

Assert the hardened shape instead: no semver range at all, and an exact
pinned version tag. The generated RGD tenant still uses semver, so its
assertion is deliberately unchanged.

* fix(tests): reject leading-zero version components in the tenant OCI tag

Addresses a CodeRabbit review finding: [0-9]+ accepted 01.2.3 and 1.13.04,
which are not valid semver. Match each component as 0 or a non-zero digit
followed by digits, which still accepts a legitimate zero component (0.1.0).

* test(envelope): pin the tenant OCI pinned-tag predicate with mutants

The pinned-tag predicate had no committed mutant, so a future weakening of it
would pass the whole safety suite. Add four rejecting mutations covering a
floating tag, a restored semver range, and a leading-zero version component in
both the major and patch positions.

The two leading-zero mutants are not redundant: each version component is
anchored separately, so a partial revert that tightens only the major component
still rejects "01.2.3" while accepting "1.2.03".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

* test(envelope): pin the minor version component too

Self-review found the same gap one level down: the major and patch positions
each had a leading-zero mutant, but the minor position did not, so a partial
revert tightening only major and patch would still have passed the suite.

Ablation proof: with the predicate weakened to
"^(0|[1-9][0-9]*)[.][0-9]+[.](0|[1-9][0-9]*)$" the suite fails specifically on
"manual OCI tag minor component leading zero".

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
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