CI/CD supply chain hardening plugin for Claude Code, designed for Rust projects.
GH-Guard packages production-tested CI/CD security configurations into reusable templates and guided workflows. It helps Rust OSS maintainers achieve high OpenSSF Scorecard scores, set up Trusted Publishing, generate SLSA L3 provenance, and configure comprehensive dependency auditing.
Add to your Claude Code settings (~/.claude/settings.json):
{
"plugins": [
"~/path/to/gh-guard"
]
}# Audit your project's supply chain security posture
/audit
# Interactively harden your project
/harden
# Generate a specific config file
/generate ci-workflow
/generate publish-workflow
/generate deny-toml
# Check for outdated SHA pins
/check-updates
# Validate generated configs
/verify
Scans your repository and produces a structured gap analysis:
- Checks for expected files (workflows, deny.toml, SECURITY.md, etc.)
- Scores against OpenSSF Scorecard checks
- Classifies your current hardening level (Minimal / Standard / Hardened)
- Identifies SHA-pinning gaps, missing permissions, Cargo.lock issues
- Detects workspace projects and validates publish ordering
- Outputs prioritized recommendations with template references
Guides you through hardening at three levels:
| Level | Components |
|---|---|
| Minimal | CI workflow + cargo-deny + Dependabot + SECURITY.md |
| Standard | + Trusted Publishing + CodeQL + Scorecard + release script |
| Hardened | + SLSA L3 provenance + fuzz testing + osv-scanner |
Detects your current hardening level and offers upgrade mode — generating only the delta files needed to reach the next level. Supports workspace projects with per-crate Trusted Publishing guidance.
Checks deployed workflows for outdated action SHAs and CLI tool versions:
- Compares pinned SHAs against latest tags via the GitHub API
- Detects outdated CLI tool versions (cargo-audit, cargo-fuzz)
- Shows what's out of date with current vs latest comparison
- Offers to apply updates automatically
- Respects the SLSA generator exception (must use
@tag, not SHA)
Validates that generated configs are syntactically correct, internally consistent, and ready to deploy:
- YAML/TOML syntax validation
- SHA pin completeness and version comment presence
- Cross-file consistency (MSRV, gate job, fuzz targets)
cargo-deny checkdry run (if installed)release.sh --dry-runvalidation
Generates a single file with auto-detected project values. Shows a unified diff before overwriting existing files.
| Target | Output Path |
|---|---|
ci-workflow |
.github/workflows/ci.yml |
publish-workflow |
.github/workflows/publish.yml |
codeql |
.github/workflows/codeql.yml |
scorecard |
.github/workflows/scorecard.yml |
fuzz |
.github/workflows/fuzz.yml |
deny-toml |
deny.toml |
rust-toolchain |
rust-toolchain.toml |
dependabot |
.github/dependabot.yml |
security-md |
SECURITY.md |
release-script |
scripts/release.sh |
osv-scanner |
osv-scanner.toml |
Production-tested config files parameterized with {{PLACEHOLDER}} syntax. Values are auto-detected from Cargo.toml, git remote, and cargo metadata:
| Placeholder | Source | Example |
|---|---|---|
{{CRATE_NAME}} |
Cargo.toml name field |
my-tool |
{{MSRV}} |
rust-version or rust-toolchain.toml |
1.82 |
{{REPO_OWNER}} |
Git remote URL | my-org |
{{REPO_NAME}} |
Git remote URL | my-tool |
{{CONTACT_EMAIL}} |
Cargo.toml authors field |
me@example.com |
{{FUZZ_TARGETS}} |
fuzz/Cargo.toml bin entries |
fuzz_parse,fuzz_decode |
{{WORKSPACE_CRATES}} |
cargo metadata --no-deps (publishable, dependency order) |
core,parser,cli |
All workflow templates follow these security practices:
- SHA-pinned actions with version comments (e.g.,
# v4.2.2) permissions: read-allat workflow level, scoped per-jobpersist-credentials: falseon all checkout steps- Script injection prevention — user-controlled values passed via environment variables, not inline
${{ }} - Concurrency groups — prevent parallel runs on the same branch/PR
- Pinned CLI tool versions —
cargo-auditpinned to specific version with--locked workflow_dispatchretrigger — publish workflow supports manual retrigger for failed publishes
Skills are deep knowledge documents loaded automatically when relevant. They encode hard-won lessons from production Rust CI/CD:
| Skill | What It Covers |
|---|---|
| scorecard-checks | All 18 OpenSSF Scorecard checks with Rust-specific implementation guidance and scoring strategy |
| trusted-publishing | OIDC threat model, prerequisites, step-by-step crates.io setup, troubleshooting |
| slsa-provenance | Three-job publish/provenance/release pipeline, hash generation, verification, common pitfalls |
| ci-pipeline | Gate pattern, multi-job design, caching, SHA pinning, permissions model |
| release-automation | PR-based release flow, signed tags, CI polling race condition, branch protection compatibility |
| dependency-policy | cargo-deny configuration, Dependabot setup, osv-scanner layered defense |
| fuzz-testing | cargo-fuzz setup, Arbitrary vs raw bytes, corpus management, CI integration, coverage analysis |
| migration-guide | Level detection algorithm, upgrade paths (Minimal to Standard to Hardened), rollback procedures |
| workspace-publishing | Multi-crate publish ordering, per-crate Trusted Publishing, version synchronization |
| hardening-detection | Shared level detection algorithm used by /audit, /harden, and migration-guide |
| cargo-vet | Supply chain audits — human review attestation for third-party crates |
| security-findings | SARIF triage workflow for CodeQL, Scorecard, cargo-deny, and Dependabot findings |
| binary-releases | Cross-platform binary distribution via cargo-dist, cross, or manual CI matrix |
| changelog | Automated changelog generation with git-cliff and conventional commits |
Based on real-world experience achieving OpenSSF Scorecard 7.5/10:
- All GitHub Actions SHA-pinned with version comments
permissions: read-allat workflow level, scoped per-job- Trusted Publishing (OIDC) — no long-lived API tokens
- SLSA L3 provenance attached to GitHub Releases
- cargo-deny for license, ban, advisory, and source checks
- Dependabot for cargo + github-actions updates
- CodeQL with Rust native analysis
- Fuzz testing with cargo-fuzz
- Signed git tags (SSH ed25519 or GPG)
- SECURITY.md with coordinated disclosure policy
gh-guard/
commands/ # User-invocable slash commands
audit.md # /audit — gap analysis
harden.md # /harden — interactive wizard
generate.md # /generate — single file generator
check-updates.md # /check-updates — SHA staleness checker
verify.md # /verify — post-generation validation
skills/ # Contextual knowledge (auto-loaded)
binary-releases/
cargo-vet/
changelog/
ci-pipeline/
dependency-policy/
fuzz-testing/
hardening-detection/
migration-guide/
release-automation/
scorecard-checks/
security-findings/
slsa-provenance/
trusted-publishing/
workspace-publishing/
templates/ # Parameterized config files
workflows/
ci.yml
codeql.yml
fuzz.yml
publish.yml
scorecard.yml
deny.toml
dependabot.yml
osv-scanner.toml
release.sh
rust-toolchain.toml
SECURITY.md
VERSIONS.md # Pinned action version manifest (human-readable)
versions.json # Pinned action version manifest (machine-readable)
tests/ # Validation infrastructure
validate-templates.sh
fixtures/
examples/ # Sample output
audit-output.md
.gitignore
CLAUDE.md # Plugin instructions
LICENSE # MIT
README.md
SECURITY.md # Plugin security policy
Hard-won lessons from production use:
- SLSA generator MUST use
@tagnot SHA — the reusable workflow requires tag references for attestation signing - Immutable releases — provenance must be generated BEFORE the GitHub Release (can't upload assets after)
- Tag protection — wrong tag = new version number (tags can't be deleted or updated)
gh pr checks --watchrace — returns immediately if checks haven't started; poll for check existence firstfetch-depth: 0required — publish workflows that verify tag ancestry break with shallow clones- Trusted Publishing configured at crates.io — not in the repo; visit crates.io/crates/NAME/settings
- osv-scanner.toml doesn't propagate — child directories need their own copies
- CodeQL default setup conflicts — disable in repo Settings > Code Security before using a custom workflow
- cargo-audit needs
--locked— prevents MSRV issues from transitive dependency upgrades - cargo-deny v0.19 breaking change — removed
vulnerabilitykey; use"all"or"workspace"for unmaintained/unsound - Workspace publish ordering — inter-dependent crates must publish in dependency order with ~60s delay for index propagation
workflow_dispatchretrigger — usegh workflow run publish.yml -f tag=vX.Y.Zinstead ofgh run rerun(which uses the original workflow file)
MIT
