Native OCaml Rego/OPA policy engine
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

ocaml-rego: pluggable now_ns clock, snapshotted per query

Rego.engine takes an optional ?now_ns callback that supplies ns
since the Unix epoch; the default uses Unix.gettimeofday. Eio
callers can pass their clock there. Each call to eval/eval_query
snapshots the clock once into env.now_ns so multiple time.now_ns()
calls in one query return the same value.

+22 -6
+11 -5
lib/eval.ml
··· 34 34 strict : bool; 35 35 (** When [true], builtin errors propagate to the caller instead of being 36 36 treated as undefined — OPA's [strict_error] mode. *) 37 + now_ns : float; 38 + (** Snapshot of [time.now_ns ()] at evaluation start so multiple calls 39 + within one query return the same value. *) 37 40 } 38 41 39 42 type bindings = (string * Value.t) list ··· 2071 2074 | None -> ( 2072 2075 let target_name = String.concat "." target in 2073 2076 match 2074 - try Some (eval_builtin target_name vargs) 2077 + try Some (eval_builtin ~env target_name vargs) 2075 2078 with Eval_error _ -> None 2076 2079 with 2077 2080 | Some _ as r -> r ··· 2089 2092 match user_function env path vargs with 2090 2093 | Some v -> Some v 2091 2094 | None -> ( 2092 - if env.strict then Some (eval_builtin name vargs) 2095 + if env.strict then Some (eval_builtin ~env name vargs) 2093 2096 else 2094 - try Some (eval_builtin name vargs) 2097 + try Some (eval_builtin ~env name vargs) 2095 2098 with Eval_error _ -> None)) 2096 2099 in 2097 2100 eval_seq env bnds args ··· 2247 2250 try_bodies bodies) 2248 2251 | _ -> None 2249 2252 2250 - and eval_builtin name args = 2253 + and eval_builtin ~env name args = 2251 2254 match (name, args) with 2252 2255 (* Aggregates *) 2253 2256 | "count", [ Value.Array xs ] | "count", [ Value.Set xs ] -> ··· 2643 2646 | "units.parse_bytes", [ Value.String s ] -> 2644 2647 Value.Number (units_parse_bytes s) 2645 2648 (* Time *) 2646 - | "time.now_ns", [] -> Value.Number (Unix.gettimeofday () *. 1e9) 2649 + | "time.now_ns", [] -> 2650 + (* Use the env-snapshotted time so multiple calls within the same 2651 + query return the same value. *) 2652 + Value.Number env.now_ns 2647 2653 | "time.parse_duration_ns", [ Value.String s ] -> 2648 2654 Value.Number (parse_duration s) 2649 2655 | "time.parse_rfc3339_ns", [ Value.String s ] ->
+11 -1
lib/rego.ml
··· 108 108 mutable strict : bool; 109 109 (** When [true], builtin errors propagate instead of producing [Undefined] 110 110 — matches OPA's [strict_error] mode. *) 111 + mutable now_ns : unit -> float; 112 + (** Clock used by [time.now_ns]. Defaults to a Unix gettimeofday-based 113 + source; pass [Eio.Time.Clock.now] (scaled to ns) at engine creation or 114 + via [set_now_ns] to use an Eio clock instead. *) 111 115 } 112 116 113 - let engine () = { modules = []; data = Value.Object []; strict = false } 117 + let default_now_ns () = Unix.gettimeofday () *. 1e9 118 + 119 + let engine ?(now_ns = default_now_ns) () = 120 + { modules = []; data = Value.Object []; strict = false; now_ns } 121 + 114 122 let set_strict e b = e.strict <- b 123 + let set_now_ns e f = e.now_ns <- f 115 124 let add_data e data = e.data <- data 116 125 117 126 let add_data_json e json = ··· 140 149 evaluating = []; 141 150 mocks = []; 142 151 strict = e.strict; 152 + now_ns = e.now_ns (); 143 153 } 144 154 145 155 let eval e ~input query =