mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
Add knowledge docs, agent definitions, and skill files
Add comprehensive documentation and GitHub Copilot configuration: - docs/knowledge/: 17 deep-dive knowledge files covering value semantics, RVM architecture, builtins, FFI boundary, feature composition, error handling migration, policy evaluation security, Rego semantics, interpreter/compiler architecture, Azure Policy/RBAC, engine API, time builtins, language extension guide, tooling architecture, causality/partial eval, Rego compiler, Azure Policy aliases, and telemetry/diagnostics - .github/agents/: 16 role-specific AI agent definitions (red-teamer, semantics-expert, architect, performance-engineer, test-engineer, verification-engineer, security-auditor, reliability-engineer, support-engineer, ci-engineer, refactorer, api-steward, program-manager, demo-engineer, dx-engineer, tech-lead) - .github/skills/: 6 workflow skill definitions (thorough-review, design-alternatives, add-builtin, opa-conformance, security-review, verification) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: anakrish <35780660+anakrish@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
3d16489ec6
commit
524aab5528
@@ -0,0 +1,230 @@
|
||||
<!-- Copyright (c) Microsoft Corporation. All rights reserved. -->
|
||||
<!-- Licensed under the MIT License. -->
|
||||
|
||||
# Knowledge: Rego Semantics
|
||||
|
||||
Deep knowledge about how regorus evaluates Rego policies. Read this before
|
||||
modifying `src/interpreter.rs`, `src/scheduler.rs`, `src/compiler/`, or
|
||||
any evaluation-related code.
|
||||
|
||||
## Evaluation Model
|
||||
|
||||
Regorus is a **compile-then-execute** engine. Key passes:
|
||||
|
||||
```
|
||||
Source → Lexer → Parser → AST → Compiler (scheduling, destructuring, loop hoisting) → Execution
|
||||
```
|
||||
|
||||
The compiler pre-computes:
|
||||
- **Destructuring plans**: how to bind variables from patterns
|
||||
- **Schedules**: statement execution order within rule bodies
|
||||
- **Loop hoisting**: which iterations can be computed at compile time
|
||||
|
||||
Runtime evaluation is then straightforward — no runtime planning.
|
||||
|
||||
## Rule Evaluation
|
||||
|
||||
### Rule Types
|
||||
|
||||
**Complete rules** — produce a single value:
|
||||
```rego
|
||||
allow = true { input.role == "admin" }
|
||||
```
|
||||
|
||||
**Partial rules** — can have multiple bodies, first success wins:
|
||||
```rego
|
||||
allow { input.role == "admin" }
|
||||
allow { input.role == "superuser" }
|
||||
```
|
||||
Bodies are evaluated in order. When one succeeds, remaining bodies are skipped.
|
||||
|
||||
**Default rules** — fallback when no rule produces a value:
|
||||
```rego
|
||||
default allow = false
|
||||
```
|
||||
Default rules are explicitly skipped during normal rule evaluation. They fire
|
||||
only when the path is `Undefined` and no complete rule exists.
|
||||
|
||||
**Precedence**: `initial data > evaluated rules > default rules`
|
||||
|
||||
### Rule Caching
|
||||
|
||||
Evaluated rules are tracked in `self.processed` set to prevent re-evaluation.
|
||||
Once a rule has been evaluated for a given context, it won't be re-evaluated
|
||||
unless the context changes (e.g., via `with` keyword).
|
||||
|
||||
## Unification and Destructuring
|
||||
|
||||
Regorus does **NOT use a traditional unification algorithm**. Instead:
|
||||
|
||||
1. The **compiler** analyzes patterns and generates `DestructuringPlan`s
|
||||
2. At runtime, `execute_destructuring_plan()` matches values against patterns
|
||||
3. Returns `true` (match succeeded, variables bound) or `false` (no match)
|
||||
|
||||
This is more like pattern matching than Prolog-style unification. There is no
|
||||
occurs check, no variable-to-variable binding chains.
|
||||
|
||||
## Backtracking
|
||||
|
||||
Backtracking in regorus is **limited and explicit** — it only occurs with
|
||||
`some...in` expressions:
|
||||
|
||||
```rego
|
||||
some x in collection
|
||||
```
|
||||
|
||||
The backtracking mechanism:
|
||||
1. Save current scope
|
||||
2. Iterate over the collection
|
||||
3. For each element, bind variables and evaluate remaining statements
|
||||
4. If remaining statements fail, restore scope and try next element
|
||||
5. Succeed if any element leads to successful evaluation
|
||||
|
||||
**There is no implicit backtracking** in other contexts. Statements in a rule
|
||||
body execute sequentially — if one fails, the entire rule body fails (no
|
||||
trying alternatives for previous statements).
|
||||
|
||||
## Undefined Propagation in Evaluation
|
||||
|
||||
### Boolean and Comparison Operations
|
||||
|
||||
```
|
||||
Undefined <op> anything → Undefined
|
||||
anything <op> Undefined → Undefined
|
||||
```
|
||||
|
||||
This applies to all binary operations: `==`, `!=`, `<`, `>`, `<=`, `>=`,
|
||||
`+`, `-`, `*`, `/`, `%`, `&`, `|`.
|
||||
|
||||
### Negation (the subtle case)
|
||||
|
||||
```
|
||||
not true → false
|
||||
not false → true
|
||||
not Undefined → true
|
||||
```
|
||||
|
||||
`not Undefined` is `true` because negating "this expression has no value"
|
||||
means "the condition is not met" which is truthy. This is correct OPA
|
||||
semantics.
|
||||
|
||||
### Reference Chains
|
||||
|
||||
```rego
|
||||
x = input.a.b.c
|
||||
```
|
||||
|
||||
If `input.a` exists but `input.a.b` doesn't, the entire reference returns
|
||||
`Undefined`. The interpreter navigates the path and returns `Undefined` at the
|
||||
first missing component.
|
||||
|
||||
### Collection Literals
|
||||
|
||||
```rego
|
||||
arr = [1, x, 3] # If x is Undefined, arr is Undefined (not [1, 3])
|
||||
```
|
||||
|
||||
Any `Undefined` element poisons the entire collection literal. This is not
|
||||
intuitive but matches OPA semantics.
|
||||
|
||||
### Builtin Arguments
|
||||
|
||||
```rego
|
||||
count(x) # If x is Undefined, result is Undefined
|
||||
```
|
||||
|
||||
If any argument to a builtin is `Undefined`, the result is `Undefined`. The
|
||||
function is never called.
|
||||
|
||||
### Rule Body Statements
|
||||
|
||||
When a statement in a rule body evaluates to `Undefined` or `false`, the
|
||||
rule body fails. Statements must succeed sequentially:
|
||||
|
||||
```rego
|
||||
allow {
|
||||
input.role == "admin" # If Undefined → body fails here
|
||||
input.active == true # Never reached
|
||||
}
|
||||
```
|
||||
|
||||
## Virtual Documents (Rules as Data)
|
||||
|
||||
Rules materialize into the `data` object. When code references `data.pkg.rule`,
|
||||
the interpreter:
|
||||
|
||||
1. Checks if the path has initial data (from `add_data()`)
|
||||
2. If not, looks for rules that define that path
|
||||
3. Evaluates those rules (if not already cached)
|
||||
4. Returns the result
|
||||
|
||||
`ensure_rule_evaluated()` is the trigger — it's called during path navigation
|
||||
when a reference might resolve to a rule-defined value.
|
||||
|
||||
## The `with` Keyword
|
||||
|
||||
`with` temporarily overrides data, input, or functions during evaluation:
|
||||
|
||||
```rego
|
||||
x = eval { y = f(1) with f as g }
|
||||
```
|
||||
|
||||
Implementation pattern (save/modify/restore):
|
||||
1. Save current state (data, input, processed rules, rule values, with_functions)
|
||||
2. Apply overrides — modify `self.with_document` and related state
|
||||
3. Clear `self.processed` to allow re-evaluation with new overrides
|
||||
4. Evaluate the expression
|
||||
5. Restore original state
|
||||
|
||||
**Function override types:**
|
||||
- `FunctionModifier::Value(v)` — replace function with a constant value
|
||||
- `FunctionModifier::Function(path)` — replace function with another function
|
||||
|
||||
## Comprehensions
|
||||
|
||||
All comprehensions follow the same pattern:
|
||||
|
||||
1. Push new context with `output_expr` and collection type
|
||||
2. Evaluate the query (generates solutions)
|
||||
3. For each solution, evaluate `output_expr` and add to context's collection
|
||||
4. Pop context and return accumulated collection
|
||||
|
||||
**Array comprehension**: `[expr | query]` → ordered array of expr values
|
||||
**Set comprehension**: `{expr | query}` → set of expr values
|
||||
**Object comprehension**: `{key: value | query}` → object of key-value pairs
|
||||
|
||||
## Scheduling
|
||||
|
||||
The scheduler (`src/scheduler.rs`) determines statement execution order within
|
||||
rule bodies. This is a **compile-time** optimization that:
|
||||
|
||||
1. Analyzes variable dependencies between statements
|
||||
2. Orders statements to minimize wasted work
|
||||
3. Moves ground-truth checks (constants, type checks) before expensive iterations
|
||||
4. Hoists loop-invariant computations
|
||||
|
||||
The schedule is pre-computed and stored — the interpreter follows it directly.
|
||||
|
||||
## OPA Conformance
|
||||
|
||||
Regorus targets faithful OPA semantics. The conformance suite (`tests/opa.rs`)
|
||||
runs the official OPA test cases. Key areas where conformance matters:
|
||||
|
||||
- **Undefined propagation** — must match OPA exactly
|
||||
- **Error messages** — builtin error messages are compared literally
|
||||
- **Type coercion** — number handling, string comparison
|
||||
- **Rule indexing** — which rules fire for which inputs
|
||||
- **Comprehension behavior** — ordering, deduplication
|
||||
|
||||
When behavior differs from OPA, it's a bug unless documented as an intentional
|
||||
extension (gated behind `rego-extensions` feature).
|
||||
|
||||
## Common Pitfalls
|
||||
|
||||
1. **Treating Undefined as false** — see value-semantics.md for the full story
|
||||
2. **Forgetting `not Undefined = true`** — the most common subtle bug
|
||||
3. **Collection literal with Undefined element** — entire collection becomes Undefined
|
||||
4. **Rule body short-circuit** — first failing statement stops the body
|
||||
5. **Default rule precedence** — defaults only fire when path is truly Undefined
|
||||
6. **`with` scope** — overrides only apply to the expression, not siblings
|
||||
7. **Virtual document evaluation order** — rules may evaluate lazily
|
||||
Reference in New Issue
Block a user