ci-cd-architect — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited ci-cd-architect (Agent Skill) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
Framework-agnostic CI/CD principles. The body presents trade-offs and common defaults; concrete pipelines live in RECIPES.md (GitHub Actions). See STACK.md for pinned action/tool versions used in the recipes.
This skill is suggestion-mode: most CI/CD decisions depend on team size, deployment target, risk tolerance, and existing infra. Each section names the choice, the trade-off, and a common default — not a mandate. Override locally with an ADR when a decision diverges from the suggestion.
Image-level rules (Dockerfile, multi-arch, scanning) live in docker-architect; this skill covers only the workflow shape around them.
Most projects need four pipeline shapes. Keeping them in separate workflow files is the common default — it makes "what triggers what" obvious and lets each evolve independently.
Trade-off: one mega-workflow is simpler at first but couples "what was built" to "where it ran" — rolling back gets harder. Splitting them lets you redeploy yesterday's image without re-running CI. Reach for the split once the project ships to more than one environment.
cron at non-peak times.concurrency: group. For PRs, cancel-in-progress (don't waste CI on stale commits); for main/release, queue (don't race deploys).GitHub Actions concurrency + path-filter examples in RECIPES.md §2.
DRY without overcomplicating. Three composition levels, in order of cost:
workflow_call) — share a multi-job pipeline across repos. Reach for this when ≥3 repos need the same shape.Trade-off: premature abstraction makes the pipeline harder to read and debug. Factor out at the third copy, not the second. Reusable workflows in particular have non-trivial debugging overhead — stay inline until the duplication is clearly painful.
CI runners can produce anything that gets deployed — they are high-value targets. Defaults that meaningfully reduce risk:
actions/checkout@<sha> with a # v5.0.0 comment for humans. Renovate auto-bumps SHAs while preserving the comment.actions/*, docker/*) — pinning by major tag (@v5) is a common compromise; SHA-pin if your threat model warrants it.contents: read). Elevate per-job as needed (packages: write, id-token: write). The default GITHUB_TOKEN grant is too broad in most repos.SHA-pinning + Renovate config snippet in RECIPES.md §4.
AWS_ACCESS_KEY_ID lives in repo secrets.environments: with required reviewers — not to the repo.${{ secrets.X }} as opaque.contents:read; one that fetches private @scope/* npm packages needs read:packages. With fine-grained tokens that means two, passed as distinct build secrets (--secret id=github_token,env=GH_PRIVATE_MODULES_TOKEN, --secret id=packages_token,env=NODE_AUTH_TOKEN); a classic token carrying repo + read:packages covers both scopes in one — simpler to wire into every job, at the cost of read/write on every repo the owner can reach. Either way the runner's GITHUB_TOKEN grants neither for other repos, so a secret is unavoidable. Confirm a token's scopes with curl -sI -H "Authorization: Bearer $TOKEN" https://api.github.com/rate_limit | grep -i x-oauth-scopes.OIDC trust-policy snippets (AWS + GCP) in RECIPES.md §5.
Cache what's expensive to fetch and safe to reuse:
setup-* actions have built-in cache flags (actions/setup-go with cache: true, actions/setup-python with cache: 'pip' or 'uv'). Prefer those over hand-rolled actions/cache blocks.docker/build-push-action with cache-from: type=gha + cache-to: type=gha,mode=max is the GitHub-native option. A registry cache (type=registry,ref=<image>:cache) survives across runners and is the better default for prod images.mise-action, aqua, asdf) caches the tool binaries it downloads — not the language's package store — so pnpm/npm still re-download every dependency each run. Use the language setup action's cache (actions/setup-node cache: pnpm, actions/setup-go's default) or an explicit actions/cache on the store path.go.sum, package-lock.json), and a workflow-level defaults.run.working-directory does not apply to uses: steps — so a module under backend/ is silently left uncached. Symptom: Primary key was not generated in the log, and the dependency downloads reappear every run.Cache restored from key: and watch the download count (go: downloading …) drop; a cache that never restores is worse than none, because it hides the cost in the setup action's own overhead.Per-language caching examples in RECIPES.md §6.
Fan out only when the dimension genuinely matters:
true saves CI minutes when any failure is a blocker.Trade-off: every matrix cell costs runner time + log volume. A 3×3×2 matrix is 18 jobs — each dimension should justify itself or come out.
skip with a tracking issue), don't normalize retry. Retry-as-default trains the team to ignore real flakiness.This skill covers the workflow shape, not the Dockerfile — see docker-architect for image rules.
docker/setup-qemu-action + docker/setup-buildx-action + docker/build-push-action with platforms: linux/amd64,linux/arm64.:<short-sha>, :<semver>, :latest) in one action. Parallel rebuilds for tags are an antipattern.docker/build-push-action attestations (provenance: true, sbom: true).Full build + push workflow in RECIPES.md §9.
release-please (GitHub-native, manifest-driven), semantic-release (Node ecosystem), git-cliff (Rust-based, language-agnostic). Pick one and own it; switching costs are low.on: push: tags: 'v*' triggers the build-and-publish workflow. Decoupling "version bump merged" from "artifact published" makes a failed release retryable.v1.2.0-rc.1) get pushed to a separate channel (npm next, container :rc, Go pseudo-versions).release-please workflow + manifest in RECIPES.md §10.
Pick by blast radius, not by fashion:
environments: with required reviewers on prod. Cheap, high-signal, no infra needed; pairs with any of the above.Whatever the strategy, the deploy workflow must be idempotent and re-runnable. A failed deploy mid-flight should be safe to retry without manual cleanup.
GitHub-hosted runners are billed per minute. A solo repo can opt out by running the same workflow locally with act, leaving the hosted workflow workflow_dispatch-only so a push never starts a runner. That trades an enforced gate on push for no bill — a fine trade for a personal repo, not for a team.
act runs the real .github/workflows/*.yml; don't fork a local-only pipeline or the two drift.~/.cache/act; `--pull=false` stops re-pulling the runner image every run.--cache-server-path, default ~/.cache/actcache), so actions/cache-based steps (setup-go, setup-node) persist between runs — verify they actually restore, per §6.archive/tar: write too long). Serialize (--concurrent-jobs 1) only until the action cache is warm, then let jobs run in parallel again — a permanent --concurrent-jobs 1 throws away the whole fan-out.--env-file /dev/null so the local .env does not leak into job containers and change test behaviour.Recipe: RECIPES.md §12.
kubernetes-architect (planned).iac-architect (planned).go-architect, python-architect).security-reviewer interprets the findings.~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.