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>
6.6 KiB
Knowledge: Azure Policy Language
Deep knowledge about the Azure Policy language extension in
src/languages/azure_policy/. Read this before modifying Azure Policy
parsing, compilation, or evaluation.
How Azure Policy Differs from Rego
| Aspect | Azure Policy | Rego |
|---|---|---|
| Syntax | JSON-based declarative constraints | Prolog-like logic language |
| Compilation | JSON → AST → RVM bytecode | Source → AST → RVM bytecode |
| Logic model | allOf/anyOf/not combinators |
Set comprehensions, rules |
| Effects | Policy decision directives (Deny, Audit, Modify, ...) | Returns values |
| Templating | ARM template expressions [concat(...)] |
No templating |
| Field access | Direct properties + aliases for resource types | Dot-notation queries |
Despite these differences, Azure Policy compiles to the same RVM bytecode as Rego. The shared VM executes both languages.
Directory Structure
src/languages/azure_policy/
mod.rs Module root
parser/ JSON → PolicyRule AST (6 files)
compiler/ AST → RVM Program (14 files)
ast/ Span-annotated AST types
aliases/ ARM resource alias normalization
normalizer/ ARM JSON → flat alias paths
denormalizer/ Flat paths → ARM JSON structure
expr.rs ARM template expression sub-parser
strings/ Case folding, key normalization
AST Types
Policy Rule Structure
PolicyRule
├── condition: Constraint // "if" clause
└── then_block: ThenBlock // "then" clause with effect
Constraint Hierarchy
enum Constraint {
AllOf { constraints: Vec<Constraint> }, // AND — all must match
AnyOf { constraints: Vec<Constraint> }, // OR — any must match
Not { constraint: Box<Constraint> }, // Negation
Condition(Box<Condition>), // Leaf condition
}
struct Condition {
lhs: Lhs, // What to evaluate (Field, Value, or Count)
operator: OperatorNode, // How to compare (19 operators)
rhs: ValueOrExpr, // What to compare against
}
19 Operators
Contains, ContainsKey, Equals, Greater, GreaterOrEquals, Exists, In, Less, LessOrEquals, Like, Match, MatchInsensitively, NotContains, NotContainsKey, NotEquals, NotIn, NotLike, NotMatch, NotMatchInsensitively.
Effects
enum EffectKind {
Deny, Audit, Append, AuditIfNotExists, DeployIfNotExists,
Disabled, Modify, DenyAction, Manual, Other,
}
Note: Effect compilation is not yet fully implemented — the compiler has stubs for effect handling.
Compilation to RVM
Azure Policy compiles directly to RVM bytecode through a dedicated compiler:
pub fn compile_policy_rule(rule: &PolicyRule) -> Result<Rc<Program>>
pub fn compile_policy_definition(defn: &PolicyDefinition) -> Result<Rc<Program>>
pub fn compile_policy_definition_with_aliases(rule, alias_map, modifiable) -> Result<Rc<Program>>
The compiler:
- Parses JSON →
PolicyRuleAST - Compiles constraints to RVM instructions (shared VM)
- Populates metadata (language annotation "azure_policy", effect info)
- Resolves parameter defaults
- Optionally resolves aliases
Compiler State
struct Compiler {
program: Program, // Shared RVM program being built
register_counter: u8, // Register allocation
alias_map: BTreeMap<String, String>,// Alias resolution
parameter_defaults: Option<Value>, // Default parameter values
cached_input_reg: Option<u8>, // Cached LoadInput register
cached_context_reg: Option<u8>, // Cached LoadContext register
}
Alias System
Azure Policy uses "aliases" to refer to resource properties in a normalized way. The alias system has two phases:
Normalizer
Converts ARM JSON resource representations to flat structures with alias paths. Handles:
- Nested resource properties
- Sub-resource types (e.g.,
Microsoft.Compute/virtualMachines/extensions) - Array element access
- Case-insensitive property matching
Denormalizer
Converts flat alias paths back to ARM JSON structure. This is needed for Modify/Append effects that need to construct resource representations.
Key complexity: Casing must survive round-trip. ARM JSON casing is preserved through normalization and denormalization.
ARM Template Expressions
Azure Policy conditions can contain ARM template expressions:
{
"field": "[concat(field('Microsoft.Storage/storageAccounts/name'), '/default')]",
"equals": "[parameters('storageName')]"
}
The expression parser (expr.rs) handles:
- Recursive descent parsing (
.,(),[]operators) - Unknown symbols enabled in lexer mode
- 65,536 character column limit for deeply nested expressions
- Functions:
concat(),field(),parameters(), etc.
Count Expressions
Azure Policy supports counting with optional where clauses:
{
"count": {
"field": "Microsoft.Network/networkSecurityGroups/securityRules[*]",
"where": { "field": "...", "equals": "..." }
},
"greater": 0
}
The compiler handles count with existence-pattern optimization — common patterns like "count > 0" can be compiled as existence checks.
Wildcard Handling
The [*] wildcard in field references creates implicit iteration:
{ "field": "Microsoft.Network/securityRules[*].destinationPortRange" }
When a wildcard is unbound, it creates an implicit allOf — the condition
must hold for ALL elements. The compiler generates appropriate iteration
code in the RVM.
Integration Points
Azure Policy integrates with the shared infrastructure:
- RVM Program: compiled output is the same
Programstruct as Rego - Value type: evaluation uses the same
Valueenum - Engine: accessible via
Engine::compile_for_target()when theazure_policyfeature is enabled - CompiledPolicy: wraps the RVM program with metadata
Key Invariants
-
Case-insensitive matching — Azure Policy field names are case-insensitive. All comparisons must use case-folded strings.
-
Alias resolution order — aliases must be resolved before compilation. Missing aliases produce compile-time errors, not runtime errors.
-
Wildcard semantics —
[*]is implicitly "for all" unless inside a count expression where it becomes "for each". -
Effect metadata — the compiled program must carry effect information in metadata, not in the instruction stream.