From a770286845cc4c915d620ff76e03b4a545d48f60 Mon Sep 17 00:00:00 2001 From: Charith Ellawala Date: Mon, 10 Aug 2026 14:13:15 +0100 Subject: [PATCH] Support output errors Signed-off-by: Charith Ellawala --- src/main/java/dev/cerbos/sdk/CheckResult.java | 55 +++++++++++++++++-- .../dev/cerbos/sdk/CerbosClientTests.java | 9 ++- 2 files changed, 57 insertions(+), 7 deletions(-) diff --git a/src/main/java/dev/cerbos/sdk/CheckResult.java b/src/main/java/dev/cerbos/sdk/CheckResult.java index 3cc80ce..c12f892 100644 --- a/src/main/java/dev/cerbos/sdk/CheckResult.java +++ b/src/main/java/dev/cerbos/sdk/CheckResult.java @@ -47,14 +47,15 @@ public boolean isAllowed(String action) { return false; } - return this.entry.getActionsMap().getOrDefault(action, EffectOuterClass.Effect.EFFECT_DENY) - == EffectOuterClass.Effect.EFFECT_ALLOW; + return this.entry.getActionsMap().getOrDefault(action, + EffectOuterClass.Effect.EFFECT_DENY) == EffectOuterClass.Effect.EFFECT_ALLOW; } /** * Return all actions and effects in this instance. * - * @return Map of action to boolean indicating whether the action is allowed or not + * @return Map of action to boolean indicating whether the action is allowed or + * not */ public Map getAll() { if (this.entry == null) { @@ -83,7 +84,8 @@ public boolean hasValidationErrors() { /** * Returns the list of validation errors if there are any. * - * @return List of {@link dev.cerbos.api.v1.schema.SchemaOuterClass.ValidationError} + * @return List of + * {@link dev.cerbos.api.v1.schema.SchemaOuterClass.ValidationError} */ public List getValidationErrors() { if (this.entry == null) { @@ -170,11 +172,54 @@ public int size() { * @return Map of output rule names and {@link Value} */ public Map asMap() { - return this.outputs.stream().collect(Collectors.toUnmodifiableMap(Engine.OutputEntry::getSrc, Engine.OutputEntry::getVal)); + return this.outputs.stream() + .collect(Collectors.toUnmodifiableMap(Engine.OutputEntry::getSrc, Engine.OutputEntry::getVal)); + } + + /** + * Returns the output entries as a map keyed by rule name. + * + * @return Map of output rule names and {@link Entry} + */ + public Map entriesAsMap() { + return this.outputs.stream() + .collect(Collectors.toUnmodifiableMap(Engine.OutputEntry::getSrc, (entry) -> { + return new Entry(entry.getSrc(), entry.getVal(), entry.getAction(), entry.getError()); + })); } public List getRaw() { return this.outputs; } + + public static final class Entry { + private final String source; + private final Value value; + private final String action; + private final Optional error; + + Entry(String source, Value value, String action, String error) { + this.source = source; + this.value = value; + this.action = action; + this.error = Optional.ofNullable(error); + } + + public String getSource() { + return source; + } + + public Value getValue() { + return value; + } + + public String getAction() { + return action; + } + + public Optional getError() { + return error; + } + } } } diff --git a/src/test/java/dev/cerbos/sdk/CerbosClientTests.java b/src/test/java/dev/cerbos/sdk/CerbosClientTests.java index 5613619..df9c93c 100644 --- a/src/test/java/dev/cerbos/sdk/CerbosClientTests.java +++ b/src/test/java/dev/cerbos/sdk/CerbosClientTests.java @@ -11,6 +11,7 @@ import com.google.protobuf.util.Values; import dev.cerbos.api.v1.engine.Engine; import dev.cerbos.api.v1.response.Response; +import dev.cerbos.sdk.CheckResult.Outputs.Entry; import dev.cerbos.sdk.builders.AuxData; import dev.cerbos.sdk.builders.Principal; import dev.cerbos.sdk.builders.Resource; @@ -196,9 +197,13 @@ public void checkResources() { Response.CheckResourcesResponse.ResultEntry.Meta.EffectMeta res1DeferMeta = res1DeferMetaOpt.get(); Assertions.assertEquals("resource.leave_request.v20210210", res1DeferMeta.getMatchedPolicy()); - Map res1Outputs = res1.getOutputs().asMap(); + Map res1Outputs = res1.getOutputs().entriesAsMap(); Assertions.assertEquals(1, res1Outputs.size()); - Value res1ViewOutput = res1Outputs.get("resource.leave_request.v20210210#public-view"); + Entry res1ViewOutputEntry = res1Outputs.get("resource.leave_request.v20210210#public-view"); + Assertions.assertNotNull(res1ViewOutputEntry); + Assertions.assertEquals("view:public", res1ViewOutputEntry.getAction()); + + Value res1ViewOutput = res1ViewOutputEntry.getValue(); Assertions.assertNotNull(res1ViewOutput); Assertions.assertEquals(res1ViewOutput, Values.of(Struct.newBuilder() .putFields("pID", Values.of("john"))