Skip to content

fix(security): keep the shared publish-workflow matchers pinned to a fixed revision - #3019

Merged
devantler merged 7 commits into
mainfrom
claude/cosign-publish-workflow-pin-guard-2818
Aug 8, 2026
Merged

fix(security): keep the shared publish-workflow matchers pinned to a fixed revision#3019
devantler merged 7 commits into
mainfrom
claude/cosign-publish-workflow-pin-guard-2818

Conversation

@devantler

@devantler devantler commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

🤖 Generated by the Agentic Engineer

Why

#2816 tightened the cosign matchers that decide which signer we trust, from "any ref" to a fixed
revision. That was done by hand, in eight separate places, and nothing keeps it that way. Widening
any one of them back does not look like breakage — verification still runs, it just accepts more —
so schema checks, kubeconform and the deploy all stay green while the control quietly weakens.

This makes the property enforced instead of conventional, which is the first acceptance criterion
on #2818 and the cheapest of the options weighed there.

What

A CI guard asserting that every cosign subject naming a shared devantler-tech/actions publish
workflow pins a fixed revision — rejecting both a branch ref and a bare "any ref" wildcard.

Two things worth the maintainer's attention:

  • The platform's own root source is deliberately out of scope. It is signed by platform workflows
    running from main and the merge queue, so its subject legitimately contains a branch ref. A guard
    that banned branch refs outright would fail on the correct deployed config — and a control that
    fires at the known-good state is one that gets switched off the first time it blocks a release.
    Scoped by subject instead, so it says nothing about first-party workflows.
  • The issue estimated five of these; there are eight, under three different key spellings. The
    guard fails closed if it ever finds fewer, because a refactor that moved them out of its reach
    would otherwise report a clean repository while checking nothing.

This keeps #2816's property from regressing; it does not restrict trust to approved revisions —
a superseded SHA still matches. That needs a generated allow-list and remains open on #2818.

Fixes #3021

Part of #2818

devantler and others added 2 commits August 8, 2026 17:28
…fixed revision

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

github-actions Bot commented Aug 8, 2026

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/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-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-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 - 12 errors
2026-08-08 16:42:46,210 [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: 1972, Failed checks: 12, Skipped checks: 30

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_40: "Containers should run as a high UID to avoid host conflict"
	FAILED for resource: Job.userns-longhorn-smoke.userns-longhorn-smoke
	File: /k8s/providers/hetzner/apps/userns-longhorn-smoke/job.yaml:5-154
	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.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: Job.openbao.vault-config
	File: /k8s/bases/infrastructure/vault-config/job.yaml:36-1200
	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: 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_38: "Ensure that Service Account Tokens are only mounted where necessary"
	FAILED for resource: CronJob.observability.cnpg-degraded-alert
	File: /k8s/bases/infrastructure/controllers/coroot/cron-job-cnpg-degraded-alert.yaml:56-202
	Guide: https://docs.prismacloud.io/en/enterprise-edition/policy-reference/kubernetes-policies/kubernetes-policy-index/bc-k8s-35

		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-202
	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: 112, Failed checks: 0, Skipped checks: 0
⚠️ SPELL / cspell - 3101 errors
"descheduler",
        "descheduling",
        "desynchronising",
        "devantler",
        "diffable",
        "dispositioned",
        "distroless",
        "dockerconfigjson",
        "docstrings",
        "dorny",
        "dpkg",
        "drainable",
        "emptydir",
        "endgroup",
        "entrys",
        "envsubst",
        "esac",
        "etcdctl",
        "evictable",
        "extensionless",
        "externalsecret",
        "externalsecrets",
        "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",
        "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",
        "luks",
        "lycheeignore",
        "machineconfig",
        "materialise",
        "materialised",
        "materialises",
        "maxage",
        "maxbackup",
        "maxsize",
        "maxx",
        "metacharacters",
        "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",
        "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",
        "siderolabs",
        "siderolink",
        "sigstore",
        "skmde",
        "slurpfile",
        "sngle",
        "specnull",
        "spiffe",
        "srole",
        "startswith",
        "statefulset",
        "statemanager",
        "stdlib",
        "storageclass",
        "subtest",
        "summarised",
        "surfaceless",
        "syft",
        "syscall",
        "sysctls",
        "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 551171)
⚠️ COPYPASTE / jscpd - 185 errors
tokens)
   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   │ 37             │ 11353       │ 43926        │ 20           │ 295 (2.60%)      │ 1797 (4.09%)      │
