Skip to content

feat: gh-attested skill + attested quality-gate workflows#459

Merged
zircote merged 6 commits into
mainfrom
feat/gh-attested-quality-gates
Jun 15, 2026
Merged

feat: gh-attested skill + attested quality-gate workflows#459
zircote merged 6 commits into
mainfrom
feat/gh-attested-quality-gates

Conversation

@zircote

@zircote zircote commented Jun 15, 2026

Copy link
Copy Markdown
Owner

Summary

Constitutes the attested quality-gate suite from the corpus guide GitHub-Native Attested Quality Gates (free-for-OSS). Every enterprise CI gate is wired as a central reusable workflow whose verdict can be turned into a signed, digest-bound attestation via GitHub keyless signing. Adds the gh-attested skill (assess → plan → implement) and the nine central workflows, composing with attested-delivery, reusable-security.yml, and sbom-and-scan.yml rather than duplicating them.

What's included

Skill.github/skills/gh-attested/

  • SKILL.md (assess → plan → implement → enforce → verify protocol)
  • 7 references: gate-catalog, assessment, attestation-seam, enforcement, verification, repo-config, limitations
  • __org__-parameterized templates: caller, ruleset.json, dependabot.yml, CODEOWNERS, secrets guidance, SECURITY snippet, + copies of the 9 workflows

Central reusable workflows.github/workflows/

  • reusable-attest-scan.yml — the custom-predicate signing seam
  • -sast-codeql, -sca-osv, -trivy, -scorecard, -vex, -k6, -zap, -verify-gates

Repo-config safety contract — auto-apply (ruleset/settings/native scanners/environments) with diff-preview + confirm; secrets/variables guided, never written or logged.

Docs — CLAUDE.md section + table, SECURITY.md "Verifying Quality-Gate Attestations", a Diátaxis how-to, reference/index updates.

Validation

  • actionlint — exit 0 on all 9 workflows + caller template
  • pin-check logic replicated over the 9 workflows — all pinned, zero violations
  • Trivy pinned to a maintainer-signed post-CVE-2026-33634 commit (verified)
  • OSV reusable path verified present at the pinned SHA
  • Skill structure validated: frontmatter, all references resolve, templates parameterized (no zircote leaks), ruleset.json valid JSON
  • pin-check reused (not duplicated) and wired as a required status check

Not done in this PR (by design)

Live dispatch dry-run + independent gh attestation verify is the post-merge acceptance test — it needs the workflows live on a callable ref first. Run it after merge per the skill's references/verification.md.

Boundaries (faithful to the guide)

Private repos need GHAS licenses for CodeQL/secret-scanning/dependency-review; GitHub has no k8s admission control (external — Kyverno/policy-controller); no standard performance predicate; a signed attestation proves a gate ran and recorded a verdict, not that it passed.

Constitute the attested quality-gate suite from the GitHub-native,
free-for-OSS guide: every enterprise CI gate (SAST, SCA, container/IaC/
license, supply-chain posture, vulnerability disposition, load, DAST) wired
as a central reusable workflow whose verdict can be turned into a signed,
digest-bound attestation via GitHub keyless signing.

Skill (.github/skills/gh-attested/): assess -> plan -> implement protocol,
7 references, and __org__-parameterized templates (caller, ruleset,
dependabot, CODEOWNERS, secrets guidance, SECURITY snippet). Composes with
attested-delivery, reusable-security.yml, and sbom-and-scan.yml rather than
duplicating them.

Central reusable workflows (.github/workflows/): reusable-attest-scan (the
custom-predicate signing seam), -sast-codeql, -sca-osv, -trivy, -scorecard,
-vex, -k6, -zap, -verify-gates. All SHA-pinned (Trivy pinned to a
maintainer-signed post-CVE-2026-33634 commit), least-privilege,
actionlint-clean, pin-check-clean. pin-check is reused (not duplicated) and
wired as a required status check via templates/ruleset.json.

