A small, opinionated kit for making "scan your dependencies for vulnerabilities" the default, not a thing you remember to do.
Vulnerability scanning fails the same way ergonomics fails: it's fine when you remember, and forgotten the one time it matters. The fix is to push the work into places that fire automatically — git hooks, repo templates, GitHub's own defaults — so a missed scan requires removing something, not failing to add it.
This repo bundles four layers, each catching what the previous one misses:
| Layer | Catches | Effort |
|---|---|---|
| 1. Global git pre-commit hook | New vulns in lockfiles before they land | install once |
| 2. Repo template | New repos start with Dependabot + CI scanner | one-time setup, then --template |
| 3. GitHub account/org defaults | Drift on existing repos | toggle in settings |
| 4. Periodic audit script | Repos that slipped past everything | cron |
git-template/hooks/pre-commit # runs osv-scanner on staged lockfiles
repo-template/ # files to drop into new repos
.github/dependabot.yml # weekly updates, grouped
.github/workflows/osv-scanner.yml # CI scan + SARIF upload
.pre-commit-config.yaml # optional: pre-commit.com framework
scripts/
install-git-template.sh # installs the global hook
audit-repos.sh # finds repos missing recommended files
configure-org.sh # enable Dependabot defaults on a GitHub org
build-dist.sh # materialize per-owner dist/ trees
publish.sh # push dist/<owner>/* to GitHub
The highest-ROI piece. Once installed, every git init and git clone you do inherits a pre-commit hook that runs osv-scanner on staged lockfiles. No per-repo opt-in.
brew install osv-scanner
osv-scanner --version # v2.x expected; hooks call: osv-scanner scan -L <lockfile>
./scripts/install-git-template.shExisting repos won't pick it up automatically — but cd existing-repo && git init re-runs init and copies the hook in (safe, non-destructive).
The hook also warns — without blocking — when staged files dodge scan coverage:
- a manifest (
package.json,pyproject.toml,Cargo.toml,Gemfile,go.mod,composer.json) staged without its lockfile, which leaves osv-scanner nothing to scan - floating version specifiers:
"latest"/"*"inpackage.json/composer.json, or a:latestbase image in a Dockerfile
Bypass when you need to:
SKIP_OSV=1 git commit ... # skip just the osv hook
git commit --no-verify ... # skip all hooksPush repo-template/ to GitHub as a template repo (Settings → "Template repository" toggle). Then:
gh repo create my-new-thing --template <you>/repo-template --private --cloneAlias it in your shell:
mkrepo() { gh repo create "$1" --template <you>/repo-template --private --clone; }What you get out of the box:
- Dependabot — weekly grouped updates for npm, pip, Docker, GitHub Actions
- OSV-Scanner workflow — runs on PR + weekly cron, uploads SARIF to GitHub Security tab
- Optional pre-commit config — for teams that use the framework
These cover repos you didn't create from a template (cloned, forked, etc.).
Personal account — github.com/settings/security_analysis:
- Enable "Dependabot alerts" → default for new repos
- Enable "Dependabot security updates" → default for new repos
- Enable "Secret scanning" → default for new repos
Org — same toggles at org level, plus consider a repository ruleset that requires OSV-Scanner / scan as a passing check before merge.
Automate the org toggles with the bundled script:
./scripts/configure-org.sh liwala # defaults for new repos
./scripts/configure-org.sh liwala --backfill # also enable on existing repos
./scripts/configure-org.sh liwala --backfill --dry-run # preview onlyErrors clearly if you point it at a user account — personal accounts use the github.com settings page above.
Catches drift on existing repos that don't have the files yet:
./scripts/audit-repos.sh # your repos
./scripts/audit-repos.sh some-org # an org's repos
./scripts/audit-repos.sh some-org --deep # also flag dependency-hygiene gapsDefault mode checks each repo for dependabot.yml and the OSV-Scanner workflow. --deep additionally mirrors the pre-commit hook's checks across the repo — flagging a manifest committed without its lockfile, and floating version specifiers ("latest"/"*" in package.json/composer.json, a :latest Docker base image). It's opt-in because it fetches each repo's tree plus the content of every manifest it finds.
Throw it in a weekly cron / scheduled GitHub Action and pipe the output to wherever you read things.
This repo is the source of truth. Two GitHub repos are derived from it per owner:
<owner>/autoscan-kit (this content) and <owner>/repo-template (just the template content, marked as a GitHub template repository).
# Build dist directories for any number of owners
./scripts/build-dist.sh liwala luisalima
# Inspect
ls dist/
# Publish (defaults to --public; pass --private to override)
./scripts/publish.sh liwala
./scripts/publish.sh luisalima --privatedist/ is gitignored; rebuild whenever the source changes and re-run publish to push updates manually. Rebuilds preserve each derived repo's .git directory, and publish creates missing GitHub repos or pushes a new commit when they already exist.
- The pre-commit hook only scans lockfiles you stage. A vulnerable transitive that's already committed won't get flagged until the lockfile changes. Layer 2's CI workflow catches this.
osv-scannerfirst run downloads the OSV database. Subsequent runs are fast (~seconds).- The reusable workflow is pinned to
@mainin the template — pin to a SHA in production for stricter supply-chain hygiene. - Dependabot's
uvecosystem support is limited at time of writing; we usepip(coversrequirements.txt+pyproject.toml). Revisit when uv lockfile support lands. - No tool catches everything. OSV-DB is broad but lags GitHub Advisory in some ecosystems. Trivy is a heavier alternative if you want filesystem + container + IaC in one tool.
- Trivy — broader scope (containers, IaC, secrets), heavier setup. Good complement, not a replacement for the pre-commit hook.
- Snyk / Mend / Socket — commercial; better UX, license cost, vendor lock-in on advisory data.
pre-commitframework — works fine; we ship a config for it, but the git-template approach needs zero per-repo opt-in.