provider_digitcount_operator_ge
The operator-form comparison example (>= on an integer provider output),
promoted from a guardrail fragment to a standalone permit. Permit Read only
when the document contains two or more digits, as counted by the
Strings::DigitCount provider:
Strings::DigitCount(context.input.document).count >= 2
Strings::DigitCount(text) -> { count: Long } counts [0-9] matches via the
regex_count host function (see digits.rhai). The provider script is inlined
into providers.json because the CLI reads that file as text and does not
resolve scriptFile references; digits.rhai is kept as the readable source.
The trace over four documents:
@0—"abc"(0 digits) → DENY@10—"a1b"(1 digit) → DENY@20—"a1b2"(2 digits) → ALLOW@30—"12345"(5 digits) → ALLOW
Referenced by guide/05-information-providers.md.
Policy
// Permit Read only when the document contains 2 or more digits, as counted by
// the Strings::DigitCount provider. Demonstrates the OPERATOR comparison form
// (>=) on an integer provider output.
@id("read_digits_gte_two")
permit (
principal,
action == Drupe::Action::"Read",
resource
)
when {
Strings::DigitCount(context.input.document).count >= 2
};
Schema
namespace Drupe {
type ReadInput = {
document: String
};
entity Gateway;
entity OAuthUser = {
id: String
} tags String;
action "Read" appliesTo {
principal: [OAuthUser],
resource: [Gateway],
context: {
input: ReadInput
}
};
}
Trace
@0 scope(principal: Drupe::OAuthUser::"alice", resource: Drupe::Gateway::"gw1") request_context(input: { document: "abc" }) Drupe::Action::"Read"::request(input: { document: "abc" }, callerPrincipal: Drupe::OAuthUser::"alice", callerResource: Drupe::Gateway::"gw1", requestId: "u1")
@10 scope(principal: Drupe::OAuthUser::"alice", resource: Drupe::Gateway::"gw1") request_context(input: { document: "a1b" }) Drupe::Action::"Read"::request(input: { document: "a1b" }, callerPrincipal: Drupe::OAuthUser::"alice", callerResource: Drupe::Gateway::"gw1", requestId: "u2")
@20 scope(principal: Drupe::OAuthUser::"alice", resource: Drupe::Gateway::"gw1") request_context(input: { document: "a1b2" }) Drupe::Action::"Read"::request(input: { document: "a1b2" }, callerPrincipal: Drupe::OAuthUser::"alice", callerResource: Drupe::Gateway::"gw1", requestId: "u3")
@30 scope(principal: Drupe::OAuthUser::"alice", resource: Drupe::Gateway::"gw1") request_context(input: { document: "12345" }) Drupe::Action::"Read"::request(input: { document: "12345" }, callerPrincipal: Drupe::OAuthUser::"alice", callerResource: Drupe::Gateway::"gw1", requestId: "u4")
Expected Output
@0 (time point 0): DENY
@10 (time point 1): DENY
@20 (time point 2): ALLOW [rules: 0]
@30 (time point 3): ALLOW [rules: 0]
Provider Declarations
{
"availableProviders": {
"Strings::DigitCount": {
"argumentTypes": [
{
"paramType": "string"
}
],
"outputType": {
"paramType": "record",
"fields": {
"count": {
"paramType": "integer"
}
},
"required": [
"count"
]
},
"implementation": {
"kind": "rhai",
"script": "// Strings::DigitCount(text) -> { count: Long }.\n// Counts the digit characters in the document via the regex_count host\n// function (non-overlapping matches of [0-9]).\n// (Kept in sync with digits.rhai; inlined here because the CLI reads\n// providers.json as text and does not resolve scriptFile references.)\nfn evaluate(text) {\n // Defensive per the provider contract: a provider may be evaluated\n // for ANY decision event, so any argument may be absent (unit).\n // Return a conforming sentinel instead of erroring (errors are UB).\n if type_of(text) == \"()\" {\n return #{ count: -1 };\n }\n\n #{ count: regex_count(\"[0-9]\", text) }\n}\n"
}
}
}
}