Repo-configuration safety contract: ruleset/settings/native-scanners/
environments applied idempotently with diff-preview + confirm; secrets and
variables are guided (names + user-run command) and never read, written,
committed, or logged.

Docs: CLAUDE.md "Attested Quality Gates" section + table, SECURITY.md
"Verifying Quality-Gate Attestations", a Diataxis how-to, and reference/index
updates.
Copilot AI review requested due to automatic review settings June 15, 2026 19:55

Copilot AI 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.

Pull request overview

This PR introduces an attested quality-gate suite for public OSS repositories: a set of centralized reusable GitHub Actions workflows (SAST/SCA/Trivy/Scorecard/VEX/k6/ZAP) plus an attestation “seam” and a deploy-time verifier, and adds a new gh-attested skill with templates/references to assess → plan → implement → enforce → verify these gates.

Changes:

  • Adds the gh-attested skill (docs + references + parameterized templates) to standardize onboarding repos to attested CI quality gates.
  • Adds nine central reusable workflows, including a generic actions/attest seam and a fail-closed verification workflow intended to block deploys.
  • Updates repository documentation (SECURITY.md, CLAUDE.md, docs index/reference pages) to document verification and onboarding.

Reviewed changes

Copilot reviewed 38 out of 38 changed files in this pull request and generated 10 comments.

Show a summary per file
File Description
SECURITY.md Documents verifying quality-gate attestations with gh attestation verify + required signer workflow.
docs/reference/workflows.md Adds a reference index for the attested quality-gate workflow suite.
docs/README.md Links the new “onboard to attested quality gates” how-to.
docs/how-to/onboard-a-repo-to-attested-quality-gates.md New Diátaxis how-to for manual onboarding and enforcement model.
CLAUDE.md Adds an “Attested Quality Gates” section summarizing workflows, rules, and verification.
.github/workflows/reusable-attest-scan.yml Central attestation “seam” that signs arbitrary evidence artifacts as custom predicates.
.github/workflows/reusable-sast-codeql.yml Central reusable SAST gate using CodeQL.
.github/workflows/reusable-sca-osv.yml Central reusable SCA gate via OSV-Scanner + dependency review.
.github/workflows/reusable-trivy.yml Central reusable Trivy gate for IaC/license + optional image scan.
.github/workflows/reusable-scorecard.yml Central reusable OpenSSF Scorecard gate (SARIF + optional publishing).
.github/workflows/reusable-vex.yml Central reusable OpenVEX normalization + attestation workflow.
.github/workflows/reusable-k6.yml Central reusable k6 load-test gate with optional attestation.
.github/workflows/reusable-zap.yml Central reusable OWASP ZAP full scan (opt-in).
.github/workflows/reusable-verify-gates.yml Central deploy-time verifier for required predicate types (fail-closed).
.github/skills/gh-attested/SKILL.md Defines the assess → plan → implement protocol and invariants for attested quality gates.
.github/skills/gh-attested/references/assessment.md Read-only assessment procedure + coverage matrix template.
.github/skills/gh-attested/references/gate-catalog.md Catalog of the 12 gates, evidence, predicate URIs, and merge/deploy roles.
.github/skills/gh-attested/references/attestation-seam.md Explains the seam mechanics and predicate-type URI mapping.
.github/skills/gh-attested/references/enforcement.md Documents merge-time rulesets and deploy-time fail-closed verification.
.github/skills/gh-attested/references/verification.md Workstation verification command set per predicate.
.github/skills/gh-attested/references/repo-config.md Repo-config safety contract: apply vs guide-only behavior.
.github/skills/gh-attested/references/limitations.md Honest limitations and licensing boundary documentation.
.github/skills/gh-attested/templates/README.md Template materialization + drift regeneration instructions.
.github/skills/gh-attested/templates/quality-gates-caller.yml Thin caller template to wire merge-time gates to the central reusables.
.github/skills/gh-attested/templates/ruleset.json Ruleset template enforcing required status checks + reviews + signatures.
.github/skills/gh-attested/templates/dependabot.yml Dependabot config template for keeping SHA pins fresh.
.github/skills/gh-attested/templates/CODEOWNERS CODEOWNERS template aligned to ruleset requirements.
.github/skills/gh-attested/templates/secrets-and-vars.md Guidance doc ensuring secrets are user-set and never logged/written by automation.
.github/skills/gh-attested/templates/SECURITY-snippet.md Snippet to append to target repo SECURITY.md for verification guidance.
.github/skills/gh-attested/templates/reusable-attest-scan.yml Parameterized copy of the central attest-scan seam workflow.
.github/skills/gh-attested/templates/reusable-sast-codeql.yml Parameterized copy of the central CodeQL reusable.
.github/skills/gh-attested/templates/reusable-sca-osv.yml Parameterized copy of the central OSV + dep-review reusable.
.github/skills/gh-attested/templates/reusable-trivy.yml Parameterized copy of the central Trivy reusable.
.github/skills/gh-attested/templates/reusable-scorecard.yml Parameterized copy of the central Scorecard reusable.
.github/skills/gh-attested/templates/reusable-vex.yml Parameterized copy of the central VEX reusable.
.github/skills/gh-attested/templates/reusable-k6.yml Parameterized copy of the central k6 reusable.
.github/skills/gh-attested/templates/reusable-zap.yml Parameterized copy of the central ZAP reusable.
.github/skills/gh-attested/templates/reusable-verify-gates.yml Parameterized copy of the central verify-gates reusable.

