Butler
Butler is a Python CLI/SQLite-backed tool that crawls all repositories in a GitHub organization to inventory workflows, actions, and reusable workflows, flagging unpinned/unpinnable third-party actions, references to archived or deleted repos, invalid runners, and organization/repo secrets & variables usage (including 'secrets: inherit'). It downloads workflow data via a GitHub PAT or GitHub App, processes it into a local database, and generates customizable HTML/CSV reports with SQL-based custom queries, aimed at large-scale GitHub Actions supply-chain and CI/CD hygiene auditing.
What it is
Butler's actual operation: a four-stage CLI pipeline (download → secrets_and_vars → process → report) that populates and then queries a SQLite database. The summary tells you what it finds; this tells you how you run it and what access it needs.
How it works
Each stage is a separate butler.py subcommand against the same --database file:
download— collects workflows/actions. Target is--repoasorg,org/name, ororg/name@branch, or a file of targets. Flags control scope:--all-repos,--include-forks,--include-archived,--all-branches,--all-tags(branch/tag flags only work with a single--repo).secrets_and_vars— optional, separate command requiring extra permissions; pulls org/repo secrets and variables. The page recommends a GitHub App installed in the org for this.process— parses the downloaded data.report— emits CSV/HTML grouped intoactions,hygiene,runners,secrets,workflows.
Preconditions
Needs a GitHub PAT (read from GITHUB_TOKEN by default). It supports rate-limit scaling via multiple tokens (GITHUB_TOKEN_1..N, selected with --token "GITHUB_TOKEN_*") or a GitHub App (--gh-app-key, --gh-app-installation-id, --gh-app-client-id). Secrets/variables inventory requires elevated permissions beyond a basic read token.
What to do
Setup and a full-org run:
python3 -m venv venv
. venv/bin/activate
pip3 install -r requirements.txt
export GITHUB_TOKEN=ghp_...
python butler.py download --repo "microsoft" --all-repos --threads 10 --very-verbose --database microsoft.db
python butler.py process --database ./microsoft.db --threads 10 --very-verbose
python butler.py report --database ./microsoft.db --output ./report --repo "github"Secrets/variables (GitHub App recommended):
python butler.py secrets_and_vars --org "microsoft" --database ./data/microsoft.db --very-verbose --gh-app-key ...Reports are SQL-driven and extensible. Custom queries are v2.0-only YAML files (--custom-query-path), each with name, description, filename, a group (from the five values above), and a sql block. Queries support placeholders :org, $_TRUSTED_ORGS_$, and $_UNSUPPORTED_RUNNERS_$ — so you can define trusted orgs and your own supported-runner allowlist rather than accept the defaults. Column display is configured per result column (hide, link/type). Override the whole report config with --config.
Caveats
secrets_and_vars is opt-in and permission-gated, so a default run inventories workflows/actions only. The linked sample reports (GitHub, OpenAI, Docker, AWS Labs) are noted as not mobile friendly. Only custom-query version 2.0 is supported.
Technologies named here
Techniques named here
- Use of unsupported CI/CD runners
- Use of 'secrets
Related in DevSecOps
JFrog: The Governance Gap Between Your Policy and Your Pipeline

Dev Machine Guard Now Supports Windows - StepSecurity

Socket: TanStack npm Packages Compromised
