DEV Community

depmedicdev-byte
depmedicdev-byte

Posted on • Originally published at depmedicdev-byte.github.io

I shipped 4 things this week: a GitHub Action, an Azure Pipelines auditor, a CircleCI auditor, and a comparison page nobody asked for

Week 2 of depmedic. Four shipments, all free, all MIT.

1. ci-doctor-action - the easiest way to put ci-doctor on a PR

Until now you'd have to write a workflow that ran npx ci-doctor, piped output to tee, then either uploaded SARIF or posted a comment. That's three steps, and most people never got past step one.

ci-doctor-action is a composite Action that does it all in three lines:

name: ci-doctor
on:
  pull_request:
    paths:
      - '.github/workflows/**'
permissions:
  contents: read
  pull-requests: write
  security-events: write
jobs:
  audit:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: depmedicdev-byte/ci-doctor-action@v1
Enter fullscreen mode Exit fullscreen mode

You get:

  • a sticky markdown PR comment with the findings table (one per PR, updated in place when you push fixes)
  • SARIF uploaded to GitHub Code Scanning so findings show under the Security tab
  • a configurable fail-on threshold (default error; bump to warn for stricter teams)
  • pinnable down to a SHA for fully reproducible audits

v1 mutable tag is already pushed at the same commit so consumers can use @v1. Pinning the action AND its CLI is the gold-standard pattern - more on that below.

2. azure-pipelines-ci-doctor - the fourth sister CLI

The depmedic family now covers GitHub Actions, GitLab CI, Bitbucket Pipelines, and Azure Pipelines.

azure-pipelines-ci-doctor ships with eight rules tuned to the quirks of Azure DevOps:

  • expensive-vm-image - flags macOS-latest (~10x cost) and windows-latest (~2x) when the steps don't actually need them
  • container-no-pin - floating container.image tags
  • missing-timeout-in-minutes - default is 60 min hosted, 360 min self-hosted; one hang can burn the whole window
  • missing-cache - npm/pip/maven/gradle/cargo/go/bundler installs without a Cache@2 task
  • wide-trigger - unscoped trigger: or pr:
  • inline-secret-leak - $(SECRET_NAME) macros that expand inline in build logs (the #1 Azure secret-handling mistake)
  • legacy-task-version - outdated built-in task majors (e.g. UseNode@1)
  • unbounded-parallelism - strategy.parallel >= 5 without maxParallel
npx azure-pipelines-ci-doctor              # audit current repo
npx azure-pipelines-ci-doctor --markdown   # PR-comment friendly
npx azure-pipelines-ci-doctor --rules      # list all 8
Enter fullscreen mode Exit fullscreen mode

In-browser scanner at /scan-azure.html alongside the GitHub, GitLab, and Bitbucket equivalents.

3. circleci-ci-doctor - the fifth sister CLI

I promised this was "drafting now" in last week's newsletter, so I shipped it the same day. circleci-ci-doctor is 8 rules over .circleci/config.yml:

  • expensive-resource-class - xlarge / 2xlarge / 3xlarge without heavy build commands (each tier roughly doubles credits/min)
  • macos-executor - macos: executor without xcodebuild/swift/fastlane (~10x Linux Docker cost)
  • docker-no-pin - docker.image not pinned to @sha256:...
  • missing-cache - install commands with no restore_cache/save_cache pair
  • orb-no-pin - orb ref not MAJOR.MINOR.PATCH (e.g. circleci/node@5 or @volatile)
  • missing-no-output-timeout - hang-prone run: step (tests, deploys, migrations) without no_output_timeout
  • secret-echo - env, printenv, set -x, echo $TOKEN in a run: block
  • wide-filters - workflow job has no filters: (runs on every branch)

Browser scanner at /scan-circleci.html.

4. ci-doctor vs zizmor - an honest comparison nobody asked for

zizmor is great. It's a Rust-based static analyzer focused on supply-chain and template-injection security audits. People keep asking which to use.

The honest answer is: run both.

Concern zizmor ci-doctor
Pin uses: to SHAs yes yes
Template injection from user input deep basic
pull_request_target + checkout yes (sub-rule precise) yes
Container image not pinned to digest no yes
Self-hosted runner label spoofing yes no
Cache poisoning vectors yes no
Service container missing healthcheck no yes
Missing concurrency: (cost) no yes
Missing timeout-minutes: (cost+reliability) no yes
Missing language/dep cache (cost) no yes
Expensive runner (cost) no yes
Auto-fix mode no yes (--fix)
SARIF output yes yes
Other CIs (GitLab, Bitbucket, Azure, CircleCI) no yes

Side-by-side workflow:

name: ci-audit
on: pull_request
permissions:
  contents: read
  security-events: write
jobs:
  zizmor:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-python@v5
        with: { python-version: '3.12' }
      - run: pip install zizmor
      - run: zizmor --format sarif . > zizmor.sarif
      - uses: github/codeql-action/upload-sarif@v3
        with: { sarif_file: zizmor.sarif, category: zizmor }
  ci-doctor:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: depmedicdev-byte/ci-doctor-action@v1
Enter fullscreen mode Exit fullscreen mode

Full comparison: /compare/ci-doctor-vs-zizmor.html.

Pattern of the week: pin the action AND its CLI

If you adopt ci-doctor-action for production gating, pin both:

- uses: depmedicdev-byte/ci-doctor-action@1bd71901bbe5b1630ceea73d27597364c9af683 # v1.0.0
  with:
    ci-doctor-version: '0.5.0'
Enter fullscreen mode Exit fullscreen mode

That way an upstream npm publish can't change what your gate flags or silently bump severity. Reproducible audits are the only audits worth gating on.

What's next

  • The CircleCI Pin Bar - same methodology as the GitHub Actions one (59% pinned to SHA), applied to the top 30 OSS repos that publish their .circleci/config.yml.
  • An end-to-end scan of .circleci/config.yml files across the 100-repo leaderboard.
  • A "how much will my repo cost on each CI?" tool that takes a single set of workflows and prices them on GHA, GitLab, Bitbucket, Azure, and CircleCI side by side.

Subscribe at /newsletter.html if you want issue #3 in your inbox Sunday.

Top comments (0)