Skip to content

report, serve and new-marker

Three small utilities that work on what is already on disk. report renders a stored run in another format. serve opens a local viewer over the run history. new-marker prints a marker. None of them sends a request to your target.

veridor report

report turns a run JSON document into SARIF, JUnit XML, a GitLab SAST report, a GitLab Code Quality report or Markdown, without repeating the probes. It also renders a drift report as Markdown.

Use it when the run is finished and you need a format you did not ask for at the time, or a second copy for another system. To write reports during the run itself, use veridor run --report FORMAT=PATH, which is repeatable; see writing them from the run.

Flags

Flag Does
--from-run RUN.json the run JSON veridor run --json wrote. --input is the older spelling
--from-drift DRIFT.json a drift report written by veridor map --baseline … --drift
--format FORMAT sarif, junit, gitlab-sast, codequality or markdown. Required unless --sarif is given
--output PATH where to write. - or no --output writes to stdout
--sarif PATH the older spelling of --format sarif --output PATH

Exactly one of --from-run and --from-drift is required.

Run it

run.json is the run document from the capsule page: one confirmed finding, gate exit 1.

veridor report --from-run run.json --format junit --output out.junit
veridor report --from-run run.json --format markdown
Wrote JUnit report to out.junit
## Veridor run `20261110T043547Z-dab5f6`

**Gate failed (exit 1):** 1 finding about the target.
Policy: `--fail-on new+confirmed`.

Target: `http://127.0.0.1:18805`. Config: `veridor.capsule-demo.json`.

| Probes | Matched their declaration | Vulnerable | Unexpected denial | Inconclusive | New | Unchanged | Resolved |
| ---: | ---: | ---: | ---: | ---: | ---: | ---: | ---: |
| 6 | 5 | 1 | 0 | 0 | 1 | 0 | 0 |

Evidence: 1 confirmed, 0 suspected, 0 ungraded.

#### Gate reasons

- `findings` (exit 1): 1 finding about the target.
…

Both exit 0. A file output prints Wrote <label> report to PATH; the labels are SARIF, JUnit, GitLab SAST, GitLab Code Quality and Markdown. The JUnit file records the gate as properties:

<testsuites name="veridor" tests="7" failures="2" errors="0" skipped="0" time="0.006">
  <testsuite name="veridor" tests="7" failures="2" errors="0" skipped="0" time="0.006" timestamp="2026-11-10T04:35:47">
    <properties>
      <property name="veridor.run_id" value="20261110T043547Z-dab5f6" />
      …
      <property name="veridor.gate.exit_code" value="1" />
      <property name="veridor.gate.fail_on" value="new+confirmed" />
      …

The gate travels, except in SARIF

veridor run records the exit-code decision in the run document as a gate object. Every format except SARIF renders it, so a run that exited 3 because nothing was answered never renders as a pass. SARIF carries findings only: a run that exited 3 for an unproven denial or an unclean teardown renders as zero results, the same as a run that exited 0. For SARIF, read the job's exit code. The reason codes and each format's mapping are on reports and SARIF and code scanning.

Drift renders to Markdown only

veridor report --from-drift drift.json --format markdown
## Veridor access-matrix drift

**0 change(s), 0 that mean more access than the baseline.** A change is an observation, not a finding: …

This document does not record the `--fail-on-drift` policy or the exit code; the job's exit code is the gate.
…

drift.json came from two veridor map runs of fixtures/veridor.map-demo.json against the demo target, the second with --baseline and --drift. Any other format is refused, because the other four would present a drift as a finding:

veridor report --from-drift drift.json --format sarif
veridor: a drift report renders to --format markdown only, not sarif: drift is an observation, never a finding, and SARIF, JUnit, GitLab SAST and Code Quality would all present it as one

Refusals

Each exits 2 and writes nothing:

Command Message
report --from-run run.json report needs --format, one of sarif, junit, gitlab-sast, codequality, markdown
report --format sarif report needs exactly one input: --from-run RUN.json (the run JSON …) or --from-drift DRIFT.json
report --from-run run.json --format junit --output run.json --output must not overwrite the input run
report --from-run run.json --sarif x.sarif --format sarif --sarif PATH is the older spelling of --format sarif --output PATH; pass one form or the other, not both

A file that is not a Veridor run, or one with a field of the wrong type, is also refused; see rendering them later.

What it does not do

  • It does not repeat a probe or change the exit code the run produced. It renders what the document records.
  • It does not render a drift as a finding, and it renders nothing other than a run or a drift document.

veridor serve

serve opens a local web viewer over the run history directory: runs, maps (with drift when there was a baseline) and mutation reports, each in its own tab. What it guards against is on safety posture.

Flags

Flag Default Does
--output-dir DIR .veridor the run history directory to read
--host HOST 127.0.0.1 the address to bind. Anything other than 127.0.0.1, localhost or ::1 is refused without the next flag
--i-understand-this-is-unauthenticated off required to bind any other address
--port PORT 8787 the port to listen on

Run it

veridor serve --port 18805
Veridor UI: http://127.0.0.1:18805

It runs until stopped. Stopped with SIGTERM, it printed veridor: stopped by SIGTERM before the command finished (exit 143).

Read-only

The viewer answers GET only, and only for its own pages and these JSON endpoints: /api/runs, /api/runs/<id>, /api/maps, /api/maps/<id>, /api/mutations and /api/mutations/<id>. Each reads one kind of document from fixed directories under --output-dir (runs/ for runs; matrix/, blast-radius/, candidates/ and drift/ for maps; mutation/ for mutation reports), so the runs endpoint can never return a map. It writes nothing. Measured against the server above:

Request Status
GET /api/runs 200, a JSON object whose runs key holds the list of run summaries
POST /api/runs 501
GET /api/runs with Host: evil.example 421
GET /api/runs/..%2f..%2fveridor.json 400

Every response carries Content-Security-Policy: default-src 'self'; frame-ancestors 'none', Referrer-Policy: no-referrer, X-Content-Type-Options: nosniff and Cache-Control: no-store. The pages and scripts are served from the installed package, never from the history directory.

No authentication

The viewer has no login. Binding anything but loopback is refused:

veridor serve --host 0.0.0.0 --port 18805
veridor: --host 0.0.0.0 binds an address other than loopback, and the viewer has no authentication: every run document it serves -- target URLs, finding messages, config paths -- becomes readable by anything that can reach that address. Pass --i-understand-this-is-unauthenticated if that is what you want, or leave --host at 127.0.0.1 and use an SSH tunnel.

Exit code 2. To read the history from another machine, leave --host at 127.0.0.1 and use an SSH tunnel.

What it does not do

  • It does not run probes, write files, or change a run document.
  • It does not authenticate anyone, and it is not a shared run history for a team.
  • It does not load anything from another origin: no web font, CDN or tracker.

veridor new-marker

new-marker prints one fresh marker and exits 0. It takes no flags.

veridor new-marker
vdr-bXki3goB8mnegdnUQfWZ4DaN

Each call prints a new value: vdr- followed by 24 random URL-safe characters, checked against the same validation a configured marker must pass. Plant it in data that belongs to one identity, then declare it as that identity's marker. The rules, and what a marker does and does not prove, are in marker.

It does not plant the marker anywhere, and it does not check that the value is unique to one identity's data. Both are up to you.

Exit codes

Command 0 2
report the report was written refused, or the input did not load
serve the server returned normally refused before binding, for example a non-loopback --host
new-marker a marker was printed not used

70, 130 and 143 mean the same as for every command. serve runs until stopped, so Ctrl-C ends it with 130 and SIGTERM with 143.