├────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ go     │ 36             │ 29795       │ 180224       │ 99           │ 804 (2.70%)      │ 7637 (4.24%)      │
├────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ python │ 4              │ 807         │ 5606         │ 2            │ 14 (1.73%)       │ 111 (1.98%)       │
├────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ txt    │ 57             │ 3378        │ 109125       │ 64           │ 2417 (71.55%)    │ 80219 (73.51%)    │
├────────┼────────────────┼─────────────┼──────────────┼──────────────┼──────────────────┼───────────────────┤
│ Total: │ 134            │ 45333       │ 338881       │ 185          │ 3530 (7.79%)     │ 89764 (26.49%)    │
└────────┴────────────────┴─────────────┴──────────────┴──────────────┴──────────────────┴───────────────────┘
Found 185 clones.
HTML report saved to megalinter-reports/copy-paste/jscpd-report.html
ERROR: jscpd found too many duplicates (7.8%) over threshold (0.0%)
time: 1.68s

(Truncated to last 6666 characters out of 39333)
⚠️ MARKDOWN / markdownlint - 63 errors
ould 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:191:401 error MD013/line-length Line length [Expected: 400; Actual: 453]
AGENTS.md:210:401 error MD013/line-length Line length [Expected: 400; Actual: 1360]
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:415:401 error MD013/line-length Line length [Expected: 400; Actual: 430]
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 6993)
⚠️ REPOSITORY / trivy - 1 error
astructure/vertical-pod-autoscalers/hubble-relay.yaml:7-11
────────────────────────────────────────
   7 ┌ spec:
   8 │   targetRef:
   9 │     apiVersion: apps/v1
  10 │     kind: Deployment
  11 └     name: hubble-relay
────────────────────────────────────────



k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/hubble-ui.yaml (kubernetes)
=========================================================================================
Tests: 117 (SUCCESSES: 116, FAILURES: 1)
Failures: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)

KSV-0037 (MEDIUM): VerticalPodAutoscaler 'hubble-ui' should not be set with 'kube-system' namespace
════════════════════════════════════════
ensure that user resources are not placed in kube-system namespace

See https://avd.aquasec.com/misconfig/ksv-0037
────────────────────────────────────────
 k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/hubble-ui.yaml:7-11
────────────────────────────────────────
   7 ┌ spec:
   8 │   targetRef:
   9 │     apiVersion: apps/v1
  10 │     kind: Deployment
  11 └     name: hubble-ui
────────────────────────────────────────



k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/metrics-server.yaml (kubernetes)
==============================================================================================
Tests: 117 (SUCCESSES: 116, FAILURES: 1)
Failures: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)

KSV-0037 (MEDIUM): VerticalPodAutoscaler 'metrics-server' should not be set with 'kube-system' namespace
════════════════════════════════════════
ensure that user resources are not placed in kube-system namespace

See https://avd.aquasec.com/misconfig/ksv-0037
────────────────────────────────────────
 k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/metrics-server.yaml:7-11
────────────────────────────────────────
   7 ┌ spec:
   8 │   targetRef:
   9 │     apiVersion: apps/v1
  10 │     kind: Deployment
  11 └     name: metrics-server
────────────────────────────────────────



k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/snapshot-controller.yaml (kubernetes)
===================================================================================================
Tests: 117 (SUCCESSES: 116, FAILURES: 1)
Failures: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)

KSV-0037 (MEDIUM): VerticalPodAutoscaler 'snapshot-controller' should not be set with 'kube-system' namespace
════════════════════════════════════════
ensure that user resources are not placed in kube-system namespace

See https://avd.aquasec.com/misconfig/ksv-0037
────────────────────────────────────────
 k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/snapshot-controller.yaml:7-11
────────────────────────────────────────
   7 ┌ spec:
   8 │   targetRef:
   9 │     apiVersion: apps/v1
  10 │     kind: Deployment
  11 └     name: snapshot-controller
────────────────────────────────────────



k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/spire-agent.yaml (kubernetes)
===========================================================================================
Tests: 117 (SUCCESSES: 116, FAILURES: 1)
Failures: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)

KSV-0037 (MEDIUM): VerticalPodAutoscaler 'spire-agent' should not be set with 'kube-system' namespace
════════════════════════════════════════
ensure that user resources are not placed in kube-system namespace

See https://avd.aquasec.com/misconfig/ksv-0037
────────────────────────────────────────
 k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/spire-agent.yaml:9-13
────────────────────────────────────────
   9 ┌ spec:
  10 │   targetRef:
  11 │     apiVersion: apps/v1
  12 │     kind: DaemonSet
  13 └     name: spire-agent
────────────────────────────────────────



k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/spire-server.yaml (kubernetes)
============================================================================================
Tests: 117 (SUCCESSES: 116, FAILURES: 1)
Failures: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)

KSV-0037 (MEDIUM): VerticalPodAutoscaler 'spire-server' should not be set with 'kube-system' namespace
════════════════════════════════════════
ensure that user resources are not placed in kube-system namespace

