Configuration file
The common CLI flags can be set in a config file so CI invocations
stay short and repo policy lives alongside the code. Both TOML
(inside pyproject.toml) and YAML (.pipeline-check.yml) are
supported. The supported keys are the allowlist _TOPLEVEL_KEYS /
_GATE_KEYS in pipeline_check/core/config.py, which is the source of
truth: every provider path flag (gha_path, gitlab_path, npm_path,
…) plus min_confidence, custom_rules, rego_rules, detect_entropy,
and resolve_remote are all config-settable. The examples below show a
representative subset; the run-mode flags (--fix, --ingest,
--verify-secrets, the --chains-require-* gates, …) stay CLI-only.
Precedence
Highest wins, matches every standard tool (ruff, mypy, pytest):
- CLI flags:
--pipeline aws --fail-on HIGH - Environment variables:
PIPELINE_CHECK_PIPELINE=aws,PIPELINE_CHECK_GATE_FAIL_ON=HIGH - Config file:
.pipeline-check.ymlor[tool.pipeline_check]inpyproject.toml - Policy (
--policy NAME): see Named scan profiles below - Built-in defaults
File discovery
Without --config, the first file that exists wins:
.pipeline-check.yml/.pipeline-check.yamlat the current working directorypyproject.tomlat the cwd,[tool.pipeline_check]table
Pass --config PATH to select an explicit file (a missing path raises
a UsageError, no silent fallback).
Schema
Every CLI flag maps to a key with - → _. Gate settings live under a
nested gate sub-section.
pyproject.toml
[tool.pipeline_check]
pipeline = "aws"
region = "eu-west-1"
profile = "prod"
standards = ["owasp_cicd_top_10", "nist_ssdf"]
severity_threshold = "MEDIUM"
min_confidence = "MEDIUM" # drop LOW-confidence findings from the gate
output = "sarif"
output_file = "pipeline-check.sarif"
# Load org-specific rules alongside the built-in catalog.
custom_rules = ["policies/internal-rules.yml"]
rego_rules = ["policies/forbidden-runner.rego"]
# Provider-specific paths (auto-detected if omitted and a canonical
# file exists at cwd).
gha_path = ".github/workflows"
gitlab_path = ".gitlab-ci.yml"
bitbucket_path = "bitbucket-pipelines.yml"
circleci_path = ".circleci/config.yml"
tf_plan = "plan.json"
# Extra credential patterns for the secret-scanning checks
# (GHA-008, GL-008, BB-008, ADO-008, JF-008, CC-008). Python regex syntax; anchor
# with ^...$ for whole-token matches.
secret_patterns = [
'^acme_[a-f0-9]{32}$', # internal service token
'^xoxo-[A-Z0-9]{20,}$', # vendor-specific API key
]
[tool.pipeline_check.gate]
fail_on = "HIGH"
min_grade = "B"
max_failures = 10
fail_on_checks = ["GHA-002", "CB-002"]
baseline = "artifacts/baseline.json"
ignore_file = ".pipelinecheckignore"
.pipeline-check.yml
Same keys, YAML shape:
pipeline: aws
region: eu-west-1
standards:
- owasp_cicd_top_10
- nist_ssdf
severity_threshold: MEDIUM
secret_patterns:
- '^acme_[a-f0-9]{32}$'
- '^xoxo-[A-Z0-9]{20,}$'
gate:
fail_on: HIGH
min_grade: B
max_failures: 10
fail_on_checks:
- GHA-002
- CB-002
baseline: artifacts/baseline.json
ignore_file: .pipelinecheckignore
Per-rule overrides
The overrides: block demotes or promotes a rule's severity without
disabling it. A rule that's intentionally noisy in your environment
can be ratcheted to LOW so the gate stops blocking on it, while still
appearing in reports for awareness. The opposite direction works
too: promote a rule the team treats as a hard stop to CRITICAL so it
trips the default gate.
overrides:
GHA-016:
severity: low # curl-pipe is noisy on our internal repos
K8S-024:
severity: critical # we treat missing health probes as a hard stop
# pyproject.toml equivalent
[tool.pipeline_check.overrides."GHA-016"]
severity = "low"
[tool.pipeline_check.overrides."K8S-024"]
severity = "critical"
Rules
- The check ID is matched case-insensitively, so
gha-016andGHA-016both work. This avoids the common typo class where a contributor copies an ID from a lowercase log line. severityis the only sub-key today; values arecritical,high,medium,low, orinfo.- Unknown check IDs are silently ignored: the override simply never
matches anything. Bad severities are dropped with a
[config]warning at load time. - Overrides are applied after centralized confidence demotion, so the rule's confidence score is preserved even when its severity is changed.
- Suppression is still done through
--ignore-file/.pipelinecheckignore. Overrides change severity; they don't suppress the finding.
Named scan profiles
For teams that run the scanner in multiple lanes (pre-commit, PR
gate, release gate), the per-lane settings collapse cleanly into
policy files under ./policies/<name>.yml (or
./.pipeline-check/policies/<name>.yml). A policy bundles a rule
filter, a standards filter, gate thresholds, and per-rule overrides:
# policies/pre-merge.yml
description: PR gate -- full pack, HIGH-fail
gate:
fail_on: HIGH
# policies/release-gate.yml
description: release-only profile, MEDIUM-fail, attestation forced
standards: [owasp_cicd_top_10, slsa]
gate:
fail_on: MEDIUM
overrides:
ATTEST-001:
severity: CRITICAL
Activate with pipeline_check --policy pre-merge (or
pipeline_check --list-policies to enumerate everything
discoverable). Five curated packs ship built in (pr-gate,
release-gate, slsa-l3, pci-dss, supply-chain-strict), so the
common gates work by name without authoring a file; a local policy of
the same name shadows the built-in. Policy values feed click's option
defaults so the
config file, env vars, and explicit CLI flags all override them
where they overlap. Per-rule overrides merge with the config file's
overrides: block on a per-key basis (config wins on conflicts).
See ci_gate.md for the
full schema + worked examples.
Environment variables
Upper-snake-case of the option name, prefixed with PIPELINE_CHECK_.
Gate settings use the PIPELINE_CHECK_GATE_ prefix.
export PIPELINE_CHECK_PIPELINE=aws
export PIPELINE_CHECK_SEVERITY_THRESHOLD=HIGH
export PIPELINE_CHECK_STANDARDS=owasp_cicd_top_10,nist_ssdf
export PIPELINE_CHECK_GATE_FAIL_ON=HIGH
export PIPELINE_CHECK_GATE_MAX_FAILURES=5
Multi-value flags (standards, checks, fail_on_checks,
secret_patterns) are comma-separated in env vars.
Env vars override config-file values for the same key, useful in CI where the file encodes repo policy but a specific job (e.g. a nightly deep scan) needs to tighten a single setting.
Unknown keys
Unknown top-level or gate keys are ignored with a stderr warning rather than raising:
Typos still surface, but a config written for a newer version keeps working on an older install.
--config-check: fail CI on typos
The warning is easy to miss in CI logs. Run the dedicated validator step to make unknown keys a hard failure:
On a typo:
pipeline_check --config-check
# [config] pyproject.toml: 'max_faillures': unknown key
# [config] 1 unknown key(s) detected.
# exit 3
Exit code 3 is reserved for this validation failure (distinct from
1 for a failed gate and 2 for a scan error), so CI can branch
on the cause:
- name: Validate pipeline_check config
run: pipeline_check --config-check
# ↑ fails the job immediately on any unknown key
--config-strict: fail the scan itself on typos
--config-check is a separate preflight step that scans nothing.
--config-strict instead guards a normal scan: an unknown key aborts
with a UsageError (exit 2) before scanning, while a clean config runs
as usual. Use it when you'd rather not add a dedicated validation step:
pipeline_check --pipeline github --config-strict
# [config] .pipeline-check.yml: 'fail_on', unknown key
# Error: --config-strict: 1 unknown config key(s) detected ...
# exit 2
The classic catch is a gate key written at the top level instead of
under gate: (fail_on: HIGH at the root is ignored, silently
disabling the threshold). --config-strict turns that into a hard
failure. A clean config makes the flag a no-op, so it's safe to leave
on in CI.
Tips
- Keep
pyproject.tomlas the single source of truth for Python projects; it's already the standard place to find[tool.ruff]/[tool.mypy]. - Use
.pipeline-check.ymlfor non-Python repos (scanning a.gitlab-ci.ymlfrom inside a Go or TypeScript project, for instance). - Commit the file: it encodes team policy; diffs to it are diffs to your security posture.
- Use env vars sparingly: they make CI logs harder to reproduce locally.
Reserve them for secrets (
--profile) and per-job overrides.