Files
regorus/docs/knowledge/azure-policy-language.md
copilot-swe-agent[bot] 524aab5528 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>
2026-04-25 21:20:10 +00:00

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:

  1. Parses JSON → PolicyRule AST
  2. Compiles constraints to RVM instructions (shared VM)
  3. Populates metadata (language annotation "azure_policy", effect info)
  4. Resolves parameter defaults
  5. 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 Program struct as Rego
  • Value type: evaluation uses the same Value enum
  • Engine: accessible via Engine::compile_for_target() when the azure_policy feature is enabled
  • CompiledPolicy: wraps the RVM program with metadata

Key Invariants

  1. Case-insensitive matching — Azure Policy field names are case-insensitive. All comparisons must use case-folded strings.

  2. Alias resolution order — aliases must be resolved before compilation. Missing aliases produce compile-time errors, not runtime errors.

  3. Wildcard semantics[*] is implicitly "for all" unless inside a count expression where it becomes "for each".

  4. Effect metadata — the compiled program must carry effect information in metadata, not in the instruction stream.