CI/CD compliance scanner for GitLab CI and GitHub Actions
One CLI, one .plumber.yaml, one Rego policy engine.
Website • Docs • Discord • Issues
Plumber scans CI/CD pipelines for risky patterns and compliance gaps.
- GitLab CI: reads
.gitlab-ci.yml, resolved includes, and repository settings. - GitHub Actions: reads
.github/workflows/*.{yml,yaml}locally or through the GitHub API. - One config:
.plumber.yamlcontains provider-specific policy sections for GitLab and GitHub.
Plumber reports findings in the terminal, JSON, SARIF, GitLab SAST, PBOM, and CycloneDX formats.
Run your first scan before reading the full docs.
brew tap getplumber/plumber
brew install plumber
plumber config generate # generates default configuration yaml file
plumber analyzeSee the generated default config in this repo: .plumber.yaml.
Plumber auto-detects the provider from your git remote. Use explicit flags when scanning a repo that is not the current checkout.
| I want to... | Use this | Start here |
|---|---|---|
| Try Plumber locally | CLI | plumber analyze |
| Add checks to GitLab CI | GitLab CI Component | GitLab CI Component |
| Add checks to GitHub Actions | GitHub Action | GitHub Action |
| Audit many repos from a script | CLI + JSON/SARIF | Outputs |
| Tune policy rules | .plumber.yaml |
Configuration |
brew tap getplumber/plumber
brew install plumberOther options:
mise use -g github:getplumber/plumber- Download a binary from GitHub Releases
- Run the Docker image:
getplumber/plumber
Full install docs:
- GitLab: getplumber.io/docs/cli/gitlab#installation
- GitHub: getplumber.io/docs/cli/github#installation
GitLab:
export GITLAB_TOKEN=glpat_xxxxGitHub (preferred — uses the gh CLI's keyring):
gh auth loginAlternative (CI runners, automation):
export GH_TOKEN=ghp_xxxxGitHub local scans can run without a token for workflow-content checks. A token enables repo-level and action-metadata checks.
Current repo:
plumber analyzeSpecific GitLab project:
plumber analyze \
--provider gitlab \
--gitlab-url https://gitlab.com \
--project group/projectSpecific GitHub repo without a local clone:
plumber analyze \
--provider github \
--github-url github.com \
--project owner/repoAdd Plumber to .gitlab-ci.yml:
include:
- component: gitlab.com/getplumber/plumber/plumber@<version>Find the latest published version on the GitLab CI/CD Catalog.
Then add GITLAB_TOKEN in Settings -> CI/CD -> Variables.
Use read_api + read_repository for scanning. Use api if you want Plumber to create MR comments or badges.
Full guide: getplumber.io/docs/cli/gitlab#gitlab-ci-component
Add Plumber to .github/workflows/plumber.yml:
name: Plumber
on:
pull_request:
push:
branches: [main]
permissions:
contents: read
security-events: write
jobs:
plumber:
runs-on: ubuntu-24.04
steps:
- uses: actions/checkout@v6
- uses: getplumber/plumber@a7fa2feca21bd02c21c2e45d87e352b5ff7e7f28 # v0.3.43Full guide (SARIF upload, Code Scanning, action inputs): getplumber.io/docs/cli/github#github-action
Plumber reads .plumber.yaml.
Create a config interactively:
plumber config initGenerate the full commented default template:
plumber config generateExample:
version: "2.0"
gitlab:
controls:
containerImageMustNotUseForbiddenTags:
enabled: true
github:
controls:
actionsMustBePinnedByCommitSha:
enabled: true
trustedOwners:
- actions
- githubUseful commands:
plumber config validate
plumber config view
plumber config diff
plumber explain ISSUE-411Full config reference:
- Default config:
.plumber.yaml - CLI docs: getplumber.io/docs/cli
- Issue reference: getplumber.io/docs/cli/issues
Plumber ships controls for:
- container image pinning and authorized sources
- branch protection
- unverified script execution (
curl | bash,base64 -d | bash, etc.) - Docker-in-Docker
- weakened security jobs
- unsafe variable expansion
- GitHub action pinning, archived actions, and known CVEs
- dangerous GitHub triggers and overbroad permissions
- hardcoded secrets in pipeline YAML (opt-in; shells out to gitleaks)
Full catalogs:
- GitLab controls: getplumber.io/docs/cli/gitlab#available-controls
- GitHub controls: getplumber.io/docs/cli/github#available-controls
| Output | Flag | Use it for |
|---|---|---|
| Terminal | default | Human review during local or CI runs |
| JSON | --output results.json |
Automation and dashboards |
| SARIF | --sarif results.sarif |
GitHub Code Scanning and SARIF-compatible tools |
| GitLab SAST | --glsast gl-sast-report.json |
GitLab Security Dashboard / MR widget |
| PBOM | --pbom pbom.json |
Pipeline inventory |
| CycloneDX | --pbom-cyclonedx cdx.json |
SBOM tooling |
Example:
plumber analyze \
--output results.json \
--sarif results.sarif \
--pbom pbom.json \
--pbom-cyclonedx cdx.jsonMore details:
- PBOM docs:
docs/PBOM.md - Scoring docs:
docs/scoring.md - CLI reference: getplumber.io/docs/cli
| Code | Meaning |
|---|---|
0 |
Compliance is greater than or equal to --threshold |
1 |
Compliance is below --threshold |
2 |
Invalid usage or configuration |
3 |
Runtime, provider, auth, or network failure |
If you run a self-hosted GitLab instance, host or mirror the Plumber component inside your instance, publish a release, and include that component URL from your pipelines.
Guide: getplumber.io/docs/cli/gitlab#hosting-on-self-hosted-gitlab
| Problem | What to check |
|---|---|
GITLAB_TOKEN environment variable is required |
Export GITLAB_TOKEN or add it as a CI/CD variable |
| GitHub upstream scan refuses to start | Set GH_TOKEN, GITHUB_TOKEN, or run gh auth login |
| No GitHub repo-level findings | Local GitHub scans soft-degrade without token/API scope |
| Config warnings | Run plumber config validate |
| Need to inspect a finding | Run plumber explain ISSUE-XXX |
More help:
- GitLab guide: getplumber.io/docs/cli/gitlab
- GitHub guide: getplumber.io/docs/cli/github
- Discord: discord.gg/932xkSU24f
Build locally:
make buildRun tests:
make testContributing guide: CONTRIBUTING.md
- Website: getplumber.io
- Documentation: getplumber.io/docs/cli
- GitHub Action listing: Plumber Compliance Scanner
- GitLab component docs:
COMPONENT_README.md - Security policy:
SECURITY.md
Plumber is licensed under the Mozilla Public License 2.0.

