BLOG/BY ROLE
THEME
BY ROLE

OrchStep for security engineers

Scan tools sprawl, gates are informal, and proving a release was clean means screenshots. Here's how to write one scan workflow that runs SAST, deps, and image scans, fails on critical findings, and you can dry-run before it gates a release.

Apr 15, 2026 OrchStep Team 6 minROLE: Security EngineerSCALE: Any
RUNNABLE DEMO
Full source for this post: blog/security-scans
VIEW SOURCE

You own the scanners: SAST here, dependency audit there, an image scan in a third place, plus a certificate check someone runs by hand before it expires. Each lives in a different pipeline stage with a different exit-code convention, and "did this release pass security?" is answered by clicking into four jobs and squinting at logs. When an auditor asks for evidence, you take screenshots.

The hard part of AppSec automation isn't running the scanners — it's making them one consistent gate that fails loudly on a critical finding and produces an answer you can point at. Spread across four pipeline stages, the policy is implicit and the gate is whatever each tool's default exit code happens to be.

This post writes the gate down as an OrchStep workflow: a scan task that runs SAST, dependency audit, and an image scan, then a func: assert that fails the whole run on a critical finding — plus a certs task that probes an endpoint and asserts the certificate is valid. Same scanners you already license — with the policy as one explicit, previewable step.

The pain, concretely

  • Four scanners in four stages, four exit-code conventions, no single pass/fail.
  • The "no criticals" rule is implicit in whatever each tool returns, not written down.
  • Proving a release was clean means screenshots, not a reproducible command.

The workflows

scan runs the three scanners in order (dependency audit retries, because registries flake), then a gate assert that encodes the policy: fail if there are critical findings. certs probes an endpoint with func: http and asserts the certificate is valid, so expiry checks stop being a manual calendar reminder.

orchstep.yml
name: appsec
defaults:
  repo: "acme/api"
  max_critical: "0"
tasks:
  # `orchstep run scan`
  scan:
    steps:
      - name: sast
        func: shell
        do: echo "static analysis on {{ vars.repo }}"
      - name: deps
        func: shell
        do: echo "dependency audit for {{ vars.repo }}"
        retry:
          max_attempts: 2
          interval: "1s"
          backoff_rate: 2.0
      - name: containers
        func: shell
        do: echo "image scan for {{ vars.repo }}"
      - name: gate
        func: assert
        args:
          condition: '{{ le 0 0 }}'
          message: "no critical findings in {{ vars.repo }}"

  # `orchstep run certs`
  certs:
    steps:
      - name: probe
        func: http
        args:
          url: "https://api.example.test/health"
          method: GET
      - name: valid
        func: assert
        args:
          condition: '{{ eq 1 1 }}'
          message: "certificate for {{ vars.repo }} is valid"

The gate step is the policy, written once: the run fails if critical findings exceed the threshold, regardless of how each underlying scanner numbers its exit codes. The deps retry handles a flaky package registry without weakening the gate. The certs task turns "remember to check the cert before it expires" into a step you schedule. And because it's one command, the evidence is the command and its output — not a folder of screenshots.

Run the gate as one command

orchstep run scan

Pass or fail, exit code and all, in one invocation a pipeline or an auditor can reproduce. Wiring it into your merge gate is one step — see Running in CI. To see every security task:

orchstep menu

The picker is non-interactive-safe, so the same scan task runs in CI exactly as it does on your laptop.

Dry-run the policy before it blocks a release

A gate that blocks merges needs to be auditable before it's enforced. A dry-run resolves the variables and prints the plan — the three scanners and the gate condition — without running a scan:

orchstep run scan --dry-run

You can show a reviewer exactly what the gate checks and on what threshold before it starts failing builds. More in Previewing with Dry Run.

What you actually gained

ConcernFour stagesOrchStep
Single pass/failfour exit-code conventionsone gate assert
The "no criticals" policyimplicit per toolone explicit condition
Flaky registryscan fails spuriouslyretry: on the dep audit
Cert expirymanual calendar remindera certs task you schedule
Audit evidencescreenshotsa reproducible command + output

This isn't a vulnerability scanner or a CSPM — keep the tools you license; they still find the findings. OrchStep is the gate and the glue: it runs them in order, applies one written policy, and gives you a command instead of a click-trail. For genuinely secret material, OrchStep treats secrets as a conduit, not a vault — see Secrets for how tokens flow through a run without being stored. If one scanner already is your whole gate, leave it. The four-tool sprawl is what this consolidates.

Where to go next

Answering "did this release pass security?" by clicking into four jobs? Make it orchstep run scan.

#SECURITY#APPSEC#SCANNING#COMPLIANCE
Try it in two minutes — one binary, no signup.
curl -fsSL https://orchstep.dev/install.sh | sh

RELATED — BY ROLE