feat: attest and version this repo as a single-plugin marketplace#1
Merged
Conversation
Add .claude-plugin/marketplace.json so this repo doubles as its own marketplace catalog, versioned independently from plugin.json. Add a release pipeline (SLSA build provenance, fail-closed gh attestation verify, tag-gated GitHub Release) and CI (pin-check, actionlint, claude plugin validate) scaled to a single solo-maintained skill bundle rather than the multi-repo container-image pipeline this was modeled on. Also fixes install docs (README, docs/how-to/install.md), which referenced a nonexistent plugins.marketplaces config key. AI-Tool: claude_code AI-Tool-Version: 2.1.199 AI-Tool-Entrypoint: cli AI-Tool-Location: local AI-Model: claude-sonnet-5 AI-Effort: high AI-Teammate-Mode: in-process AI-Touched-Lines-Pct: 0.9258 AI-Generated-At: 2026-07-03T14:00:27.806641+00:00 AI-Cohort: ai_assisted AI-Session-Id: claude-code:c1d77b9a-f74e-4cd6-90e4-ec73cf6aa592 AI-Authoring-Mode: cli-agent Vcs-Repository-Name: zircote/cdc-error-handling
- Replace hand-rolled pin-check and actionlint-install steps with the maintained actions they reimplemented (zgosalvez/github-actions-ensure-sha-pinned-actions, reviewdog/action-actionlint) per the Don't Reinvent the Wheel rule. This also resolves a latent false-negative in the hand-rolled pin-check regex for digest-less docker:// references. - Fix release.yml publish gating: previously only checked ref shape, not the triggering event, so a workflow_dispatch run manually pointed at an existing tag would still publish despite the header comment's claim that dispatch never publishes. Now requires the push event too. - Remove build job's unused artifact-name output; no downstream job consumed it. AI-Tool: claude_code AI-Tool-Version: 2.1.199 AI-Tool-Entrypoint: cli AI-Tool-Location: local AI-Model: claude-sonnet-5 AI-Effort: high AI-Teammate-Mode: in-process AI-Touched-Lines-Pct: 0.2 AI-Generated-At: 2026-07-03T14:09:03.424292+00:00 AI-Cohort: ai_assisted AI-Session-Id: claude-code:c1d77b9a-f74e-4cd6-90e4-ec73cf6aa592 AI-Authoring-Mode: cli-agent Vcs-Repository-Name: zircote/cdc-error-handling
There was a problem hiding this comment.
Pull request overview
This PR turns the repository into a self-contained single-plugin marketplace and adds an attested, tag-driven release process plus CI validation to support supply-chain verification for published tarballs.
Changes:
- Added
.claude-plugin/marketplace.jsonand updated the plugin manifest version/metadata. - Introduced CI and a release workflow that builds a reproducible tarball, generates SLSA provenance, verifies it fail-closed, and publishes a GitHub Release on tag pushes.
- Updated docs (
README, install + verification how-tos,SECURITY.md) and added aCHANGELOG.mdto document installation and verification workflows.
Reviewed changes
Copilot reviewed 9 out of 9 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| SECURITY.md | Adds a security policy plus a concrete release verification model and commands. |
| README.md | Updates installation/validation guidance and documents marketplace + release verification workflow. |
| docs/how-to/verify-release.md | New walkthrough for verifying release checksums and SLSA provenance with gh. |
| docs/how-to/install.md | Updates installation instructions to use marketplace add + current settings syntax. |
| CHANGELOG.md | Introduces Keep a Changelog history and documents the new CI/release posture. |
| .github/workflows/release.yml | Adds a tag-gated release pipeline with provenance attestation + fail-closed verification. |
| .github/workflows/ci.yml | Adds CI for SHA pinning, actionlint, and strict plugin/marketplace validation. |
| .claude-plugin/plugin.json | Bumps plugin version to 0.4.0 and adds homepage/repository metadata. |
| .claude-plugin/marketplace.json | New single-plugin marketplace catalog pointing to the repo root (./). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- CHANGELOG.md: the 0.4.0 entry said CI runs `claude plugin validate .`, but the workflow actually runs `claude plugin validate . --strict`. - docs/how-to/verify-release.md: commands were hard-coded to v0.4.0 and its exact filenames, which would go stale after the next release and invite copy/paste failures. Switched to a substitutable TAG variable and glob patterns, matching SECURITY.md's existing convention. - SECURITY.md: fixed the same hard-coded-checksum-filename issue in the adjacent verification section for consistency. AI-Tool: claude_code AI-Tool-Version: 2.1.199 AI-Tool-Entrypoint: cli AI-Tool-Location: local AI-Model: claude-sonnet-5 AI-Effort: high AI-Teammate-Mode: in-process AI-Touched-Lines-Pct: 0.619 AI-Generated-At: 2026-07-03T14:24:10.303330+00:00 AI-Cohort: ai_assisted AI-Session-Id: claude-code:c1d77b9a-f74e-4cd6-90e4-ec73cf6aa592 AI-Authoring-Mode: cli-agent Vcs-Repository-Name: zircote/cdc-error-handling
Per your explicit choice ("Full: mirror the reference repo exactly") for
attestation depth, on default GITHUB_TOKEN for release auth (no GitHub
App token minting):
- Six quality-gate jobs (SAST via CodeQL language:actions, SCA via
OSV-Scanner, IaC/license via Trivy, Semgrep, secrets via Gitleaks +
TruffleHog, manifest structural review), each seam-attested as a signed
custom predicate (https://zircote.github.io/attestations/<gate>/v1)
bound to the release tarball's digest.
- CycloneDX SBOM (anchore/sbom-action + actions/attest-sbom).
- Cosign keyless signature over .claude-plugin/marketplace.json, verified
in-run before publish.
- OpenVEX disposition attestation (.vex/openvex.json).
- ShellCheck deliberately not wired: this repo has no .sh scripts to scan.
Also adds MIF Level 1 frontmatter (id/type/created) to every doc touched
in this branch (README, install.md, verify-release.md, SECURITY.md,
CHANGELOG.md), alongside the existing diataxis_type/title convention,
per your explicit choice to satisfy the globally-installed mif-docs
plugin's fail-closed guard rather than ignore it.
This body of work went through an independent review pass before commit
(delegated, not self-reviewed) that found and fixed:
- The verify job's 9 gh attestation verify calls omitted
--signer-workflow, so --repo alone only proved "signed by some workflow
in this repo," not specifically release.yml. Fixed, and updated every
consumer-facing verify command in SECURITY.md/verify-release.md to
match.
- Gitleaks' fallback line masked a crashed/failed scan as a clean "0
findings" SARIF instead of failing the job. Now fails closed like every
other gate.
- gate-sca's SARIF upload was missing an explicit category (every sibling
gate has one).
- The header comment named job names (attest-sbom, attest-vex) that don't
exist; corrected to the real names (sbom, vex).
- Hardened the verify job's artifact resolution to use the build job's
recorded subject-name instead of a fragile `ls dist` glob.
- Dropped unused contents:read from the six attest-* jobs, which never
check out the repo.
- Left the cosign catalog-signer regex intentionally unanchored on @ref
(documented why: it also self-verifies on workflow_dispatch dry-runs
from a branch, and anchoring to refs/tags/ would break that).
AI-Tool: claude_code
AI-Tool-Version: 2.1.199
AI-Tool-Entrypoint: cli
AI-Tool-Location: local
AI-Model: claude-sonnet-5
AI-Effort: high
AI-Teammate-Mode: in-process
AI-Touched-Lines-Pct: 0.9512
AI-Generated-At: 2026-07-03T14:59:35.453747+00:00
AI-Cohort: ai_only
AI-Session-Id: claude-code:c1d77b9a-f74e-4cd6-90e4-ec73cf6aa592
AI-Authoring-Mode: cli-agent
Vcs-Repository-Name: zircote/cdc-error-handling
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This repository now doubles as its own single-plugin marketplace, versioned independently from the plugin, with a full attested release pipeline:
.claude-plugin/marketplace.json(catalog1.0.0,source: "./") alongsideplugin.json(bumped0.3.0->0.4.0, addedhomepage/repository).ci.yml): pin-check, actionlint,claude plugin validate . --strict.release.yml): reproducible tarball, SLSA build provenance, a CycloneDX SBOM, six quality-gate verdicts (SAST/CodeQL, SCA/OSV-Scanner, IaC+license/Trivy, Semgrep, secrets/Gitleaks+TruffleHog, manifest structural review) each seam-attested as a signed custom predicate bound to the tarball digest, an OpenVEX disposition, and a cosign-signed marketplace.json catalog. Every attestation and the catalog signature fail-closed re-verify before the tag-gated publish step.SECURITY.md,docs/how-to/verify-release.md,CHANGELOG.mddocumenting the verification model and commands.id/type/created) on every doc touched, alongside the existingdiataxis_type/titleconvention.Scope decisions
GITHUB_TOKEN, scoped per job. The full-tier attestation/signing machinery (SBOM, cosign, VEX, per-gate attestations) doesn't require a separate release identity; that was a distinct concern in the reference architecture this was adapted from.release.ymlrunning in this same repo, so verification pins--signer-workflowto that one workflow rather than a distinct central identity..shscripts to scan (its only executable logic is.github/workflows/*.ymlrun:blocks). A gate with nothing to scan would produce a permanently-empty attestation that asserts nothing.Review
Two independent review passes (delegated to an out-of-session reviewer, not self-reviewed), both before commit:
release.ymlpublish-gating bug (workflow_dispatchagainst an existing tag could force-publish outside the intended tag-push-only flow) and two hand-rolled CI steps reimplementing maintained actions (zgosalvez/github-actions-ensure-sha-pinned-actions,reviewdog/action-actionlint) — all fixed.gh attestation verifycalls in theverifyjob omitting--signer-workflow(so--repoalone only proved "signed by some workflow in this repo," not specificallyrelease.yml), and a Gitleaks fallback that masked a crashed scan as a clean "0 findings" pass instead of failing closed. Full list in the commit message for0d47ff3.Copilot's automated review (first pass) also caught 2 stale hard-coded-version issues in docs, both fixed and threads resolved.
Test Plan
claude plugin validate . --strictpasses on both manifests.actionlintclean on both workflow files.osv-scanner-action) was caught pointing at a stale, no-longer-current commit and corrected to the live tag's actual SHA.mif-validate --level 1) passes on every touched doc.git archivetarball-build step dry-run locally.workflow_dispatchonce this PR is up, and for real on the first tag (v0.4.0, planned immediately after merge).