See https://avd.aquasec.com/misconfig/ksv-0037
────────────────────────────────────────
 k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/spire-server.yaml:7-11
────────────────────────────────────────
   7 ┌ spec:
   8 │   targetRef:
   9 │     apiVersion: apps/v1
  10 │     kind: StatefulSet
  11 └     name: spire-server
────────────────────────────────────────



k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/tetragon-operator.yaml (kubernetes)
=================================================================================================
Tests: 117 (SUCCESSES: 116, FAILURES: 1)
Failures: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)

KSV-0037 (MEDIUM): VerticalPodAutoscaler 'tetragon-operator' should not be set with 'kube-system' namespace
════════════════════════════════════════
ensure that user resources are not placed in kube-system namespace

See https://avd.aquasec.com/misconfig/ksv-0037
────────────────────────────────────────
 k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/tetragon-operator.yaml:7-11
────────────────────────────────────────
   7 ┌ spec:
   8 │   targetRef:
   9 │     apiVersion: apps/v1
  10 │     kind: Deployment
  11 └     name: tetragon-operator
────────────────────────────────────────



k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/tetragon.yaml (kubernetes)
========================================================================================
Tests: 117 (SUCCESSES: 116, FAILURES: 1)
Failures: 1 (UNKNOWN: 0, LOW: 0, MEDIUM: 1, HIGH: 0, CRITICAL: 0)

KSV-0037 (MEDIUM): VerticalPodAutoscaler 'tetragon' should not be set with 'kube-system' namespace
════════════════════════════════════════
ensure that user resources are not placed in kube-system namespace

See https://avd.aquasec.com/misconfig/ksv-0037
────────────────────────────────────────
 k8s/providers/hetzner/infrastructure/vertical-pod-autoscalers/tetragon.yaml:9-13
────────────────────────────────────────
   9 ┌ spec:
  10 │   targetRef:
  11 │     apiVersion: apps/v1
  12 │     kind: DaemonSet
  13 └     name: tetragon
────────────────────────────────────────



📣 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 341001)

✅ 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

…bad shapes

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

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

No review requested at this head yet, deliberately. CodeRabbit refused twice in the last twenty minutes
on this account, at two different heads on monorepo#2720 — both times the acknowledgement's visible line
claimed it would review while the collapsed block read ⚠️ Action not completed — Review rate limited,
with no retry window — and Codex is mid-review on that PR. Requesting here now would either be spent on
a lane that is declining or fan out to a second provider concurrently.

Recording it so the next run resumes at the right lane instead of re-deriving this.

Self-review already applied, and it found a real gap rather than confirming the diff: the guard
originally rejected two known-bad ref shapes (refs/heads/, a bare .+), which would still have waved
through @main or @v1. It now judges each alternative against an allow-list — a 40-hex commit or a
refs/tags/ tag. Ablation matrix is 5/5 (.+, refs/heads/main, main, v1, and a mixed alternation
where only one branch is bad — that last one names the offending alternative specifically), plus the
floor case, plus the control that the root source's legitimate branch ref stays unflagged.

@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

CodeRabbit is rate-limited at this head (cr:no-gate recorded above), so advancing to the next lane. CI is green and no threads are open.

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4e9a831008

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/guard-shared-publish-workflow-pin.sh
Comment thread .github/workflows/ci.yaml
Comment thread scripts/guard-shared-publish-workflow-pin.sh Outdated
devantler and others added 4 commits August 8, 2026 18:27
… every path

Three gaps Codex found at 4e9a831, all reproduced against the real repository
before fixing.

The tag arm matched by shell GLOB PREFIX, so `(refs/tags/v.+)?refs/heads/.+$` —
an optional tag group followed by a branch ref — was accepted and the guard
reported all eight subjects pinned. Reproduced: exit 0 on a subject permitting
refs/heads. Each alternative is now matched whole against an explicit grammar,
and a ref that is not a fully grouped alternation is rejected outright rather
than having a leading paren stripped and the remainder read as part of one
alternative.

The count floor only proved the eight KNOWN subjects were still found; a ninth
consumer written in valid multiline YAML or under a new key was invisible to the
subject pattern while the existing eight satisfied the floor. Discovery now keys
on the shared workflow identity alone, with no key name or line structure, and
any reference the strict pattern did not validate fails closed naming the file.

The guard ran only in ci.yaml, whose triggers are pull_request and merge_group.
A matcher widened by a direct push to main therefore reached production through
the manual CD route with the check never having run. It is now also a step in
cd.yaml's pre-deploy contract job and in validate-main.yaml, matching the reason
already stated in both files: the routes to production must share one gate, or
the weakest becomes the real policy.

