Skip to content
Supply chain security, in your terminal

Scan your supply chain without shipping your code

Safeguard CLI builds the SBOM, finds the vulnerabilities and license risks in it, and patches them — all on your machine. Only the results ever leave.

curl -fsSL https://cli.safeguard.sh/install | bash
  • checksum-verified
  • macOS · Linux · Windows
  • npm — coming soon
safeguard — tmux

Terminal session. ~/acme/api $ safeguard scan --dir .. building SBOM from source…. ✓ 214 components across 9 ecosystems. matching against the advisory database…. ✓ scan complete — 3 critical · 7 high · 12 medium. ◆ CRITICAL lodash@4.17.11 CVE-2021-23337 → 4.17.21. ▲ HIGH axios@0.21.1 CVE-2021-3749 → 0.21.4. → safeguard fix --severity critical --create-pr. ↳ nothing left this machine — results are in ./output

assistant ready
why is CVE-2021-23337 critical?
lodash < 4.17.21 allows command injection through
the template option. Reachable from utils/render.js.
→ open a fix PR? (y/n)
y
✓ opened PR — fix: bump lodash to 4.17.21

[safeguard]0:scan*1:assistant

◱ the boundary · source halts at the wall
What it does

Everything runs where your code already is

The scan, the graph walk, and the patch all happen locally. The platform only ever sees what you send it.

01

Scan where the code already is

Point it at a directory, a Git repository, a container image, or an existing SBOM. The dependency graph, the vulnerabilities, the secrets and the license risks are all computed on this machine.

safeguard scan --dir .

02

Only the results leave

Your source is never uploaded. The SBOM and the findings are the entire payload the platform receives — and only when you upload them or the runner returns a job.

payload: sbom.json · findings.json

03

Patch, don't just report

safeguard fix updates the vulnerable packages, writes a patched SBOM, and opens the pull request. --dry-run shows you the diff before anything moves.

safeguard fix --create-pr

04

One static binary

No runtime, no daemon, no language toolchain to install first. The same one-line install works on a laptop and inside a CI job.

→ /usr/local/bin/safeguard

Your code never leaves this machine

Safeguard uploads SBOMs and findings — never your source. The scan does not need the internet to do its work, so the same binary behaves identically everywhere you run it:

  • laptop
  • corporate proxy
  • on-prem
  • air-gapped

◌ capture · what enters never leaves

Interactive mode

A terminal that scans, fixes, and answers

Run safeguard on its own and it opens the runner session — the job poller and the assistant, in one prompt.

  • One command, a whole session

    Run safeguard with no arguments and the runner terminal opens. /login authenticates this machine; /help lists the rest.

  • A runner that comes to you

    It claims the scan jobs queued for your tenant, runs them here on your own infrastructure, and posts the results back. Your code stays put; the platform stays current.

  • The assistant, inline

    Ask why a finding matters or what a version bump breaks, and act on the answer without leaving the prompt.

Continuous watch. The runner polls for queued jobs in the background — the platform schedules, this machine executes.

safeguard — runner
safeguard /login
✓ authenticated as dev@acme.com
runner online — polling for scan jobs…
job claimed — repo scan for t_acme
running locally · building SBOM…
✓ results returned to the platform
source never left this machine
zsh
~/acme/api$safeguard runner status
Runner ID: rnr_4f81c2a9 Tenant: t_acme Poll: 30s
Command reference

The commands you'll actually type

The core of the surface. Every command below is in the shipped binary — run safeguard --help for the rest.

Set up

  • safeguard login

    Authenticate this machine over the OAuth 2.0 device flow (RFC 8628). whoami reports the current token, logout clears it.

  • safeguard init

    Write the local scanner configuration for your organization. config show / config set adjust it afterwards.

Scan

  • safeguard scan --dir . | --repo URL | --image REF | --sbom FILE

    Build the SBOM and match it against the advisory database. Takes a local directory, a Git repository, a container image, or an existing SPDX/CycloneDX document.

  • safeguard resolve PURL

    Resolve a package's dependencies and version constraints, including transitive resolution.

  • safeguard validate FILE…

    Validate SBOM documents against the SPDX and CycloneDX specifications before you ship them.

Remediate

  • safeguard fix --severity high

    Update vulnerable packages to safe versions, write a patched SBOM, and emit a fix report. --dry-run previews; --create-pr opens the pull request.

  • safeguard patch-image

    Rebuild a container image with the patched layers applied, rather than re-vendoring the source.

  • safeguard report

    Generate a report from an existing scan result — the artifact you hand an auditor.

Run it for the platform

  • safeguard runner

    Open the on-prem runner. It claims scan jobs queued for your tenant, runs them here, and returns the results. runner status shows the current registration.

  • safeguard update

    Refresh the local vulnerability databases the scanners match against.

In your pipeline

The same binary your laptop runs

No agent to provision, no image to maintain. Install it in the job, scan, and gate on the artifacts it writes.

  • Pin the version

    SAFEGUARD_VERSION pins the release; SAFEGUARD_INSTALL_DIR picks where the binary lands. Neither needs root unless you install to /usr/local/bin.

  • Read the artifacts

    Every run writes the SBOM plus vuln.json, license.json, secret.json and scorecard.json per component — machine-readable, so the gate is whatever policy you write.

  • Or let the runner do it

    For scans the platform schedules, register a runner instead. Same binary, same isolation, and the queue lives on the platform side.

.github/workflows/security.yml
- name: Install the CLI
  run: curl -fsSL https://cli.safeguard.sh/install | SAFEGUARD_VERSION=1.0.0 bash

- name: Scan the working tree
  run: safeguard scan --dir . --output out/

- name: Gate the build
  # vuln.json is grype-compatible under .data.matches
  run: |
    jq -e '[.data.matches[].vulnerability.severity | ascii_downcase]
           | index("critical") | not' out/*/vuln.json

Shown for GitHub Actions; the three steps are shell, so they port to GitLab CI, Jenkins, or anything else that can run a script.

Install

One command, one binary

The installer detects your OS and architecture, verifies the release checksum, and drops a single safeguard binary on your PATH.

curl -fsSL https://cli.safeguard.sh/install | bash
irm https://cli.safeguard.sh/install.ps1 | iex

What the installer does

  1. Detect

    Reads your OS and architecture; anything unsupported stops here, before a single byte downloads.

    uname -s · uname -m → darwin|linux · amd64|arm64
  2. Resolve

    Takes the latest release — or exactly the one you pinned.

    GET /releases/latest.txt → safeguard_1.0.0_linux_amd64.tar.gz
  3. Verify

    Checks the archive against the published checksums. A mismatch aborts before anything runs.

    sha256sum -c checksums.txt
  4. Install

    One binary onto your PATH. No root unless you chose /usr/local/bin.

    install -m 0755 safeguard → /usr/local/bin

Prefer to read it first?

curl -fsSL https://cli.safeguard.sh/install -o install.sh && less install.sh

Ninety-one lines of plain bash — the same file the one-liner pipes. Never pipe anything you would not read.

SAFEGUARD_VERSION
pin a release instead of taking the latest
SAFEGUARD_INSTALL_DIR
choose where the binary lands

Platforms

  • darwin/amd64 ready
  • darwin/arm64 ready
  • linux/amd64 ready
  • linux/arm64 ready
  • windows/amd64 ready
  • npmsoon

Ship clean. Stay clean.

One command to install. Everything after that runs on hardware you control.

curl -fsSL https://cli.safeguard.sh/install | bash