v0 spec
Scanner Input
Pluggable scanner findings flow into Delimit attestations as upstream evidence. We govern the merge regardless of who scans.
Why this exists
Bugcrawl, Snyk, Semgrep, and CodeQL each find a different slice of the problem space. Buying into a single vendor for the entire bug-scanning layer is a structural lock-in.
Delimit's Scanner Input layer accepts findings from any of them and folds the result into a signed merge decision. Bugcrawl is one source among many — not a competitor we replicate, an input we consume.
Three properties of the contract
Vendor-agnostic
Reserved source names: bugcrawl, snyk, semgrep, codeql. Custom names allowed.
Signed in the bundle
Each input's sha256 lands in the attestation. Tampering at the input layer is detectable from the signed artifact alone.
Replayable
The full findings array travels with the attestation so a third party can re-derive the gate decision from the same evidence.
The v0 contract
{
"scanner_input_version": "v0",
"source": {
"name": "snyk",
"version": "1.1296.0",
"vendor": "snyk-io",
"kind": "sast"
},
"subject": {
"kind": "git_ref",
"repo": "owner/repo",
"sha": "abc123...",
"ref": "refs/heads/main"
},
"produced_at": "2026-04-27T22:00:00Z",
"findings": [
{
"id": "snyk:SNYK-JS-LODASH-1018905",
"severity": "high",
"kind": "vulnerability",
"title": "Prototype Pollution in lodash",
"location": { "path": "package-lock.json", "line": 1234 },
"raw_ref": "snyk-output.json#/vulnerabilities/0",
"policy_disposition": null
}
]
}Field semantics
| Field | Required | Notes |
|---|---|---|
| scanner_input_version | yes | Pin to "v0". Versioned so replay can branch on schema. |
| source.kind | yes | One of sast, dast, sca, secret, iac, agent. Defaults gate-policy weighting. |
| findings[].id | yes | Globally-unique, scanner-name-prefixed (e.g. snyk:SNYK-...) to avoid collisions across sources. |
| findings[].severity | yes | critical · high · medium · low · info |
| findings[].kind | yes | vulnerability · quality · style · policy · secret. Policy DSL filters on this. |
| findings[].policy_disposition | no | Set by Delimit at gate time. Adapter MUST leave it null. |
What lands in the attestation
Each scanner input is summarised in bundle.scanner_inputs[] with its source, severity breakdown, and a doc_hash. The full findings travel alongside so verification re-derives both the bundle hash and each input doc hash.
"scanner_inputs": [
{
"source": "snyk",
"kind": "sast",
"produced_at": "2026-04-27T22:00:00Z",
"subject_sha": "abc123...",
"findings_count": 3,
"severity_breakdown": { "critical": 0, "high": 1, "medium": 2, "low": 0 },
"doc_hash": "sha256:...",
"doc_ref": "/path/to/snyk-output.scanner-input.json"
}
]Deliberately out of v0
- Suppression syntax — v0 emits
policy_disposition: null. The Policy DSL goes live in v0.1. - Streaming / incremental updates — one finding-set per scan run, immutable.
- Non-git subjects — service-mesh, runtime-trace, infra-state are reserved kinds for v0.x.
- Per-finding signatures — adapters do not sign. Tamper-evidence is at the bundle level via committed input hashes.
Use it alongside the Bugcrawl battlecard — same artifact, scanner-input layer made explicit.
Attestation schema