You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
core: let a check read a value from a path with ref #63
Every value in a check is written into the policy, and every path starts inside the subject. So a policy can't read params, and it can't look something up in another part of the input. Policies work around both in Rego before calling ergo. SDLC-CTRL-0004 copies its licence allowlist out of data.params, and it joins each SBOM component to its lockfile pin itself.
Design
$$input is the top of the document given to ergo.report. A path that starts with it reads from there and not from the subject:
path: ["$$input", lock, packages]
$$ marks names that ergo provides. Names a policy binds itself (#52's each and as, like $pr) use one $. Keeping them apart means ergo can add built-ins later without breaking a policy that already uses that name. A policy name can't start with $.
{ref: path} reads a value where a literal would go: value, values, patterns, min, max and the values in a selector's where:
values: [MIT, Apache-2.0] # a literal, as todayvalues: {ref: ["$$input", params, allowed_licenses]} # read from the input
{literal: x} forces a literal, for a value that is itself an object with a ref or literal key. Nothing inside it is interpreted, so {literal: {literal: {ref: [main]}}} is the object {literal: {ref: [main]}}. In a path, {literal: "$$input"} is the key $$input.
Params need nothing more. The caller puts them in the document, for example {trail: ..., params: ...}, and the policy reads ["$$input", params, ...]. ergo has no defaults. A param that has a default is written into the policy or the params file.
Joins come with #52's names. The lock package with the same name as the component being checked is:
The expression shows where a value comes from, and the row's inputs show what it was:
expression: some licences: licences[] in $$input.params.allowed_licenses
inputs: licences[] = ["GPL-3.0"], $$input.params.allowed_licenses = ["0BSD", "Apache-2.0", ...]
Params can change between runs, so the row has to record what was actually compared.
Failing closed
A reference that can't be read fails the check with the usual cause (absent, null, unmatched or not_an_object). A missing param fails every row that uses it.
A present filter whose selector matches nothing rules the subject out, like a missing field since core: let a present filter rule out a subject whose field is missing #62. For a join, "no lock entry for this package" is an answer, not an unreadable filter. A selector that matches several items still fails.
What's left of SDLC-CTRL-0004's Rego after both is the text parsing and the version comparison between Snyk and uv, which belong in how the evidence is attested and not in ergo.
From #113, DEV-0401: a vulnerability must be fixed within a number of days set by its severity. The days come from the params, keyed by a field of the subject:
Two things stop this today: a ref can only start with $$input or $$params, and a ref inside a ref's own path isn't followed. Step 2 above covers the first, for refs that start from a name like $component. This needs a ref step inside a ref as well, read from the subject.
Every value in a check is written into the policy, and every path starts inside the subject. So a policy can't read params, and it can't look something up in another part of the input. Policies work around both in Rego before calling ergo. SDLC-CTRL-0004 copies its licence allowlist out of
data.params, and it joins each SBOM component to its lockfile pin itself.Design
$$inputis the top of the document given toergo.report. A path that starts with it reads from there and not from the subject:$$marks names that ergo provides. Names a policy binds itself (#52'seachandas, like$pr) use one$. Keeping them apart means ergo can add built-ins later without breaking a policy that already uses that name. A policy name can't start with$.{ref: path}reads a value where a literal would go:value,values,patterns,min,maxand the values in a selector'swhere:{literal: x}forces a literal, for a value that is itself an object with areforliteralkey. Nothing inside it is interpreted, so{literal: {literal: {ref: [main]}}}is the object{literal: {ref: [main]}}. In a path,{literal: "$$input"}is the key$$input.Params need nothing more. The caller puts them in the document, for example
{trail: ..., params: ...}, and the policy reads["$$input", params, ...]. ergo has no defaults. A param that has a default is written into the policy or the params file.Joins come with #52's names. The lock package with the same name as the component being checked is:
The report
The expression shows where a value comes from, and the row's
inputsshow what it was:Params can change between runs, so the row has to record what was actually compared.
Failing closed
absent,null,unmatchedornot_an_object). A missing param fails every row that uses it.presentfilter whose selector matches nothing rules the subject out, like a missing field since core: let a present filter rule out a subject whose field is missing #62. For a join, "no lock entry for this package" is an answer, not an unreadable filter. A selector that matches several items still fails.Order
$$input,refandliteral. That's enough for params, and it doesn't need core: let from iterate at any step and name what it iterates over #52.$component), and thepresentchange above, for joins.What's left of SDLC-CTRL-0004's Rego after both is the text parsing and the version comparison between Snyk and uv, which belong in how the evidence is attested and not in ergo.