One verdict from every engine, reconciled by fingerprint.
Running multiple security scanners side by side produces overlapping findings, drift across reruns, and a triage channel the team learns to ignore. Parry collapses every engine's output into one finding per real issue, with a stable lifecycle that survives refactors.
The four failure modes of a multi-scanner stack
- Same issue, three findings
Your secrets scanner flags an AWS key on line 42. The container scanner's secrets module flags the same key. A regex post-commit hook flags it again. Three rows, one underlying secret. Multiply across a 200-file diff and a security review becomes a deduplication exercise.
- The lifecycle drifts on every rerun
A scanner that re-asks every question on every run is not a security tool — it's a notification firehose. Without lifecycle, a fixed finding looks the same as a new one, a suppression evaporates after a refactor, and the team learns to ignore the channel.
- Triage decisions don't survive code changes
You marked a SAST finding as 'won't fix — false positive on a test fixture' three months ago. Someone renamed the file. The next scan resurrects the finding under a new ID and you triage it again. And again.
- No way to prove a scanner ran
Procurement asks: 'Do you scan for secrets, SAST, deps, IaC, containers?' Yes. 'Show me.' You have five tool logs, three retention windows, and no single artifact. The reconciled report is the artifact.
Five steps, one verdict
- 01
Run every engine in its own sandbox
Each scanner runs in an isolated container — no network egress by default, read-only mount of your code, bounded CPU and memory, hard time limit. A bug in one engine cannot affect the rest of the scan.
- 02
Normalize output into a common shape
Every engine speaks a different dialect — SARIF, JSON, custom YAML. Adapters translate each engine's output into one schema: rule id, severity, file, line, snippet. Adapters are small, fixture-tested, and replaceable.
- 03
Compute a stable fingerprint per finding
Fingerprint = sha256(tool | rule_id | file | trimmed_snippet). The same secret detected by two engines collapses to one fingerprint. A rename or whitespace edit does not perturb it. A real new finding has a new fingerprint.
- 04
Reconcile against the previous scan
New fingerprint → open. Previously-open + present this scan → still open. Previously-open + absent this scan → fixed. Suppressed and accepted states are preserved. The transition table is one file. No replication elsewhere.
- 05
Emit one Check Run, one drawer, one SBOM
The reconciled view lands on the GitHub pull request as one Check Run, in the Parry web app as one finding drawer with provenance back to every engine that flagged it, and as one CycloneDX SBOM for procurement.
The engines under the hood
Open, auditable, swappable. Pinned by digest, updated on our cadence. You can verify what ran and how.
| Scope | Engine | How we use it |
|---|---|---|
| Secrets | Open-source secrets scanning + live provider-API validation | Live-verified — a regex match against an inactive token does not become a finding. |
| SAST | Open-source static analysis | Readable rule format. Reachability filtering before the finding is emitted. |
| Dependencies | Open-source dependency scanning against the public CVE / OSV feed | The same feed major code hosts, registries, and language ecosystems publish to. Reachable-only CVEs by call-graph. |
| Containers | Open-source layer-by-layer image scanning | Every layer, including the base image. Same finding feed as the rest. |
| IaC | Two reconciled open-source engines | One for Terraform / CloudFormation, one for Kubernetes manifests. Output reconciled before it reaches you. |
| Supply-chain posture | Industry-standard open posture benchmark | Per-repo grade. Reproducible, published, not a vendor-private risk score. |
| DAST | Open-source baseline scan | Spider-and-passive against a staging URL you supply. Same finding feed. |
| Custom policy | Open policy engine | Drop a policy file in policy/ — runs on every push, gates the merge. |
Things we don't pretend to do
- We do not invent a proprietary scanner
Every vendor with a proprietary-engine marketing line is asking you to trust a black box. We run the engines the security community already runs in production. The differentiation is reconciliation, lifecycle, and the verdict on the commit — not a rebranded rule pack.
- We do not replace human review
A scanner without lifecycle is a notification firehose; a scanner with reconciliation and AI Review is a triage assistant. The merge decision is still yours.
- We do not score 'risk' with a hidden model
Severity comes from the engine that flagged the finding, mapped to SARIF levels. Reachability comes from call-graph analysis you can re-run. We don't multiply numbers together and call the product a risk score.
One Check Run per push. Lifecycle that survives the refactor.
Free for public repositories. Flat per-org for private. No per-committer billing.