Show what enforces a control
controls on a rule reads rule-first everywhere else. You write a rule
and say what it is for, and every decision it makes carries those
identifiers onto the audit record. A reader asking the question the
other way round, “what enforces sa-pdpl:art-11 here”, has to go
looking through the document for it.
kirto-gate controls is that inversion. One row per identifier, with every
rule that names it, where those rules run, and what they apply to.
Read the ledger
Section titled “Read the ledger”Point it at the same file the gateway reads:
$ kirto-gate controls -config kirto-gate.yamlsa-pdpl:art-11 NOTHING ENFORCES IT access_rules at llm "dead-claim" deny, where route is embeddings never runs: "exempt" allows every request it would match; the controls it carries (sa-pdpl:art-11) are never recorded
sa-pdpl:art-29 guardrails "mask-email" redact, on every request, turning on annotations
sa-pdpl (Saudi Personal Data Protection Law): this document cites 2 controls, and no rule here names these sa-pdpl:art-19 The controller takes organisational, administrative and technical measures to protect personal data, including during its transfer (Article 19).It reads the document and nothing else. No listener, no raft log, no
provider contacted, so it belongs in a pipeline. A ${secret:NAME} the
cluster holds has a value stood in for it, as in
kirto-gate check.
What each part is claiming
Section titled “What each part is claiming”The clause after a rule is what that rule applies to, and it is answered only on the paths the document holds: the route labels, the declared providers, the profiles, the fronted servers and agents. Those are resolved before any rule runs, so the document settles them.
turning on names what the rule still depends on that the document
does not hold: a key’s metadata, who the agent is, what a client sent,
what the detectors found. Those are the request’s to answer, and the
ledger leaves them named rather than guessing.
That is why no line says a control is enforced. What the command can say exactly is the negative, and the negative is the half people get wrong.
The two exact answers
Section titled “The two exact answers”A control cited only by rules that never run is a claim with nothing behind it. The rule is in the document, its identifier is in the document, and no audit record will ever carry it, because an earlier rule takes every request it would have acted on. That exits non-zero, so a pipeline can hold a change on it.
A control a pack declares that no rule here names is the second. It is reported for every pack this document draws on, meaning every pack whose controls some rule still cites, and it does not change the exit status: removing a rule a pack brought is a decision an operator is allowed to make. A pack the deployment never added is not a gap and is not listed. Neither is a control the pack maps to a mechanism rather than to a rule, since no rule was ever going to carry it.
Hand it to something other than a person
Section titled “Hand it to something other than a person”-json writes the same rows, with the applies-to as data rather than
as a clause:
$ kirto-gate controls -config kirto-gate.yaml -json > controls.jsonEach control carries its citations, each citation carries applies
(the paths and values), open (what it still turns on) and dead
(empty where the rule runs). uncited carries the pack gaps. The exit
status is the same in either format.
What it does not answer
Section titled “What it does not answer”Which keys exist. Keys live in the store, not the document, so a rule
that applies to key.metadata.team == "finance" is reported as turning
on key.metadata whether or not any key carries that. An offline read
of a file cannot say otherwise, and a ledger that implied it could
would be worse than one that says nothing.
Whether the rule is the right rule. The ledger says a rule names a control and what that rule applies to. Whether that rule is what the regime asks for is the reading a person does, which is why the packs carry the citation alongside each control.