Native OCaml Rego/OPA policy engine
0
fork

Configure Feed

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

ocaml-rego: with-mock redirect tries multiple candidate paths

When a rule is mocked via [with foo as bar], the [bar] reference was
resolved by always prepending [env.current_pkg], which broke for
builtin paths and import targets. Fix:

- For unqualified names that aren't imports, try the current-package
qualified path AND the bare path as written (e.g. for builtins).
- For [data.*] paths, use the path verbatim (no current_pkg prefix).
- Inside a redirect, drop *all* in-scope mocks (was: only the current
one) so the replacement sees originals — matches OPA's "a mock
doesn't call another mock" rule.
- Fall through user functions, builtins, and data values in order.

+40 -14
+40 -14
lib/eval.ml
··· 1570 1570 } 1571 1571 | Some path -> 1572 1572 (* Builtin / function mock. The replacement may be a value or a 1573 - reference to another rule (function or rule-defined value). *) 1573 + reference to another rule (function or builtin path). *) 1574 1574 let mock = 1575 1575 match wm.Ast.wm_as with 1576 1576 | Ast.Var (_, name) when not (List.mem_assoc name bnds) -> ( 1577 1577 match List.assoc_opt name env.imports with 1578 1578 | Some import_path -> Mock_redirect import_path 1579 - | None -> Mock_redirect (env.current_pkg @ [ name ])) 1579 + | None -> Mock_redirect [ name ]) 1580 1580 | (Ast.RefDot _ | Ast.RefBrack _) as e -> ( 1581 1581 match path_of_ref e with 1582 1582 | Some p -> Mock_redirect p ··· 1886 1886 match mock_for path with 1887 1887 | Some (Mock_value v) -> Some v 1888 1888 | Some (Mock_redirect target) -> ( 1889 - (* Inside the redirect, drop the mock so the replacement 1890 - can call the original target without looping back into 1891 - itself. *) 1892 - let env' = 1893 - { 1894 - env with 1895 - mocks = List.filter (fun (p, _) -> p <> path) env.mocks; 1896 - } 1889 + (* Inside the redirect, drop *all* in-scope mocks. The 1890 + replacement therefore sees the original implementations 1891 + of every other builtin/function, matching OPA's "a mock 1892 + doesn't call another mock" rule. *) 1893 + let env' = { env with mocks = [] } in 1894 + (* Candidates: current-package qualified (for unqualified 1895 + names), then the path as written. *) 1896 + let candidates = 1897 + if target = [] then [] 1898 + else 1899 + match target with 1900 + | "data" :: _ -> [ target ] 1901 + | _ -> [ env.current_pkg @ target; target ] 1897 1902 in 1898 - match user_function env' target vargs with 1903 + let rec try_user = function 1904 + | [] -> None 1905 + | t :: rest -> ( 1906 + match user_function env' t vargs with 1907 + | Some _ as r -> r 1908 + | None -> try_user rest) 1909 + in 1910 + match try_user candidates with 1899 1911 | Some _ as r -> r 1900 - | None -> 1901 - let v = resolve_data_path env' target in 1902 - if Value.equal v Value.Undefined then None else Some v) 1912 + | None -> ( 1913 + let target_name = String.concat "." target in 1914 + match 1915 + try Some (eval_builtin target_name vargs) 1916 + with Eval_error _ -> None 1917 + with 1918 + | Some _ as r -> r 1919 + | None -> 1920 + let try_value = 1921 + List.find_map 1922 + (fun t -> 1923 + let v = resolve_data_path env' t in 1924 + if Value.equal v Value.Undefined then None 1925 + else Some v) 1926 + candidates 1927 + in 1928 + try_value)) 1903 1929 | None -> ( 1904 1930 match user_function env path vargs with 1905 1931 | Some v -> Some v