Workflows
Safeguard's workflow engine — chain discovery, scanning, policy, remediation, and notification steps into repeatable automations.
Workflows
A workflow is a sequence of Safeguard steps triggered by an event. Workflows let you encode "when this happens, do these things" without glue code — for example, "when a new image appears in prod-registry, generate an SBOM, evaluate the production policy, and open a PR if Griffin can auto-fix any findings."
Concepts
A workflow is composed of:
- Trigger — what starts the workflow. Triggers are events, schedules, or manual runs.
- Steps — the actions to execute, in order or in parallel.
- Inputs and outputs — each step reads from the workflow context and can write to it.
- Conditions — step-level
ifexpressions that decide whether a step runs. - Concurrency — limits on how many instances of a workflow run simultaneously.
Workflows are defined in YAML, live in a Git repository (or inside the Safeguard UI), and run on Safeguard's managed runner or a self-hosted runner.
Triggers
| Trigger | Fires on |
|---|---|
on.image.pushed | New image or tag in a connected registry |
on.repo.pushed | New commit or tag on a connected Git repository |
on.sbom.received | SBOM uploaded to Portal or via API |
on.vulnerability.published | New vulnerability affects one of your components |
on.zero_day.published | Safeguard publishes a new zero-day advisory |
on.policy.violation | A guardrail records a BLOCK or WARN |
on.vendor.sbom_updated | TPRM vendor sends a new SBOM |
on.schedule | Cron expression (UTC) |
on.manual | Triggered from the UI, CLI, or API |
Triggers can be combined — a workflow can declare multiple on.* handlers.
Example: Auto-fix critical CVEs on main
apiVersion: safeguard.sh/workflows/v1
kind: Workflow
metadata:
name: auto-fix-critical-on-main
spec:
on:
vulnerability.published:
filters:
severity: ["critical", "high"]
kev: true
repositories: ["org/api", "org/webapp"]
branch: main
concurrency:
group: "auto-fix-${{ workflow.repository }}"
cancelInProgress: true
steps:
- id: scan
uses: safeguard/scan-repository@v2
with:
repository: ${{ trigger.repository }}
ref: ${{ trigger.ref }}
- id: reachability
uses: safeguard/reachability-analyze@v1
with:
sbom: ${{ steps.scan.outputs.sbom }}
vulnerability: ${{ trigger.vulnerability_id }}
if: ${{ steps.scan.outputs.found == true }}
- id: remediate
uses: safeguard/griffin-remediate@v3
with:
vulnerability: ${{ trigger.vulnerability_id }}
repository: ${{ trigger.repository }}
strategy: conservative
if: ${{ steps.reachability.outputs.reachable == true }}
- id: open-pr
uses: safeguard/open-pull-request@v1
with:
repository: ${{ trigger.repository }}
branch: safeguard/auto-fix/${{ trigger.vulnerability_id }}
title: "Auto-fix ${{ trigger.vulnerability_id }}"
body-template: remediation-summary
if: ${{ steps.remediate.outputs.fixed == true }}
- id: notify
uses: safeguard/slack-notify@v1
with:
channel: "#security-ops"
template: remediation-posted
if: ${{ steps.open-pr.outputs.pr_url != '' }}Example: Gate every production admission
apiVersion: safeguard.sh/workflows/v1
kind: Workflow
metadata:
name: prod-admission-gate
spec:
on:
policy.violation:
filters:
policy: prod-admission-policy
decision: BLOCK
steps:
- id: open-ticket
uses: safeguard/jira-create@v2
with:
project: SEC
summary: "Blocked production admission: ${{ trigger.image }}"
severity: ${{ trigger.severity }}
- id: page-oncall
uses: safeguard/pagerduty-trigger@v1
with:
service: prod-admission-failures
if: ${{ trigger.severity == 'critical' }}Example: Weekly SBOM freshness audit
apiVersion: safeguard.sh/workflows/v1
kind: Workflow
metadata:
name: weekly-sbom-freshness
spec:
on:
schedule:
cron: "0 9 * * 1" # Mondays 09:00 UTC
steps:
- id: audit
uses: safeguard/sbom-freshness-audit@v1
with:
max-age-days: 30
environments: ["production"]
- id: email-owners
uses: safeguard/email-owners@v1
with:
assets: ${{ steps.audit.outputs.stale_assets }}
template: sbom-stale-reminder
if: ${{ steps.audit.outputs.stale_count > 0 }}Built-In Step Library
Steps are published as versioned uses: references. Major categories:
| Category | Steps |
|---|---|
| Scanning | scan-repository, scan-image, scan-sbom, scan-model |
| Analysis | reachability-analyze, license-analyze, eagle-classify |
| Remediation | griffin-remediate, open-pull-request, pin-dependency |
| Policy | evaluate-policy, apply-guardrail |
| Notifications | slack-notify, teams-notify, email-owners, pagerduty-trigger |
| Tickets | jira-create, jira-comment, linear-create |
| Export | export-sbom, export-attestation, s3-upload |
| Integration | github-check, gitlab-pipeline-emit, bitbucket-comment |
See the step reference for the full list with inputs/outputs.
Runners
Workflows execute on runners:
- Safeguard Cloud runner (default) — fully managed, runs in the Safeguard FedRAMP-HIGH environment.
- Self-hosted runner — runs inside your VPC / cluster, useful for accessing private networks, air-gapped sites, or regulated data. See Runner for installation.
A workflow can target either with runs-on: cloud (default) or runs-on: self-hosted.
Observability
Every workflow run produces:
- A step-by-step timeline in the Workflows tab.
- Structured logs streamed to the UI and archived for 90 days (Enterprise: configurable up to 7 years).
- OpenTelemetry spans emitted to your configured OTLP endpoint.
- Audit records signed by Safeguard for every external side-effect (PR opened, ticket created, notification sent).
Versioning and Promotion
Workflows are versioned via Git — you can require that all workflow changes go through code review before they land. The Safeguard UI shows a diff between the running version and the proposed version for any change.
Environments (dev, staging, prod) can each pin to different workflow versions for safe rollout.
Related
- Griffin AI — the remediation model workflows invoke.
- Auto-Fix — opinionated auto-fix workflow template.
- Guardrails & Enforcement — policies that generate
policy.violationtriggers. - Runner — self-hosted workflow execution.