Comment thread .github/workflows/reusable-verify-gates.yml
Comment thread .github/workflows/reusable-verify-gates.yml Outdated
Comment thread .github/workflows/reusable-verify-gates.yml
Comment thread .github/workflows/reusable-k6.yml
Comment thread .github/skills/gh-attested/templates/README.md
Comment thread .github/skills/gh-attested/templates/quality-gates-caller.yml
Comment thread .github/skills/gh-attested/templates/reusable-verify-gates.yml
Comment thread .github/skills/gh-attested/templates/reusable-verify-gates.yml Outdated
Comment thread .github/skills/gh-attested/templates/reusable-verify-gates.yml
Comment thread .github/skills/gh-attested/templates/reusable-k6.yml
zircote added 4 commits June 15, 2026 16:05
Add versioned definitions for the seven custom predicate types referenced by
the quality-gate workflows: sast, sca, container-scan, iac-license, scorecard,
dast (SARIF 2.1.0 bodies) and k6-load (k6 summary JSON). Each type gets a
JSON Schema (draft 2020-12) describing the predicate body and the verdict rule
a verifier applies — making explicit that a valid signature proves a gate ran
and was recorded, not that it passed.

The zircote.github.io/attestations/<gate>/v1 URIs are stable type identifiers
(used with `gh attestation verify --predicate-type`); docs/reference/
attestation-predicates/ is their source of truth, ready to publish if the
namespace is ever served. Standard types (OpenVEX, SLSA provenance, SBOM) are
referenced, not redefined.

Wire the index into the docs reference list and the skill's attestation-seam
reference. Verified: all 7 schemas valid JSON Schema; every custom predicate
URI mentioned in workflows/docs has a matching schema; actionlint and
pin-check clean.
Apply GitHub Copilot review findings on PR #459 (live workflows and their
parameterized template copies kept in sync):

- reusable-verify-gates: drop unused `id-token: write` (verify uses only
  GH_TOKEN; no OIDC step) for least privilege.
- reusable-verify-gates: make `predicate-types` required and hard-fail on an
  empty list instead of silently verifying only the default provenance
  predicate — the gate now fails closed.
- reusable-k6: validate subject-name/subject-digest up front and fail fast
  when attest=true, so an expected attestation is never silently skipped.
- templates/README: use portable `perl -pi` instead of BSD-only `sed -i ''`.
- templates/quality-gates-caller: prompt adopters to set their actual default
  branch instead of assuming `main`.

