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
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-onthreshold (defaulterror; bump towarnfor 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- flagsmacOS-latest(~10x cost) andwindows-latest(~2x) when the steps don't actually need them -
container-no-pin- floatingcontainer.imagetags -
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 aCache@2task -
wide-trigger- unscopedtrigger:orpr: -
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 >= 5withoutmaxParallel
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
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.imagenot pinned to@sha256:... -
missing-cache- install commands with norestore_cache/save_cachepair -
orb-no-pin- orb ref notMAJOR.MINOR.PATCH(e.g.circleci/node@5or@volatile) -
missing-no-output-timeout- hang-pronerun:step (tests, deploys, migrations) withoutno_output_timeout -
secret-echo-env,printenv,set -x,echo $TOKENin arun:block -
wide-filters- workflow job has nofilters:(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
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'
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.ymlfiles 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)