From 98a689d7db8528cd5f0fd9c3dda54fc2207df35f Mon Sep 17 00:00:00 2001 From: Friel Date: Tue, 11 Aug 2026 17:50:35 +0000 Subject: [PATCH] capi: expose authorizer runtime limits --- biscuit-capi/src/lib.rs | 30 +++++++++++++++++++++++++++++- biscuit-capi/tests/capi.rs | 34 ++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/biscuit-capi/src/lib.rs b/biscuit-capi/src/lib.rs index 15e8f1be..3096936d 100644 --- a/biscuit-capi/src/lib.rs +++ b/biscuit-capi/src/lib.rs @@ -9,9 +9,10 @@ use std::{ ffi::{CStr, CString}, fmt, os::raw::c_char, + time::Duration, }; -use biscuit_auth::datalog::SymbolTable; +use biscuit_auth::datalog::{RunLimits, SymbolTable}; enum Error { Biscuit(biscuit_auth::error::Token), @@ -1092,6 +1093,16 @@ pub unsafe extern "C" fn block_builder_add_check( pub unsafe extern "C" fn block_builder_free(_builder: Option>) {} impl AuthorizerBuilder { + fn set_limits(&mut self, max_facts: u64, max_iterations: u64, max_time_microseconds: u64) { + let mut inner = self.0.take().unwrap(); + inner = inner.set_limits(RunLimits { + max_facts, + max_iterations, + max_time: Duration::from_micros(max_time_microseconds), + }); + self.0 = Some(inner); + } + fn add_fact(&mut self, fact: &str) -> Result<(), biscuit_auth::error::Token> { let mut inner = self.0.take().unwrap(); inner = inner.fact(fact)?; @@ -1128,6 +1139,23 @@ pub unsafe extern "C" fn authorizer_builder() -> Option> )))) } +#[no_mangle] +pub unsafe extern "C" fn authorizer_builder_set_limits( + builder: Option<&mut AuthorizerBuilder>, + max_facts: u64, + max_iterations: u64, + max_time_microseconds: u64, +) -> bool { + if builder.is_none() { + update_last_error(Error::InvalidArgument); + return false; + } + let builder = builder.unwrap(); + + builder.set_limits(max_facts, max_iterations, max_time_microseconds); + true +} + #[no_mangle] pub unsafe extern "C" fn authorizer_builder_add_fact( builder: Option<&mut AuthorizerBuilder>, diff --git a/biscuit-capi/tests/capi.rs b/biscuit-capi/tests/capi.rs index 96306dee..2e37f7ea 100644 --- a/biscuit-capi/tests/capi.rs +++ b/biscuit-capi/tests/capi.rs @@ -150,6 +150,40 @@ biscuit block 0 context: (null) ); } +#[test] +fn authorizer_limits() { + (assert_c! { + #include + #include + #include "biscuit_auth.h" + + int main() { + char *seed = "abcdefghabcdefghabcdefghabcdefgh"; + PrivateKey *root_kp = key_pair_new((const uint8_t *) seed, strlen(seed), 0); + BiscuitBuilder *b = biscuit_builder(); + biscuit_builder_add_fact(b, "right(\"file1\", \"read\")"); + Biscuit *biscuit = biscuit_builder_build(b, root_kp, (const uint8_t *) seed, strlen(seed)); + + AuthorizerBuilder *ab = authorizer_builder(); + authorizer_builder_add_rule(ab, "can_read($file) <- right($file, \"read\")"); + authorizer_builder_add_policy(ab, "allow if true"); + authorizer_builder_set_limits(ab, 1, 100, 1000000); + Authorizer *authorizer = authorizer_builder_build(ab, biscuit); + + if (!authorizer_authorize(authorizer)) { + printf("authorizer error code: %d\n", error_kind()); + } + + authorizer_free(authorizer); + biscuit_free(biscuit); + key_pair_free(root_kp); + return 0; + } + }) + .success() + .stdout("authorizer error code: 25\n"); +} + #[test] fn serialize_keys() { (assert_c! {