`POST /v1/orgs/{org}/policies/preview`.
const url = 'https://api.updawg.net/v1/orgs/example/policies/preview';const options = { method: 'POST', headers: {'Content-Type': 'application/json'}, body: '{"yaml":"example","replaces":"example"}'};
try { const response = await fetch(url, options); const data = await response.json(); console.log(data);} catch (error) { console.error(error);}curl --request POST \ --url https://api.updawg.net/v1/orgs/example/policies/preview \ --header 'Content-Type: application/json' \ --data '{ "yaml": "example", "replaces": "example" }'What saving this document would do to the fleet as it is right now. Reads and evaluates; writes nothing.
replaces is not optional in the way it looks
A proposal’s identity is its dedupe_key, which begins with the policy
id. So previewing an edit without saying which policy it replaces compiles
the candidate under a fresh id, every key differs, and the answer is “all of
these would open and all of those would close” — which is true of a new
policy and nonsense for an edit.
With replaces, the candidate is compiled under that policy’s id and
substituted for it, and the diff is about the change rather than about the
identity. Without it, the candidate is added to what is already there,
which is the honest reading of previewing something that does not exist yet.
What this deliberately does not compare against
The proposals that are actually open. Those were written by the policies in force at some past moment, so comparing with them would fold “the policy changed” together with “the fleet changed since” — two answers in one number, and the editor only asked about the first. Both sides here are evaluated now, over the same snapshot.
Parameters
Section titled “Parameters”Path Parameters
Section titled “Path Parameters”Organization slug.
Request Bodyrequired
Section titled “Request Bodyrequired”object
Option so that a missing field produces this API’s own 400 rather
than axum’s plain-text 422 — see DAWG-246 and the note in
routes::proposals::reject.
The policy this document would replace, as pol_<hex>. Absent means a
policy that does not exist yet — see [preview].
Examplegenerated
{ "yaml": "example", "replaces": "example"}Responses
Section titled “Responses”What saving this would do: which proposals it would open, and — the half nobody asks for — which updates it would stop covering.
object
Same key before and after, and something about it differs: more hosts,
more packages, a worse severity — or, the one that matters,
[Action::AutoMerge] where it used to be [Action::Propose]. Carries
the after shape.
⚠️ This list exists because of a bug I wrote and then tested for.
unchanged originally held every shared key, so turning propose into
auto_merge — which opens no proposal, closes none and loses no
coverage — made [Preview::is_empty] report a no-op. A portal using
that to decide whether to warn would have stayed silent for the single
most dangerous edit anybody can make to a policy.
One proposal, as the fleet would produce it.
object
What would happen. auto_merge here is the answer to “would this go out
without anybody looking”, which is the question a preview is really for.
How many hosts would be in it.
Ord is derived so this can key an ordered collection — the policy engine
groups proposals by kind in a BTreeMap and needs a total order to produce
the same output twice. The order itself is the declaration order and carries
no meaning; nothing should read severity into it.
How bad an advisory is, on one scale.
Severity::None is not the same as no severity
This enum is what a vendor said. Somewhere it is stored as a nullable
column and read back as Option<Severity>, and the two levels mean
different things:
None(the variant) — rated, and rated as not worth acting on. Ubuntu’snegligibleand Debian’sunimportantland here.Option::None— nobody rated it. Debian DSAs frequently carry no rating at all.
Collapsing them would let a policy written severity >= low quietly skip
everything nobody had got round to rating yet, which is the opposite of what
somebody writing that rule wants.
How many distinct packages, across every host.
A policy.
The named rollout strategy, if the rule named one the policy defines.
Which rule decided it, by position. Renders as “rule 3 of web-production” — and is the reason reordering churns keys.
Set on an opening entry when a closing one covers exactly the same work under a different key, and the other way round. Almost always a rule that moved. See the module documentation.
What else the rule decided. See [Settings] for why this is a struct
rather than the one field that used to be here.
object
When an approved proposal may start.
Whether a human has to say yes, and how many of them.
object
Ignored when required is false. Zero is meaningless and the schema
rejects it; the engine treats anything below one as one rather than as
“no approvers needed”, because rounding towards asking is the safe
direction.
A step that may be required before a proposal applies.
What to do about a host that needs a reboot afterwards.
A step that may be required before a proposal applies.
Proposals that exist now and would not.
One proposal, as the fleet would produce it.
object
What would happen. auto_merge here is the answer to “would this go out
without anybody looking”, which is the question a preview is really for.
How many hosts would be in it.
Ord is derived so this can key an ordered collection — the policy engine
groups proposals by kind in a BTreeMap and needs a total order to produce
the same output twice. The order itself is the declaration order and carries
no meaning; nothing should read severity into it.
How bad an advisory is, on one scale.
Severity::None is not the same as no severity
This enum is what a vendor said. Somewhere it is stored as a nullable
column and read back as Option<Severity>, and the two levels mean
different things:
None(the variant) — rated, and rated as not worth acting on. Ubuntu’snegligibleand Debian’sunimportantland here.Option::None— nobody rated it. Debian DSAs frequently carry no rating at all.
Collapsing them would let a policy written severity >= low quietly skip
everything nobody had got round to rating yet, which is the opposite of what
somebody writing that rule wants.
How many distinct packages, across every host.
A policy.
The named rollout strategy, if the rule named one the policy defines.
Which rule decided it, by position. Renders as “rule 3 of web-production” — and is the reason reordering churns keys.
Set on an opening entry when a closing one covers exactly the same work under a different key, and the other way round. Almost always a rule that moved. See the module documentation.
What else the rule decided. See [Settings] for why this is a struct
rather than the one field that used to be here.
object
When an approved proposal may start.
Whether a human has to say yes, and how many of them.
object
Ignored when required is false. Zero is meaningless and the schema
rejects it; the engine treats anything below one as one rather than as
“no approvers needed”, because rounding towards asking is the safe
direction.
A step that may be required before a proposal applies.
What to do about a host that needs a reboot afterwards.
A step that may be required before a proposal applies.
⚠️ Updates a rule decides today and nothing would decide after.
The half that does not show up in proposal counts, and the one that
leaves a fleet unpatched. An ignore rule counts as deciding: choosing
to do nothing is not the same as nothing matching.
An update whose coverage changes.
object
How many hosts it affects.
Updates nothing decides today and a rule would decide after.
An update whose coverage changes.
object
How many hosts it affects.
Proposals that do not exist now and would.
One proposal, as the fleet would produce it.
object
What would happen. auto_merge here is the answer to “would this go out
without anybody looking”, which is the question a preview is really for.
How many hosts would be in it.
Ord is derived so this can key an ordered collection — the policy engine
groups proposals by kind in a BTreeMap and needs a total order to produce
the same output twice. The order itself is the declaration order and carries
no meaning; nothing should read severity into it.
How bad an advisory is, on one scale.
Severity::None is not the same as no severity
This enum is what a vendor said. Somewhere it is stored as a nullable
column and read back as Option<Severity>, and the two levels mean
different things:
None(the variant) — rated, and rated as not worth acting on. Ubuntu’snegligibleand Debian’sunimportantland here.Option::None— nobody rated it. Debian DSAs frequently carry no rating at all.
Collapsing them would let a policy written severity >= low quietly skip
everything nobody had got round to rating yet, which is the opposite of what
somebody writing that rule wants.
How many distinct packages, across every host.
A policy.
The named rollout strategy, if the rule named one the policy defines.
Which rule decided it, by position. Renders as “rule 3 of web-production” — and is the reason reordering churns keys.
Set on an opening entry when a closing one covers exactly the same work under a different key, and the other way round. Almost always a rule that moved. See the module documentation.
What else the rule decided. See [Settings] for why this is a struct
rather than the one field that used to be here.
object
When an approved proposal may start.
Whether a human has to say yes, and how many of them.
object
Ignored when required is false. Zero is meaningless and the schema
rejects it; the engine treats anything below one as one rather than as
“no approvers needed”, because rounding towards asking is the safe
direction.
A step that may be required before a proposal applies.
What to do about a host that needs a reboot afterwards.
A step that may be required before a proposal applies.
Same key, same everything.
One proposal, as the fleet would produce it.
object
What would happen. auto_merge here is the answer to “would this go out
without anybody looking”, which is the question a preview is really for.
How many hosts would be in it.
Ord is derived so this can key an ordered collection — the policy engine
groups proposals by kind in a BTreeMap and needs a total order to produce
the same output twice. The order itself is the declaration order and carries
no meaning; nothing should read severity into it.
How bad an advisory is, on one scale.
Severity::None is not the same as no severity
This enum is what a vendor said. Somewhere it is stored as a nullable
column and read back as Option<Severity>, and the two levels mean
different things:
None(the variant) — rated, and rated as not worth acting on. Ubuntu’snegligibleand Debian’sunimportantland here.Option::None— nobody rated it. Debian DSAs frequently carry no rating at all.
Collapsing them would let a policy written severity >= low quietly skip
everything nobody had got round to rating yet, which is the opposite of what
somebody writing that rule wants.
How many distinct packages, across every host.
A policy.
The named rollout strategy, if the rule named one the policy defines.
Which rule decided it, by position. Renders as “rule 3 of web-production” — and is the reason reordering churns keys.
Set on an opening entry when a closing one covers exactly the same work under a different key, and the other way round. Almost always a rule that moved. See the module documentation.
What else the rule decided. See [Settings] for why this is a struct
rather than the one field that used to be here.
object
When an approved proposal may start.
Whether a human has to say yes, and how many of them.
object
Ignored when required is false. Zero is meaningless and the schema
rejects it; the engine treats anything below one as one rather than as
“no approvers needed”, because rounding towards asking is the safe
direction.
A step that may be required before a proposal applies.
What to do about a host that needs a reboot afterwards.
A step that may be required before a proposal applies.
Whether saving this would change anything at all.
⚠️ false means the fleet was larger than one preview evaluates, so
host counts are lower bounds. Which kinds of proposal appear is still
reliable — those come from the rules rather than from the hosts.
How many hosts this answer is about.
How many the organization has.
How many proposals would go out with nobody looking at them, after this.
Example
{ "changing": [ { "action": "propose", "kind": "security", "max_severity": "none", "settings": { "apply": "asap", "preflight": "optional", "reboot": "never", "snapshot": "optional" } } ], "closing": [ { "action": "propose", "kind": "security", "max_severity": "none", "settings": { "apply": "asap", "preflight": "optional", "reboot": "never", "snapshot": "optional" } } ], "opening": [ { "action": "propose", "kind": "security", "max_severity": "none", "settings": { "apply": "asap", "preflight": "optional", "reboot": "never", "snapshot": "optional" } } ], "unchanged": [ { "action": "propose", "kind": "security", "max_severity": "none", "settings": { "apply": "asap", "preflight": "optional", "reboot": "never", "snapshot": "optional" } } ]}The document does not compile.
object
Examplegenerated
{ "detail": "example", "status": 1, "title": "example", "type": "example"}No session.
object
Examplegenerated
{ "detail": "example", "status": 1, "title": "example", "type": "example"}Refused: no CSRF token or not this session’s, or not permitted for this role.
object
Examplegenerated
{ "detail": "example", "status": 1, "title": "example", "type": "example"}No such organization, or not yours.
object
Examplegenerated
{ "detail": "example", "status": 1, "title": "example", "type": "example"}Another live policy already holds that name — which is what saving it would answer, and therefore what previewing it has to.
object
Examplegenerated
{ "detail": "example", "status": 1, "title": "example", "type": "example"}Over the organization’s request limit. Retry-After says when to try again; RateLimit-Limit is the burst.
object
Examplegenerated
{ "detail": "example", "status": 1, "title": "example", "type": "example"}