skip to content

Why is a policy decision point's deny inert without the enforcer?

level: middleimportance: should knowfreq 47%

answer

  1. the decider returns a value, not an effect
  2. gather, apply, distinguish
  3. a correction has to be written back
  4. a timeout is not an approval
  5. the submitted object is the one that counts

basics

~20 s

A decision point returns a message; it has no hands on the resource. The enforcer sits in the change's path and owes it three things: gather the input, apply the verdict including any correction, and never read a missing answer as approval.

solid answer

~40 s

The decision service produces a value, not an effect. It cannot stop a listener being created — only the code on that create path can. So the enforcer owes the decision three duties. First, **gather**: assemble the input the rule needs, because a rule that never sees the minimum-protocol field cannot enforce a protocol floor. Second, **apply**: on a deny, abandon the change; if the answer comes back with a corrected value — say a minimum of TLS 1.2 — write it into what is actually submitted, not into a copy that is discarded. Third, **distinguish an answer from no answer**: a timeout or a 500 is not an approval, and recording `policy passed` when nothing was evaluated is a defect on its own terms.

go deeper

for a junior

Remember the core split: the decider answers, the enforcer acts. Be able to say that a deny changes nothing unless the calling code refuses to go ahead.

for a middle

Expect to list the enforcer's duties concretely — assemble the input, honour the verdict, write back any correction, and never read an error as approval — and to name what breaks when each is skipped.

for a senior

Be ready to review someone's enforcer code and point at the failure paths: broad exception handling around the policy call, a patched object that is not the one submitted, and success logged when no evaluation happened.

for a principal

Own the argument that enforcement, not rule authorship, is where control assurance actually lives, and that evidence of enforcement is what a review should demand rather than a list of merged rules.

## A verdict is a value; enforcement is an effect The decision point's whole contract is: given this input, here is an answer. It returns JSON. It does not touch the load balancer, the pipeline or the cluster. The moment a team says `the policy blocks that`, they are really describing something the *enforcer* does — and if no enforcer honours the verdict, the rule is a document, not a control. Run it against one guardrail: **no load-balancer listener may accept anything below TLS 1.2.** A deploy tool is about to create a listener. The enforcer is the guard on that create path. ### Duty one: gather The enforcer decides what the decider gets to see. Two failures live here. - **Under-gathering.** If the payload omits the listener's minimum protocol version, the rule cannot key on it. Depending on how the rule is written, the result is either a spurious deny or — worse — a quiet allow, because a condition over an absent field simply does not fire. - **Mis-gathering.** The enforcer sends the values it *intends* to submit, not the ones it will actually submit. If defaults are applied after the check, the decider judged an object that never existed. When the rule needs a fact the change does not carry — is this certificate on the approved list, does its issuing profile permit older protocols — the enforcer is also the component that fetches it from the inventory and folds it into the input. ### Duty two: apply the answer, including a correction The obvious half is: on deny, do not proceed. The half people miss is that a decision is not always a bare yes or no. Many gates return a **corrected value** — the verdict says the listener's floor of TLS 1.0 is not acceptable and the acceptable minimum is TLS 1.2. Applying that answer means: - Writing the correction into the object that is actually submitted, not into a copy that is then discarded. - Deciding, deliberately, whether a corrected object is re-checked. If the same enforcer both patches and approves, nothing verifies that the patch produced a compliant object. - Making the correction visible. Silently altering a team's configuration and reporting success produces a resource nobody in the team knows the shape of, and a repository whose committed configuration no longer matches reality. Emitting a clear record of what was changed and why is part of applying the answer. The general form of the duty is: **the enforcer must make the world match the decision**, whether that means refusing, amending, or proceeding. ### Duty three: an error is not an answer A non-200 from the decision service, a connection timeout, a malformed body, a response whose verdict field the enforcer does not recognise — none of these are approvals. Two things follow, and only the first is in scope here: - The enforcer must be able to tell `evaluated and allowed` apart from `never evaluated`, in its own control flow **and in whatever record it emits**. Logging `policy check passed` after a 500 is a defect on its own terms: it manufactures evidence of a control that did not run, and it is exactly what makes a later review believe a quarter of clean runs proves something. - What the enforcer then *does* about a decider it cannot reach — refuse, proceed, degrade — is a separate, deliberate configuration choice with its own tradeoffs. What is never acceptable is arriving at that behaviour by accident, through a swallowed exception in a `catch` block. ### Why this concentrates the risk in the enforcer A rule is easy to test in isolation: feed it inputs, assert verdicts. The enforcer is the part wired into a real code path, under a real timeout, in a tool someone else maintains — and it is where the guardrail actually lives or dies. Which is why, when a control is not working, the enforcer is the first place to look and the rule is usually the last.

  • If the decision comes back with a corrected value, should the corrected object be re-evaluated?
    Ideally yes, or the correction is trusted on faith. If the same component both patches and approves, nothing verifies that the patch produced a compliant object — a bug in the correction path ships a non-compliant resource with a clean record. Re-submitting the amended object for evaluation costs one more call and turns the correction into something you can prove worked.
  • What is wrong with an enforcer that catches every exception around the policy call?
    It converts every failure of the control into a silent success. A timeout, a bad certificate on the decision service, a renamed response field — all become `proceed`, and the logs claim the check passed. Whatever behaviour you want on an unreachable decider, it should be chosen and configured explicitly, not inherited from a broad catch block.
  • The team says the guardrail is enforced because the rule is merged. What do you ask for?
    Evidence that the enforcer ran on the paths that matter and honoured the verdicts: records of calls, verdicts, and what the enforcer did with each. A merged rule proves an evaluation is possible, not that any change was ever evaluated, and certainly not that a deny stopped anything.

saying these in an interview costs you the question

  • Says the policy engine blocks the deploy
  • Treats a timeout or 500 as an implicit allow
  • Applies a correction to a copy that is never submitted
  • Logs policy passed when nothing was evaluated
  • Sends intended values rather than the ones actually submitted

context