Skip to content
PROCTOR Form 0.5.0
Menu

Formats#

This page describes the four formats PROCTOR writes with --format: text, json, codequality and sarif. Pick the format your consumer reads, run the check once, and point the report where the consumer looks. One exam, four ways to file the mark sheet.

Choosing a format#

The default is text. Choose another with --format:

vendor/bin/proctor check --format=json
Format What it is
text A header line with the tool and the versions of the external tools used (composer), then one line naming the policy in use (origin, path, refresh date), then one line per finding, then one line per override, then a RESULT line.
json One machine-readable object with tool, version, path, today, result, exit, tools, policy, findings and overrides.
codequality GitLab's Code Quality JSON: a single array of findings, so a merge request shows them.
sarif A SARIF 2.1.0 log: one run, one rule per check, one result per non-pass finding, so GitHub code scanning and other SARIF viewers show them.

text#

The default human-readable format: a header line with the tool and the versions of the external tools used, then one line per finding in check order, then one line per override, then a summary line:

proctor 0.1.0 | composer: 2.10.3
Policy: option (/app/policy.json), refreshed 2026-10-20, 7 days ago
PASS php-floor: php floor 8.4 is active
FAIL unbounded-constraints: vendor/a constraint "dev-master" is unbounded
OVERRIDE lock-committed: x (expires 2026-01-01, approved by t)
RESULT: fail (1 failures, 0 warnings)

Nine real lines from PROCTOR's text report, one per check shown: FAIL php-floor, WARN unpatched, FAIL unbounded-constraints, PASS lock-committed, WARN portability, WARN mysql56, WARN ci-pipelines, PASS composer-audit, FAIL overrides. Each line is written in words; color only repeats what the word says.

The parts of a report:

  • The header line is proctor <version> | <tool>: <version>, one part per external tool joined with |, and unknown for a tool whose version could not be determined. It is printed only when the run used external tools.
  • The policy line is Policy: <origin> (<path>), refreshed <date>, <n> days ago, or Policy: <origin> (<path>), no refresh date when the policy carries no refreshed_on. See Policy for where the policy comes from.
  • Each finding is one line: <status> <check id>: <message>, where the status is PASS, INFO, WARN or FAIL.
  • Each override is one line: OVERRIDE <check>: <reason> (expires <date>, approved by <approver>).
  • The summary is RESULT: pass, or RESULT: fail (<failures> failures, <warnings> warnings).

Finding messages, override reasons and approvers come from files the app controls, so they are printed with terminal control characters replaced by a visible ?: an escape sequence or carriage return in one of them must not reach the log.

json#

One machine-readable object, pretty-printed on stdout. Slashes and Unicode are left unescaped, so the output stays readable.

  • Top level: tool, version, path, today (a YYYY-MM-DD date), result (pass or fail), exit (0 or 1), tools, policy, findings, overrides.
  • policy holds origin, path, refreshed_on and age_days.
  • Each finding in findings holds check_id, rule_id, status, message, path and line. An advisory finding carries an advisories array with one entry per advisory (package, id, cve, title, link, severity); other findings have no such key.
  • Each entry in overrides holds check, reason, expires, approved_by and expired, computed from today.

When the report cannot be encoded, PROCTOR fails the run with a tool error (exit 2): Could not encode the JSON report: <reason>.

codequality#

GitLab's Code Quality JSON: a single array of findings on stdout, so a merge request shows them. One object per non-pass finding, each with:

  • description: the finding message.
  • check_name: the rule id.
  • fingerprint: the stable identity of the finding (below).
  • severity: major for a fail, minor for a warning, info for an info.
  • location: path and lines.begin; the path falls back to composer.json when the finding has none.

When the run itself fails before a report exists, PROCTOR still writes one item: severity blocker, check name proctor, line 1, so the merge request shows why the run stopped instead of an empty array.

sarif#

A SARIF 2.1.0 log: one run, one rule per check, one result per non-pass finding, so GitHub code scanning and other SARIF viewers show them. See GitHub code scanning for the workflow that uploads the log.

  • The driver block names the tool proctor, its version, and the repository's information URI.
  • The rules list holds one entry per distinct rule id in the report, in first-seen order, each with a short description carrying the id.
  • Each result holds ruleId, level, message.text and one location. The level maps fail to error, warning to warning, and any other non-pass status to note.
  • The location uses the finding's path (backslashes normalized to forward slashes) and its line as region.startLine; a finding without a path points at the app's composer.json.
  • Each result also carries partialFingerprints with the finding's fingerprint under proctorFingerprint/v1.

The fingerprint#

Both codequality and sarif identify a finding with the same fingerprint, its stable identity: the lower-case hex SHA-256 of the rule id, a newline, the path (an empty string when the finding has none), a newline, and the message.