Repository navigation
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$well_formed. Their problem readsa condition after and starts with whose or that, and awhoseorthatin the wrong place names the word that was written. The expression of athatfilter writes the subject's name in quotes when it is a word of the grammar, asergo.regodoes, like"item" starts with "b". itis gone. A subject's name means the subject, as the spec says, so a check on a subject calledthingwritesthing is not empty, andthing.xis written wrong withnothing can follow thing, which means the subject: for a field called thing, write .thing.x. On the right side the name reads the subject too, a leading dot reaches a field named like the subject, andfirst of thinganditem 2 of thingread an item of a list subject.named by thingis written wrong,thing is the whole subject, so it can't name a key. A subject, field, alias or part calleditis an ordinary name, and an alias named like its subject is written wrong. A message about a subject that isn't an object names the subject, likething is null, which isn't an object. Reports change for every policy that wroteit, and the messages of the rows that read the subject change fromitto its 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. Same asergo.rego.
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 the spec says, where the engine read the parent's field. 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, likeergo.rego. - A tie in the second list of a
forline names the second item's key, likeitem 1 and item 2 of p.items tie on hi, where it named the first item's. - A
forline whose first item is the subject's own name, likeevery thing as k, fails asnot_an_objecton a subject that is a list, text, a number ornull, asergo.regodoes, where it read a list subject as the list. - The
fromthe report gives for a subject keeps the.of awhosethat reads a field named like the subject, likeevery kids whose .kid is 1for the subjectkid, and so does theassertionof a failedforitem, like.thing is 1for the subjectthing. - A check
count of .kid is 1on a subjectkidsayskid is 1, which isn't a list or an objectonce, asergo.regodoes, where it said it twice, once with a dot. The input is namedcount of .kid. - A
whosein a check that reads a field named like the subject, likecount of ys whose thing is pfor the subjectthing, names that field with its dot in a message,.thing is 1, which isn't an object, asergo.regodoes. - A
whoseon afromline reads the item's field when its left side starts with a subject's name, likekid.xinrel.kids whose kid.x is 1orrel.winrels whose rel.w is 1, where the engine wrote the policy wrong withnothing can follow kid. first of xs sorted by relsorts by the item's fieldrelwhenrelis the subject's name or a parent's or grandparent's name, asergo.regodoes, where it sorted by the subject or the parent and failed asunusable."item" is ."item"is no longer said to compare a field with itself whenitemis the subject's name.- A
count of ys whose thing is pon a subject that isn't an object lists the partpininputs, asergo.regodoes, where it left it out. - A failed
count ofwhose path ends in a key read from a field, likecount of x named by zz is 1withxholding{"k": 1}andzzset to"k", names the value once, asergo.regodoes:x.k is 1, which isn't a list or an object, where the message said it twice. does not existon a path with anamed byfield that can't be read, likex[0] named by zz does not existwithxmissing andzzmissing,nullor not text, now fails asabsent, as spec 0.5 says andergo.regodoes, where it passed. Reports change for such a check:passedgoes fromtruetofalse.- A check that reads the params by a position, like
every $params[0].a is 1orsome $params[0].a is 1, with params that aren't a list or an object, now says$params is 3, which isn't a listasergo.regodoes, where it saidevery $params[0].a is 1 is false, and a check that reads them by a key, like$params.a is 1orzz is in $params.a, says$params is 3, which isn't an object, where it said$params.a is 1 is false.count of $params[0] is 1with params[]says$params is [], which isn't an object, where it saidneeds more than 15 digits. Messages change for such checks. Params that are a list, text, a number or a boolean are read forinputs, so an entry that reads a position of them has the value and the location the spec says,$params:/0, where it had no value and$params:. - A
forline over params that aren't an object, a sentence of aforline, anamed bykey and awhosethat read them, likefor: every $params as p,x named by $params.v is 1orevery ws whose x is $params.v is 1, say$params is 3, which isn't an objectasergo.regodoes, where they said the check was false, and so doescount of $params whose v is 1 is 1with params[3], where it saidneeds more than 15 digits.x is in $params[0].vwith params[[1]]saysitem 1 of $params is [1], which isn't an object. Messages change for such checks. - A subject's
fromline that reads params that aren't an object, likethings named by each of $params.ksorthings named by $params.env, says so in its$min_subjectsmessage,$params is 3, which isn't an object, asergo.regodoes, where it said$params.ks is missing. A position says what it found, likeitem 1 of $params is 3, which isn't a list of textfor$params[0]with params[3]. It still makes no subjects, also when the list of keys can be read, like$params[0]with params[["k"]]. Messages change for such policies. - When both sides of
containsoris incan't be read and the right side is a path from$inputor$params, the message names the left side first, asergo.regodoes:zz is "v", which isn't a list, and $input.y is 3, which isn't an object. Acount ofthrough a position, likecount of y[0].v is 1withyholding[{"v": 1}], names the item once,item 1 of y: v is 1, which isn't a list or an object, where it also saidy[0].v is 1, which isn't a list or an object. Messages change for such checks.