pub struct ParsedPolicy {
pub rules: Vec<PolicyRule>,
pub allow_rules: Vec<AllowRule>,
pub layer_rules: Vec<LayerRule>,
pub errors: Vec<PolicyError>,
pub used_aliases: BTreeMap<String, BTreeSet<String>>,
}Expand description
The rule kinds parsed from a CANDOR_POLICY file.
Fields§
§rules: Vec<PolicyRule>§allow_rules: Vec<AllowRule>§layer_rules: Vec<LayerRule>§errors: Vec<PolicyError>⟨0.24⟩ POLICY ERRORS — a policy that cannot be honoured AS WRITTEN (SPEC §6.2). Non-empty ⇒ every
gate route MUST refuse: exit 2, the unreadable-policy posture. Not a warning list: the rules in
rules are what the text would mean if the error were tolerated, and tolerating it is the defect.
Today the only member is an unrecognised reason-class/alias token in an Unknown[…] filter. The
asymmetry that used to justify a warning — “a dropped policy token leaves a WIDER rule standing,
so the failure is loud” — is false in the case that matters, and the false half is FAIL-OPEN:
deny Unknown[corp](sole unrecognised token) — the filter empties and the rule WIDENS to a baredeny Unknown, while the engine prints “ignoring policy rule” and then KEEPS and re-scopes it. Merely surprising, but a FALSE DISCLOSURE.deny Unknown[dispatch,nativ](a typo BESIDE valid tokens) — the token is dropped, the rule NARROWS to[dispatch], and it stops gating native-caused holes entirely while the operator reads a gate that looks armed. That is the fail-open, and it is the common case: a typo lands beside correct tokens far more often than alone.
A policy that cannot be honoured as written is not silently rewritten into a different policy.
⟨0.24⟩ THIS LIST NOW HOLDS EVERY LINE THE PARSER DID NOT HONOUR, fatal or not (SPEC §3.1
195d45a) — parsepolicy reports them all, and the gate routes refuse on
ParsedPolicy::fatal_messages alone. Widening the LIST without widening what REFUSES is the
whole of the change: a dropped nonsense line was always survivable and stays so.
used_aliases: BTreeMap<String, BTreeSet<String>>⟨0.24⟩ The .candor/config unknown-alias definitions this policy actually resolved a token
through (SPEC §3.1) — name → the reason-class TOKENS it expanded to, not a bare name list.
Non-empty ⇒ a config file supplied vocabulary that PARTICIPATED in the verdict, and the
--gate-json document MUST name that file. Recorded at the point of USE, not from the alias map:
a config defining ten aliases none of which the policy mentions changed nothing, and naming it
would train the reader to ignore the field.
⟨0.24⟩ THE VALUE TRAVELS WITH THE NAME, AND THAT IS A SPEC MUST (§3.1, candor-spec 7f5b5ba).
This engine shipped the bare name — as did java and swift — and candor-ts kept the map and won the
argument from the clause’s OWN sentence: configSources: [path] is rejected there because a
disclosure that names the source but not the content leaves the reader knowing they were affected
and not how, and ["corp"] fails that same test one level down. corp = reflect and
corp = reflect,native gate DIFFERENTLY under one unchanged policy line, so a reader given only
the name cannot tell which gate ran. The map is a strict superset — the keys recover the old array.
Class TOKENS rather than ReasonClass, so the wire order is the token’s alphabetical one (which
is what candor-ts’s [...set].sort() produces) and not ReasonClass’s declaration order.
Implementations§
Source§impl ParsedPolicy
impl ParsedPolicy
Sourcepub fn fatal_messages(&self) -> Vec<&str>
pub fn fatal_messages(&self) -> Vec<&str>
⟨0.24⟩ The messages of the errors that make the policy UNHONOURABLE — what every gate route refuses on. Non-empty ⇒ exit 2, the unreadable-policy posture.
Separate from errors because REPORTED and FATAL are different questions, and conflating them in
either direction is a defect: refusing on every dropped line would make nonsense line fail a
build, and reporting only the fatal ones is the silent narrowing this rung exists to close.