Gate a CI job on a verification
loquitur-verify ends every run with an exit code that a pipeline can act on and, unless the
command line itself is wrong (exit 64), writes a JSON report that a later step can read. The exit
codes are defined by the report contract:
A verifier that runs as a process exits with the report’s exit_code, with one addition and one
operator option:
| process exit | meaning | report |
|---|---|---|
0, 1, 2 |
the report’s exit_code |
yes |
3 |
the verifier failed: a fault of the tool, not a property of the evidence | yes: status INTERNAL_ERROR, verdict null, exit_code 3, and the single error internal_error |
4 |
an unsupported version (§5.5) | yes: status UNSUPPORTED_VERSION, verdict null, exit_code 4, and the single error unsupported_version |
5 |
a host failure (§5.3) | yes: status HOST_FAILURE, verdict null, exit_code 5 |
64 |
usage error: the invocation cannot be honored, and no verdict was computed | none |
Exit 3 is reserved for the verifier’s own faults. No content of a bundle, a registry entry,
a trust registry or a trust-root document may produce it: content a verifier cannot read is a
refusal, OFFLINE_FAIL, with the error §5.3 names for it, and a time a verifier cannot spend on
content is a fault of the verifier. A library interface does not return an INTERNAL_ERROR
report; a fault there is an exception of the host language.
Exit 4 and exit 5 are not verdicts. No option changes them, and neither is converted into another exit code.
Exit 64 is a refusal of the invocation. A command line MUST return it, with no report,
when an argument is missing or malformed under the grammar of §4.1; when a trust registry is
supplied without a registry entry; when an evaluation time is supplied without a trust registry,
or is given an empty value; when a supplied evaluation time is not a calendar instant of the form
YYYY-MM-DDTHH:MM:SSZ; and when trust roots are supplied without a trust registry, or the
trust-root document’s path names no regular file or the document is malformed under
trust-root.md §3, in any of its roots, whether or not the trust registry names
that root. A trust-root document of a well-formed version this verifier does not support is not
malformed: the run is UNSUPPORTED_VERSION (§5.5). A trust-root document the host fails to read is
not refused either: the run reports the host failure trust_root_read_failed (§5.3). A command line
judges the dependencies of §4.1 before it reads any document, so trust roots supplied without a
trust registry are refused with exit 64 whatever the document holds, a later version included.
A library interface has no exit 64. Given a trust registry without a registry entry, it returns a
report: OFFLINE_FAIL, with the errors §5.3 gives the run, and registry_link and
trust_registry both null among its per-check results; it does not read the trust registry.
Those errors are every error the bundle gives, in the order of §5.3, followed by
trust_registry_requires_registry_entry, which is the only error when the bundle gives none; a
refusal of the input as a whole (§5.3, input_not_found to filesystem_error) stays the only
error of its run, with the status §3.1 gives it. Given trust roots that break
trust-root.md §3, any one of them, it returns no report: it refuses them with an
error of the host language before it reads any evidence (trust-root.md §3). Given
an evaluation time that is empty or that is not a calendar instant of the form
YYYY-MM-DDTHH:MM:SSZ, it returns no report either: it refuses the time with an error of the host
language before it reads any evidence
(trust-registry-authorization.md §2). Given trust roots or an
evaluation time without a trust registry, it refuses them as above when they break those rules, and
otherwise does not use them: it returns the report of the same run without them. The trust-root
document’s version gate (§5.5) is the exception: it fires whether or not a trust registry is
supplied, so a library given a trust-root document of a well-formed later version returns the
UNSUPPORTED_VERSION report with or without a trust registry, where a command line given it without
a trust registry exits 64.
Registered vocabularies. A command line MUST also return exit 64, with no report, when a
registered vocabulary document an option of §4.1 supplies is refused under
verification-vocabularies.md §8: its path names no regular file,
the host fails to read it, or the document is not strict JSON, is not an object, breaks
verification-vocabularies.md §6 or registers another kind than its
option names. A library interface given such a document returns no report: it refuses it with an
error of the host language before it reads any evidence.
A library interface that takes documents. The registry entry, the trust registry and the trust
roots are given as paths (document-contracts.md §12), and §5.3 decides
errors on what a path names. A library interface whose host reads those files and hands it documents
instead MUST accept, in a document’s place, three values no document can be: one by which the
host says nothing is found at the path, one by which it says what is found is not a regular file,
and one by which it says it failed to read the regular file the path names. It MUST report each
as this contract reports the path itself: for a registry entry or a trust registry, nothing found
with the error input_not_found, which refuses the run as a whole (§5.3); for a registry entry,
something that is not a regular file and a read failure with the errors §5.3 gives those conditions;
for a trust registry, something that is not a regular file as a registry that cannot be read
(trust-registry-authorization.md §6, row 1), and a regular file
the host failed to read with the error trust_registry_read_failed; for trust roots, the first two
values alike, refused as above, and a regular file the host failed to read with the error
trust_root_read_failed (§5.3). A document that is not strict JSON or is not an object is a third
fact, and neither value stands for it. The path is read as it is written (§5.3, “A path is read as
it is written”), and, links followed, names no regular file when nothing is found at it (§5.3,
“Nothing found, and a host failure”) or what is found is not a regular file; any other failure to
inspect, open or read it is a failure to read it.
Accepting review reasons. A command line MAY offer the option --accept-review, whose
value is a comma-separated list of review reasons of §3.3. Under it the process exits 0 for an
OFFLINE_REVIEW run when every reason in the report’s review_reasons is in the list, and
with the report’s exit_code otherwise. The report is unchanged by it: its status stays
OFFLINE_REVIEW and its exit_code stays 2. Accepting one reason never accepts another:
accepting registry_entry_verdict_requires_review leaves a run that also holds
trust_registry_root_not_pinned at exit 2. The option never changes exit 1, 3, 4, 5 or
64. threat-model.md §10 states what an operator takes on by using it. No
other option changes a process exit, and without this one the process exit equals the report’s
exit_code.
4.1 Command-line grammar
A command line that implements this contract takes the elements below. It MAY add options of its own, such as a choice of output format, under the same rules.
| element | form | occurrences |
|---|---|---|
| the bundle | one path, given as a positional argument | exactly one |
--registry-entry |
--registry-entry PATH or --registry-entry=PATH |
at most one |
--trust-registry |
--trust-registry PATH |
at most one, and only with --registry-entry |
--trust-root |
--trust-root PATH, one trust-root document |
at most one, and only with --trust-registry |
--evaluation-time |
--evaluation-time YYYY-MM-DDTHH:MM:SSZ |
at most one, and only with --trust-registry |
--accept-review |
--accept-review REASON[,REASON...] |
at most one |
--asset-type-vocabulary |
--asset-type-vocabulary PATH, one registered vocabulary document of the kind asset_type |
at most one |
--workflow-vocabulary |
--workflow-vocabulary PATH, one registered vocabulary document of the kind workflow |
at most one |
--anchoring-method-vocabulary |
--anchoring-method-vocabulary PATH, one registered vocabulary document of the kind anchoring_method |
at most one |
Every option takes its value in either form, --option VALUE or --option=VALUE. The order of the
elements is free. The invocation is malformed, exit 64 with no report, when:
- an option is given more than once, in either form, whatever its values;
- an option is given by a prefix of its name, such as
--reg, or is not an option the command line defines (--attested-time,--tsa-tokenand--review-zeroare not options of this version); - an option has no value, or its value is empty, the bundle path included: an empty path is a malformed argument, not a path that names nothing;
- the bundle is missing, or more than one is given;
--accept-reviewnames a value that is not a review reason, or holds an empty element or the same reason twice;- a dependency of the table does not hold, or a condition of §4 above holds.
Included from loquitur-protocol/docs/specification/report-contract.md, section 4. CC BY 4.0.
A gate that passes only on PASS
This step verifies a bundle with every check, keeps the report, and lets the job continue only on
exit code 0. REVIEW, exit 2, stops the job as well: it means a question was not answered,
and the report’s review_reasons says which.
set +eloquitur-verify "$BUNDLE" \ --registry-entry "$REGISTRY_ENTRY" \ --trust-registry "$TRUST_REGISTRY" \ --trust-root "$TRUST_ROOT" \ --evaluation-time "$EVALUATION_TIME" \ --json > report.jsoncode=$?set -ecase "$code" in 0) echo "verified: PASS" ;; 2) echo "not verified: REVIEW, see review_reasons in report.json"; exit 1 ;; *) echo "not verified: exit code $code, see report.json"; exit 1 ;;esacWith exit 64 the command line was wrong and report.json is empty.
EVALUATION_TIME is a time your pipeline chooses, such as the start of the job, in the form
YYYY-MM-DDTHH:MM:SSZ; the verifier never takes it from the evidence. TRUST_ROOT is a trust-root
document your organisation obtained out of band, never one shipped with the bundle
(trust-root.md section 7).
Accepting a named review reason
If your process accepts a particular review reason, name it with --accept-review. The run then
exits 0 when every review reason it has is in the list; the report still says OFFLINE_REVIEW.
Keep the report, and read section 10 of the threat model first:
accepting a reason moves its risk to you.
Project site: loquitur.dev
Written for this site; text licensed CC BY 4.0. Included sections keep the licence of their source, named under each.