mirror of
https://github.com/microsoft/regorus.git
synced 2026-08-05 02:16:11 +00:00
feat(azure-policy): implement condition, expression, field, and template dispatch compilation (#686)
Fill in the compiler stubs for the evaluation layer. Condition and wildcard compilation: - Compile allOf/anyOf/not constraints, operator conditions with value-condition guards, and implicit allOf for unbound [*] fields via recursive Every loops. - Defensively lowercase prefix/suffix path segments in wildcard handling for consistency with the collect path. Expression and field compilation: - Parse ARM template expressions and dispatch calls to parameters, field, current, resourceGroup, subscription, and others. - Compile all FieldKind variants (type, id, name, location, tags, aliases, dynamic if/concat), resolve resource paths, and collect wildcard values via ForEach loops. Template function dispatch: - Wire up 50+ ARM template functions covering string, numeric, encoding, collection, date/time, logical, and comparison categories. Compiler infrastructure (core.rs): - Add emit helpers: load_literal, emit_builtin_call, emit_chained_index_literal_path, load_input, load_context, emit_coalesce_undefined_to_null, add_literal_u16, and get_or_add_builtin_index. - Add alias resolution via resolve_alias_path and strip_fq_prefix. Misc cleanup: - Handle ARM template `[[` escape sequences in json_value_to_runtime and add a test for it. - Tighten module visibility (pub -> pub(crate)/pub(super)) where appropriate. - Add span context to bail errors in stubs so diagnostics carry source locations. - Take CountBinding by reference in compile_from_binding. - Suppress clippy warnings on the no-op memory_check stub.
This commit is contained in:
committed by
GitHub
parent
f727096a1d
commit
f50a9744ff
@@ -1,6 +1,6 @@
|
||||
// Copyright (c) Microsoft Corporation.
|
||||
// Licensed under the MIT License.
|
||||
#![allow(dead_code, clippy::pattern_type_mismatch, clippy::redundant_pub_crate)]
|
||||
#![allow(dead_code, clippy::pattern_type_mismatch)]
|
||||
|
||||
//! Free helper functions used by the Azure Policy compiler.
|
||||
|
||||
@@ -27,17 +27,22 @@ pub(super) fn extract_string_literal(expr: &Expr) -> Result<String> {
|
||||
pub(super) fn split_count_wildcard_path(path: &str) -> Result<(String, Option<String>)> {
|
||||
let wildcard_index = path
|
||||
.find("[*]")
|
||||
.ok_or_else(|| anyhow!("count.field must contain [*]: {}", path))?;
|
||||
.ok_or_else(|| anyhow!("wildcard path must contain [*]: {}", path))?;
|
||||
|
||||
let (prefix_str, rest) = path.split_at(wildcard_index);
|
||||
let prefix = prefix_str.trim_end_matches('.');
|
||||
if prefix.is_empty() {
|
||||
bail!(
|
||||
"count.field must have a non-empty prefix before [*]: {}",
|
||||
"wildcard path must have a non-empty prefix before [*]: {}",
|
||||
path
|
||||
);
|
||||
}
|
||||
let after_wildcard = &rest[3..];
|
||||
let after_wildcard = rest.strip_prefix("[*]").ok_or_else(|| {
|
||||
anyhow!(
|
||||
"wildcard path could not be parsed after [*] split: {}",
|
||||
path
|
||||
)
|
||||
})?;
|
||||
if after_wildcard.contains("[*]") {
|
||||
bail!("nested [*] wildcards are not supported: {}", path);
|
||||
}
|
||||
@@ -145,14 +150,20 @@ pub(super) fn split_path_without_wildcards(path: &str) -> Result<Vec<String>> {
|
||||
}
|
||||
|
||||
/// Convert a parsed JSON value from the Azure Policy AST into a runtime [`Value`].
|
||||
pub(crate) fn json_value_to_runtime(value: &JsonValue) -> Result<Value> {
|
||||
pub(super) fn json_value_to_runtime(value: &JsonValue) -> Result<Value> {
|
||||
match value {
|
||||
JsonValue::Null(_) => Ok(Value::Null),
|
||||
JsonValue::Bool(_, b) => Ok(Value::Bool(*b)),
|
||||
JsonValue::Number(_, raw) => {
|
||||
Value::from_numeric_string(raw).map_err(|_| anyhow!("invalid number literal: {}", raw))
|
||||
}
|
||||
JsonValue::Str(_, s) => Ok(Value::from(s.clone())),
|
||||
JsonValue::Str(_, s) => {
|
||||
// Handle ARM template escape: `[[...` → `[...`
|
||||
s.strip_prefix("[[").map_or_else(
|
||||
|| Ok(Value::from(s.clone())),
|
||||
|unescaped| Ok(Value::from(alloc::format!("[{unescaped}"))),
|
||||
)
|
||||
}
|
||||
JsonValue::Array(_, items) => {
|
||||
let mut out = Vec::with_capacity(items.len());
|
||||
for item in items {
|
||||
@@ -269,6 +280,12 @@ mod tests {
|
||||
assert_eq!(v, Value::from("hello".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn json_string_double_bracket_escape() {
|
||||
let v = json_value_to_runtime(&JsonValue::Str(dummy_span(), "[[escaped]".into())).unwrap();
|
||||
assert_eq!(v, Value::from("[escaped]".to_string()));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn json_array() {
|
||||
let arr = JsonValue::Array(
|
||||
|
||||
Reference in New Issue
Block a user