diff --git a/core/src/main/java/com/styra/opa/wasm/builtins/String.java b/core/src/main/java/com/styra/opa/wasm/builtins/String.java index 24c863f..023847a 100644 --- a/core/src/main/java/com/styra/opa/wasm/builtins/String.java +++ b/core/src/main/java/com/styra/opa/wasm/builtins/String.java @@ -64,6 +64,10 @@ private static JsonNode sprintfImpl(OpaWasm instance, JsonNode operand0, JsonNod if (format.contains("%v")) { format = format.replaceAll("%v", "%s"); } + // %q wraps the string in double quotes (Go/Rego semantics) + if (format.contains("%q")) { + format = format.replace("%q", "\"%s\""); + } var result = java.lang.String.format(format, args.toArray()); return TextNode.valueOf(result); diff --git a/core/src/test/java/com/styra/opa/wasm/OpaStringBuiltinsTest.java b/core/src/test/java/com/styra/opa/wasm/OpaStringBuiltinsTest.java index 8f523f8..1683a1d 100644 --- a/core/src/test/java/com/styra/opa/wasm/OpaStringBuiltinsTest.java +++ b/core/src/test/java/com/styra/opa/wasm/OpaStringBuiltinsTest.java @@ -16,7 +16,8 @@ public static void beforeAll() throws Exception { "string-builtins", "string_builtins/invoke_sprintf", "string_builtins/integer_fastpath", - "string_builtins/string_example") + "string_builtins/string_example", + "string_builtins/quoted") .resolve("policy.wasm"); } @@ -46,4 +47,16 @@ public void stringExample() { assertEquals("my string", result.get("printed").asText()); } + + @Test + public void quoted() { + var opa = OpaPolicy.builder().withPolicy(wasmFile).build(); + + var result = + Utils.getResult( + opa.entrypoint("string_builtins/quoted") + .evaluate("{\"value\": \"String\"}")); + + assertEquals("requested \"String\" is invalid", result.get("printed").asText()); + } } diff --git a/core/src/test/resources/fixtures/string-builtins/policy.rego b/core/src/test/resources/fixtures/string-builtins/policy.rego index c39e6a7..50858fa 100644 --- a/core/src/test/resources/fixtures/string-builtins/policy.rego +++ b/core/src/test/resources/fixtures/string-builtins/policy.rego @@ -11,3 +11,7 @@ integer_fastpath := { string_example := { "printed": sprintf("%s", ["my string"]) } + +quoted := { + "printed": sprintf("requested %q is invalid", [input.value]) +}