Browsable, shareable scan output with no server and no network. Everything renders to a single self-contained HTML file — it works fully offline, so air-gapped teams get a dashboard feel without standing up a service.
Every PullGuard surface leads with a grade and a drift score. The score runs 0–100 and lower is better — it is a severity-weighted measure of finding density, so a big healthy codebase is not punished for its size.
| Grade | Score | What it means |
|---|---|---|
| A | 0–15 | Excellent — minimal drift, well-maintained. |
| B | 16–35 | Good — some issues, nothing urgent. |
| C | 36–55 | Needs attention — tech debt accumulating. |
| D | 56–75 | Significant problems — active remediation needed. |
| F | 76+ | Critical — security or architecture issues demanding immediate action. |
Not every category counts the same. Security carries double weight, because a vulnerability is not the same kind of problem as an inconsistent name:
security ×2, operations ×1.5, architecture/complexity ×1.2,
dependencies/history/quality ×1, documentation/imports/patterns/structure ×0.8, naming ×0.6
The same legend is printed on the HTML report, the CI step summary and the PR comment, and it is generated from the scoring code itself — so what you read can never drift from what produced the grade. Informational findings contribute nothing to the score.
pullguard scan . --format html > pullguard-report.html
One .html with grade/score/findings/cost cards, a severity bar, the trend
strip, and a findings table you can filter by severity. Each finding shows two date columns:
git blame), with commit + author. Present with --blame..pullguardignore entry (and the /pullguard ignore command where it applies), so a reviewer who decides "not a real issue" can record that decision without leaving the report. Security findings that always surface get the reviewed, reason-required path instead, and stay visible.taint-flow / interprocedural (a dataflow from an attacker-controlled source to a sink was traced, within a file or across functions and files), content-shape (a structured agent/MCP config was parsed and its shape is the evidence), or pattern (a calibrated pattern rule matched — no proven flow is claimed). Triage the proven flows first. The tier is display metadata only: it never changes a severity, a grade, or whether a finding blocks.| Date | What it is | How |
|---|---|---|
| First discovered by PullGuard | Finding age & "new since" — when a fingerprint first appeared. | Persisted in .drift-history.json; always on. Commit it so dates survive CI. |
| Introduced | When/by-whom the code was written. | Local git blame via --blame (opt-in). Fully local, air-gap-safe. |
Both dates are also present in --format json output.
pullguard scan . --format ai-bom > pullguard-ai-bom.json
Enterprise. A standard
CycloneDX 1.6 machine-learning
bill of materials, derived from the same AI Usage inventory that powers the report's
AI Usage panel — one machine-learning-model component per distinct
model your code calls, plus an application component per provider, each
carrying call-site counts and a pullguard:dataEgress flag (set when a
secret or PII was observed flowing into that call). Consumable by BOM tooling and
useful as procurement / EU AI Act / NIST AI RMF evidence of which AI components a
codebase actually depends on. Model names are sourced from scanned (untrusted) code,
so they're allowlist-sanitized before inclusion. An empty components: []
array is a valid, honest result on a repo with no detected AI-provider calls.
pullguard dashboard . -o pullguard-dashboard.html
A self-contained dashboard built from your local history. Click any chart point (or history row) to drill down to that scan's findings and their file:line — no server required.
.pullguardignore entry (or /pullguard ignore command) uses, so triage decisions can be made from the dashboard.Build history by scanning over time (e.g. on every push to main or on a schedule)
and committing .drift-trend.json + .drift-scan-details.json.
dashboard.retainScans in .driftrc.yml controls how many recent scans keep
finding-level detail (default 50; 0 = keep all).
pullguard dashboard --org ./all-repos -o portfolio.html
A 10,000-ft view across every repository PullGuard runs on — one self-contained page for leadership and platform teams. Point it at a directory where each repo's history lives (each repo commits its own history file, or a CI job collects them into one folder):
Same air-gapped, single-file design — nothing hosted, nothing leaves your boundary.
The GitHub Action renders both files on every run and uploads them as the
pullguard-report artifact — no extra steps:
pullguard-report.html — the per-scan report.pullguard-dashboard.html — the over-time dashboard.workflow_dispatch: to your workflow's on: block to get a "Run workflow" button on the Actions tab — regenerate the report + dashboard from the web UI, no commit needed.How to view the graphics: open the run → Artifacts → download pullguard-report, unzip, and open either .html in any browser.
GitHub doesn't render interactive HTML inline (it strips scripts/SVG from comments & summaries), so the rich report/dashboard are download-and-open. To view at a URL instead, publish the artifact to GitHub Pages — but that makes it web-hosted, so keep it off for air-gapped/confidential repos.
Developers can jump from a finding straight to the offending line inside their editor — no PullGuard-specific plugin to install. PullGuard emits SARIF (the industry-standard static-analysis format), and every major IDE has a free SARIF viewer that turns each result into a click-to-source jump, resolved against your open checkout.
1. Get the SARIF file. The GitHub Action uploads
pullguard.sarif inside the pullguard-report artifact automatically (v1.3.2+) — just
download it. To generate it directly (locally, or in the container/CLI form):
pullguard scan . --format sarif > pullguard.sarif
You can also send it straight to GitHub's Security tab, so findings annotate the PR and appear in code scanning:
- run: pullguard scan . --format sarif > pullguard.sarif
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: pullguard.sarif # needs: permissions → security-events: write
Copy-paste workflow: docs/sarif-security-tab.example.yml (runs the image, uploads to the Security tab, and keeps the SARIF as an artifact for IDE viewers).
2. Open it in your IDE with the repository as the open folder/project — PullGuard's SARIF paths are repo-root-relative, so the viewer maps each finding to your local file:
| IDE | Free viewer | How |
|---|---|---|
| VS Code | Microsoft SARIF Viewer (open-source) | Install from the Marketplace → "SARIF: Open" → pick pullguard.sarif → click any result. |
| Visual Studio | Microsoft SARIF Viewer | Open the .sarif file; results dock into the Error List with go-to-source. |
| JetBrains (IntelliJ, PyCharm, GoLand, …) | Qodana plugin / SARIF import | Import the .sarif; findings appear in the Problems view, click to navigate. |
| Eclipse | SARIF viewer plugin | Open the .sarif file; results link to source. |
| GitHub (zero install) | Security tab (code scanning) | The upload-sarif step above renders findings inline on the PR + in the Security tab. |
Tip: open the SARIF with the repo at its root so relative paths resolve. The HTML report's clickable links (above) go to your git host in a browser; the SARIF route opens the file in your editor — use whichever fits the moment.
For VS Code there is also a dedicated PullGuard extension (v1.3.3+). It reads
the pullguard-report.json your CI or CLI already produces and shows findings inline:
No scanner runs in the editor — the extension just renders the report — so it's tiny and needs
no license key. When the report was produced with --blame, it also shows each
finding's introduced date and owner.
The extension is rolling out to the VS Code Marketplace — contact us for early access. The SARIF viewers above remain the primary, available-today IDE path (and cover every other editor).
Run the portfolio aggregator in a dedicated platform repo (on a schedule or via the
"Run workflow" button). It collects each repo's committed history and renders one
portfolio.html artifact — see docs/portfolio-workflow.example.yml.
All three outputs are single files with zero external references — no CDN, fonts, analytics, or network calls. Generate them on an isolated runner, copy them anywhere, open them in any browser. The data lives entirely in your repo; nothing is hosted and nothing leaves your boundary.