Enforcement modes
OBSERVE, SIMULATE and ENFORCE — what each one actually does, and the one thing about OBSERVE that surprises everyone.
Enforcement mode lives on the environment, not on a policy or an agent. One setting governs everything in that environment, which is what makes it a safe thing to change and an auditable thing to have changed.
Three modes, meant to be walked in order.
Described in text
OBSERVE executes everything and records the divergences, which is how you
learn what will break. SIMULATE refuses for real and executes nothing, which
is where policy correctness gets settled. ENFORCE refuses for real. Moving
backwards is allowed, and it needs a reason, step-up authentication and a
CRITICAL audit event.
#What each mode does
OBSERVE |
SIMULATE |
ENFORCE |
|
|---|---|---|---|
| Pipeline stages 1–9 run | yes | yes | yes |
| A refusal stops the action | no | yes | yes |
| Credential brokered | yes | no | yes, if allowed |
| Tool actually executes | yes | no | yes, if allowed |
| Approval can be created | no | no | yes |
shadow.decision populated |
yes | yes | — |
| Decision recorded in audit | yes | yes | yes |
| Protects anything | no | n/a | yes |
#OBSERVE executes everything
This is the thing to understand
In OBSERVE, Veefore runs the full pipeline, computes a decision, records it —
and then lets the action proceed regardless. An action that ENFORCE would
BLOCK executes in OBSERVE. It reaches your downstream system. It has
whatever side effect it was going to have.
OBSERVE is instrumentation. It is not a safety setting, and an environment
left in OBSERVE is an unprotected environment with good logs.
The two fields that matter:
json{
"mode": "OBSERVE",
"decision": "ALLOW",
"outcome": "OBSERVED",
"allowed": true,
"shadow": {
"decision": "BLOCK",
"reason": "Destructive database operations are not permitted through an agent."
}
}
decisionis the effective decision. InOBSERVEit isALLOW.shadow.decisionis what enforcement would have done.
When those two disagree, you are looking at something that will break the moment you promote. That divergence is the whole value of the mode: it is a list of work to do, generated from real traffic rather than guessed at.
#SIMULATE is the honest middle
SIMULATE runs the full pipeline and executes nothing. No credential is
brokered, no downstream call is made, no external side effect occurs anywhere.
Refusals are real refusals.
This is the mode for shaking out policy correctness, because a mistake costs you
a wrong line in a report rather than a wrong row in a database. It is also what
veefore deploy preflight replays your observed traffic through.
#ENFORCE refuses
Full pipeline, real refusals, real execution for what is permitted, approvals created where policy asks for them. This is the mode Veefore exists for.
#Moving between modes
bashveefore deploy --mode ENFORCE --reason "Refund policy reviewed in CHG-4411"
or over the API:
httpPOST /v1/environments/{environmentId}/gateway-mode
veefore deploy is the better path because of what it does first:
- Preflight. Checks for agents with no policy coverage, dangerous tools permitted only by a default decision, expired trust evidence, and credentials overdue for rotation.
- Replay. Re-evaluates your recent observed traffic in the target mode and shows you exactly which calls start being refused — before anything changes.
- Confirm. Shows the blast radius and asks.
- Authorise. Requires a reason and step-up authentication.
The replay is the step that earns its keep. "Enabling enforcement will refuse 14 of your last 400 actions, and here they are" is a decision you can make.
#Going backwards
Allowed, and never quiet.
Reducing enforcement requires environment:set_mode, a recorded reason, step-up
authentication, and it writes a CRITICAL audit event. The Security Center
surfaces it, and a webhook fires if you have one subscribed.
The asymmetry is deliberate. Tightening is routine. Loosening is the action an attacker would want, and the action a team under pressure reaches for at 2am, so it leaves a mark either way.
Mode is not a kill switch
If something is actively going wrong, dropping to OBSERVE is the worst
available option — it stops refusing anything while leaving everything running.
Use the controls built for it: POST /v1/environments/{id}/pause stops all
protected execution in the environment, and POST /v1/agents/{id}/pause stops
one agent. Both are immediate. See
Emergency controls.
#Per-environment, deliberately
Each environment has its own mode, so the normal shape is:
| Environment | Mode | Why |
|---|---|---|
| Development | SIMULATE |
Policy feedback with no side effects |
| Staging | ENFORCE |
Behaves like production, so surprises happen here |
| Production | ENFORCE |
Obviously |
A new environment starts in OBSERVE so that adding Veefore to a running system
cannot break it on day one. The expectation is that you leave OBSERVE quickly.
veefore doctor and the Security Center both flag a production environment
sitting in OBSERVE, because that is a finding and not a configuration.
#Knowing when you are ready
Promote when all of these are true:
shadow.decisionhas not diverged fromdecisionon traffic you consider correct for several days.- Every divergence you did see is either a policy you intended or a bug you fixed.
veefore doctor --strictis clean.- Every policy's test cases pass.
- Someone knows what to do when an approval request appears, and the approval queue has an owner.
That last one is the one teams forget. ENFORCE with REQUIRE_APPROVAL rules
and nobody watching the queue is just a slower kind of blocked.