Ablations, each firing its own named branch: optional-tag-group, bare branch ref
in the alternation, a tag form smuggling a second ref kind through `/`, a bare
`.+`, a bare `@main`, and a new consumer in an unmatched form. Control: the clean
repository still reports all 8 pinned, exit 0.
…ys single-step

scripts/validate-dr-signing requires validate-publication-contract to run exactly
one command step: any other step in that job could export BASH_ENV or put a fake
`go` on $PATH through $GITHUB_ENV/$GITHUB_PATH, leaving the validator step looking
correct while it was subverted. Adding the pin guard as a second step there broke
that invariant — which is the invariant working, not an obstacle to route around.

The guard now runs in its own job in both workflows, and cd.yaml's deploy-prod
gains it as a `needs` prerequisite, so the manual deploy is still gated. Neither
validator job grows a tampering surface, and the guard covers the direct-push and
manual-deploy paths as intended.
…entry

Adding the pin guard to deploy-prod's `needs` wrapped that line past the
formatter's width, and validate-dr-signing's ablations mutate it as a literal —
three of them reported "ablation changed nothing", i.e. they had silently stopped
biting. That is the meta-guard doing exactly its job, and re-aiming a security
validator's ablations to accommodate a formatting change is the wrong direction.

validate-publication-contract now depends on the pin guard instead, so the deploy
is still blocked when a matcher is widened (the guard's failure skips the contract
job, which skips deploy-prod) while deploy-prod's `needs` line stays byte-identical
and every ablation keeps biting. The guard also stays in its own job, so the
contract job still runs exactly one command step.
@devantler

Copy link
Copy Markdown
Contributor Author

🤖 Generated by the Agentic Engineer

All three Codex findings from the previous round are fixed and their threads resolved; CI is green at
this head. Restarting the ordered provider loop at CodeRabbit.

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

@devantler: I will review the changes at 84fda3f844ad20c092a2f2d0324484b2dc71e6f8.

✅ 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 8, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

The pull request adds a Bash guard for shared publish workflow pinning. The guard validates Cosign subjects against full revisions or constrained tags. CI, main-branch validation, and production deployment workflows run the guard. Production publication-contract validation now depends on the shared pin validation job.

Possibly related issues

  • devantler-tech/platform#2818: The pull request adds the recommended CI and deployment enforcement for shared publish workflow pins.

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 describes the main change: pinning shared publish-workflow matchers to fixed revisions.
Description check ✅ Passed The description directly explains the guard, its scope, validation behavior, and deployment integration.

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

User evaluation at 84fda3f8 — ran the guard itself against the real repository and against
each regression it claims to stop, rather than reading the tests.

Positive control first. Against the deployed configuration it reports
8 shared-publish-workflow subject(s) all pin a fixed revision, exit 0. That control is meaningful
rather than vacuous: three families of cosign subject in this repo legitimately carry a branch ref —
the platform's own ci/cd/dr-rebuild workflows, and the provider-upjet-*
publish-provider-package workflow — and the guard stays silent on all of them. The scoping claim in
the PR body is exercised, not assumed.

Then the five failure modes, each mutation verified to have actually landed (a 1+/1- diff),
because an ablation that changes nothing proves nothing:

Mutation Result
matcher widened back to @.+ exit 1 — ref alternative .+ does not pin a fixed revision, with file and line
@refs/heads/main exit 1
@v1 moving tag alias exit 1
one subject deleted exit 1 — found 7 …, expected at least 8, and it names the scan rather than the repo as the likely cause
a new consumer written in a multiline form the strict pattern cannot see exit 1 — reports the file as referenced-but-unvalidated

The last two are the ones worth having. A guard whose grep silently stops matching reports a clean
repository while checking nothing, and both structural paths fail closed instead. Restoring the file
returns it to exit 0, so the failures are the mutations and not drift in the guard.

Also linked the delivery issue: this PR previously said only Part of #2818, so nothing closed on
merge and CodeRabbit's linked-issues evaluation skipped for want of a link. It now says
Fixes #3021 — the delivery child scoped to the parent's first acceptance criterion — and keeps
Part of #2818, which stays open for the approved-revision half this deliberately does not attempt.

@devantler
devantler marked this pull request as ready for review August 8, 2026 17:09
@devantler
devantler added this pull request to the merge queue Aug 8, 2026
Merged via the queue into main with commit 0ca5538 Aug 8, 2026
31 checks passed
@devantler
devantler deleted the claude/cosign-publish-workflow-pin-guard-2818 branch August 8, 2026 17:16
@github-project-automation github-project-automation Bot moved this from 🫴 Ready to ✅ Done in 🌊 Project Board Aug 8, 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.

security(ci): enforce that shared publish-workflow matchers stay pinned to a fixed revision

1 participant