Resolves review comments on PR #459
Max-effort self-review (two convergent finders + advisor) caught a fail-closed
defect: reusable-verify-gates loops a single --signer-workflow over all
predicate-types, but predicates have different signers under SLSA L3 — the seam
(reusable-attest-scan.yml) signs the SARIF gates, while OpenVEX self-signs in
reusable-vex.yml and k6 in reusable-k6.yml (each runs its own actions/attest, so
its Fulcio SAN is itself). Every verify example pinned the seam signer while
also listing the OpenVEX predicate, which would fail verification on a
correctly-signed artifact and block a valid deploy.

- reusable-verify-gates: document one-signer-per-invocation; sharpen the
  signer-workflow input description; usage now shows verify-seam + verify-vex.
- verification.md / SECURITY.md / templates/SECURITY-snippet.md / enforcement.md:
  pin --signer-workflow per predicate (seam for SARIF gates, reusable-vex.yml for
  OpenVEX, reusable-k6.yml for k6); the predicates-README "Signed by" column is
  the source of truth.
- enforcement.md: drop the stale id-token: write from the verify example (the
  verify job signs nothing).
- CLAUDE.md: correct the verification note to per-predicate signers.

Signer fix is verified by reasoning about the SLSA L3 cert identity, not a live
gh attestation verify run. Live workflow and its template copy kept in sync.

Resolves review comments on PR #459
@zircote

zircote commented Jun 15, 2026

Copy link
Copy Markdown
Owner Author

Max-effort self-review (/code-review max --fix)

Ran 4 parallel finder angles + advisor (Opus 4.8) over the authored diff (46 files). Two real findings, both fixed in 9bf0981.

1. Fail-closed signer bug — reusable-verify-gates.yml + 4 doc files (must-fix)

reusable-verify-gates.yml loops a single --signer-workflow over all predicate-types, but predicates have different signers under SLSA L3: the seam (reusable-attest-scan.yml) signs the SARIF gates, while OpenVEX self-signs in reusable-vex.yml and k6 in reusable-k6.yml (each runs its own actions/attest, so its Fulcio SAN is itself). Every verify example pinned the seam signer and listed the OpenVEX predicate → gh attestation verify fails the SAN check on a correctly-signed artifact → a valid deploy is blocked fail-closed.

Fix: pin --signer-workflow per predicate (the predicates-README "Signed by" column is the source of truth); document reusable-verify-gates.yml as one-signer-per-invocation (verify-seam + verify-vex, deploy needs: both). Corrected in verification.md, SECURITY.md, templates/SECURITY-snippet.md, enforcement.md, the workflow usage comment, and CLAUDE.md.

2. Stale id-token: writeenforcement.md verify example (minor)

Left over from the earlier fix that removed id-token: write from the verify job (it signs nothing). Removed.

Verified clean (not assumed)

  • Live ↔ template: all 9 workflow pairs byte-identical after zircote__org__ (no drift).
  • ruleset.json contexts (sast / analyze, sca / dependency-review, trivy / iac-license, pin-check / pin-check) all resolve to real jobs; ruleset/dependabot schemas valid.
  • Permissions least-privilege per job; id-token: write only on the 3 signers (attest-scan, vex, k6) — scorecard's is for publish_results, not signing.
  • vexctl PATH (setup-go adds $GOPATH/bin), gh api calls in assessment.md/repo-config.md, predicate-URI↔schema consistency — all check out.

Honest caveat

The signer fix is verified by reasoning about the SLSA L3 certificate identity, not a live gh attestation verify run (can't execute here). Also unchanged from the PR's existing disclosure: the seam-signed SARIF predicates verify end-to-end only once gate jobs upload their evidence to the seam; OpenVEX and k6 are the predicates that sign inline today, which is exactly why their wrong-signer was the live bug worth fixing now.

Not fixed (deliberately): the live↔template duplication is a maintenance note (no drift today), and the dependabot.yml header-comment scope wording is a trivial nit — neither is a defect.

@zircote zircote merged commit f02449f into main Jun 15, 2026
3 checks passed
@zircote zircote deleted the feat/gh-attested-quality-gates branch June 15, 2026 20:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants