oscerd opened a new pull request, #26469:
URL: https://github.com/apache/camel/pull/26469

   ## What
   
   `camel-opa` clears its decision headers on entry to `evaluate` instead of 
relying on overwriting them at the end, so a verdict a message claimed for 
itself cannot survive a failed evaluation.
   
   ## The gap
   
   The component writes `CamelOpaDecisionAllow` (plus `CamelOpaDecision` and 
`CamelOpaPolicyPath`) *after* reaching a verdict:
   
   ```java
   boolean allowed = isAllowed(decision);
   setDecisionHeaders(exchange, decision, allowed);
   ```
   
   On the allow and deny paths that is enough — an inbound claim is 
overwritten. `buildInput` already excludes the three headers 
case-insensitively, so a claimed verdict never reaches OPA or its decision log 
either. Both were deliberate.
   
   **The failure paths never get there.** When the policy cannot be evaluated 
at all — server unreachable, decision undefined, input not serializable — 
`evaluate` throws and the headers are untouched:
   
   ```java
   throw new OpaPolicyEvaluationException("Failed to evaluate policy " + 
policyPath, exchange, e);
   ```
   
   Whatever the message carried is still on it. `OpaSecurityPolicy` throws 
`CamelAuthorizationException` through the same shared `evaluate`, so it has the 
same gap.
   
   ## Why it matters
   
   A route that lets the exception propagate is unaffected — the exchange is 
failed. A route that **handles** it is not: `doTry`/`doCatch`, or 
`onException(...).handled(true)` / `.continued(true)`, resumes routing with the 
sender's own `CamelOpaDecisionAllow=true` still set. A downstream step reads 
"allowed", attributed to a policy that never said so — and the component 
documents that header as how a route acts on the verdict, with a filter or a 
choice.
   
   A route author setting the header is trusted and out of scope. The reachable 
case is a consumer in front of the route that maps untrusted input into the 
header map without a strict, case-insensitive `Camel*` `HeaderFilterStrategy` — 
the header-injection class the security model puts explicitly in scope, and the 
reason a security component should not depend on the consumer having got that 
right.
   
   ## Fix
   
   ```java
   // a verdict the message arrived with is a claim, not evidence. Clear it 
before deciding anything, so that
   // every way out of this method - allowed, denied, or a failure the route 
goes on to handle - leaves only
   // what this component decided. Overwriting at the end is not enough: the 
paths that throw never get there
   clearDecisionHeaders(exchange);
   ```
   
   Clearing rather than overwriting also makes the invariant total and 
one-line-checkable: these headers are only ever written by this component.
   
   ## Testing
   
   Three cases, all in existing classes:
   
   - `doesNotLeaveAVerdictClaimedByTheMessageBehindWhenEvaluationFails` — the 
reproduction. Confirmed to **fail with the fix reverted**; the pre-existing 
`failsClosedWhenThePolicyCannotBeEvaluated` does not catch it, because it never 
sets the header inbound.
   - `replacesAVerdictClaimedByTheMessageWithTheOneThePolicyGave` — pins the 
allow/deny path, which was already correct.
   - `doesNotForwardAVerdictClaimedByTheMessageToTheDecisionPoint` — pins the 
`buildInput` exclusion. It passed first time: the behaviour was already right 
but untested, so it was one refactor from being lost.
   
   Full reactor build green.
   
   ## Scope
   
   `main` only. `camel-opa` is new and unreleased in 4.23.0, so no released 
behaviour changes and no advisory is warranted.
   
   Related: **CAMEL-24738** proposes a `CamelOpaDecisionFailedOpen` header so a 
route can tell "allowed by policy" from "allowed because the decision point was 
down". If that lands, it needs clearing here too — otherwise a sender could 
preload `FailedOpen=false` and make a fail-open look like a real allow.
   
   _Claude Code on behalf of @oscerd_
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to