Fix RVM evaluation of default-only rules (#664)

Default-only rules (e.g., `default deny := true` with no conditional body)
returned Undefined in the RVM instead of the default value.

Compiler:
- compute_rule_type: return Complete when rule exists only in default_rules map
- compile_worklist_rule: emit register slots and data-tree entries for
  default-only rules (else branch)

VM:
- execute_call_rule_common + execute_call_rule_suspendable: check
  default_literal_index before returning Undefined when definitions is empty

Tests:
- 3 new RVM cases (default_rules.yaml): bool, object, entry-point
- 3 new interpreter cases (default/basic.yaml): matching coverage

Co-authored-by: Mark Birger <markbirger@microsoft.com>
This commit is contained in:
Mark Birger
2026-04-07 18:38:50 +02:00
committed by GitHub
parent e5ac9a2734
commit 83ce8c3580
4 changed files with 106 additions and 2 deletions
+12 -2
View File
@@ -191,7 +191,13 @@ impl RegoVM {
let rule_definitions = rule_info.definitions.clone();
if rule_definitions.is_empty() {
let result = Value::Undefined;
// No compiled definitions — check for a default value before returning Undefined.
// Default-only rules (e.g., `default deny := true`) have no body definitions
// but their default value was evaluated at compile time and stored as a literal.
let result = rule_info
.default_literal_index
.and_then(|idx| self.program.literals.get(usize::from(idx)).cloned())
.unwrap_or(Value::Undefined);
if !is_function_rule {
let available = self.rule_cache.len();
let entry =
@@ -336,7 +342,11 @@ impl RegoVM {
}
if rule_info.definitions.is_empty() {
let result = Value::Undefined;
// No compiled definitions — check for a default value before returning Undefined.
let result = rule_info
.default_literal_index
.and_then(|idx| self.program.literals.get(usize::from(idx)).cloned())
.unwrap_or(Value::Undefined);
if !is_function_rule {
let available = self.rule_cache.len();
let entry =