Build Your Own Workflow
BYOWBuild Your Own Workflow

Secure SDLC field guide ยท CI/CD automation

Build Your Own Workflow

Hands-on tutorials for building secure delivery pipelines on GitHub Actions, Azure DevOps and GitLab CI/CD. One reference pipeline, three platforms, and every security gate explained with working YAML.

The reference pipeline

Seven stages, four gates

Every platform tutorial builds this same pipeline. A change moves left to right. At each amber gate a failed check stops it, so nothing reaches production without passing the checks before it.

  1. 1 Code developer workstation
    • Pre-commit secret scan
    • Signed commits
    • Lint and format hooks
    Push protection
  2. 2 Pull request untrusted code, no secrets
    • SAST and IaC scan
    • Dependency review (SCA)
    • Pipeline-file lint
    • Code owner review
    Merge gate
  3. 3 Build ephemeral runner
    • Least-privilege token
    • Pinned actions and tasks
    • Lockfile install, no scripts
  4. 4 Verify the built artifact
    • Unit and integration tests
    • Container image scan
    • License policy
    Release gate
  5. 5 Package & attest registry, by digest
    • SBOM (SPDX / CycloneDX)
    • Signature
    • SLSA build provenance
    Approval + verify
  6. 6 Deploy protected environment
    • OIDC to the cloud, no stored keys
    • Deploy the verified digest
    • Serialized, audited
  7. 7 Operate running service
    • DAST against staging
    • Scheduled rescans
    • Dependency alerts, audit logs
Stage: work that runs Gate: a check that blocks on failure

Pick your platform

Three tutorials, same outcome

Each tutorial starts with platform settings you change once, then builds the pipeline file by file. Every third-party action and image is pinned, and every example authenticates to the cloud with OIDC.

GitHub Actions

Rulesets, least-privilege GITHUB_TOKEN, CodeQL, dependency review, Trivy, artifact attestations, and environment-gated deploys to Azure with OIDC.

.github/workflows/ci.yml .github/workflows/release.yml .github/dependabot.yml .github/CODEOWNERS
Open the GitHub Actions tutorial โ†’

Azure DevOps

Organization lockdown, a required extends template, workload identity federation, Advanced Security tasks, Notation signing, and environments with approvals and checks.

azure-pipelines.yml templates/secure-pipeline.yml (separate, protected repo)
Open the Azure DevOps tutorial โ†’

GitLab CI/CD

Protected branches and variables, the job-token allowlist, built-in security templates, security policies, Sigstore keyless signing with id_tokens, and protected environments.

.gitlab-ci.yml .gitlab/security-policies/policy.yml (security policy project)
Open the GitLab CI/CD tutorial โ†’

Principles

Six rules that hold on every platform

The platforms name things differently, but a secure pipeline makes the same six decisions everywhere. The tutorials show how each one is done.

Treat the pipeline as production

A pipeline holds deploy rights to production. Protect its definition files with code owners, review changes to them like application code, and log who changed what.

No long-lived cloud secrets

Use OIDC workload identity federation. The job receives a short-lived token scoped to one repository, branch or environment, and nothing is left behind to leak.

Least privilege by default

Start every job's token at read-only or no access and grant only what that job needs. Scope service connections and runners to the projects that use them.

Pin everything you execute

Reference actions by full commit SHA, templates by tag or SHA, and container images by digest. Let Dependabot or Renovate propose updates so pinning stays current.

Untrusted code never meets secrets

Code from a pull request, especially from a fork, runs without secrets and without write tokens. Jobs that hold secrets only run on reviewed, protected branches.

Gates fail closed

A gate that cannot run counts as a failure. Exceptions are explicit, owned, and expire, so a dismissed finding comes back for review instead of disappearing.

Why the rules exist

Pipeline incidents that shaped them

Each of these attacks went through the build system rather than the application. Each one maps to a rule above.

  1. SolarWinds Orion build compromise

    Attackers planted an implant on the build servers that swapped source files during compilation. The resulting updates were signed and shipped through the normal channel to thousands of customers.

    RuleTreat the pipeline as production. Isolate build machines and record provenance from a hardened builder.

  2. Codecov Bash Uploader

    A modified copy of a script that many pipelines downloaded and piped to bash sent the CI environment, including credentials, to an attacker for about two months before discovery.

    RulePin everything you execute and verify checksums. Keep secrets out of jobs that do not need them.

  3. tj-actions/changed-files (CVE-2025-30066)

    The action's version tags were moved to a malicious commit that printed runner secrets into build logs. Workflows that referenced a tag ran it automatically; workflows pinned to a commit SHA did not.

    RulePin to full commit SHAs and restrict which actions an organization allows.

  4. Trivy and trivy-action (CVE-2026-33634)

    With stolen credentials, attackers force-pushed 76 of 77 trivy-action tags and all setup-trivy tags, and published a malicious Trivy v0.69.4. A credential stealer ran before the real scan, so jobs still looked normal.

    RuleSecurity tools are dependencies too. Pin them, enforce pinning by policy, and use short-lived credentials so a stolen token expires quickly.