Supply-chain worm hunting for developer machines and CI.
A single compromised dependency is how one package becomes an organisation-wide incident. Self-propagating packages spread through installs, builds and merges — arriving with code you asked for, and running before you ever read it.
saw hunts them where they land: repositories, lockfiles, installed packages, and the
machine's start-up surface. It runs offline, out of the box. It removes what it confirms, opens the
fix as a pull request, hardens the host and gates the merge.
| Detect | saw scan — repositories, lockfiles and installed dependency trees; read-only. saw hook — each clone, pull, switch, rebase and push. saw audit — this machine and a repository's branch protection, ending with a rotation-safety verdict. |
| Remediate | saw fix — clears a confirmed infection from your checkout and prepares the cleanup branch; --pr opens it as a pull request. saw fix amend replaces past commits that still carry the payload. saw discard undoes the branch. |
| Prevent | saw harden — protections on this machine, each checked once it is written. saw guard — the CI gate that blocks an infected merge. |
| Advisories | saw db — the offline advisory corpus for CVE and malicious-package matching. |
Prerequisites: Python 3.11+ — see Your first scan.
pip install stayawakebotOr the latest from source:
pip install "stayawakebot @ git+https://github.com/Ndevu12/stayAwakeBot@main"Then hunt. Each of these stands alone:
Scan every repository under your home folder:
saw scanOr only the folder you are in:
saw scan .Or sweep every repository under a path:
saw scan ~/devScan with your own allowlist, rather than the packaged defaults:
saw scan --config config/security.ymlCheck the machine itself, not a repository — credential hygiene and start-up entries:
saw auditNew here? saw intro is a 60-second tour, and saw search "…" finds the command you want.
The distribution is published as
stayawakebot; the security CLI is the tersesawcommand (see the CLI reference).
saw guard writes the CI gate, keeps it pinned, and proves branch protection requires it.
Every repository you own should refuse an infected merge. saw guard writes that GitHub Actions
workflow, keeps it pinned, and proves it is enforced — for one repository or a whole organisation.
Each command below stands alone; reach for the one you need.
Set it up. Writes the gate here, for you to review and commit:
saw guard setupOr raise it as a pull request:
saw guard setup --prCheck that a repository is actually guarded — present, SHA-pinned, current, and required:
saw guard checkCheck a whole organisation, failing if any repository lacks a required gate:
saw guard check --org your-org -fsaw guard setup surgically pin-bumps a gate that already exists rather than replacing it, and
never clobbers a workflow installed by some other means. saw guard check goes further than "is the
file there" — it verifies branch protection actually requires the check, because a gate that is
not required is decoration.
Both sweep many repositories at once (--remote / --user / --org), like saw scan and
saw fix. See the CLI reference.
A minimal equivalent, if you would rather write it yourself than run saw guard setup. The
installed file is not identical — it also carries a weekly pin-drift job and prefers a
GH_SECURITY_TOKEN secret — so run saw guard setup --dry-run to see exactly what it would write.
Save it as .github/workflows/worm-scan.yml:
name: Worm scan
on:
push:
branches: [main]
pull_request:
permissions:
contents: read
pull-requests: write
security-events: write
jobs:
saw-guard:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1
with:
fetch-depth: 0
- uses: Ndevu12/SAW_GUARD@7d3ef571f0094c223902fcfc500838abc46e1d7b
with:
version: '0.15.0'
pr-comment: true
upload-sarif: trueThe scan only reads: pull-requests: write lets it say what it found on the pull request
(pr-comment), and security-events: write lets it put the findings in the Security tab
(upload-sarif). saw guard setup puts remediation in a second job, so write access exists only on
a run that already found something; see the CLI reference for the shape it installs. fetch-depth: 0
is required, because the scan reads the full history.
Ndevu12/SAW_GUARD ("SAW Guard") is the public Action — a thin wrapper that installs the
published stayawakebot scanner from PyPI.
Pin every action by commit SHA, including this one: a tag can be moved to point at different code
after you have reviewed it, a SHA cannot. Here 7d3ef571… is SAW Guard v0.2.0 and 3d3c42e5… is
actions/checkout v7.0.1. In production pin version: as well: it selects the stayawakebot
release from PyPI, 0.15.0 here, and otherwise tracks whatever is latest at run time.
Other inputs: config-file to supply your own allowlist, fail-on to choose the verdict that fails
the build (default infected), and upload-sarif to send findings to code scanning.
See Harden a repository.
Scan a mounted repository from the published image:
docker run --rm -v "$PWD:/repo:ro" ghcr.io/ndevu12/stayawakebot \
saw scan /repoTo keep the report file too, mount a writable dir and run as your own user so the bind-mount is writable:
docker run --rm --user "$(id -u):$(id -g)" -v "$PWD:/repo" \
ghcr.io/ndevu12/stayawakebot \
saw scan /repo --reports-dir /repo/reportsTags: :latest, :X.Y.Z, :X.Y, and :sha-<commit>. The image runs as a non-root user, is
built from the same wheel published to PyPI, and ships SLSA provenance + SBOM attestations.
stayawakebot additionally ships a health sentinel — a URL/uptime availability monitor
(HTTP status, latency, TLS and keyword checks) run with stayawake-health-check. It is
independent of saw and shares only the packaging. See
Configuration.
stayawake-health-check --config config/urls.ymlsaw-docs.ndevuspace.com — the full documentation, searchable and versioned.
- Documentation index — everything below, in one place
- Your first scan — install, scan, read the verdict, act
- Gate a repository — from unguarded to a required check
- CLI reference — every command and flag, documented once
- Configuration · advisory DB
- Trust model · verdicts · fail closed · safety envelope
- Credential hygiene — what a cached-credential finding means, and how to act on one safely
- Harden a repository — the layered baseline for any repo
- Contributing — development setup and guidelines
- Support — where to ask a question, file a bug, or report a false positive
- Security policy — how to report a security issue privately
- Code of conduct — what taking part here commits you to
stayAwakeBot is dual-licensed:
- AGPL-3.0-or-later — free and open source. You must preserve attribution, and if you modify it and convey it or offer it over a network (e.g. as a hosted service), you must release your corresponding source under the AGPL too.
- Commercial license — a paid, proprietary-use option for closed-source or proprietary-SaaS use without the AGPL's source-disclosure obligations. For terms, contact.