Skip to content
Back to skills

Ci Cd Pipeline

BSecurity

Use when setting up CI for a new project, refactoring existing pipelines, migrating between platforms, or standardising deployment workflows. Triggers on "set up CI/CD", "GitHub Actions", "GitLab CI", "pipeline for this repo", "deployment workflow", or "why is CI slow".

  • 2 stars
  • 0 votes
  • 0 copies
  • 2 views
  • Added September 5, 2026
ai-agentsrustgonoderefactoringgitdevopsci/cd

Security analysis

B84/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned September 29, 2026

npx -y skills add tmj-90/gaffer --skill ci-cd-pipeline --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Ci Cd Pipeline?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Ci Cd Pipeline
[![Security: B — Skills Directory](https://www.skillsdirectory.com/api/skills/tmj-90-ci-cd-pipeline/badge)](https://www.skillsdirectory.com/skills/tmj-90-ci-cd-pipeline)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: ci-cd-pipeline
description: Use when setting up CI for a new project, refactoring existing pipelines, migrating between platforms, or standardising deployment workflows. Triggers on "set up CI/CD", "GitHub Actions", "GitLab CI", "pipeline for this repo", "deployment workflow", or "why is CI slow".
stack: []
area: devops
---

# Build pragmatic CI/CD pipelines

A pipeline runs the repo's own commands, fast, with the least privilege that works, and
deploys one immutable artifact through environments. It runs untrusted code (every pull
request), so it is also an attack surface: follow GitHub's "Secure use" guidance for
Actions and SLSA for build provenance. For a red pipeline, use `debug-failing-ci` instead.

## Procedure

1. **Detect the real commands.** Read `package.json` scripts, `Makefile`, `pyproject.toml`,
   `go.mod`, `Cargo.toml`, `pom.xml`/`build.gradle`, the lockfile, and any existing
   workflow. Extract the exact lint, typecheck, test and build commands; `search_lore` for
   CI conventions. Never invent a command; if a stage has no command, omit the stage.
2. **Order the workflow's stages cheap-to-expensive** (you write these; you never run
   the install yourself): install (lockfile-exact: `npm ci`,
   `pnpm install --frozen-lockfile`, `pip install -r` with hashes, `go mod download`) →
   lint/typecheck → unit tests → integration tests → build → scan → deploy. Fail fast;
   parallelise independent jobs.
3. **Make tests gate.** No `continue-on-error: true`, no `|| true`, no skipped suites on the
   test job. Run the integration and concurrency tests the repo has — a green pipeline that
   skips them is how concurrent-writer data loss shipped twice in live runs.
4. **Harden the workflow (GitHub Actions):**
   - Top-level `permissions: contents: read`; grant more per job only where needed
     (`packages: write` to publish, `id-token: write` only on the deploy job).
   - Pin every third-party action to a full-length commit SHA with the tag as a comment:
     `uses: actions/checkout@<40-char-sha> # v4.2.2`. Add a Dependabot entry for
     `package-ecosystem: github-actions` so pins get updated.
   - Never interpolate untrusted context into `run:` — `github.event.pull_request.title`,
     `.body`, `github.head_ref`, issue/comment bodies, commit messages. Pass via `env:` and
     quote: `env: TITLE: ${{ github.event.pull_request.title }}` then `"$TITLE"`.
   - Use `pull_request`, not `pull_request_target`, for building PR code. Never check out
     PR head code in a `pull_request_target` or `workflow_run` job.
   - `actions/checkout` with `persist-credentials: false` unless the job must push.
   - Cloud access via OIDC federation, not long-lived keys; restrict the cloud trust policy
     to the repo and the protected environment (`sub` claim).
   - Secrets only from the secret store, one secret per value (no JSON blobs — redaction
     fails); register derived secrets with `::add-mask::`.
5. **Serialise deploys.** `concurrency: { group: deploy-<env>, cancel-in-progress: false }`
   on deploy jobs so two runs never deploy the same environment at once; use
   `cancel-in-progress: true` only for PR validation. Production deploys use a protected
   `environment:` with required reviewers. Set `timeout-minutes` on every job.
6. **Build once, promote the digest.** Build the artifact/image once, tag it by commit SHA,
   deploy that exact digest to staging and then production. For release artifacts, emit
   signed build provenance (e.g. `actions/attest-build-provenance`) — on hosted runners
   this reaches SLSA Build L2.
7. **Cache by lockfile hash** (`actions/setup-node` `cache:`, or `actions/cache` keyed on
   `hashFiles('**/pnpm-lock.yaml')`). A cold cache must still produce a correct build.
8. **GitLab CI equivalents:** `rules:` instead of `only/except`; `resource_group` to
   serialise deploys; `id_tokens:` for OIDC; protected, masked variables; images pinned by
   digest; `interruptible: true` only on validation jobs.
9. **Verify and evidence** (below) with the `record-evidence` skill, then stop. You cannot
   push or trigger CI, so the workflow first runs only after the branch leaves the
   factory (the runner pushes and opens a PR only when PR creation is enabled). Say so in
   the evidence rather than claiming a green run.

## Verification

- `actionlint` (GitHub) or `gitlab-ci-lint`/`glab ci lint` if already installed; otherwise
  parse the YAML with an available parser and record that the linter was not run. Do not
  install tools.
- Run every lint, typecheck, test and build command the workflow runs, locally, in the
  same order (skip install and deploy steps — no dependency installs); record the output.
- Grep checks: `grep -nE 'uses: +[^./][^@]*@' .github/workflows/* | grep -vE '@[0-9a-f]{40}'`
  returns nothing (every remote action pinned to a SHA); `grep -n '\${{ *github.event' .github/workflows/*`
  shows no hits inside `run:` blocks; every workflow has a `permissions:` block.

## Review checklist (concrete defects only)

- A stage runs a command that does not exist in the repo, or the test job can pass while
  tests fail.
- Missing top-level `permissions:` or a write scope not needed by that job.
- Third-party action pinned to a tag/branch; untrusted context inside `run:`.
- `pull_request_target`/`workflow_run` job that checks out or executes PR code.
- Long-lived cloud keys where OIDC is available; secrets echoed or stored as structured
  blobs.
- Deploy job without a concurrency group, or production deploy without a protected
  environment.

## Capture lore

Pipeline structure, deploy targets, required checks and environment promotion policy are
high-value lore: call `suggest_lore` with `tags: [ci-cd, pipeline, deploy]`.

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.