Repository navigation
core: let a check read a subject that is one object by its name #244
Description
Steps
-
core: list the subjects in the report(core: list the subjects in the report #245) -
core: call the word after as an alias, in messages, the spec and the docs(core: call the word after as an alias, in messages, the spec and the docs #246) -
core: let a subject declare parts with has:(core: let a subject declare parts with has: #247) -
core: tag each input read through a part with the part's alias and id
Policies on Kosli trails repeat long paths. Every attestation sits at compliance_status.attestations_statuses.<name>.attestation_data, and many checks compare fields from two attestations. pr-reviewer's review-controls policy, moved to sentences in kosli-dev/pr-reviewer#491, builds these paths with Rego helpers. Written as YAML, a check looks like this:
every_hunk_acknowledged: compliance_status.attestations_statuses.coverage-verification.attestation_data.hunks_acknowledged equals compliance_status.attestations_statuses.coverage-verification.attestation_data.hunks_totalIdea
A subject can stand for one object, like one attestation, and a check reads it by its name. With this input:
{"trail": {"name": "pr-491-r1", "compliance_status": {"attestations_statuses": {
"coverage-verification": {"attestation_data": {"hunks_total": 25, "hunks_acknowledged": 25}},
"findings": {"attestation_data": {"truncated": false}}
}}}}the policy could say:
subjects:
round:
from: trail
identified_by: name
coverage:
from: round.compliance_status.attestations_statuses.coverage-verification.attestation_data
findings:
from: round.compliance_status.attestations_statuses.findings.attestation_data
requirements:
review_round:
subject: round
checks:
every_hunk_acknowledged: coverage.hunks_acknowledged equals coverage.hunks_total
findings_complete: findings.truncated is falseand a row would name its inputs coverage.hunks_acknowledged and coverage.hunks_total.
ergo half-does this already: a chained subject's checks read their parent by name, like artifact.name (subjects.chain). This would let a check read any subject that's one object, not only its parent, so the long path is written once, in that subject's from.
To decide
- Which subjects can be read this way. Only one that's a single object? One whose
fromleads to a list would have several values, which a plain path can't stand for. - Missing,
nullor not an object. A check that readscoverage.xwhen the coverage attestation isn't there should fail asabsent,nullorunusable, like any path, and never pass. - Where it's read from. In the example,
coveragestarts fromround, so each round reads its own coverage. A subject that starts from the input would be the same for every row. - Names. A subject's name and a field of the subject can clash. Chains already say the subject wins, and this would follow the same rule.
- The report. Inputs named
coverage.hunks_totalread well, but a reader also needs to know wherecoveragecomes from. The subject'sfromis in the policy, and the report could repeat it.
Two other ways were considered:
- a separate section of named path prefixes: it does nearly the same thing as subjects, as a second concept
- words specific to Kosli, like
attestation "coverage-verification": it would tie ergo's grammar to one product
Activity
jbpros commentedon Oct 17, 2026
Decided (2026-10-17): the first idea, letting a check read another subject by name, runs into #210 whenever that subject doesn't come from the one being checked. Instead, a subject declares parts, paths inside it, under
has::coverage.hunks_totalmeans that path inside the round being checked. With this input:{"trail": {"name": "r1", "compliance_status": {"attestations_statuses": { "coverage-verification": {"attestation_data": {"hunks_total": 25, "hunks_acknowledged": 25}}}}}}the check passes, exactly as it would with the full paths written out.
has:in the policy, part for what it declares, in the report and the docs. Alias for a word that stands for something longer, everywhere: in the docs, the spec, the ABNF and the messages. That covers the word afterason aforline, a part's key, and a chained subject's parent. The ABNF rulenamebecomesalias, andname given twiceandunknown name <word>becomealias given twiceandunknown alias <word>..empty, still only marks a field named like a grammar word. It doesn't get around an alias: rename the alias instead.from: round whose …, keeps its parts and can add its own. A kept part's alias given again is written wrong.artifact.pr_attestation.approvers, and afromline can start from a parent's part. A part is only reached through its subject:pr_attestationalone means nothing outside the subject that has it. With core: descend from a subject that has several subjects #210, this works per parent.passed,causeand values. Only the names in expressions and inputs differ. So a missing,nullor wrong-typed part gives whatever the full path gives today. A test swaps every part's alias for its path in the spec cases' policies and compares the rows. This doesn't apply toforaliases, which stand for each item in turn.subjectssection, with one entry for each subject a requirement uses, directly or as one it narrows or descends from. Each entry hasdescription,fromandidentified_byprinted as sentences, and every part with its path,{}when there are none. Each requirement entry says which subject it checks with"subject". This changes every report.jbpros commentedon Oct 17, 2026
Decided (2026-10-17): a part can have an id, so a row says which attestation it read. Peter asked for this, and it's what #34 did with
labelson selectors.A part is written in either of two ways, as a subject is. It's one line when it has no id, and it has
fromand an optionalidentified_byunder it when it has one:With this input:
{"trail": {"name": "pr-491-r1", "compliance_status": {"attestations_statuses": { "coverage-verification": {"attestation_id": "att-7", "attestation_data": {"hunks_total": 25, "hunks_acknowledged": 25}}, "findings": {"attestation_data": {"truncated": false}}}}}}an input read through
coveragecarries the part's alias and id:{"name": "coverage.attestation_data.hunks_total", "value": 25, "part": {"name": "coverage", "id": "att-7"}}A row that compares two parts names both attestations, which a subject's id can't do. The id never changes whether a check passes or its cause, and a missing id is
null. The swap rule still holds, because swapping the alias for its path gives the same passed, cause and values, and only names and theparttag differ.The plan gets a fourth step: #245 lists the subjects in the report, then the alias rename, then
has:with both forms printed in thesubjectssection, then theparttag on inputs.core: list the subjects in the report (#245)
core: call the word after as an alias, in messages, the spec and the …
core: let a subject declare parts with has: (#247)