LineBreak security gate at the git/CI boundary: dependency CVE scan + AI SAST, human-approved overrides, git-native audit records
Project description
linebreak-gate — the LineBreak security gate at the git/CI boundary
Blocks merges that carry known vulnerabilities. One tool, two detectors:
- Dependency CVE scan — osv-scanner
across every ecosystem (npm, PyPI, Go, Cargo, Maven, …), with an
npm auditfallback for npm projects (npm-only coverage and no installed-version data — the GitHub Action fails closed if osv-scanner can't be installed instead of degrading to it). - AI SAST — an LLM security review of first-party source (injection,
broken auth, secret exposure, SSRF, unsafe deserialization, crypto misuse)
with adversarial verification, enabled by
ANTHROPIC_API_KEY.
The gate blocks and can propose; it never auto-clears on an agent's say-so. A human approves the fix or records an override — with a reason and an approver — in a git-committed audit file.
This is the same scanner core that powers the LineBreak desktop app's in-app security gate (the desktop backend imports this package), but it is fully standalone: a team that has never opened the desktop app can add the gate to their repo and get real enforcement.
Where this code lives. Development happens in the LineBreak monorepo (
packages/gate); every green change to it is automatically mirrored toBaktun-Studio/linebreak-gate(the public repo the Action snippet uses) and published to PyPI aslinebreak-gate. Never edit the mirror directly — the next sync overwrites it. Licensed Apache-2.0.
Quickstart — GitHub Actions
# .github/workflows/security-gate.yml
name: Security gate
on:
pull_request:
permissions:
contents: read
pull-requests: write # for the summary comment
jobs:
gate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v5
- uses: Baktun-Studio/linebreak-gate@v1
with:
# fail-on: high # blocking floor; default: critical
# Optional today; required once license enforcement is enabled.
license-key: ${{ secrets.LINEBREAK_LICENSE_KEY }}
# Enables the AI code review; leave unset for dependency scan only.
anthropic-api-key: ${{ secrets.ANTHROPIC_API_KEY }}
The action runs linebreak-gate scan, always runs report, posts one PR
comment (updated in place on every push, never spammed), uploads the JSON
report + audit artifacts as a workflow artifact, and fails the check per the
scan's exit code.
Make it a real boundary: require the check
A CI job that can be ignored is a dashboard, not a gate. In your repo:
Settings → Branches → Branch protection rules → your default branch →
"Require status checks to pass before merging" → add the gate job (the
name of the job that runs this action). From then on a PR carrying a critical
CVE cannot be merged through the GitHub UI.
Quickstart — any other CI (GitLab example)
The CLI is a plain Python package with strict exit codes — 0 pass, 1
blocking findings, 2 tool/config error (fail closed: a scanner crash
fails the pipeline, it is never a clean pass). Any CI that respects exit codes
gets the same enforcement:
# .gitlab-ci.yml
security-gate:
image: python:3.11
script:
- pip install linebreak-gate
- curl -fsSL -o /usr/local/bin/osv-scanner
"$(curl -fsSL https://api.github.com/repos/google/osv-scanner/releases/latest
| python -c "import json,sys;print(next(a['browser_download_url'] for a in json.load(sys.stdin)['assets'] if a['name'].endswith('linux_amd64')))")"
- chmod +x /usr/local/bin/osv-scanner
- linebreak-gate scan
- linebreak-gate report
Mark the job as required (no allow_failure) and protect the branch.
CLI
linebreak-gate init [--path .] [--fail-on critical|high|medium|low] [--force] [--non-interactive]
linebreak-gate scan [--path .] [--fail-on critical|high|medium|low] [--format summary|json]
linebreak-gate report [--path .] [--format summary|json]
linebreak-gate override --finding <id> --reason "…" --approver <name/email> [--path .]
-
initsets a repo up in one command: writes the workflow file (never clobbers an existing one without--force), optionally writes.linebreak/gate.yml, offers to store the secrets via the GitHub CLI and to require thegatecheck — and prints the exact settings links for anything it can't do for you. -
scanruns both detectors, writes git-native audit artifacts under.linebreak/audit/, and exits 0/1/2. -
reportrenders the recorded scan: counts by severity and every finding with CVE id, CVSS, advisory link, and override status.--format jsonfor machines. -
overriderecords a human-approved acknowledgment of one exact finding — the package + installed version + CVE tuple. A different CVE, a bumped version, or a new finding still blocks.--reasonand--approverare required; the record lands in the artifact's approval trail. Commit the updated.linebreak/audit/*.jsonso CI sees it.
Configuration — .linebreak/gate.yml
The gate's strictness is governance, so it lives in the repo — changing the threshold is itself a PR: visible, reviewable, attributable in git history.
# .linebreak/gate.yml
fail_on: critical # critical (default) | high | medium | low
exclude_paths: # optional: root-relative globs excluded from scanning
- fixtures
- "sandbox/*"
code_scan: auto # auto (run when ANTHROPIC_API_KEY is set) | on (required) | off
Precedence: explicit --fail-on flag / Action input → .linebreak/gate.yml →
built-in default (critical). An invalid config is a tool error (exit 2) —
a broken governance file never silently falls back to a default.
Audit records
Every scan and every override is recorded in .linebreak/audit/security.json
(dependencies) and .linebreak/audit/code.json (AI SAST) — the same versioned
document format the LineBreak desktop app writes, carrying findings (CVE id,
CVSS, advisory link), scanner engine, timestamp, actor, and the approval trail
with each override's reason + approver. Who relaxed the gate, and when, is
itself auditable.
Licensing
The gate reads LINEBREAK_LICENSE_KEY from the environment (the Action's
license-key input). Entitlements currently default open: without a key the
gate runs and prints a notice. The check is wired through LineBreak's
entitlements provider, so flipping LINEBREAK_ENTITLEMENTS_PROVIDER=remote
enforces licensing without a client change — set the key in CI secrets now so
the gate keeps working then.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file linebreak_gate-1.1.0.tar.gz.
File metadata
- Download URL: linebreak_gate-1.1.0.tar.gz
- Upload date:
- Size: 50.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0a607bff5ae1816394454c43b1426944b6acef55774aed5df27c047e40062f24
|
|
| MD5 |
6896adb573dc80c93971f6dcef7a25bd
|
|
| BLAKE2b-256 |
a6db0e5ae2dd7005e54aeb6ed8c07208da34a9ba10accd66a41e269088912a5f
|
Provenance
The following attestation bundles were made for linebreak_gate-1.1.0.tar.gz:
Publisher:
publish-gate.yml on Baktun-Studio/linebreak
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
linebreak_gate-1.1.0.tar.gz -
Subject digest:
0a607bff5ae1816394454c43b1426944b6acef55774aed5df27c047e40062f24 - Sigstore transparency entry: 2051051192
- Sigstore integration time:
-
Permalink:
Baktun-Studio/linebreak@71733c93a99eb6bb3d3a95304369a457de109883 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Baktun-Studio
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-gate.yml@71733c93a99eb6bb3d3a95304369a457de109883 -
Trigger Event:
push
-
Statement type:
File details
Details for the file linebreak_gate-1.1.0-py3-none-any.whl.
File metadata
- Download URL: linebreak_gate-1.1.0-py3-none-any.whl
- Upload date:
- Size: 45.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
842a4ea2d6f61a8cacd99c433b8d6f1194edfe0f5b2fb19342a44c721c04212a
|
|
| MD5 |
573927dbb7132ab90b2609c4f5709084
|
|
| BLAKE2b-256 |
deb5540c08f07a1e33f2c939faf918d069e15c4d9a1776dfdbf463af6214b6ea
|
Provenance
The following attestation bundles were made for linebreak_gate-1.1.0-py3-none-any.whl:
Publisher:
publish-gate.yml on Baktun-Studio/linebreak
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
linebreak_gate-1.1.0-py3-none-any.whl -
Subject digest:
842a4ea2d6f61a8cacd99c433b8d6f1194edfe0f5b2fb19342a44c721c04212a - Sigstore transparency entry: 2051051259
- Sigstore integration time:
-
Permalink:
Baktun-Studio/linebreak@71733c93a99eb6bb3d3a95304369a457de109883 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/Baktun-Studio
-
Access:
private
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish-gate.yml@71733c93a99eb6bb3d3a95304369a457de109883 -
Trigger Event:
push
-
Statement type: