Repository navigation
Releases
Ergo spec 0.5
New
- Every failed row has a
message, a line of plain text that says what Ergo found, never what the check expected:approver is "ana", and author is "ana",item 2 of tests: ok is falseorsigned: signature is missing; reviewed: reviewer is missing. message.row and the rules after it say how each cause, value, list,forline andany_ofoption is written, and how aforitem is named, with or without its alias (message.alias). A row that passed has none. - A violation carries the
messageof its row. - A path on the right side of
is one of,is not one of,contains,does not contain,contains all of,contains none of,contains some of,does not contain all of,matchesanddoes not matchwalks lists the way a path aftereverydoes (walk.right):pin is in $input.sbom.components.namecomparespinwith the names of the components. The right side is listed as$input.sbom.components[].name, and a list it can't read from every item fails every row, with the cause and wordseveryuses. A leading dot on that path reads the subject's field, and a message and an input name keep the dot only when a part, a parent subject or an alias has the same first name. A field that is on both sides of a phrase is said once in the message. - A message that repeats an earlier one in its row is left out, a
forline over a part whosewhoseleaves no item prints the part's list, aforitem that isn't an object readsitem 2 of commits is null, which isn't an object, within an item, the items of a list under it come before a part that couldn't be read, a sentence on aforline over two lists that walks another list gives each of that list's items its own part, and aforline whose sentence reads a param that isn't a list prints the list it read, or the check followed byis false(message.join, message.empty, message.items). - A
count of, asum ofor awhosethat reads an item that isn't an object names it,item 2 of commits is null, which isn't an object, and an alias or a part is named without a$(message.items, message.alias). A value or a key that spells an alias, like"$z: x", prints as the input had it. - A
$min_subjectsrow that failed because afromline couldn't be read names where the read stopped,item 2 of things is missingorws is missingfor a child subject, without the parent's name (message.from). thatpicks items by the value itself, wherewhosepicks them by a field:from: every ws that starts with "b"(sentence.condition.word). It works whereverwhosedoes, on afromline, in a check and on aforline. A field calledthatis written.that. On afromline the$appliesrow names the item by the subject's plain name, in itsinputsand its message, and itsexpressionwrites the name in quotes when it has a space or is a word of the grammar, and in a check athatnames a list it walks as awhosedoes (sentence.that.name).distinctafterevery,some,count oforsum ofdrops an item whose value equals an earlier one's, by deep JSON equality, so1and1.0are the same (sentence.distinct). Its scope is the value its path points at, so aneveryorsomephrase withdistinctthat reads another field of the item is written wrong (sentence.distinct.place). A failed item lists the location of every copy when the read goes through the subject, and a direct$inputpath lists its own location.- A path that reads inside an
every,someorforalias that isn't an object and names its key by a field, likew.k named by zzwithwa list, endsnot_an_objectwhateverzzholds, andw named by zzwithwholding3ends as the field says:absent,nullorunusablewhenzzis missing,nullor not text, andnot_an_objectwhen it is text. A list alias read by a position, likew[0] named by zz, is read as a list (path.field_step). A tie in the second list of aforline names the second item's key (message.cause). Cases cover all three. - A
fromline whosenamed by each oflist starts anywhere but$paramsor$input, liket named by each of t.keyswithta parent subject,keysor.keys, is written wrong, and$well_formedlistsnamed by each of takes a list from $params or $input, so it can't start at a field or a subjectundersubjects.<name>.from(subjects.keyed.list). Nothing is read from it, so the subject has no other rows. - A list in a list that no step separates from the list around it, like
x[0]orx[0][0], is nameditin a message:item 1 of x: item 1 of it is 1, which isn't an object(message.items). A count of a key read from a field names the value once,x.k is 1, which isn't a list or an object. - A
named byfield that can't be read, missing,nullor not a string, never lets a check pass,does not existincluded, whatever the path before it holds, the path being missing among them:x[0] named by zz does not existwith noxand nozzfails asabsent(path.field_step). - A check whose path into params that aren't an object stops on them names them in its message:
$params is 3, which isn't an objectfor$params.a is 1,zz is in $params.aand$params.a named by zz is 1,$params is 3, which isn't a listwhen the path starts with a position, likeevery $params[0].a is 1, anditem 1 of $params is 3, which isn't an objectwhen the position is there and the key after it isn't. It never says the check is false. A walk or a count that readsnullparams, likeevery $params.a is 1orcount of $params.a is 1, fails asabsentwith$params is missing, as a plain path does (path.start). A report that changes for a policy that reads such params has a new message, and for those walks and counts a new cause. The same goes for aforline over them, likefor: every $params as p, a sentence of aforline, anamed bykey and awhosethat read them, and asum ofor acount of ... whoseover params that are a list, and$params existsand$params does not existwithnullparams fail asabsent. A subject'sfromline that reads them, likethings named by each of $params.ks, makes no subjects, and its$min_subjectsrow fails asunusableand names them in the same way, where it failed asabsentand said$params.ks is missing. A check that reads them whole, likex is in $params, or reads a value that is there, says what it says with any params. Cases cover each. - A path from
$inputor$paramson the right ofcontainsoris inis named after the left side when both can't be read,zz is "v", which isn't a list, and $input.y is 3, which isn't an object, and a field of the subject there is named first,y is 3, which isn't an object, and zz is "v", which isn't a list. Acount ofthrough a position names the item once,item 1 of y: v is 1, which isn't a list or an object, andid is in $input[0].idwith the input[{"id": "a"}]says$input[0].id is "a", which isn't a list(message.cause). Cases cover each.
Changed
- A bare field called
distinctis written wrong, and.distinctreads it. Reports of a policy with such a field now fail$well_formed. - Reports change: the report's
ergosaysv0.5, every failed row has a newmessagefield, and so does every violation. The report schema allows it. Nothing else in a report changes, except that a path on the right side of those phrases that goes through a list of objects used to fail every row asunusablewith no message that said why, and now compares with the list it reads or fails with the cause and message of the item that can't be read, and that a$inputor$paramspath that reads into text, like$input.a.bwithatext, now says$input.a is "x", which isn't an object. - Every condition in a
whosechain starts with its ownwhoseorthat, after eachand:deployments whose environment is "prod" and whose change_type is "emergency". A line written the old way,whose a is 1 and b is 2, is written wrong. Reports of policies that usewhosewithandchange that way, since they now fail$well_formeduntil the policy is changed. Their problem readsa condition after and starts with whose or that. Other reports change in a few places:whose a and whose bused to fail withdoesn't parseand ...
Ergo CLI and Rust engine 0.3.0
New
-
Every failed row has a
message, a line that says in plain words what Ergo found, as the spec says:approver is "ana", and author is "ana",item 2 of tests: ok is missingorsigned: signature is missing; reviewed: reviewer is missing. A row that passed has none. Each violation carries the message of its row. The Rego engine writes the same text for every case in the spec. -
A path on the right side of
is one of,contains,matchesand the other phrases that take a list walks lists, as the spec says, from the input, the params, the subject, a parent, a part or an alias and insidewhose,count of,sum ofandforlines:pin is in $input.sbom.components.namecomparespinwith the names of the components. A list it can't read from every item fails every row, with the cause and wordseveryuses. A leading dot on that path reads the subject's field, and a message and an input name keep the dot only when a part, a parent subject or an alias has the same first name. A$inputpath or a field on the right that reads into text now says which value can't hold the next step, where it saidthe check is false. A position after a key, likeid is in $input.l[0], fails every row asunusablewhen an item holds a value that isn't a list there, and the message names it,item 2 of $input: l is "ab", which isn't a list, where it read the position asnulland a row could pass on the other items. -
thatpicks items by the value itself, wherewhosepicks them by a field, as the spec says:from: every ws that starts with "b". It works on afromline, in a check and on aforline, and a field calledthatis written.that. -
distinctdrops exact copies afterevery,some,count ofandsum of, as the spec says, and a bare field calleddistinctis written.distinct.
Changed
ergoreads YAML the way OPA 1.21 and later do, and no longer the way OPA 1.20 does.ergo.regois tested with OPA 1.22.0, which reads YAML the same way as 1.21. Reports change for YAML inputs, policies and params that use any of these:- Values that read differently:
yes,no,on,off,yandn(in any of their spellings) are strings, as values and as keys, where they were booleans. Withapproved: yes,approved is trueused to pass and now fails asunusablewithapproved is "yes", which isn't true or false, as inergo.rego. A key written in a mapping wins over a merged one wherever the<<is, and the first of several merges wins, where the later one did. A date tagged!!timestampis written out in full, like2001-12-14T00:00:00Z, where it kept its text. - Files that were refused and are now read: a tag YAML doesn't define on a value, like
!custom 5, which keeps the text,"5"; a bare!, which reads a plain value as if it had no tag, so! 5is 5 and! .inf: 1is{".inf": 1}; a verbatim tag like!<tag:yaml.org,2002:int> 5;!!merge; a key from 9223372036854775808 to 18446744073709551615; and%YAML 01.1or%YAML 1.01. - Files that were read and are now refused: a later document that isn't valid YAML, has an alias with no anchor, nests more than 10,000 levels or says
%YAML 1.2after...; a directive other than%YAMLand%TAG, like%FOO bar; the same alias twice as a key of one mapping, compared by the anchor's name; a!!timestampkey; a!!timestampwhose time zone is 24 hours or more; and!!bool yesand!!bool on. These are refused too, where OPA reads them: a directive inside a document with no...before it, likea: 1,%YAML 1.1,---andb: 2on four lines, which OPA reads as{"a": 1}; a byte order mark right after---at the start of a later document; and flow collections nested more than 255 levels in a later document. CLI.md lists them.
- Values that read differently:
- The message of a
$min_subjectsrow that failed because afromline couldn't be read is the same asergo.rego's for every shape inspec/cases/messages:item 2 of things is missing, and for a child subject the path as it walks its parent's value, without the parent's name, likews is missing,item 1 of ws is missingormeta.owner is missing. - A
whosein afromline that compares a field of the item with itself, likethings whose x is xort.ws whose t.lo is at most .t.lo, is written wrong,whose: x is compared with itself, as inergo.rego. A left side that names a parent, liket.ws whose t.lo is at least t.lo, reads the item's own field, and the right side reads the parent only when it has no dot, so that one is fine. - When a child's parent has a
fromline that fails on anamed bykey or onlast of, awhoseof the child that compares or tests membership against a subject further up, likew.kids whose lo is at least t.cov.x, adds the problemsubjects.g.from: unknown alias $t, listed after the other problems, asergo.regodoes. The same goes for a parent written wrong by awhosethat compares a field with itself, where acontainson the right is reported too. It isn't reported when the parent'sfromhaseveryornamed by each of, when the right side is acount of, asum of, aplus,contains,matchesorcontains all of, or when the name starts with a dot. The child'sfromis<invalid from>in the report'ssubjects, as in Rego. For a parent written wrong by a self-comparison,matcheson the right isn't reported, and Rego does report it. The policy fails$well_formedeither way.named by one, whereoneis a word of the grammar, gives onlyone can't be an alias. - A comparison whose right side can't be read through something that isn't an object, like
lo is at least t.cov.xwitht.cov5 andlotrue, names the left side too when it isn't a number:t.cov is 5, which isn't an object, and lo is true, which isn't a number. - In an
any_of, an input that reads the same path as a part of the check carries the part'sparttag, likeergo.rego:has: {cv: "name"}withname existsin one option andcv is 1in another. - On the left of a
whoseand aftersorted by, the subject's name is the item's field, in a check, aforline and afromline, as the spec says, sofrom: every ws whose w starts with "b", for a subject calledw, reads each item'swfield. On the right of awhosethe name reads the subject and.sthe item's field. A field named like the subject or a part, read on the item, is printed with its dot, likeitem 3 of ys: .s is missinganditem 1 of .cov.xs is 1, asergo.regoprints it. - The engine follows spec 0.5, so a policy says
ergo_spec: v0.5. Reports change for every policy: the report'sergosaysv0.5, itsengineversion says0.3.0, and each failed row and each violation has amessage. Every case inspec/casespasses, soknown-failures.txtis empty. The text still differs from the Rego engine's in a few cases that no spec case covers.named by each of t.keys, a list that is a field of a parent, is an open question: the spec doesn't define it and the grammar allows it. Rego never reads it, and says<invalid ref> is missingwhatever the parent holds, and the Rust engine reads the parent's field. Asum ofover a number of more than 15 digits next to a missing value isabsentwithitem 2 of ws: lo is missingin Rego andunusablewithsum of ws.lo needs more than 15 digitsin the Rust engine. For a child subject whose own value isn't an object, Rego saysitem 1 of items: it is 3, ...and the Rust engineitem 1 of items is 3, ..., and Rego looks wrong there. When both sides of a child'swhosename an ancestor, likew is .w within 1 and t.lo is more than t.lo, Rego gives two problems and the Rust engine only the first. Thefromprinted in the report'ssubjectscan differ in a dot,.t.loagainstt.lo, when another subject is broken, as it also does onmainfor valid policies likew.kids whose t contains all of .t.lo. The pass or fail result is the same in all of these. In afromline, awhosethat is a quantified condition isn't checked for comparing a field with itself.unknown alias $tis still missing forw.kids whose .w.lo contains t.lounder a parent withnamed by zz. For an$appliesrow ofis inoris not inwith a path on the right, likew.kids whose .w.lo is in .w.lo, the message and sometimes the cause differ. The Rust engine adds problems that Rego doesn't in some policies with more than one:unknown alias zzandlast of isn't supported yet herenext to anexistsproblem, andcan't build on a subject read from another subject yetnext to Rego'slast ofproblem. An$appliesmessage can name one side more than Rego's, liket.ws whose x is before t.cov.ywitht.cov[1]andxnull. A grandchild oft.ws named by each of $params.keyswithwsa list,nullor a scalar, or with the keys missing or[], gets one row without the key in Rego and a row with it in the Rust engine. On aforline over a path through two lists, likekids.kids, Rego repeats the outer item and the Rust engine printsitem 1 of kids[0].kids: .... Rego has bugs the Rust engine doesn't share:w: t.ws whose meta.owner contains all of twithmeta5 andwhose sum of lo is not t.zz.x and lo is not in tend in aneval_conflict_error, and on aforline over two lists, awhoseorsorted bythat meets an item of the second list that isn't an object can leave the message empty, a key sort that can't be used is named by its value (item 1 of items is missingfor a missinglo), and when two sentences of aforline read the same, likei.k is in $params.landi.k is one of $params.l, Rego lists each failed item initemsonce for each of them. - Every condition after an
andin awhosechain starts with its ownwhoseorthat, asergo.regoreads it, sowhose a is 1 and b is 2is written wrong. Reports of policies written the old way change, because they now fail ...
ergo.rego 0.5.0
New
-
Every failed row has a
message, a line of plain text that says what Ergo found, as spec 0.5 says:approver is "ana", and author is "ana",item 2 of tests: ok is falseorsigned: signature is missing; reviewed: reviewer is missing. A row that passed has none. Each violation carries the message of its row. -
A path on the right side of
is one of,contains,matchesand the other phrases that take a list walks lists, as spec 0.5 says:pin is in $input.sbom.components.namecomparespinwith the names of the components. It works from$input,$params, the subject's fields, a parent, a part or an alias, and insidewhose,count of,sum ofandforlines. A list it can't read from every item fails every row, with the cause and wordseveryuses, and the right side is in$refsor the row'sinputsas$input.sbom.components[].name. A leading dot reads the subject's field. The message and the input name keep the dot only when a part, a parent subject or an alias has the same first name, sox is in .lock.pkgs.namesays.lock.pkgs.name is missingthen, andlock.pkgs.name is missingotherwise, also for an item that isn't an object and in the names of acount ofand asum of. On aforline the message names the item with its alias, and the inputs are sorted by name. A field that is on both sides, liketags contains none of tags, is said once,tags is ["a"], where a message that repeats a clause used to say it twice. No policy that worked changes, except that last one, because a right side that walks a list failed asunusablebefore. -
thatpicks items by the value itself, wherewhosepicks them by a field:from: every ws that starts with "b", as spec 0.5 says. It works whereverwhosedoes, on afromline, in a check and on aforline, and a field calledthatis written.that. -
distinctafterevery,some,count oforsum ofdrops exact copies, as spec 0.5 says:every distinct sbom.componentsmakes one subject of components that are the same,count of distinct commits.author is at least 2counts each author once, andsum of distinct stages.usdadds each different amount once.1and1.0are the same value. A failed item lists the location of every copy when it was read through the subject, andnullis kept as a value. On afromline it goes afterevery. See REFERENCE.md.
Changed
- A bare field called
distinctis written wrong, as spec 0.5 says: write.distinct. Reports of a policy with such a field change, because they now fail$well_formed. - This version follows spec 0.5, so a policy says
ergo_spec: v0.5. Reports change for every policy: the report'sergosaysv0.5, itsengineversion says0.5.0, and each failed row and each violation has amessage. Besides that, a path on the right side of those phrases that goes through a list of objects used to fail every row asunusablewithit is in $input.sbom.components.name is false, and now compares or says what couldn't be read, and a$inputor$paramspath that reads into text says which value can't hold the next step. - Every condition after an
andin awhosechain starts with its ownwhoseorthat, as spec 0.5 says, sowhose a is 1 and b is 2is written wrong and becomeswhose a is 1 and whose b is 2. Reports of policies written the old way change, because they now fail$well_formed. Their problem readsa condition after and starts with whose or that. Other reports change in a few places:whose a and whose bused to fail withdoesn't parseand now reads,a is a word of the grammar: write .awhenais a word of the grammar, a field calledthatmust be written.that, awhoseorthatin the wrong place names the word that was written, and aforline with awhoseand athatgets the same cause in either order. On afromline, the$appliesrow of athatnames the item by the subject's plain name, so a subject calleditemgivesitem is "apple"where it gave.item is "apple", and a subject calledmy wgivesmy w is "apple"where it gave"my w" is "apple". itis gone, and the subject's name takes its place, as spec 0.5 says. With subjectregion,region is one of $params.allowed_regionschecks each region string, andevery tags is a stringchecks a subject that is a list. The name reads the subject on the right side of a phrase too, sosome $input.deps whose name is lib existscompares each dependency'snamewith the subjectlib. Nothing can follow the name:lib.name is 1is written wrong, withlib.name: nothing can follow lib, which means the subject: for a field called lib, write .lib.name, andnamed by libwithnamed by lib: lib is the whole subject, so it can't name a key. A field called like the subject is written with a dot,.lib. A name with a space, or one that is a word of the grammar likeitem, goes in double quotes, as in"production deployment" is an object.itis an ordinary word, so a subject, a field, an alias or a part can be calledit. Reports change for every policy that wroteit: it now reads a field calledit, or fails with a missing field, until it names the subject. They change for plain names too, because a row that read a value that isn't an object names the subject by its name,deployment is "str", which isn't an object, where it saidit is "str", which isn't an object, and because a row'sinputsname a subject that is a list or a value by its name, and a field named like the subject with a dot,.lib. See REFERENCE.md.ergo.as_sentencesno longer writes a check with an empty path,[], asit is "x". It leaves the check as it was, and it is written wrong: write the check with the subject's name.- A message no longer says
the subject is ..., and names the subject or where a read starts instead. Aforline on a subject that isn't an object names it,thing is 3, which isn't an object. Aforline'swhosethat meets an item that isn't an object names the item without a colon,item 1 of xs is 1, which isn't an object, where it saiditem 1 of xs: it is 1, which isn't an object. An$appliesrow on an item that isn't an object names the subject,t is 3, which isn't an object, and a$min_subjectsrow whosefromstops before its first step names where it starts,$input is null, or the parent subject,artifact is "x", which isn't a list or an object. A child subject read from an item of its parent names the parent,item 1 of p is missing, where it saiditem 1 of $input is missing. Reports of plain policies change in those messages. - The subject's name followed by brackets,
s[0], is written wrong like any other step, and the problem sayswrite .s[0]for a field calleds.first of sanditem 2 of sread an item of a subject that is a list. Follows spec 0.5. - On the left of a
whoseand aftersorted by, the subject's name is the item's field, like any bare word there, in a check, aforline and afromline, as spec 0.5 says. Sofrom: every ws whose w starts with "b", for a subject calledw, reads each item'swfield, where it read the item itself, and a quoted word of the grammar there, like"item", is a field too. On the right of awhosethe name reads the subject and.sthe item's field, socount of $input.ys whose k is s is 1compares eachkwith the subject, where it compared it with the item's owns. A row that reads a field named like the subject or a part prints it with its dot, like.kid is missinganditem 1 of .cov.xs is 1.count of "my rel"[0] is 1is written wrong withwrite ."my rel"[0], ascount of rel[0]is. Reports change for policies that write the subject's name in awhoseor aftersorted by, or read a field named like the subject or a part.
Fixed
- A
fromline whosenamed by each oflist starts at a field or a subject, liket named by each of t.keys, is written wrong, as spec 0.5 says, where it read<invalid ref> is missingwhatever the field held. Its$well_formedrow listsnamed by each of takes a list from $params or $input, so it can't start at a field or a subject, and the subject has no other rows. - A
foritem that isn't an object no longer stops the report witheval_conflict_errorwhen a path reads inside it and names its key by a field, likew.k named by zzwithwa list, orw[1] named by zzandw[0].a named by zzwithwa list: the check fails with the cause the spec gives. Reports change for checks that read such a path and used to fail asnot_an_objectbecause the key field was bad. Withfor: every ws as w,assert: w named by zz is 1and input{"things": [{"id": "a", "ws": [3]}]}(nozz), the row saiditem 1 of ws is 3, which isn't an objectwith causenot_an_object, and saysitem 1 of ws: zz is missingwith causeabsent. Azzthat isnullor not text givesnullorunusablethe same way. Withassert: w[0] named by zz is 1and{"ws": [[{"a": 1}]]},not_an_objectbecameabsent, and with"zz": 3it isunusable.w[0] named by zz does not existwith{"ws": [[1]], "zz": "a"}failed asnot_an_objectbefore and now passes, asw[0].a does not existalready did. - A path that starts at a
foralias holding a list and reads a position first, likew[0].a does not existorw[0] named by zz is 1withfor: every ws as w, now reads the alias as a list, as spec 0.5 says.w[0].a does not existfails asunusablewhen the item at that position is a number or text, where it passed.w[0] named by zz is 1andw[0] named by zz does not existfail asunusablewhen the alias is a number (they saidnot_an_object) or when the item at that position is a number (they saidabsentor passed). `w[0] named b...
Ergo spec 0.4
New
- Every phrase that lacked an opposite has one:
does not start withanddoes not end with(sentence.phrase.starts),is not a <type>andis not a non-empty string(sentence.phrase.type),is not between(sentence.phrase.between),is not <value> within <number>anddoes not equal <field> within <number>(sentence.phrase.within), andcontains some ofanddoes not contain all of(sentence.phrase.contains_all).is alphabetically on or beforeandis alphabetically on or afterjoin the alphabetical phrases (sentence.phrase.alphabetical). Each one fails as the phrase it is the opposite of does when a field is missing,nullor of the wrong type, so it never passes by reading nothing. They read intolacks_type,not_non_empty_string,outside_range,includes_someandnot_includes_all, and into the newnot_starts_with,not_ends_with,alphabetically_lteandalphabetically_gtecomparisons, andcomparewithnetakes awithin(compare.within). A sentence that was written wrong before, likex is not 3 within 1orcount of x is not 3 within 1, now reads, and so doesis not ... withinafter acount of, asum of, aplusor an elapsed time. Only sentences that did not read before change: a policy that was written wrong because of one now reads and gets rows. - Text can be joined on the right side with
followed by, likerego.version is tag.version followed by "-dev"(sentence.operand.followed_by, compare.join). It takes written strings and fields, any number of them, and goes afteris,is not,starts with,ends with, their negatives,contains,does not containand the alphabetical phrases. Every piece must be a string: a written one that isn't is written wrong, and a field that isn't one fails asunusable. The first piece that can't be read decides the cause, before the left side does. It is written wrong afterwithin, the order and time phrases, a count and a plus, and whereplusisn't run yet: aftereveryorsome, in awhoseand in afromline. A sentence withfollowed bywas not readable before, so no report changes.
Changed
- In a comparison of plain paths and written values, and in the pieces of
followed by, a path that names its key by a field, likem named by p, lists the field in the row'sinputsright after the entry of the path, som named by p is qshowsm named by p,p,q(path.field_step).ergo.regolisted the field after every other entry, so it showedm named by p,q,p. The Rust engine already listed it this way. The same goes for acount of, asum of, an elapsed time, aplus, aneveryand asome, and the check of aforline lists the field among its entries sorted by name. Reports change for such checks that read another path after the one with the field step. - The steps of a path before a field step are read first, and when they can't be read the path ends as they do, whatever the field holds (path.field_step):
$params.m named by p is qwith nomin the params isabsentwhenpisnull.ergo.regoread the field first, so it wasnull, and both engines did so for aneveryorsome. Soevery zz.x named by p is 1withzzmissing or a string isabsentorunusablewhenpisnull, whereergo.regoand the Rust engine saidnull. A list before the field in anevery,some,count of,sum ofor aforline is walked, not read, so there the field still decides, as before:every rows.w named by k is "xy"isnullwhenkis. Anullbefore the value the field picks from ends such a walknullwhatever the field holds, as the walk does without the field: withrowsnull,every rows.w named by k is "xy"isnullwhenkis missing or a number, where both engines saidabsentorunusable, and itsfailed_itemsnamesrows, where it was empty whenkcouldn't be read. Where nothing walks it, a list before the field ends the pathunusable:rows.w named by p is "xy"withrowsa list isunusablewhateverpholds, whereergo.regogave the cause ofp. The Rust engine already saidunusable. - A report's
enginename isergo-and the engine, likeergo-regoorergo-rust, so a name and version match a release tag likerego-v0.3.0(report.engine). The Rego engine saidergo.regoand the Rust engineergo-policy-engine. A policy saysergo_spec: v0.4, and the report'sergochanges to match. The schemas are underhttps://ergo.kosli.com/spec/0.4/. Reports change inengineonly, and a report's hash leavesengineout, so hashes stay the same. - added.text now says that a
fromthat starts at the input with anamed bystep, likeevery $input named by $params.k, is written as it is, whatever follows it, in the$min_subjectsand$unique_idsexpressions. subjects.every_narrowed says that a subject narrowing a subject read witheverytakes that subject's flat list and filters it. name.dot says that an input that reads the item's own field named like a parent subject keeps its., like.art.k, in a check, aforline and thewhoseof afromline, ininputs, infailed_itemsand in thefromthe report gives, with a position after the dot, likeitem 1 of .art.xs. Reports change for such policies: the expressions werecount(matching(every ))andcount(matching(artifacts.releases))inergo.rego, a subject narrowing aneverysubject had none of its subjects, and the input was namedart.k. - A policy with no requirement to hold the
$well_formedrow, becauserequirementsis missing,null, not an object or empty, gets a requirement of Ergo's own,$policy, with one failing$well_formedrow that says what is wrong, likerequirementswith["missing"]orpolicy ergo_specwith["unsupported version v9.9, expected v0.4"](policy.no_requirements). Its subject is{"type": "$policy", "id": "$policy"}. The violations list that row, where they were empty for such a policy whilecompliantwasfalse. Reports change for such policies: they had no requirement and no row. The report schema says$policycan be a subject type and id. - A name that starts with
$is written wrong, whether it names a subject, a requirement, a check, anany_ofoption or a part, witha name can't start with $(names.dollar). It replacesname reserved, which only a check named like one of Ergo's own rows got,a subject can't be named $inputand$params,invalid aliasfor a part called$dollar, and the$policyrule above. A$after the first character stays fine, and so do$inputand$paramsat the start of a path. A check with such a name has no entry inrequirements. Reports change for such policies: a name like$xwas read before, and showed quoted in the report. The Markdown compiler already refused these names with the same words. - A name that starts or ends with a space or an invisible character is written wrong too, with
a name can't start or end with a space or an invisible character(names.edge): any name names.dollar refuses, when its first or last character is Unicode White_Space or has the general category Cf, like" $well_formed","approved "or U+200B followed by$x. Spaces inside a name and a full-width$xstay fine. Reports change for such policies: a name like"approved "was read before. - names.empty says that an empty name,
"", is written wrong too, whether it names a requirement, a check, anany_ofoption or a part, witha name can't be empty. Reports change for such policies: a""was read before. - written_wrong.row now says what "sorted by name" means for a name that needs quoting. The
$well_formedrow lists the problems of fields, parts and checks sorted by name as the report writes it, quotes and escapes included, by code point. Reports change for such names: the Rego engine sorted parts by the raw name and the Rust engine ignored quotes, and the order of a part like"x y"changes. Arequirethat is written wrong is listed second, where the Rego engine listed it among the other fields. The requirement's own fields come first, then the subject's, then the checks, each group sorted, as the Rego engine had it. - [name.dot](https://github.com/kosli-dev/ergo/blob/spec-v0.4/spec/syntax.md#namin...
Ergo CLI and Rust engine 0.2.0
New
- Every phrase that lacked an opposite has one, as spec 0.4 says:
does not start with,does not end with,is not a <type>,is not a non-empty string,is not between,is not <value> within <number>,does not equal <field> within <number>,contains some ofanddoes not contain all of, plusis alphabetically on or beforeandis alphabetically on or after. The sentence reader'sPhrasehas the variantsNotStartsWith,NotEndsWith,NotType,NotNonEmptyString,ContainsSomeandNotContainsAll,Betweenhas anotfield andAlphabeticallyanor_equalfield. A count, a sum, a plus or an elapsed time can now be followed byis not ... withintoo, which the engine refused before. - Text can be joined on the right side with
followed by, as spec 0.4 says:rego.version is tag.version followed by "-dev". The sentence reader'sOperandhas a new variantJoined, with the pieces in order, andcompareandcontainsread it.
Changed
- A path that names its key by a field lists the field in a row's
inputsfor acount of, asum of, aneveryand asometoo, right after the list's entry, and the check of aforline keeps its whole path,m named by pand thenp, where it showed onlym, as spec 0.4 says. When the path before the field can't be read, aneveryorsomefails with that path's cause, not the field's, soevery zz.x named by p is 1withzzmissing or a string isabsentorunusablewhenpisnull, where it wasnull. A list it walks before the field doesn't count, soevery rows.w named by k is "xy"still fails asnullwhenkisnull. Withrowsnullit fails asnullwhateverkholds, where a missing or numberkgaveabsentorunusable, andfailed_itemsnamesrows, where it was empty whenkcouldn't be read. Aforline whose own path has such a field, likeevery rows.w named by p as w, listsptoo, sorted with the rest by name, asergo.regodoes. Aplusor an elapsed time that reads such a path no longer has the field's location in its own entry, as spec 0.4 says. Reports change for such policies. - The report's
enginename isergo-rust, where it wasergo-policy-engine, so it matches the Rego engine'sergo-regoand therust-v*tag. Every report changes in that field only, and the hash leavesengineout, so hashes stay the same. The version is the same. - The engine follows spec 0.4, so a policy says
ergo_spec: v0.4. - An empty name,
"", is written wrong too, whether it names a requirement, a check, anany_ofoption or a part, witha name can't be empty. - The CLI has its own page,
CLI.md: install, how to run it, its exit codes and how it reads YAML. They were in the README and in this folder's README. - The
$well_formedrow lists the problems of fields, parts and checks sorted by name as the report writes it, quotes and escapes included, by code point, where the quotes were left out, and lists the requirement's own fields first, then the subject's, then the checks. Reports change for names that need quoting and for a requirement with both a field and a subject problem. - An own field named like a part of the subject or like a
foralias keeps its dot in the name of an input, like.cov.pct, and so does the list acount of,sum ofor a walk reads, like.art.xs[]. A policy written wrong keeps the dots it was written with in the expression and infrom: a check whoseforisn't a string, and a part named like one of its parent's. - An input that reads the item's own field named like a parent subject keeps its dot, like
.art.k, as spec 0.4 says. Afromthat starts at the input with anamed bystep is written as it is in the$min_subjectsand$unique_idsexpressions, soevery $input named by $params.kis no longercount(matching(every [$params.k])). Reports change for such policies. Thefroma subject gets insubjectskeeps every dot the policy wrote on the left of awhose, like.art.k,.art.xs[0]or a part's.att.id, where it dropped them. - A policy with no requirement, because
requirementsis missing,null, not an object or empty, gets Ergo's own requirement$policywith a failing$well_formedrow that says what is wrong, as spec 0.4 says, where the report had no row andviolationswas empty whilecompliantwasfalse. A requirement called$policyis written wrong. Reports change for such policies. - A name that starts with
$is written wrong, whether it names a subject, a requirement, a check, anany_ofoption or a part, witha name can't start with $, as spec 0.4 says, in place ofname reserved,a subject can't be named $inputandinvalid aliasfor a part called$dollar. A check with such a name has no entry inrequirements. Reports change for such policies. - A name that starts or ends with a space or an invisible character (Unicode White_Space or general category Cf, like U+200B or U+FEFF) is written wrong too, with
a name can't start or end with a space or an invisible character, as spec 0.4 says, for a subject, a requirement, a check, anany_ofoption and a part. Reports change for such policies. - A key read from
$paramsor$input, afternamed byor in brackets, has to be a string, as spec 0.4 says. A whole number used to read that item of a list, som named by $input.k is 1withkholding1andmholding[5, 1]passed by reading1, andcommits[$params.n]read a commit. It fails asunusablenow, and afromline with such a key gives no subjects. Reports change for such policies. - A
fromline likescans named by $params.env named by each of $params.kgave$min_subjectsthe worst of the causes ofenvandk, so anullenvwithkmissing gaveabsent. The ref before the list decides now, as subjects.sentence says, so that one givesnull. Reports change for such policies, in the cause only.
Fixed
- A check could pass when it should fail. A path named by a
foralias that holds a number read the number as a list position, som named by k is 1underevery ks as kpassed on{"ks": [1], "m": [5, 1]}, by readingm[1]. So did a later item,every ks as k, every m named by k as x, and a one-lineeveryorsomeunder theforline. Aforalias that holds anything but a string now fails asunusable, as for.named_by says, and asergo.regodoes. When the path before it is an object, the failed item is namedm named by k, where it wasitem 4 of mfor a3. Reports change for such policies: some that passed now fail.
ergo.rego 0.4.0
New
- Every phrase that lacked an opposite has one, as spec 0.4 says:
does not start with,does not end with,is not a <type>,is not a non-empty string,is not between,is not <value> within <number>,does not equal <field> within <number>,contains some ofanddoes not contain all of, plusis alphabetically on or beforeandis alphabetically on or after. Each fails as its opposite does when a field is missing,nullor of the wrong type. A sentence likex is not 3 within 1was written wrong before and reads now, after acount of, asum of, aplusor an elapsed time too (count of x is not 3 within 1), and acomparewithnecan have awithin. In a comparison of plain paths and written values, and in the pieces offollowed by, a path that names its key by a field now lists the field right after the path in a row'sinputs, as spec 0.4 says:m named by p is qshowsm named by p,p,q, where it showedm named by p,q,p. So does acount of, asum of, an elapsed time and aplus:count of m named by p is qshowscount of m named by p,m named by p[],p,q, wherepcame last. When the path before the field can't be read, the cause comes from that path and not from the field, so$params.m named by p is qwith nomin the params fails asabsentwhenpisnull, where it failed asnull, androws.w named by p is qwithrowsa list fails asunusable. Anevery,some,count oforsum ofwalks a list before the field, soevery rows.w named by p is qfails as the field says whenrowsis a list. Whenrowsisnull, it now fails asnullwhateverpholds, a missingpincluded, where a missingpfailed asabsent, andfailed_itemsnamesrows, where it was empty whenpcouldn't be read, asevery rows.w.k is qdoes. - Text can be joined on the right side with
followed by, as spec 0.4 says:rego.version is tag.version followed by "-dev",rego.spec is "v" followed by tag.version. It takes written strings and fields. Nothing that read before changes.
Changed
- This version follows spec 0.4, so a policy says
ergo_spec: v0.4, and the report'sergofollows. One that saysv0.3is written wrong, withunsupported version v0.3, expected v0.4. - The report's
enginename isergo-rego, where it wasergo.rego. Every report changes in that field only, and the hash leavesengineout, so hashes stay the same. A compiled policy made by an older copy saysergo.rego, soergo.reportreads it as one from another engine, and the message saysexpected ergo-rego. Compile the policy again. - A
fromthat starts at the input with anamed bystep is written as it is, whatever follows it, in the$min_subjectsand$unique_idsexpressions, soevery $input named by $params.kis no longercount(matching(every )). A subject that narrows a subject read witheverytakes its flat list of subjects and filters it, whereergo.regodropped theeveryand found none. An input that reads the item's own field named like a parent subject keeps its dot, like.art.k. Reports change for such policies. - A policy with no requirement, because
requirementsis missing,null, not an object or empty, gets Ergo's own requirement$policywith a failing$well_formedrow that says what is wrong, where its report had no row andergo.violationsreturned[]whilecompliantwasfalse. A requirement called$policyis written wrong. Reports change for such policies. - A name that starts with
$is written wrong, whether it names a subject, a requirement, a check, anany_ofoption or a part, witha name can't start with $, where only a check named like one of Ergo's own rows was (name reserved),$inputand$paramsas subject names (a subject can't be named $input), and a part called$dollar(invalid alias). Reports change for such policies. A check with such a name has no entry inrequirementsany more. - A name that starts or ends with a space or an invisible character (Unicode White_Space or general category Cf, like U+200B or U+FEFF) is written wrong too, with
a name can't start or end with a space or an invisible character, for a subject, a requirement, a check, anany_ofoption and a part. Reports change for such policies. - An empty name,
"", is written wrong too, whether it names a requirement, a check, anany_ofoption or a part, witha name can't be empty. Reports change for such policies: a""was read before. - The docs are split by engine.
README.mdis short and the same for both engines,OPA.mdholds how to install and runergo.regoand the parts ofREFERENCE.mdthat only it has (OPA, Wasm, numbers,ergo.compile), andREFERENCE.mddescribes only the language. - The
$well_formedrow lists the problems of fields, parts and checks sorted by name as the report writes it, quotes and escapes included, by code point, where parts were sorted by the raw name. Reports change for parts with names that need quoting, and arequirethat is written wrong is listed second in the$well_formedrow. - An own field named like a part of the subject or like a
foralias keeps its dot in the name of an input, like.cov.pct, and so does the list acount of,sum ofor a walk reads, like.art.xs[]. Reports change for such policies: they were namedcov.pctandart.xs[]. Thefailed_itemsof a walk or aforline keep the dot too. - A key read from
$paramsor$input, afternamed byor in brackets, has to be a string, as spec 0.4 says. A number used to read that item of a list, som named by $input.k is 1withkholding1andmholding[5, 1]passed by reading1, andcommits[$params.n]read a commit. It fails asunusablenow, and so does a boolean. An object, a list ornullfailed asabsentin afollowed bypiece, anevery, asome, acount of, asum of, aforline and a field aftersorted byon aforline, and fails asunusable, ornullfornull, now, as it did in a plain comparison. Reports change for such policies. - A
fromline likescans named by $params.env named by each of $params.kgave$min_subjectsthe list's cause when bothenvandkcouldn't be read. The ref before the list decides now, as subjects.sentence says:envholding1or an object givesunusablewhateverkholds. Reports change for such policies, in the cause only.
Fixed
- A
forline whose check reads a path with anamed byfield, likerow.w named by p is "xy"underevery rows as row, stopped the whole report witheval_conflict_errorwhen an item wasn't an object andpwasnullor a number. The row fails asnot_an_objectnow, with the item infailed_items, as in the Rust engine. - A later
foritem whose path is named by an alias of an earlier one, likeevery ks as k, every m named by k as x, failed asabsentwhen the alias held an object, a list, a number ornull. It fails asunusablenow, and asnullwhen the alias holdsnull, as for.named_by says and as the Rust engine does. So doesevery rows as r, every r.xs named by r.k as x, where the key afternamed byis the one wordr, the whole row. Reports change for such policies, in the cause only: none of them passed. some vals is m named by kunderevery ks as kstopped the whole report witheval_conflict_errorwhenkheld anything but a string, and so didevery,is inand the other comparisons where aneveryorsomereads a path named by aforalias on the right. The row fails asunusablenow, or asnullwhen the alias holdsnull, as in the Rust engine. Reports change for such policies: they have rows where there was an error.
ergo.rego 0.3.1
ergo.rego is the same as in 0.3.0 apart from its version, and follows spec 0.3. This release brings the docs up to date with the first release of the Rust engine: README.md says how to install the ergo CLI from crates.io or download it, and calls it the ergo CLI where it meant the command. It also says again how to update ergo.rego.
Ergo spec 0.3
Changed
- A policy says
ergo_spec: v0.3, and the report'sergochanges from"ergo": "v0.2"to"ergo": "v0.3". A policy that saysv0.2is written wrong, withunsupported version v0.2, expected v0.3. The schemas are underhttps://ergo.kosli.com/spec/0.3/. - An implementation may fail a check as
unusablewhen it can't read or compare a number exactly, like one whose exponent is too long to hold (Values). It used to have to compare every number it was given.ergo.regocompares such numbers as before, so its reports don't change. - Whitespace of any kind at either end of a sentence, a
forline or afromline is dropped before it's read, not only spaces: every character with Unicode'sWhite_Spaceproperty, like a tab, a newline or U+3000 (sentence.ends). So a YAML block likeassert: |, which ends in a newline, reads as the sentence it holds.ergo.regoalready read these lines, so no report changes. A byte order mark or a zero-width space at either end still makes a line not read. The same goes for the path of anidentified_byor a part, whichergo.regoalso trimmed already. - min_subjects is now a whole number from 0 to 1,000,000. It used to say a whole number of 0 or more, so engines disagreed on big values. A requirement with a larger
min_subjectsis written wrong, and the message for every wrongmin_subjectsisnot a whole number from 0 to 1000000, where it wasnot a whole number of 0 or more. A number a 64-bit float can't hold still saysnumber out of range. The policy schema has"maximum": 1000000onmin_subjects. Reports change for such policies: a requirement with amin_subjectsover 1,000,000 fails$well_formedand gets no other row, and the$well_formedrow of any wrongmin_subjectsshows the new message. - subjects.keyed.id says that a subject listed by
named by each oftakes its key as its id, so anidentified_byon it is written wrong, withnot allowed with named by each of: the key is the id. Before, subjects.id saididentified_bygave the id, with no exception, andergo.regoignored it and used the key. A report changes only for a policy that has both. - subjects.sentence says a position after another subject's name, like
p[1]orfirst of p, isn't narrowing: it is a child subject that reads the position inside each parent, and subjects.from says afromline witheverywhosenamed bycan't be read keeps its requirement and fails$min_subjectslike one withoutevery. New cases cover both. Reports change for a policy that relied onergo.regodropping the position or losing the requirement.
Fixed
- for.flaws now says that an item of a
forline that isn't an object,nullincluded, fails asnot_an_objectwhen the item's path goes on into it, withsomeand a position too, aseverydoes. It used to say so only for a second item that reads into the first, and the spec didn't say what the other items fail as. for.walk says it too. Reports change for such inputs: withtset to["a"],for: every t.k as xfaileditem 1 of tasunusableand now fails it asnot_an_object.ergo.regoalso failednullitems asabsent, andcount ofandsum ofon anullitem asabsentwhere tally.walk saysnot_an_object. Only the cause changes, not whether a check fails. - tally.whose now says that the path of an item the
whosecan't decide isn't read, so only its cause counts:nullfor anullkandabsentfor a missing one. Cases pin it forsum ofandcount of.ergo.regoread the path anyway, so such a side failed asunusablewhen the value wasn't a number, and asabsentwherekwasnulland the path missing. Reports change for such inputs, in the cause only. - sentence.for.pick now says that an index in brackets doesn't pick, so a
foritem liket[0] as iis written wrong, as the grammar already had it.ergo.regoread it as a position, sot[0] as imeantfirst of t as i, and a second item was read the same way. Reports change for such a policy: the check fails$well_formedand the requirement gets no other row. - A child subject whose parent isn't an object,
nullincluded, fails$min_subjectsasnot_an_object, as subjects.chain.not_an_object now says. The spec didn't say, andergo.regogaveunusablefor a string, number, list or boolean parent andabsentfor anullone. Reports change for such inputs. A parent that is an object without the field still givesabsent. - A
fromline that is a subject's name and thennamed by each of, likeartifact named by each of $params.keys, makes a child subject, as subjects.chain now says. It reads the keys inside each parent, within, and a parent that isn't an object fails$min_subjectsasnot_an_object. A first key with a dot is the input field and never the parent, and the report prints it with its dot when it is named like another subject (sentence.print.canonical), and a position after the parent's name is read as a list and not dropped, so$min_subjectsfails asunusable.ergo.regoread a top-level input field of the parent's name, and dropped such a position. Reports change for such a policy. - The spec now says these things that
ergo.regoalready did, so no report changes:- the
expressionof a check written wrong (sentence.print.written_wrong) - how a number prints in a sentence (sentence.print.numbers)
- that a subject that isn't an object is its own id (subjects.id)
- that
\d,\w,\sand\bin a pattern only know ASCII (patterns.syntax) - that the keys of every object in a report are sorted (report.keys)
- the order of the
inputsof a failed sentence on aforline (for.failure_inputs)
- the
- tally.sum now says when a
sum_ofor anaddfails asunusable: when a number added, or the result, isn't a whole number below 10^15 once scaled by 10^p, where p is the most decimal places any of them has, counted on the value, or when p is above 15. It used to say such sums are added as the runtime adds them, which gave different answers in different runtimes. Reports change for such inputs, like0.123456789012345plus100, which now fails asunusablewith anullentry. - sentence.phrase.within now says the gap is worked out exactly on the decimals, for the numbers Values covers, and that an implementation that can't compare the numbers exactly fails the check as
unusable, as Values says.ergo.regoand the Rust engine do when the exponents of the two sides and thewithinnumber are more than 4096 apart. It used to say nothing, andergo.regoused OPA's arithmetic, which isn't exact. Reports may change for such inputs:x equals y within 0.2on0.3and0.1failed asvalueand now passes. - A
fromline withnamed by each offails$min_subjectswhen the path before it doesn't lead to an object, as subjects.sentence now says: asabsentornullwhen the object is missing ornull, and asunusablewhen it's a list, a string or a number. Each listed key is still a subject, as before, so its checks still show what's missing, but the requirement is never met. A list of keys that holds anything but strings makes no subjects and fails$min_subjectsasunusable. The spec didn't say, andergo.regomet the requirement whenever every check passed, so withfrom: scans named by each of $params.requiredand noscansin the input,x does not existpassed for every key and the policy was compliant. The same holds when a ref step beforenamed by each ofcan't be used, likenamed by $params.envwithenvset to5, which was met too. Reports change for such inputs:$min_subjectsfails and the requirement isnot_met, a key list with a non-string key gives no subject rows, and a child subject of such a paren...
Ergo CLI and Rust engine 0.1.0
New
- The first version of the Rust engine. It follows spec 0.3, so a policy says
ergo_spec: v0.3, and it's experimental: anything in it may still change. ergo-policy-sentencesreads check sentences,forlines,fromlines and paths, without the engine.ergo-policy-enginebuilds the report and the violations from a policy, an input and params, as JSON.ergo-policy-cliis theergocommand, which prints the report or the violations from policy, input and params files in JSON or YAML.ergo-policy-wasmbuilds the report in a browser, from JSON text. It isn't published: it's built from the repository for the editor.ergo-policy-sentences-wasmreads check sentences in a browser, from and to JSON text. It isn't published either: it's built from the repository for the editor.- A
foritem whose path goes on into a list item that isn't an object,nullincluded, fails that item asnot_an_object, aseveryandsomedo, where it failed asunusable.
ergo.rego 0.3.0
Changed
- This version follows spec 0.3, so a policy says
ergo_spec: v0.3. One that saysv0.2is written wrong, withunsupported version v0.2, expected v0.3, and still works with 0.2.0. The report'sergochanges with it, from"ergo": "v0.2"to"ergo": "v0.3". min_subjectsis a whole number from 0 to 1,000,000. A requirement with a larger one, like1000001or1e308, is written wrong, with its$well_formedrow failing and no other row, where beforeergo.regoread any whole number up to what a 64-bit float holds, and rejected some big ones like1e308by accident. The message for every wrongmin_subjects,-1,1.5,"2"and1000001too, is nownot a whole number from 0 to 1000000, where it wasnot a whole number of 0 or more. A number past a float, like1e400, still saysnumber out of range. Reports change for such policies: the$well_formedrow shows the new message.- A subject with an
identified_bywhosefromline usesnamed by each ofis written wrong, withnot allowed with named by each of: the key is the idunderidentified_byin the$well_formedrow, and no other row for its requirements. Before,ergo.regoignored theidentified_byand used the key as the id.
Fixed
- A
sum ofor acount ofwith a path doesn't read the path of an item itswhosecan't decide, so the side fails with thewhose's own cause, as tally.whose says. It read the path and gave the cause of what it found. Withsum of items.x whose k is "a" is 1on{"things": [{"id": "t", "items": [{"x": "ab", "k": null}]}]}, the check now fails asnull, where it failed asunusable. Withkmissing it now givesabsent, and a field that is missing withknullgivesnull, where it gaveabsent. The same goes for a path that goes on, likeitems.x.y, and forcount of items.x whose k is "a": on[{"k": null}]it went fromabsenttonull, andcount of items.x.y whose k is "a" is 1on[{"x": "s", "k": null}]fromunusabletonull. Only the cause changes. - A
forline whose item path goes on into a list item that isn't an object,nullincluded, fails that item asnot_an_object, aseveryandsomedo. It failed asunusable, or asabsentfor anullitem. Withtset to["a"]or[null],for: every t.k as xnow failsitem 1 of tasnot_an_object.count ofandsum offail anullitem asnot_an_objecttoo, where they saidabsent. The same checks fail as before, and only the cause changes, in the row, infailed_itemsand in the requirement's causes. - A
foritem that picks with brackets, liket[0] as i, is written wrong, as the spec says. Before,ergo.regoread the brackets as a position, sot[0] as imeantfirst of t as i. It fails$well_formedwithfor: an item starts with "every", "some" or a position, like "last of", and the requirement gets no other row. The same goes for an item after the first, likeevery t as x, t[0] as i, which used to be read.first of t as iand brackets aftereveryorsome, likeevery t[0].u as i, are read as before. Reports change for a policy that has such an item: with{"things": [{"id": "a", "t": [{"u": [1, 2]}]}]},for: t[0] as iwithassert: i existsused to be satisfied, with the inputitem 1 of t, and is now not met. - A child subject under a parent that isn't an object fails
$min_subjectsasnot_an_object, as the spec now says (subjects.chain.not_an_object). Before, a parent that was a string, a number, a list or a boolean gaveunusable, and anullparent gaveabsent. Reports change for such inputs, like{"trail": {"artifacts": ["x"]}}with a pull request subject fromartifact.pull_requests. The verdict doesn't change, and a parent that is an object without the field still givesabsent. - A
fromline that is another subject's name and thennamed by each of, likeartifact named by each of $params.keys, reads the keys inside each parent subject and puts the parent underin, as the spec says. Before,ergo.regoread a top-level input field with the parent's name, so a check could pass on data the policy never pointed at. A parent that isn't an object fails$min_subjectsasnot_an_object. A first key with a dot, like.artifact named by each of $params.keysor.artifact.p, reads the input field and not the parent, and a position, likeartifact[0] named by each of $params.keys,first of artifact named by each of $params.keysorartifact.x[0] named by each of $params.keys, is no longer dropped: it reads the parent as a list and fails$min_subjectsasunusable. The report prints.artifact.pand.artifact named by each of $params.keyswith their dot, insubjects.<name>.fromand in the$min_subjectsand$unique_idsexpressions, where it printedartifact.p, which reads the parent. A policy with such afromline could pass on data it never pointed at. Reports change for such a policy: with{"artifacts": [{"id": "a1"}], "artifact": {"x": {"ok": true}}}and keys["x"],ok is trueused to pass on/artifact/x/okand now fails asabsentforxina1. - A
sum ofor apluswhose numbers can't all be held as whole numbers below 10^15 at one scale fails asunusable, with its entrynull. The scale is the most decimal places any number added has, counted on the value, and the result counts too. More than 15 decimal places fails too. Before, such a sum fell back to the runtime's own addition, which gave different answers in different runtimes. Reports change for such inputs:x plus y is at least 0on{"x": 0.123456789012345, "y": 100}was satisfied and now fails asunusable, and so does1e20plus1. Sums of ordinary numbers, and numbers with trailing zeros like1.500000000000000000, are added exactly as before. - A
withincheck works out the gap exactly on the decimals, where it used OPA's arithmetic, which isn't exact. That's promised for numbers with at most 15 significant digits, the ones the spec covers. Reports change for such inputs:x equals y within 0.2on{"x": 0.3, "y": 0.1}failed asvalueand is now satisfied, and so is0.1and0.3, whilewithin 0.19999still fails asvalue. A check that passed before still passes, except one whose two sides andwithinnumber have exponents more than 4096 apart, like0and1e-5000within1, which passed and now fails asunusable. - A
fromline withnamed by each offails$min_subjectswhen the object it reads the keys from is missing,nullor not an object, asabsent,nullorunusable, so the requirement isn't met. Each listed key is still a subject and gets its rows, as before. A key that isn't a string makes no subjects and fails$min_subjectsasunusable. Before,from: scans named by each of $params.requiredon an input withoutscansgave one subject per key, so a check likex does not existpassed for each and the policy was compliant. The same holds when a ref step before it can't be used, likescans named by $params.env named by each of $params.requiredwithenvset to5, which used to be met too. A child subject of such a parent gets one$min_subjectsrow with noin, failing with the parent's cause, and one$unique_idsrow with noin, instead of a row per key. - When the input is a list,
from: $input,from: every $inputand aneverywalk that starts at the input, likefrom: every commits, make each item a subject. They failed$min_subjectsasunusable. Each item gets its own rows, with locations like/0/x, and an empty list fails$min_subjectsasvalue. A position on a list input, likefrom: $input[0]orfrom: first of $input, reads the item, and endsabsentpast the end or on[], where it failedunusable. The same goes for a child subject whosefromstarts with a position on a parent that is a list, likeartifact[0].c: it reads the item of each parent, and a parent that is[]ornullfails$min_subjectsasabsent. A field, like$input.commits, staysunusableon a list. The$min_subjectsand$unique_idsexpressions offrom: every $inputandfrom: every $input whose ...now keepevery, likecount(matching(every $input)) >= 1, on any input and not only a list. A report for a policy whose subjects come from a list input changes, and so does the expression text of every policy withfrom: every $input. subjectsat the top of a report is written the way the spec says for a policy written wrong. A chain of more than three subjects lists every subject in it, not only the last. Afromline that reads but has a problem, likevalues of mixed types, shows as<invalid from>instead of the line. A subject whosefromstarts at another subject lists that subject even when the line is written wrong, as withevery parent.items, and a subject that narrows another has that subject's id then, even with anidentified_byof its own. Afromthat doesn't parse, or isn't a string, lists no other subject, as before.- A check written wrong with
values of mixed typesand nothing else is printed as written, like every other check written wrong, and its$well_formedinput is named after the check. Before, itsexpressionwas printed from the parse and its input was named by the place inside the check. Reports change for such checks:x is one of 1.0, 'a'had theexpressionx is one of 1, "a"and now hasx is one of 1.0, 'a', and its input, which was named by the place inside the check, is now named after the check:checks.f.checks.0under aforline is nowchecks.f,checks.g.checks.1in a list of assertions is nowchecks.g, withline 2:in front of the problem, andchecks.c.whose.0orchecks.c.left.whose.0, for...