Compare commits

..

7 Commits

Author SHA1 Message Date
copilot-swe-agent[bot]
eb6e156e8a fix: cover outer-scope bracket key handling
Agent-Logs-Url: https://github.com/microsoft/regorus/sessions/992f5462-7cc4-4e4f-bd7f-799308063765

Co-authored-by: anakrish <35780660+anakrish@users.noreply.github.com>
2026-05-07 03:08:59 +00:00
copilot-swe-agent[bot]
5ae1d8abf2 chore: clarify bracket-head rule semantics
Agent-Logs-Url: https://github.com/microsoft/regorus/sessions/272a971a-ae52-45ae-8cb3-714e747599c4

Co-authored-by: anakrish <35780660+anakrish@users.noreply.github.com>
2026-05-06 22:31:09 +00:00
copilot-swe-agent[bot]
03c4275855 fix: classify constant-key bracket rules precisely
Agent-Logs-Url: https://github.com/microsoft/regorus/sessions/272a971a-ae52-45ae-8cb3-714e747599c4

Co-authored-by: anakrish <35780660+anakrish@users.noreply.github.com>
2026-05-06 22:27:07 +00:00
copilot-swe-agent[bot]
78f226f957 fix: refine constant-key bracket rule handling
Agent-Logs-Url: https://github.com/microsoft/regorus/sessions/272a971a-ae52-45ae-8cb3-714e747599c4

Co-authored-by: anakrish <35780660+anakrish@users.noreply.github.com>
2026-05-06 22:19:56 +00:00
copilot-swe-agent[bot]
bec159a580 test: align VM ObjectSet collision expectations
Agent-Logs-Url: https://github.com/microsoft/regorus/sessions/34a4e1b3-d364-46c4-9998-b00780f5d339

Co-authored-by: anakrish <35780660+anakrish@users.noreply.github.com>
2026-05-06 19:38:42 +00:00
copilot-swe-agent[bot]
117671d959 fix: preserve all bindings for partial object iteration
Agent-Logs-Url: https://github.com/microsoft/regorus/sessions/34a4e1b3-d364-46c4-9998-b00780f5d339

Co-authored-by: anakrish <35780660+anakrish@users.noreply.github.com>
2026-05-06 19:34:41 +00:00
copilot-swe-agent[bot]
8617c79da5 Initial plan 2026-05-06 19:25:36 +00:00
35 changed files with 927 additions and 1605 deletions

View File

@@ -8,5 +8,3 @@ steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
fetch-depth: 0 # full history needed for git diff against main
- run: git fetch origin main:refs/remotes/origin/main
name: Ensure origin/main ref is available for diff computation

View File

@@ -25,21 +25,15 @@ Key constraints (details in copilot-instructions.md):
## Step 1: Get the Diff
```bash
# Primary: use gh pr diff (works in cloud agent + any PR context).
# Fallback: git merge-base for local non-PR usage.
if gh pr diff --name-only >/dev/null 2>&1; then
echo "---STAT---"
gh pr diff --name-only
echo "---DIFF---"
gh pr diff
else
BASE=$(git merge-base upstream/main HEAD 2>/dev/null \
|| git merge-base origin/main HEAD 2>/dev/null \
|| git merge-base main HEAD 2>/dev/null)
echo "Reviewing changes since: $BASE"
git diff "$BASE"..HEAD --stat
git diff "$BASE"..HEAD
BASE=$(git merge-base upstream/main HEAD 2>/dev/null \
|| git merge-base origin/main HEAD 2>/dev/null)
if [ -z "$BASE" ]; then
echo "ERROR: Cannot find upstream/main or origin/main. Cannot determine review scope."
exit 1
fi
echo "Reviewing changes since: $BASE"
git diff "$BASE"..HEAD --stat
git diff "$BASE"..HEAD -- '*.rs' '*.toml' 'examples/'
```
If the diff is empty, stop and report: "No changes found to review."
@@ -202,9 +196,3 @@ one pass. If any were skipped, note them and briefly assess.
### Summary
X findings (N critical, N high, N medium, N low). One sentence overall assessment.
### Output
After generating the report above, write the COMPLETE report to `/tmp/code-review-report.md`
using the `create` tool or shell. This ensures the full report is preserved even if
display output is truncated.

View File

@@ -40,25 +40,22 @@ Use `read_agent` with `wait: true` to wait for each background agent.
## Step 1: Get the Diff and Build Inventory
```bash
# Primary: use gh pr diff (works in cloud agent + any PR context).
# Fallback: git merge-base for local non-PR usage.
if gh pr diff --name-only >/dev/null 2>&1; then
echo "---STAT---"
gh pr diff --name-only
echo "---DIFF---"
gh pr diff
else
BASE=$(git merge-base upstream/main HEAD 2>/dev/null \
|| git merge-base origin/main HEAD 2>/dev/null \
|| git merge-base main HEAD 2>/dev/null)
echo "Reviewing changes since: $BASE"
git diff "$BASE"..HEAD --stat
git diff "$BASE"..HEAD
BASE=$(git merge-base upstream/main HEAD 2>/dev/null \
|| git merge-base origin/main HEAD 2>/dev/null)
if [ -z "$BASE" ]; then
echo "ERROR: Cannot find upstream/main or origin/main."
exit 1
fi
echo "Reviewing changes since: $BASE"
git diff "$BASE"..HEAD --stat
git diff "$BASE"..HEAD -- '*.rs' '*.toml' 'examples/' | head -2000
```
If the diff is empty, stop and report: "No changes found to review."
**Scope rule:** Focus on code files (`*.rs`, `*.toml`, examples). Do NOT pass
docs/config diffs to agents.
**Build a risk-classified inventory.** List every changed function, struct,
impl, trait, pub item, and significant code block. Number them and tag with
risk predicates:
@@ -109,10 +106,8 @@ Use `model: "gpt-5.4"` in the task tool call (provides model diversity).
> Get the diff:
> ```
> BASE=$(git merge-base upstream/main HEAD 2>/dev/null \
> || git merge-base origin/main HEAD 2>/dev/null \
> || git merge-base main HEAD 2>/dev/null)
> # If no merge-base, use: gh pr diff
> git diff "$BASE"..HEAD # or: gh pr diff
> || git merge-base origin/main HEAD 2>/dev/null)
> git diff "$BASE"..HEAD -- '*.rs' '*.toml' 'examples/'
> ```
>
> Key regorus constraints:
@@ -166,10 +161,8 @@ Use `model: "claude-opus-4.6"` in the task tool call.
> Get the diff AND read full source files for context:
> ```
> BASE=$(git merge-base upstream/main HEAD 2>/dev/null \
> || git merge-base origin/main HEAD 2>/dev/null \
> || git merge-base main HEAD 2>/dev/null)
> # If no merge-base, use: gh pr diff
> git diff "$BASE"..HEAD # or: gh pr diff
> || git merge-base origin/main HEAD 2>/dev/null)
> git diff "$BASE"..HEAD -- '*.rs' '*.toml' 'examples/'
> ```
> Then use `view` to read the full source files that were changed.
>
@@ -226,10 +219,8 @@ Use the default model (no `model` parameter).
> Get the diff:
> ```
> BASE=$(git merge-base upstream/main HEAD 2>/dev/null \
> || git merge-base origin/main HEAD 2>/dev/null \
> || git merge-base main HEAD 2>/dev/null)
> # If no merge-base, use: gh pr diff
> git diff "$BASE"..HEAD # or: gh pr diff
> || git merge-base origin/main HEAD 2>/dev/null)
> git diff "$BASE"..HEAD -- '*.rs' '*.toml' 'examples/'
> ```
> Use `view` to read surrounding context.
>
@@ -448,10 +439,8 @@ Launch **1 general-purpose agent in background mode**.
> Get the diff:
> ```
> BASE=$(git merge-base upstream/main HEAD 2>/dev/null \
> || git merge-base origin/main HEAD 2>/dev/null \
> || git merge-base main HEAD 2>/dev/null)
> # If no merge-base, use: gh pr diff
> git diff "$BASE"..HEAD # or: gh pr diff
> || git merge-base origin/main HEAD 2>/dev/null)
> git diff "$BASE"..HEAD -- '*.rs' '*.toml' 'examples/'
> ```
> Use `view` to read full source files.
>
@@ -492,8 +481,8 @@ Launch **1 general-purpose agent in background mode**.
## Step 5: Synthesize and Report
**CRITICAL:** Write the report to `/tmp/deep-review-report.md` FIRST, then display it.
Use a shell command to write the file before any other output in this step.
**IMPORTANT:** This is the primary output. Everything above was preparation.
Keep the report COMPACT — one finding per block, no filler prose.
Apply verdicts from the adversarial verifier:
- **CONFIRMED**: keep at stated severity
@@ -533,9 +522,3 @@ would catch it. If not, name the minimal test that should exist.
X findings (N critical, N high, N medium, N low). Y "likely" findings.
Z dropped (one-line reasons).
Risk assessment in one sentence.
---
**Remember:** The report above MUST be written to `/tmp/deep-review-report.md` at the
START of Step 5 (before displaying it). Use shell: `cat > /tmp/deep-review-report.md << 'REPORT_EOF'`
... report content ... `REPORT_EOF`

71
Cargo.lock generated
View File

@@ -180,9 +180,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "cc"
version = "1.2.62"
version = "1.2.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98"
checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d"
dependencies = [
"find-msvc-tools",
"shlex",
@@ -474,9 +474,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "fancy-regex"
version = "0.18.0"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1e1dacd0d2082dfcf1351c4bdd566bbe89a2b263235a2b50058f1e130a47277"
checksum = "72cf461f865c862bb7dc573f643dd6a2b6842f7c30b07882b56bd148cc2761b8"
dependencies = [
"bit-set",
"regex-automata",
@@ -650,12 +650,9 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.17.1"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
dependencies = [
"foldhash 0.2.0",
]
checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51"
[[package]]
name = "heck"
@@ -835,7 +832,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
dependencies = [
"equivalent",
"hashbrown 0.17.1",
"hashbrown 0.17.0",
"serde",
"serde_core",
]
@@ -869,9 +866,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "js-sys"
version = "0.3.98"
version = "0.3.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08"
checksum = "a1840c94c045fbcf8ba2812c95db44499f7c64910a912551aaaa541decebcacf"
dependencies = [
"cfg-if",
"futures-util",
@@ -881,9 +878,9 @@ dependencies = [
[[package]]
name = "jsonschema"
version = "0.46.5"
version = "0.45.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a5fe5206f06e589caf25e79fc05ccdf91fca745685fe9fe1a13bbdfb479a631"
checksum = "257eb0e588b76827bbddc9e73945a9743693dd2adeaee9da26420f93cfedb798"
dependencies = [
"ahash",
"bytecount",
@@ -950,9 +947,9 @@ checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "lru"
version = "0.18.0"
version = "0.16.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a860605968fce16869fd239cf4237a82f3ac470723415db603b0e8b6c8d4fb9"
checksum = "7f66e8d5d03f609abc3a39e6f08e4164ebf1447a732906d39eb9b99b7919ef39"
[[package]]
name = "memchr"
@@ -960,12 +957,6 @@ version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
[[package]]
name = "micromap"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a86d3146ed3995b5913c414f6664344b9617457320782e64f0bb44afd49d74"
[[package]]
name = "miniz_oxide"
version = "0.8.9"
@@ -1353,16 +1344,14 @@ dependencies = [
[[package]]
name = "referencing"
version = "0.46.5"
version = "0.45.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69e4e17ef386c5383591d07623d3de49cbc601156e7582973e6db98d66a57de2"
checksum = "e2f38748ceca8d0b0013e60f534d94a6e23dfd89fd2a88318fc5a2d04fda1010"
dependencies = [
"ahash",
"fluent-uri",
"getrandom 0.3.4",
"hashbrown 0.16.1",
"itoa",
"micromap",
"parking_lot",
"percent-encoding",
"serde_json",
@@ -1410,7 +1399,7 @@ dependencies = [
"dashmap",
"data-encoding",
"globset",
"hashbrown 0.17.1",
"hashbrown 0.16.1",
"icu_casemap",
"indexmap",
"ipnet",
@@ -1556,9 +1545,9 @@ checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214"
[[package]]
name = "siphasher"
version = "1.0.3"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e"
[[package]]
name = "slab"
@@ -1841,9 +1830,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
version = "0.2.121"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790"
checksum = "df52b6d9b87e0c74c9edfa1eb2d9bf85e5d63515474513aa50fa181b3c4f5db1"
dependencies = [
"cfg-if",
"once_cell",
@@ -1854,9 +1843,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.121"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578"
checksum = "78b1041f495fb322e64aca85f5756b2172e35cd459376e67f2a6c9dffcedb103"
dependencies = [
"quote 1.0.45",
"wasm-bindgen-macro-support",
@@ -1864,9 +1853,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.121"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2"
checksum = "9dcd0ff20416988a18ac686d4d4d0f6aae9ebf08a389ff5d29012b05af2a1b41"
dependencies = [
"bumpalo",
"proc-macro2 1.0.106",
@@ -1877,9 +1866,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.121"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441"
checksum = "49757b3c82ebf16c57d69365a142940b384176c24df52a087fb748e2085359ea"
dependencies = [
"unicode-ident",
]
@@ -1920,9 +1909,9 @@ dependencies = [
[[package]]
name = "web-sys"
version = "0.3.98"
version = "0.3.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b572dff8bcf38bad0fa19729c89bb5748b2b9b1d8be70cf90df697e3a8f32aa"
checksum = "2eadbac71025cd7b0834f20d1fe8472e8495821b4e9801eb0a60bd1f19827602"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -2193,9 +2182,9 @@ dependencies = [
[[package]]
name = "zerofrom"
version = "0.1.8"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272"
checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df"
dependencies = [
"zerofrom-derive",
]

View File

@@ -99,7 +99,7 @@ rand = ["dep:rand"]
anyhow = { version = "1.0.102", default-features = false }
serde = {version = "1.0.150", default-features = false, features = ["derive", "rc", "alloc"] }
serde_json = { version = "1.0.89", default-features = false, features = ["alloc"] }
hashbrown = { version = "0.17", default-features = false, features = ["default-hasher"], optional = true }
hashbrown = { version = "0.16", default-features = false, features = ["default-hasher"], optional = true }
lazy_static = { version = "1.4.0", default-features = false }
thiserror = { version = "2.0", default-features = false }
@@ -114,7 +114,7 @@ regex = {version = "1.12.3", optional = true, default-features = false }
semver = {version = "1.0.28", optional = true, default-features = false }
url = { version = "2.5.4", optional = true }
uuid = { version = "1.22.0", default-features = false, features = ["v4", "fast-rng"], optional = true }
jsonschema = { version = "0.46.5", default-features = false, optional = true }
jsonschema = { version = "0.45.1", default-features = false, optional = true }
chrono = { version = "0.4.44", optional = true }
chrono-tz = { version = "0.10.1", optional = true }
ipnet = { version = "2.12.0", optional = true, default-features = false }
@@ -127,7 +127,7 @@ rand = { version = "0.10.0", default-features = false, features = ["thread_rng"]
# Causes the project to link with the Spectre-mitigated CRT and libs.
msvc_spectre_libs = { version = "0.1", features = ["error"], optional = true }
dashmap = { version = "6.1", default-features = false, optional = true }
lru = { version = "0.18", default-features = false, optional = true }
lru = { version = "0.16", default-features = false, optional = true }
mimalloc = { package = "regorus-mimalloc", path = "mimalloc", version = "2.2.6", optional = true }
# rvm related deps

View File

@@ -172,9 +172,9 @@ dependencies = [
[[package]]
name = "cc"
version = "1.2.62"
version = "1.2.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98"
checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d"
dependencies = [
"find-msvc-tools",
"shlex",
@@ -353,9 +353,9 @@ dependencies = [
[[package]]
name = "fancy-regex"
version = "0.18.0"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1e1dacd0d2082dfcf1351c4bdd566bbe89a2b263235a2b50058f1e130a47277"
checksum = "72cf461f865c862bb7dc573f643dd6a2b6842f7c30b07882b56bd148cc2761b8"
dependencies = [
"bit-set",
"regex-automata",
@@ -508,12 +508,9 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.17.1"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
dependencies = [
"foldhash 0.2.0",
]
checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51"
[[package]]
name = "heck"
@@ -687,7 +684,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
dependencies = [
"equivalent",
"hashbrown 0.17.1",
"hashbrown 0.17.0",
"serde",
"serde_core",
]
@@ -712,9 +709,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "js-sys"
version = "0.3.98"
version = "0.3.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08"
checksum = "a1840c94c045fbcf8ba2812c95db44499f7c64910a912551aaaa541decebcacf"
dependencies = [
"cfg-if",
"futures-util",
@@ -724,9 +721,9 @@ dependencies = [
[[package]]
name = "jsonschema"
version = "0.46.5"
version = "0.45.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a5fe5206f06e589caf25e79fc05ccdf91fca745685fe9fe1a13bbdfb479a631"
checksum = "257eb0e588b76827bbddc9e73945a9743693dd2adeaee9da26420f93cfedb798"
dependencies = [
"ahash",
"bytecount",
@@ -796,9 +793,9 @@ checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "lru"
version = "0.18.0"
version = "0.16.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a860605968fce16869fd239cf4237a82f3ac470723415db603b0e8b6c8d4fb9"
checksum = "7f66e8d5d03f609abc3a39e6f08e4164ebf1447a732906d39eb9b99b7919ef39"
[[package]]
name = "memchr"
@@ -806,12 +803,6 @@ version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
[[package]]
name = "micromap"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a86d3146ed3995b5913c414f6664344b9617457320782e64f0bb44afd49d74"
[[package]]
name = "msvc_spectre_libs"
version = "0.1.3"
@@ -1082,16 +1073,14 @@ dependencies = [
[[package]]
name = "referencing"
version = "0.46.5"
version = "0.45.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69e4e17ef386c5383591d07623d3de49cbc601156e7582973e6db98d66a57de2"
checksum = "e2f38748ceca8d0b0013e60f534d94a6e23dfd89fd2a88318fc5a2d04fda1010"
dependencies = [
"ahash",
"fluent-uri",
"getrandom 0.3.4",
"hashbrown 0.16.1",
"itoa",
"micromap",
"parking_lot",
"percent-encoding",
"serde_json",
@@ -1136,7 +1125,7 @@ dependencies = [
"dashmap",
"data-encoding",
"globset",
"hashbrown 0.17.1",
"hashbrown 0.16.1",
"icu_casemap",
"indexmap",
"ipnet",
@@ -1296,9 +1285,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "siphasher"
version = "1.0.3"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e"
[[package]]
name = "slab"
@@ -1535,9 +1524,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
version = "0.2.121"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790"
checksum = "df52b6d9b87e0c74c9edfa1eb2d9bf85e5d63515474513aa50fa181b3c4f5db1"
dependencies = [
"cfg-if",
"once_cell",
@@ -1548,9 +1537,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.121"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578"
checksum = "78b1041f495fb322e64aca85f5756b2172e35cd459376e67f2a6c9dffcedb103"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -1558,9 +1547,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.121"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2"
checksum = "9dcd0ff20416988a18ac686d4d4d0f6aae9ebf08a389ff5d29012b05af2a1b41"
dependencies = [
"bumpalo",
"proc-macro2",
@@ -1571,9 +1560,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.121"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441"
checksum = "49757b3c82ebf16c57d69365a142940b384176c24df52a087fb748e2085359ea"
dependencies = [
"unicode-ident",
]
@@ -1837,9 +1826,9 @@ dependencies = [
[[package]]
name = "zerofrom"
version = "0.1.8"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272"
checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df"
dependencies = [
"zerofrom-derive",
]

View File

@@ -109,9 +109,9 @@ checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33"
[[package]]
name = "cc"
version = "1.2.62"
version = "1.2.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98"
checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d"
dependencies = [
"find-msvc-tools",
"shlex",
@@ -237,9 +237,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "fancy-regex"
version = "0.18.0"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1e1dacd0d2082dfcf1351c4bdd566bbe89a2b263235a2b50058f1e130a47277"
checksum = "72cf461f865c862bb7dc573f643dd6a2b6842f7c30b07882b56bd148cc2761b8"
dependencies = [
"bit-set",
"regex-automata",
@@ -380,9 +380,9 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.17.1"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51"
[[package]]
name = "heck"
@@ -530,7 +530,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
dependencies = [
"equivalent",
"hashbrown 0.17.1",
"hashbrown 0.17.0",
"serde",
"serde_core",
]
@@ -598,9 +598,9 @@ dependencies = [
[[package]]
name = "js-sys"
version = "0.3.98"
version = "0.3.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08"
checksum = "a1840c94c045fbcf8ba2812c95db44499f7c64910a912551aaaa541decebcacf"
dependencies = [
"cfg-if",
"futures-util",
@@ -610,9 +610,9 @@ dependencies = [
[[package]]
name = "jsonschema"
version = "0.46.5"
version = "0.45.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a5fe5206f06e589caf25e79fc05ccdf91fca745685fe9fe1a13bbdfb479a631"
checksum = "257eb0e588b76827bbddc9e73945a9743693dd2adeaee9da26420f93cfedb798"
dependencies = [
"ahash",
"bytecount",
@@ -676,9 +676,9 @@ checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "lru"
version = "0.18.0"
version = "0.16.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a860605968fce16869fd239cf4237a82f3ac470723415db603b0e8b6c8d4fb9"
checksum = "7f66e8d5d03f609abc3a39e6f08e4164ebf1447a732906d39eb9b99b7919ef39"
[[package]]
name = "memchr"
@@ -686,12 +686,6 @@ version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
[[package]]
name = "micromap"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a86d3146ed3995b5913c414f6664344b9617457320782e64f0bb44afd49d74"
[[package]]
name = "msvc_spectre_libs"
version = "0.1.3"
@@ -954,16 +948,14 @@ dependencies = [
[[package]]
name = "referencing"
version = "0.46.5"
version = "0.45.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69e4e17ef386c5383591d07623d3de49cbc601156e7582973e6db98d66a57de2"
checksum = "e2f38748ceca8d0b0013e60f534d94a6e23dfd89fd2a88318fc5a2d04fda1010"
dependencies = [
"ahash",
"fluent-uri",
"getrandom 0.3.4",
"hashbrown 0.16.1",
"itoa",
"micromap",
"parking_lot",
"percent-encoding",
"serde_json",
@@ -1176,9 +1168,9 @@ checksum = "e3a9fe34e3e7a50316060351f37187a3f546bce95496156754b601a5fa71b76e"
[[package]]
name = "siphasher"
version = "1.0.3"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e"
[[package]]
name = "slab"
@@ -1360,9 +1352,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
version = "0.2.121"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790"
checksum = "df52b6d9b87e0c74c9edfa1eb2d9bf85e5d63515474513aa50fa181b3c4f5db1"
dependencies = [
"cfg-if",
"once_cell",
@@ -1373,9 +1365,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.121"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578"
checksum = "78b1041f495fb322e64aca85f5756b2172e35cd459376e67f2a6c9dffcedb103"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -1383,9 +1375,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.121"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2"
checksum = "9dcd0ff20416988a18ac686d4d4d0f6aae9ebf08a389ff5d29012b05af2a1b41"
dependencies = [
"bumpalo",
"proc-macro2",
@@ -1396,9 +1388,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.121"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441"
checksum = "49757b3c82ebf16c57d69365a142940b384176c24df52a087fb748e2085359ea"
dependencies = [
"unicode-ident",
]
@@ -1659,9 +1651,9 @@ dependencies = [
[[package]]
name = "zerofrom"
version = "0.1.8"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272"
checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df"
dependencies = [
"zerofrom-derive",
]

View File

@@ -103,9 +103,9 @@ checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e"
[[package]]
name = "cc"
version = "1.2.62"
version = "1.2.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98"
checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d"
dependencies = [
"find-msvc-tools",
"shlex",
@@ -221,9 +221,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "fancy-regex"
version = "0.18.0"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1e1dacd0d2082dfcf1351c4bdd566bbe89a2b263235a2b50058f1e130a47277"
checksum = "72cf461f865c862bb7dc573f643dd6a2b6842f7c30b07882b56bd148cc2761b8"
dependencies = [
"bit-set",
"regex-automata",
@@ -364,9 +364,9 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.17.1"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51"
[[package]]
name = "heck"
@@ -514,7 +514,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
dependencies = [
"equivalent",
"hashbrown 0.17.1",
"hashbrown 0.17.0",
"serde",
"serde_core",
]
@@ -533,9 +533,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "js-sys"
version = "0.3.98"
version = "0.3.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08"
checksum = "a1840c94c045fbcf8ba2812c95db44499f7c64910a912551aaaa541decebcacf"
dependencies = [
"cfg-if",
"futures-util",
@@ -545,9 +545,9 @@ dependencies = [
[[package]]
name = "jsonschema"
version = "0.46.5"
version = "0.45.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a5fe5206f06e589caf25e79fc05ccdf91fca745685fe9fe1a13bbdfb479a631"
checksum = "257eb0e588b76827bbddc9e73945a9743693dd2adeaee9da26420f93cfedb798"
dependencies = [
"ahash",
"bytecount",
@@ -611,9 +611,9 @@ checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "lru"
version = "0.18.0"
version = "0.16.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a860605968fce16869fd239cf4237a82f3ac470723415db603b0e8b6c8d4fb9"
checksum = "7f66e8d5d03f609abc3a39e6f08e4164ebf1447a732906d39eb9b99b7919ef39"
[[package]]
name = "memchr"
@@ -621,12 +621,6 @@ version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
[[package]]
name = "micromap"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a86d3146ed3995b5913c414f6664344b9617457320782e64f0bb44afd49d74"
[[package]]
name = "msvc_spectre_libs"
version = "0.1.3"
@@ -963,16 +957,14 @@ dependencies = [
[[package]]
name = "referencing"
version = "0.46.5"
version = "0.45.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69e4e17ef386c5383591d07623d3de49cbc601156e7582973e6db98d66a57de2"
checksum = "e2f38748ceca8d0b0013e60f534d94a6e23dfd89fd2a88318fc5a2d04fda1010"
dependencies = [
"ahash",
"fluent-uri",
"getrandom 0.3.4",
"hashbrown 0.16.1",
"itoa",
"micromap",
"parking_lot",
"percent-encoding",
"serde_json",
@@ -1152,9 +1144,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "siphasher"
version = "1.0.3"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e"
[[package]]
name = "slab"
@@ -1332,9 +1324,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
version = "0.2.121"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790"
checksum = "df52b6d9b87e0c74c9edfa1eb2d9bf85e5d63515474513aa50fa181b3c4f5db1"
dependencies = [
"cfg-if",
"once_cell",
@@ -1345,9 +1337,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.121"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578"
checksum = "78b1041f495fb322e64aca85f5756b2172e35cd459376e67f2a6c9dffcedb103"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -1355,9 +1347,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.121"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2"
checksum = "9dcd0ff20416988a18ac686d4d4d0f6aae9ebf08a389ff5d29012b05af2a1b41"
dependencies = [
"bumpalo",
"proc-macro2",
@@ -1368,9 +1360,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.121"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441"
checksum = "49757b3c82ebf16c57d69365a142940b384176c24df52a087fb748e2085359ea"
dependencies = [
"unicode-ident",
]
@@ -1613,9 +1605,9 @@ dependencies = [
[[package]]
name = "zerofrom"
version = "0.1.8"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272"
checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df"
dependencies = [
"zerofrom-derive",
]

View File

@@ -121,9 +121,9 @@ checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e"
[[package]]
name = "cc"
version = "1.2.62"
version = "1.2.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98"
checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d"
dependencies = [
"find-msvc-tools",
"shlex",
@@ -244,9 +244,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "fancy-regex"
version = "0.18.0"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1e1dacd0d2082dfcf1351c4bdd566bbe89a2b263235a2b50058f1e130a47277"
checksum = "72cf461f865c862bb7dc573f643dd6a2b6842f7c30b07882b56bd148cc2761b8"
dependencies = [
"bit-set",
"regex-automata",
@@ -393,9 +393,9 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.17.1"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51"
[[package]]
name = "heck"
@@ -543,7 +543,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
dependencies = [
"equivalent",
"hashbrown 0.17.1",
"hashbrown 0.17.0",
"serde",
"serde_core",
]
@@ -571,9 +571,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "js-sys"
version = "0.3.98"
version = "0.3.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08"
checksum = "a1840c94c045fbcf8ba2812c95db44499f7c64910a912551aaaa541decebcacf"
dependencies = [
"cfg-if",
"futures-util",
@@ -583,9 +583,9 @@ dependencies = [
[[package]]
name = "jsonschema"
version = "0.46.5"
version = "0.45.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a5fe5206f06e589caf25e79fc05ccdf91fca745685fe9fe1a13bbdfb479a631"
checksum = "257eb0e588b76827bbddc9e73945a9743693dd2adeaee9da26420f93cfedb798"
dependencies = [
"ahash",
"bytecount",
@@ -659,9 +659,9 @@ checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "lru"
version = "0.18.0"
version = "0.16.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a860605968fce16869fd239cf4237a82f3ac470723415db603b0e8b6c8d4fb9"
checksum = "7f66e8d5d03f609abc3a39e6f08e4164ebf1447a732906d39eb9b99b7919ef39"
[[package]]
name = "magnus"
@@ -692,12 +692,6 @@ version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
[[package]]
name = "micromap"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a86d3146ed3995b5913c414f6664344b9617457320782e64f0bb44afd49d74"
[[package]]
name = "minimal-lexical"
version = "0.2.1"
@@ -935,18 +929,18 @@ checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
[[package]]
name = "rb-sys"
version = "0.9.128"
version = "0.9.127"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "45ca28513560e56cfb79a62b1fce363c73af170a182024ce880c77ee9429920a"
checksum = "d7d7c9560fe42dcffa576941394075f18a17dce89fcf718a2fa90b7dc2134d12"
dependencies = [
"rb-sys-build",
]
[[package]]
name = "rb-sys-build"
version = "0.9.128"
version = "0.9.127"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce04b2c55eff3a21aaa623fcc655d94373238e72cac6b3e1a3641ff31649f99a"
checksum = "f1688e8f32967ba48c89e4dfa283b57f901075f542fc7ee9c3d7c5f9091ca1d9"
dependencies = [
"bindgen",
"lazy_static",
@@ -994,16 +988,14 @@ dependencies = [
[[package]]
name = "referencing"
version = "0.46.5"
version = "0.45.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69e4e17ef386c5383591d07623d3de49cbc601156e7582973e6db98d66a57de2"
checksum = "e2f38748ceca8d0b0013e60f534d94a6e23dfd89fd2a88318fc5a2d04fda1010"
dependencies = [
"ahash",
"fluent-uri",
"getrandom 0.3.4",
"hashbrown 0.16.1",
"itoa",
"micromap",
"parking_lot",
"percent-encoding",
"serde_json",
@@ -1211,9 +1203,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "siphasher"
version = "1.0.3"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e"
[[package]]
name = "slab"
@@ -1391,9 +1383,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
version = "0.2.121"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790"
checksum = "df52b6d9b87e0c74c9edfa1eb2d9bf85e5d63515474513aa50fa181b3c4f5db1"
dependencies = [
"cfg-if",
"once_cell",
@@ -1404,9 +1396,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.121"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578"
checksum = "78b1041f495fb322e64aca85f5756b2172e35cd459376e67f2a6c9dffcedb103"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -1414,9 +1406,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.121"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2"
checksum = "9dcd0ff20416988a18ac686d4d4d0f6aae9ebf08a389ff5d29012b05af2a1b41"
dependencies = [
"bumpalo",
"proc-macro2",
@@ -1427,9 +1419,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.121"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441"
checksum = "49757b3c82ebf16c57d69365a142940b384176c24df52a087fb748e2085359ea"
dependencies = [
"unicode-ident",
]
@@ -1672,9 +1664,9 @@ dependencies = [
[[package]]
name = "zerofrom"
version = "0.1.8"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272"
checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df"
dependencies = [
"zerofrom-derive",
]

View File

@@ -120,9 +120,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "cc"
version = "1.2.62"
version = "1.2.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a1dce859f0832a7d088c4f1119888ab94ef4b5d6795d1ce05afb7fe159d79f98"
checksum = "d16d90359e986641506914ba71350897565610e87ce0ad9e6f28569db3dd5c6d"
dependencies = [
"find-msvc-tools",
"shlex",
@@ -238,9 +238,9 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "fancy-regex"
version = "0.18.0"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1e1dacd0d2082dfcf1351c4bdd566bbe89a2b263235a2b50058f1e130a47277"
checksum = "72cf461f865c862bb7dc573f643dd6a2b6842f7c30b07882b56bd148cc2761b8"
dependencies = [
"bit-set",
"regex-automata",
@@ -396,9 +396,9 @@ dependencies = [
[[package]]
name = "hashbrown"
version = "0.17.1"
version = "0.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51"
[[package]]
name = "heck"
@@ -546,7 +546,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
dependencies = [
"equivalent",
"hashbrown 0.17.1",
"hashbrown 0.17.0",
"serde",
"serde_core",
]
@@ -565,9 +565,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]]
name = "js-sys"
version = "0.3.98"
version = "0.3.97"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67df7112613f8bfd9150013a0314e196f4800d3201ae742489d999db2f979f08"
checksum = "a1840c94c045fbcf8ba2812c95db44499f7c64910a912551aaaa541decebcacf"
dependencies = [
"cfg-if",
"futures-util",
@@ -577,9 +577,9 @@ dependencies = [
[[package]]
name = "jsonschema"
version = "0.46.5"
version = "0.45.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a5fe5206f06e589caf25e79fc05ccdf91fca745685fe9fe1a13bbdfb479a631"
checksum = "257eb0e588b76827bbddc9e73945a9743693dd2adeaee9da26420f93cfedb798"
dependencies = [
"ahash",
"bytecount",
@@ -649,9 +649,9 @@ checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
[[package]]
name = "lru"
version = "0.18.0"
version = "0.16.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a860605968fce16869fd239cf4237a82f3ac470723415db603b0e8b6c8d4fb9"
checksum = "7f66e8d5d03f609abc3a39e6f08e4164ebf1447a732906d39eb9b99b7919ef39"
[[package]]
name = "memchr"
@@ -659,12 +659,6 @@ version = "2.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
[[package]]
name = "micromap"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a86d3146ed3995b5913c414f6664344b9617457320782e64f0bb44afd49d74"
[[package]]
name = "minicov"
version = "0.3.8"
@@ -953,16 +947,14 @@ dependencies = [
[[package]]
name = "referencing"
version = "0.46.5"
version = "0.45.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69e4e17ef386c5383591d07623d3de49cbc601156e7582973e6db98d66a57de2"
checksum = "e2f38748ceca8d0b0013e60f534d94a6e23dfd89fd2a88318fc5a2d04fda1010"
dependencies = [
"ahash",
"fluent-uri",
"getrandom 0.3.4",
"hashbrown 0.16.1",
"itoa",
"micromap",
"parking_lot",
"percent-encoding",
"serde_json",
@@ -1152,9 +1144,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]]
name = "siphasher"
version = "1.0.3"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e"
[[package]]
name = "slab"
@@ -1344,9 +1336,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen"
version = "0.2.121"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49ace1d07c165b0864824eee619580c4689389afa9dc9ed3a4c75040d82e6790"
checksum = "df52b6d9b87e0c74c9edfa1eb2d9bf85e5d63515474513aa50fa181b3c4f5db1"
dependencies = [
"cfg-if",
"once_cell",
@@ -1357,9 +1349,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-futures"
version = "0.4.71"
version = "0.4.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "96492d0d3ffba25305a7dc88720d250b1401d7edca02cc3bcd50633b424673b8"
checksum = "af934872acec734c2d80e6617bbb5ff4f12b052dd8e6332b0817bce889516084"
dependencies = [
"js-sys",
"wasm-bindgen",
@@ -1367,9 +1359,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.121"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8e68e6f4afd367a562002c05637acb8578ff2dea1943df76afb9e83d177c8578"
checksum = "78b1041f495fb322e64aca85f5756b2172e35cd459376e67f2a6c9dffcedb103"
dependencies = [
"quote",
"wasm-bindgen-macro-support",
@@ -1377,9 +1369,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-macro-support"
version = "0.2.121"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d95a9ec35c64b2a7cb35d3fead40c4238d0940c86d107136999567a4703259f2"
checksum = "9dcd0ff20416988a18ac686d4d4d0f6aae9ebf08a389ff5d29012b05af2a1b41"
dependencies = [
"bumpalo",
"proc-macro2",
@@ -1390,18 +1382,18 @@ dependencies = [
[[package]]
name = "wasm-bindgen-shared"
version = "0.2.121"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c4e0100b01e9f0d03189a92b96772a1fb998639d981193d7dbab487302513441"
checksum = "49757b3c82ebf16c57d69365a142940b384176c24df52a087fb748e2085359ea"
dependencies = [
"unicode-ident",
]
[[package]]
name = "wasm-bindgen-test"
version = "0.3.71"
version = "0.3.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "af5ec93229ad9ccd0a545a516dec76dc276613f278f6a91aa6b463d5b33d42d0"
checksum = "29826f9d9ecaa314c480d376b276d1c790e6cb6a4681fab8532da69cbabf977d"
dependencies = [
"async-trait",
"cast",
@@ -1421,9 +1413,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-test-macro"
version = "0.3.71"
version = "0.3.70"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3c81b9fef827e575e0e54431736d1baa0d700315d8c62cfef1f61fa3aad0cbeb"
checksum = "c610311887f9e6599a546d278d12d69dfd3a3e92639b2129e4b11ad6cf1961d6"
dependencies = [
"proc-macro2",
"quote",
@@ -1432,9 +1424,9 @@ dependencies = [
[[package]]
name = "wasm-bindgen-test-shared"
version = "0.2.121"
version = "0.2.120"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4f4d8ae7ad5440360e9799dfd42857d126454a88441ddf72d288ef83fa47f527"
checksum = "60238e5b4b1b295701d6f9a66d2a126fe19990348f5fb9dae3b623a370119d94"
[[package]]
name = "wasm-encoder"
@@ -1692,9 +1684,9 @@ dependencies = [
[[package]]
name = "zerofrom"
version = "0.1.8"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272"
checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df"
dependencies = [
"zerofrom-derive",
]

View File

@@ -55,7 +55,7 @@ getrandom03 = { package = "getrandom", version = "0.3.1", features = ["std", "wa
getrandom = { version = "0.4.2", features = ["wasm_js"] }
[dev-dependencies]
wasm-bindgen-test = "0.3.71"
wasm-bindgen-test = "0.3.67"
[lints.rust]
unexpected_cfgs = { level = "warn", check-cfg = ['cfg(wasm_bindgen_unstable_test_coverage)'] }

View File

@@ -23,7 +23,8 @@ use regorus::languages::azure_policy::aliases::AliasRegistry;
use regorus::languages::azure_policy::compiler;
use regorus::languages::azure_policy::parser;
use regorus::rvm::RegoVM;
use regorus::{Rc, Source, Value};
use regorus::Source;
use regorus::Value;
/// Evaluate an Azure Policy definition against a resource.
///
@@ -59,8 +60,11 @@ pub fn azure_policy_eval(
println!("Parsed policy definition from {policy_definition}");
// 3. Compile to RVM bytecode.
let registry = Rc::new(registry);
let program = compiler::compile_policy_definition_with_aliases(&defn, Rc::clone(&registry))?;
let program = compiler::compile_policy_definition_with_aliases(
&defn,
registry.alias_map(),
registry.alias_modifiable_map(),
)?;
println!("Compiled policy to RVM bytecode");
// 4. Build normalized input.
@@ -134,7 +138,7 @@ pub fn azure_policy_aliases(aliases: String, resource_type: Option<String>) -> R
if let Some(ref rt) = resource_type {
let rt_lower = rt.to_lowercase();
let mut found = false;
for alias_name in registry.alias_map().keys() {
for (alias_name, _) in registry.alias_map() {
if alias_name.to_lowercase().starts_with(&rt_lower) {
println!(" {alias_name}");
found = true;
@@ -144,7 +148,7 @@ pub fn azure_policy_aliases(aliases: String, resource_type: Option<String>) -> R
bail!("no aliases found for resource type '{rt}'");
}
} else {
for alias_name in registry.alias_map().keys() {
for (alias_name, _) in registry.alias_map() {
println!(" {alias_name}");
}
}

View File

@@ -4,9 +4,9 @@
use crate::ast::*;
use crate::builtins::{self, BuiltinFcn};
use crate::compiled_policy::CompiledPolicyData;
#[cfg(feature = "azure_policy")]
use crate::compiled_policy::TargetInfo;
use crate::compiled_policy::{CompiledPolicyData, DefaultRuleInfo};
use crate::compiler::destructuring_planner::{
AssignmentPlan, BindingPlan, DestructuringPlan, WildcardSide,
};
@@ -1724,6 +1724,9 @@ impl Interpreter {
// For now, we restrict constant refs to those that contain only simple literals.
fn is_constant_ref(mut expr: &Ref<Expr>) -> Result<bool> {
loop {
if Self::is_simple_literal(expr)? {
return Ok(true);
}
match expr.as_ref() {
Expr::Var { .. } => break,
Expr::RefDot { refr, .. } => expr = refr,
@@ -1747,6 +1750,30 @@ impl Interpreter {
))
}
fn is_constant_key_expr(&self, expr: &Ref<Expr>) -> Result<bool> {
if Self::is_simple_literal(expr)? {
return Ok(true);
}
match expr.as_ref() {
Expr::Var { span, .. } => {
// A variable that is not currently bound in any active local scope behaves like
// a stable global/package reference for this evaluation.
let is_bound = self
.scopes
.iter()
.rev()
.any(|scope| scope.contains_key(&span.source_str()));
Ok(!is_bound)
}
Expr::RefDot { refr, .. } => self.is_constant_key_expr(refr),
Expr::RefBrack { refr, index, .. } => {
Ok(self.is_constant_key_expr(refr)? && self.is_constant_key_expr(index)?)
}
_ => Ok(false),
}
}
// A rule's output expression is constant if it does not contain local variables.
// For now, we restrict output expressions to those that contain only simple literals.
fn is_constant_output(key_expr: &Option<Ref<Expr>>, output_expr: &Ref<Expr>) -> Result<bool> {
@@ -1782,7 +1809,6 @@ impl Interpreter {
let mut comps = self.eval_rule_ref(&rule_ref)?;
if let Some(ke) = &key_expr {
is_const_rule = is_const_rule && Self::is_simple_literal(ke)?;
comps.push(self.eval_expr(ke)?);
}
let output = if let Some(oe) = &output_expr {
@@ -1798,7 +1824,12 @@ impl Interpreter {
comps.pop();
output
} else {
// Rule's constness is determined only by its ref.
// Implicit-true partial object rules can vary with each successful key binding.
if let Some(ke) = &key_expr {
if !is_old_style_set && !self.is_constant_key_expr(ke)? {
is_const_rule = false;
}
}
Value::Bool(true)
};
@@ -2943,6 +2974,41 @@ impl Interpreter {
Ok(())
}
fn default_rules_for_path(&self, path: &str) -> Option<Vec<DefaultRuleInfo>> {
if let Some(rules) = self.compiled_policy.default_rules.get(path) {
return Some(rules.clone());
}
let (parent_path, index) = path.rsplit_once('.')?;
let rules = self.compiled_policy.default_rules.get(parent_path)?;
let matches = rules
.iter()
.filter(|(_, rule_index)| Self::default_rule_index_matches(rule_index, index))
.cloned()
.collect::<Vec<_>>();
if matches.is_empty() {
None
} else {
Some(matches)
}
}
fn has_default_rules_for_path(&self, path: &str) -> bool {
self.default_rules_for_path(path).is_some()
}
fn default_rule_index_matches(index: &Option<String>, path_component: &str) -> bool {
match index.as_deref() {
Some(index) if index == path_component => true,
Some(index) => index
.strip_prefix('"')
.and_then(|index| index.strip_suffix('"'))
.is_some_and(|index| index == path_component),
None => false,
}
}
fn ensure_rule_evaluated(&mut self, path: String) -> Result<()> {
self.check_execution_time()?;
let mut matched = false;
@@ -2957,9 +3023,9 @@ impl Interpreter {
}
// Evaluate the associated default rules after non-default rules
if let Some(rules) = self.compiled_policy.default_rules.get(&path) {
if let Some(rules) = self.default_rules_for_path(&path) {
matched = true;
for (r, _) in rules.clone() {
for (r, _) in rules {
if !self.processed.contains(&r) {
let module = self.get_rule_module(&r)?;
let prev_module = self.set_current_module(Some(module))?;
@@ -3050,10 +3116,7 @@ impl Interpreter {
let prefix = fields.iter().take(i).copied().collect::<Vec<_>>();
let prefix_path = format!("data.{}", prefix.join("."));
if self.compiled_policy.rules.contains_key(&prefix_path)
|| self
.compiled_policy
.default_rules
.contains_key(&prefix_path)
|| self.has_default_rules_for_path(&prefix_path)
{
self.ensure_rule_evaluated(prefix_path)?;
break;
@@ -3077,7 +3140,7 @@ impl Interpreter {
if !no_error
&& !self.compiled_policy.rules.contains_key(&rule_path)
&& !self.compiled_policy.default_rules.contains_key(&rule_path)
&& !self.has_default_rules_for_path(&rule_path)
&& !self.compiled_policy.imports.contains_key(&rule_path)
{
bail!(span.error(&format!(
@@ -3100,7 +3163,7 @@ impl Interpreter {
};
if self.compiled_policy.rules.contains_key(&path)
|| self.compiled_policy.default_rules.contains_key(&path)
|| self.has_default_rules_for_path(&path)
{
self.ensure_rule_evaluated(path)?;
found = true;
@@ -3647,7 +3710,7 @@ impl Interpreter {
self.data = Value::Undefined;
self.ensure_loop_var_values_capacity();
let default_rules = self.compiled_policy.default_rules.get(rule_path).cloned();
let default_rules = self.default_rules_for_path(rule_path);
if let Some(rules) = default_rules {
for (rule, _) in rules {

View File

@@ -172,31 +172,11 @@ impl AliasRegistry {
let prefix = alloc::format!("{}/", fq_type);
for alias in aliases {
// Skip aliases without a default_path — the normalizer's
// resolve_resource_type also skips these, so inserting them into
// compiler maps would cause a divergence where the compiler
// resolves the alias but normalized input never contains the field.
if alias.default_path.is_none() {
continue;
}
// Derive the short name by stripping the resource type prefix.
let raw_short = if alias.name.len() > prefix.len()
&& alias
.name
.get(..prefix.len())
.is_some_and(|s| s.eq_ignore_ascii_case(&prefix))
&& alias.name[..prefix.len()].eq_ignore_ascii_case(&prefix)
{
// Both slice boundaries are valid: prefix is ASCII
// (resource type + '/'), so if `..prefix.len()` succeeded
// above, `prefix.len()..` is guaranteed to be on a char
// boundary too. The `unwrap_or` is a defensive fallback
// that can never trigger for well-formed Azure alias names.
alias
.name
.get(prefix.len()..)
.unwrap_or(&alias.name)
.to_string()
alias.name[prefix.len()..].to_string()
} else if let Some(rest) = alias
.name
.rfind('/')
@@ -280,19 +260,20 @@ impl AliasRegistry {
.map(String::as_str)
}
/// Return a reference to the alias-to-short-name map.
/// Return a clone of the alias-to-short-name map for use by the compiler.
///
/// Keys are lowercase fully-qualified alias names; values are short names.
pub const fn alias_map(&self) -> &BTreeMap<String, String> {
&self.alias_to_short
/// The compiler stores this map internally so it can resolve fully-qualified
/// alias names without holding a reference to the registry.
pub fn alias_map(&self) -> BTreeMap<String, String> {
self.alias_to_short.clone()
}
/// Return a reference to the alias-to-modifiable map.
/// Return a clone of the alias-to-modifiable map for use by the compiler.
///
/// Keys are lowercase fully-qualified alias names; values are `true` when
/// the alias has `defaultMetadata.attributes = "Modifiable"`.
pub const fn alias_modifiable_map(&self) -> &BTreeMap<String, bool> {
&self.alias_modifiable
/// Maps lowercase fully-qualified alias names to `true` when the alias
/// has `defaultMetadata.attributes = "Modifiable"`.
pub fn alias_modifiable_map(&self) -> BTreeMap<String, bool> {
self.alias_modifiable.clone()
}
/// Normalize a raw ARM resource and wrap it in the input envelope.

View File

@@ -4,13 +4,14 @@
//! Per-alias path resolution: reads values from versioned ARM paths and places
//! them at alias short name paths in the normalized output.
use crate::Rc;
use alloc::string::String;
use crate::Value;
use super::super::obj_map::remove_element_field;
use super::super::obj_map::{
collision_safe_key, is_root_field_collision, obj_contains, obj_insert, obj_insert_rc,
obj_remove, set_nested_lowercased, ObjMap,
collision_safe_key, is_root_field_collision, obj_contains, obj_insert, obj_remove,
set_nested_lowercased, ObjMap,
};
use super::super::types::ResolvedAliases;
use super::element_remap::apply_element_remap_precomputed;
@@ -47,14 +48,12 @@ pub fn apply_alias_entries(
if let Some(value) = value {
let value = normalize_value(&value, &entry.short_name, None);
if is_root_field_collision(&entry.short_name, &entry.default_path) {
let target = collision_safe_key(&entry.short_name);
set_nested_lowercased(result, &target, value);
} else if entry.short_name.contains('.') {
set_nested_lowercased(result, &entry.short_name, value);
let target = if is_root_field_collision(&entry.short_name, &entry.default_path) {
collision_safe_key(&entry.short_name)
} else {
obj_insert_rc(result, Rc::clone(&entry.short_name_lc), value);
}
entry.short_name.clone()
};
set_nested_lowercased(result, &target, value);
}
}
@@ -85,13 +84,13 @@ pub fn apply_alias_entries(
}
/// Navigate an ARM path using precomputed segments (avoids per-call split).
fn navigate_arm_path_segments(value: &Value, segments: &[Rc<str>]) -> Option<Value> {
fn navigate_arm_path_segments(value: &Value, segments: &[String]) -> Option<Value> {
let mut current = value;
for segment in segments {
current = current
.as_object()
.ok()?
.get(&Value::String(Rc::clone(segment)))?;
.get(&Value::from(segment.as_str()))?;
}
Some(current.clone())
}

View File

@@ -7,7 +7,7 @@
//! then converts to `Value::Object` (a `BTreeMap<Value, Value>`) only at
//! the output boundary via [`make_value`].
use alloc::string::String;
use alloc::string::{String, ToString as _};
use alloc::vec::Vec;
use hashbrown::HashMap;
@@ -41,33 +41,6 @@ pub fn obj_insert(map: &mut ObjMap, key: &str, val: Value) {
map.insert(Rc::from(key), val);
}
/// Insert a key-value pair using a pre-allocated `Rc<str>` key.
///
/// Avoids the `Rc::from(key)` heap allocation that [`obj_insert`] performs.
pub fn obj_insert_rc(map: &mut ObjMap, key: Rc<str>, val: Value) {
map.insert(key, val);
}
/// Lowercase a string, returning an `Rc<str>`.
///
/// Both paths allocate an `Rc<str>` (header + string bytes). The fast-path
/// avoids creating an intermediate lowercased `String` when the input is
/// already all-lowercase ASCII.
pub fn rc_lowercase(s: &str) -> Rc<str> {
if s.bytes().all(|b| !b.is_ascii_uppercase()) {
Rc::from(s)
} else {
Rc::from(s.to_ascii_lowercase())
}
}
/// Insert a key-value pair with the key lowercased, using [`rc_lowercase`]
/// for the allocation fast-path.
pub fn obj_insert_lc(map: &mut ObjMap, key: &str, val: Value) {
let lc = rc_lowercase(key);
map.insert(lc, val);
}
/// Check whether a key exists.
pub fn obj_contains(map: &ObjMap, key: &str) -> bool {
map.contains_key(key)
@@ -139,7 +112,7 @@ pub fn set_nested_lowercased(result: &mut ObjMap, path: &str, value: Value) {
}
if segments.len() == 1 {
if let Some(&seg) = segments.first() {
obj_insert_lc(result, seg, value);
obj_insert(result, &seg.to_ascii_lowercase(), value);
}
return;
}
@@ -171,28 +144,28 @@ fn set_nested_inner(obj: &mut ObjMap, segments: &[&str], value: Value, lowercase
};
if segments.len() == 1 {
let key: Rc<str> = if lowercase {
rc_lowercase(first)
let key = if lowercase {
first.to_ascii_lowercase()
} else {
Rc::from(first)
first.to_string()
};
obj_insert_rc(obj, key, value);
obj_insert(obj, &key, value);
return;
}
let seg: Rc<str> = if lowercase {
rc_lowercase(first)
let seg = if lowercase {
first.to_ascii_lowercase()
} else {
Rc::from(first)
first.to_string()
};
// Ensure an intermediate object exists at `seg`.
if !obj.contains_key(&*seg) {
obj_insert_rc(obj, Rc::clone(&seg), make_value(new_map()));
if !obj_contains(obj, &seg) {
obj_insert(obj, &seg, make_value(new_map()));
}
// Descend directly into the BTreeMap, avoiding ObjMap round-trip.
if let Some(Value::Object(inner_rc)) = obj.get_mut(&*seg) {
if let Some(Value::Object(inner_rc)) = obj_get_mut(obj, &seg) {
let inner_btree = Rc::make_mut(inner_rc);
set_nested_in_btree(
inner_btree,
@@ -218,12 +191,12 @@ pub fn set_nested_in_btree(
return;
};
let key_rc: Rc<str> = if lowercase {
rc_lowercase(first)
let key_str: String = if lowercase {
first.to_ascii_lowercase()
} else {
Rc::from(first)
first.to_string()
};
let key_val = Value::String(Rc::clone(&key_rc));
let key_val = Value::String(Rc::from(key_str.as_str()));
if segments.len() == 1 {
btree.insert(key_val, value);
@@ -270,24 +243,13 @@ pub const ROOT_FIELDS: &[&str] = &[
"extendedLocation",
];
const PROPERTIES_DOT: &[u8] = b"properties.";
/// Check whether an alias short name collides with a reserved ARM root field
/// and needs a collision-safe key.
pub fn is_root_field_collision(short_name: &str, default_path: &str) -> bool {
ROOT_FIELDS
.iter()
.any(|f| f.eq_ignore_ascii_case(short_name))
&& default_path.len() > PROPERTIES_DOT.len()
&& default_path
.as_bytes()
.get(..PROPERTIES_DOT.len())
.is_some_and(|prefix| {
prefix
.iter()
.zip(PROPERTIES_DOT)
.all(|(a, b)| a.to_ascii_lowercase() == *b)
})
&& default_path.to_ascii_lowercase().starts_with("properties.")
}
/// Return a collision-safe key for an alias whose short name collides with a

View File

@@ -18,22 +18,6 @@ use alloc::vec::Vec;
use serde::{Deserialize, Deserializer};
use crate::Rc;
// ---------------------------------------------------------------------------
// Deserialization helpers
// ---------------------------------------------------------------------------
/// Deserialize a `Vec<T>` that tolerates JSON `null` by mapping it to an
/// empty vector.
fn deserialize_null_as_empty_vec<'de, T, D>(deserializer: D) -> Result<Vec<T>, D::Error>
where
T: Deserialize<'de>,
D: Deserializer<'de>,
{
Ok(Option::<Vec<T>>::deserialize(deserializer)?.unwrap_or_default())
}
// ─── Top-level response wrappers ────────────────────────────────────────────
/// ARM API response envelope: `{ "value": [...] }`
@@ -114,10 +98,7 @@ pub struct AliasEntry {
/// Versioned path entries. Empty for the vast majority of aliases that
/// have only a `defaultPath`.
///
/// In real Azure catalog data (~97% of aliases), `az provider list` emits
/// `"paths": null` rather than an empty array.
#[serde(default, deserialize_with = "deserialize_null_as_empty_vec")]
#[serde(default)]
pub paths: Vec<AliasPath>,
}
@@ -423,13 +404,11 @@ pub struct ResolvedEntry {
// ── Precomputed fields (derived at registry-load time) ──────────────
/// Whether `short_name` contains `[*]` (i.e., this is a wildcard/array alias).
pub is_wildcard: bool,
/// Pre-lowercased short name as `Rc<str>` for allocation-free common-case inserts.
pub(crate) short_name_lc: Rc<str>,
/// Precomputed `default_path.split('.').collect()` for fast ARM path navigation.
pub(crate) default_path_segments: Vec<Rc<str>>,
pub default_path_segments: Vec<String>,
/// Precomputed path segments for each versioned path, in the same order
/// as `versioned_paths`.
pub(crate) versioned_path_segments: Vec<Vec<Rc<str>>>,
pub versioned_path_segments: Vec<Vec<String>>,
}
impl ResolvedEntry {
@@ -441,15 +420,10 @@ impl ResolvedEntry {
metadata: Option<AliasPathMetadata>,
) -> Self {
let is_wildcard = short_name.contains("[*]");
let short_name_lc = if short_name.bytes().all(|b| !b.is_ascii_uppercase()) {
Rc::from(short_name.as_str())
} else {
Rc::from(short_name.to_ascii_lowercase())
};
let default_path_segments = default_path.split('.').map(Rc::from).collect();
let default_path_segments = default_path.split('.').map(String::from).collect();
let versioned_path_segments = versioned_paths
.iter()
.map(|(_, p)| p.split('.').map(Rc::from).collect())
.map(|(_, p)| p.split('.').map(String::from).collect())
.collect();
Self {
short_name,
@@ -457,7 +431,6 @@ impl ResolvedEntry {
versioned_paths,
metadata,
is_wildcard,
short_name_lc,
default_path_segments,
versioned_path_segments,
}
@@ -483,7 +456,7 @@ impl ResolvedEntry {
/// Returns the versioned segments if `api_version` matches, otherwise
/// the default segments. This avoids per-call `split('.')` for both
/// default and versioned scalar alias navigation.
pub(crate) fn select_path_segments(&self, api_version: Option<&str>) -> &[Rc<str>] {
pub fn select_path_segments(&self, api_version: Option<&str>) -> &[String] {
if let Some(ver) = api_version {
for (i, (v, _)) in self.versioned_paths.iter().enumerate() {
if v.eq_ignore_ascii_case(ver) {

View File

@@ -18,7 +18,6 @@ use crate::rvm::program::{Program, SpanInfo};
use crate::rvm::Instruction;
use crate::{Rc, Value};
use crate::languages::azure_policy::aliases::AliasRegistry;
use crate::languages::azure_policy::ast::PolicyRule;
// ---------------------------------------------------------------------------
@@ -45,9 +44,10 @@ pub(super) struct Compiler {
pub(super) cached_input_reg: Option<u8>,
/// Cached register for `LoadContext` — allocated once on first use.
pub(super) cached_context_reg: Option<u8>,
/// Alias registry for resolving fully-qualified alias names.
/// Shared via `Rc` to avoid cloning the 73K-entry alias maps.
pub(super) alias_registry: Option<Rc<AliasRegistry>>,
/// Map from lowercase fully-qualified alias name → short name.
pub(super) alias_map: BTreeMap<String, String>,
/// Map from lowercase fully-qualified alias name → modifiable flag.
pub(super) alias_modifiable: BTreeMap<String, bool>,
/// Default values for policy parameters.
pub(super) parameter_defaults: Option<Value>,
/// Cached literal-table index for `parameter_defaults` (or an empty object
@@ -338,13 +338,8 @@ impl Compiler {
path: &str,
span: &crate::lexer::Span,
) -> Result<String> {
let alias_map = match &self.alias_registry {
Some(reg) => reg.alias_map(),
None => return Ok(path.to_string()),
};
let lc = path.to_ascii_lowercase();
if let Some(short) = alias_map.get(&lc) {
if let Some(short) = self.alias_map.get(&lc) {
let resolved = short.clone();
let result = Self::strip_fq_prefix(&resolved).to_ascii_lowercase();
return Ok(result);
@@ -353,7 +348,7 @@ impl Compiler {
// Fallback: derive array path from a corresponding `[*]` alias.
if !lc.contains("[*]") {
let wildcard_key = alloc::format!("{}[*]", lc);
if let Some(short) = alias_map.get(&wildcard_key) {
if let Some(short) = self.alias_map.get(&wildcard_key) {
let resolved = Self::strip_fq_prefix(short).to_ascii_lowercase();
if let Some(base) = resolved.strip_suffix("[*]") {
return Ok(base.to_string());
@@ -361,14 +356,14 @@ impl Compiler {
}
}
if !alias_map.is_empty() && !self.alias_fallback_to_raw {
if !self.alias_map.is_empty() && !self.alias_fallback_to_raw {
bail!(span.error(&alloc::format!(
"unknown alias '{}': field references must use fully-qualified alias names when an alias catalog is loaded",
path
)));
}
if alias_map.is_empty() {
if self.alias_map.is_empty() {
Ok(path.to_string())
} else {
let result = Self::strip_fq_prefix(path).to_ascii_lowercase();

View File

@@ -998,13 +998,7 @@ impl Compiler {
return Ok(result);
}
}
Err(e)
if self
.alias_registry
.as_ref()
.is_some_and(|r| !r.alias_map().is_empty())
&& !self.alias_fallback_to_raw =>
{
Err(e) if !self.alias_map.is_empty() && !self.alias_fallback_to_raw => {
return Err(e);
}
_ => {}

View File

@@ -692,18 +692,13 @@ impl Compiler {
field_path: &str,
span: &crate::lexer::Span,
) -> Result<()> {
let modifiable_map = match &self.alias_registry {
Some(reg) => reg.alias_modifiable_map(),
None => return Ok(()),
};
if modifiable_map.is_empty() {
if self.alias_modifiable.is_empty() {
return Ok(());
}
let lc = field_path.to_lowercase();
if let Some(&modifiable) = modifiable_map.get(&lc) {
if let Some(&modifiable) = self.alias_modifiable.get(&lc) {
if !modifiable {
bail!(span.error(&format!(
"alias '{}' is not modifiable (defaultMetadata.attributes != 'Modifiable')",
@@ -808,6 +803,7 @@ fn unescape_arm_literal(s: &str) -> alloc::string::String {
/// 1. Build a template `BTreeMap` with `Value::Undefined` placeholders.
/// 2. Sort keys by their literal value (BTreeMap order).
/// 3. Emit `ObjectCreate`.
#[allow(clippy::indexing_slicing)]
pub(super) fn build_object_from_keys(
compiler: &mut Compiler,
mut keys: Vec<(u16, u8)>,
@@ -816,33 +812,17 @@ pub(super) fn build_object_from_keys(
// Build template: object with all keys set to Undefined.
let mut template = BTreeMap::new();
for &(key_idx, _) in &keys {
// key_idx was returned by `add_literal_u16` in the calling code,
// so it is always in bounds. We use `.get()` + `?` instead of
// direct indexing to satisfy the crate-wide `deny(indexing_slicing)`.
let key_val = compiler
.program
.literals
.get(usize::from(key_idx))
.ok_or_else(|| {
anyhow!(
"internal error in build_object_from_keys: \
literal index {} out of bounds (literals len = {})",
key_idx,
compiler.program.literals.len()
)
})?
.clone();
// SAFETY: key_idx was just returned by `add_literal_u16`, so the
// index is guaranteed to be in bounds.
let key_val = compiler.program.literals[usize::from(key_idx)].clone();
template.insert(key_val, Value::Undefined);
}
let template_idx = compiler.add_literal_u16(Value::Object(crate::Rc::new(template)))?;
// Sort keys by literal value (BTreeMap order). All indices were
// validated in the loop above (which returns Err for out-of-bounds),
// so `.get()` always returns `Some` here — `None` is unreachable.
// Sort keys by literal value (BTreeMap order).
keys.sort_by(|a, b| {
let a_val = compiler.program.literals.get(usize::from(a.0));
let b_val = compiler.program.literals.get(usize::from(b.0));
a_val.cmp(&b_val)
compiler.program.literals[usize::from(a.0)]
.cmp(&compiler.program.literals[usize::from(b.0)])
});
let dest = compiler.alloc_register()?;

View File

@@ -30,11 +30,11 @@ mod metadata;
mod template_dispatch;
mod utils;
use alloc::string::ToString as _;
use alloc::collections::BTreeMap;
use alloc::string::{String, ToString as _};
use anyhow::Result;
use crate::languages::azure_policy::aliases::AliasRegistry;
use crate::languages::azure_policy::ast::{PolicyDefinition, PolicyRule};
use crate::rvm::program::Program;
use crate::{Rc, Value};
@@ -69,14 +69,17 @@ pub fn compile_policy_rule(rule: &PolicyRule) -> Result<Rc<Program>> {
/// Compile a parsed Azure Policy rule with alias resolution.
///
/// The registry provides alias-to-short-name resolution and modifiability
/// data. Pass it as an `Rc` to avoid cloning the internal alias maps.
/// The `alias_map` maps lowercase fully-qualified alias names to their short
/// names. Obtain it from
/// [`AliasRegistry::alias_map()`](crate::languages::azure_policy::aliases::AliasRegistry::alias_map).
pub fn compile_policy_rule_with_aliases(
rule: &PolicyRule,
registry: Rc<AliasRegistry>,
alias_map: BTreeMap<String, String>,
alias_modifiable: BTreeMap<String, bool>,
) -> Result<Rc<Program>> {
let mut compiler = Compiler::new();
compiler.alias_registry = Some(registry);
compiler.alias_map = alias_map;
compiler.alias_modifiable = alias_modifiable;
init_effect_annotation(&mut compiler, rule);
compiler.compile(rule)
}
@@ -97,10 +100,12 @@ pub fn compile_policy_definition(defn: &PolicyDefinition) -> Result<Rc<Program>>
/// Compile a parsed Azure Policy definition with alias resolution.
pub fn compile_policy_definition_with_aliases(
defn: &PolicyDefinition,
registry: Rc<AliasRegistry>,
alias_map: BTreeMap<String, String>,
alias_modifiable: BTreeMap<String, bool>,
) -> Result<Rc<Program>> {
let mut compiler = Compiler::new();
compiler.alias_registry = Some(registry);
compiler.alias_map = alias_map;
compiler.alias_modifiable = alias_modifiable;
compiler.parameter_defaults = Some(build_parameter_defaults(&defn.parameters)?);
compiler.populate_definition_metadata(defn);
init_effect_annotation(&mut compiler, &defn.policy_rule);
@@ -114,11 +119,13 @@ pub fn compile_policy_definition_with_aliases(
/// a known alias are silently treated as raw property paths.
pub fn compile_policy_definition_with_aliases_opts(
defn: &PolicyDefinition,
registry: Rc<AliasRegistry>,
alias_map: BTreeMap<String, String>,
alias_modifiable: BTreeMap<String, bool>,
alias_fallback_to_raw: bool,
) -> Result<Rc<Program>> {
let mut compiler = Compiler::new();
compiler.alias_registry = Some(registry);
compiler.alias_map = alias_map;
compiler.alias_modifiable = alias_modifiable;
compiler.alias_fallback_to_raw = alias_fallback_to_raw;
compiler.parameter_defaults = Some(build_parameter_defaults(&defn.parameters)?);
compiler.populate_definition_metadata(defn);

View File

@@ -63,14 +63,6 @@ pub enum CompilerError {
#[error("Invalid function expression with package")]
InvalidFunctionExpressionWithPackage,
#[error("partial object rules with constant keys are not yet supported by the RVM compiler")]
PartialObjectConstantKeyUnsupported,
#[error(
"partial object rules with nested bracket keys are not yet supported by the RVM compiler"
)]
PartialObjectNestedKeyUnsupported,
#[error("Compilation error: {message}")]
General { message: String },
}

View File

@@ -181,7 +181,7 @@ impl<'a> Compiler<'a> {
}
fn evaluate_default_rule(&mut self, rule_path: &str) -> Option<u16> {
if !self.policy.inner.default_rules.contains_key(rule_path) {
if !self.may_have_default_rule(rule_path) {
return None;
}
@@ -200,6 +200,33 @@ impl<'a> Compiler<'a> {
None
}
fn may_have_default_rule(&self, rule_path: &str) -> bool {
if self.policy.inner.default_rules.contains_key(rule_path) {
return true;
}
let Some((parent_path, index)) = rule_path.rsplit_once('.') else {
return false;
};
self.policy
.inner
.default_rules
.get(parent_path)
.is_some_and(|rules| {
rules
.iter()
.any(|(_, rule_index)| match rule_index.as_deref() {
Some(rule_index) if rule_index == index => true,
Some(rule_index) => rule_index
.strip_prefix('"')
.and_then(|rule_index| rule_index.strip_suffix('"'))
.is_some_and(|rule_index| rule_index == index),
None => false,
})
})
}
fn extract_destructuring_blocks(&self, rule_index: u16) -> Vec<Option<u32>> {
self.rule_definition_destructuring_patterns[rule_index as usize].clone()
}

View File

@@ -11,7 +11,7 @@
)]
use super::{CompilationContext, Compiler, CompilerError, ContextType, Result, WorklistEntry};
use crate::ast::{Expr, ExprRef, Rule, RuleHead};
use crate::ast::{AssignOp, Expr, ExprRef, Rule, RuleHead};
use crate::compiler::destructuring_planner::plans::BindingPlan;
use crate::lexer::Span;
use crate::rvm::program::{Program, RuleType};
@@ -52,14 +52,29 @@ impl<'a> Compiler<'a> {
let rule_types: BTreeSet<RuleType> = definitions
.iter()
.map(|def| {
if let Rule::Spec { head, .. } = def.as_ref() {
if let Rule::Spec { head, bodies, .. } = def.as_ref() {
match head {
RuleHead::Set { .. } => RuleType::PartialSet,
RuleHead::Compr { refr, assign, .. } => match refr.as_ref() {
crate::ast::Expr::RefBrack { .. } if assign.is_some() => {
// Variable-key bracket heads emit one object entry per successful
// binding, so they must compile as partial objects.
crate::ast::Expr::RefBrack { index, .. }
if super::expressions::try_eval_const(index.as_ref()).is_none() =>
{
RuleType::PartialObject
}
crate::ast::Expr::RefBrack { .. } => RuleType::PartialObject,
crate::ast::Expr::RefBrack { .. }
if matches!(
assign.as_ref().map(|assign| &assign.op),
Some(AssignOp::Eq)
) =>
{
RuleType::PartialObject
}
crate::ast::Expr::RefBrack { .. } if bodies.is_empty() => {
RuleType::PartialObject
}
crate::ast::Expr::RefBrack { .. } => RuleType::Complete,
_ => RuleType::Complete,
},
_ => RuleType::Complete,
@@ -88,54 +103,6 @@ impl<'a> Compiler<'a> {
})
}
fn validate_partial_object_shape(&self, refr: &ExprRef) -> Result<()> {
let Expr::RefBrack {
refr: prefix,
index,
..
} = refr.as_ref()
else {
return Ok(());
};
if Self::has_unsupported_bracket_prefix(prefix) {
return Err(CompilerError::PartialObjectNestedKeyUnsupported.at(refr.span()));
}
if Self::is_simple_literal(index) {
return Err(CompilerError::PartialObjectConstantKeyUnsupported.at(index.span()));
}
Ok(())
}
fn has_unsupported_bracket_prefix(expr: &ExprRef) -> bool {
match expr.as_ref() {
Expr::RefBrack { refr, index, .. } => {
!Self::is_string_literal(index) || Self::has_unsupported_bracket_prefix(refr)
}
Expr::RefDot { refr, .. } => Self::has_unsupported_bracket_prefix(refr),
_ => false,
}
}
fn is_string_literal(expr: &ExprRef) -> bool {
matches!(expr.as_ref(), Expr::String { .. } | Expr::RawString { .. })
}
fn is_simple_literal(expr: &ExprRef) -> bool {
match expr.as_ref() {
Expr::String { .. }
| Expr::RawString { .. }
| Expr::Number { .. }
| Expr::Bool { .. }
| Expr::Null { .. } => true,
// Unary expressions like `-1` are constant literals too.
Expr::UnaryExpr { expr, .. } => Self::is_simple_literal(expr),
_ => false,
}
}
pub(super) fn get_or_assign_rule_index(&mut self, rule_path: &str) -> Result<u16> {
if let Some(&index) = self.rule_index_map.get(rule_path) {
return Ok(index);
@@ -393,10 +360,6 @@ impl<'a> Compiler<'a> {
let (key_expr, value_expr) = match head {
RuleHead::Compr { refr, assign, .. } => {
if rule_type == RuleType::PartialObject {
self.validate_partial_object_shape(refr)?;
}
self.rule_definition_function_params[rule_index as usize].push(None);
self.rule_definition_destructuring_patterns[rule_index as usize]
.push(None);

View File

@@ -454,7 +454,19 @@ impl RegoVM {
let mut obj_value = self.take_register(obj)?;
if let Ok(obj_mut) = obj_value.as_object_mut() {
obj_mut.insert(key_value, value_value);
match obj_mut.get(&key_value) {
Some(existing_value) if existing_value != &value_value => {
self.set_register(obj, obj_value)?;
return Err(VmError::RuleMultipleOutputs { pc: self.pc });
}
Some(_) => {
self.set_register(obj, obj_value)?;
return Ok(InstructionOutcome::Continue);
}
None => {
obj_mut.insert(key_value, value_value);
}
}
self.set_register(obj, obj_value)?;
} else {
let offending = obj_value.clone();

View File

@@ -209,6 +209,9 @@ pub enum VmError {
#[error("Rule-data conflict: {message} (pc={pc})")]
RuleDataConflict { message: String, pc: usize },
#[error("rules must not produce multiple outputs (pc={pc})")]
RuleMultipleOutputs { pc: usize },
#[error("Arithmetic error: {message} (pc={pc})")]
ArithmeticError { message: String, pc: usize },

View File

@@ -17,8 +17,9 @@ use super::execution_model::{
use super::machine::RegoVM;
impl RegoVM {
/// Returns true if the error represents a resource-limit violation that
/// must never be silently absorbed by rule evaluation.
/// Returns true if the error must never be silently absorbed by rule
/// evaluation backtracking, including resource-limit failures and semantic
/// rule consistency errors.
pub(super) const fn is_fatal_vm_error(err: &VmError) -> bool {
matches!(
err,
@@ -26,6 +27,7 @@ impl RegoVM {
| VmError::MemoryLimitExceeded { .. }
| VmError::RegexSizeLimitExceeded { .. }
| VmError::InstructionLimitExceeded { .. }
| VmError::RuleMultipleOutputs { .. }
)
}

View File

@@ -23,7 +23,8 @@ use regorus::languages::azure_policy::aliases::AliasRegistry;
use regorus::languages::azure_policy::compiler;
use regorus::languages::azure_policy::parser;
use regorus::rvm::RegoVM;
use regorus::{Rc, Source, Value};
use regorus::Source;
use regorus::Value;
use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::fs;
@@ -193,7 +194,7 @@ fn yaml_test_impl(file: &str) -> Result<()> {
let test: YamlTest = serde_yaml::from_str(&yaml_str)?;
// Load alias registry if an aliases file is specified.
let alias_registry: Option<Rc<AliasRegistry>> = if let Some(ref aliases_file) = test.aliases {
let alias_registry = if let Some(ref aliases_file) = test.aliases {
let aliases_dir = Path::new(file)
.parent()
.unwrap_or_else(|| Path::new("."))
@@ -208,7 +209,7 @@ fn yaml_test_impl(file: &str) -> Result<()> {
})?;
let mut registry = AliasRegistry::new();
registry.load_from_json(&aliases_json)?;
Some(Rc::new(registry))
Some(registry)
} else {
None
};
@@ -280,7 +281,11 @@ fn yaml_test_impl(file: &str) -> Result<()> {
);
}
if let Some(ref registry) = alias_registry {
compiler::compile_policy_definition_with_aliases(&defn, Rc::clone(registry))
compiler::compile_policy_definition_with_aliases(
&defn,
registry.alias_map(),
registry.alias_modifiable_map(),
)
} else {
compiler::compile_policy_definition(&defn)
}
@@ -303,7 +308,11 @@ fn yaml_test_impl(file: &str) -> Result<()> {
);
}
if let Some(ref registry) = alias_registry {
compiler::compile_policy_rule_with_aliases(&ast, Rc::clone(registry))
compiler::compile_policy_rule_with_aliases(
&ast,
registry.alias_map(),
registry.alias_modifiable_map(),
)
} else {
compiler::compile_policy_rule(&ast)
}
@@ -357,7 +366,7 @@ fn yaml_test_impl(file: &str) -> Result<()> {
let mut vm = RegoVM::new();
vm.load_program(program);
vm.set_input(make_input(case, alias_registry.as_deref())?);
vm.set_input(make_input(case, alias_registry.as_ref())?);
vm.set_context(make_context(case)?);
// Load host-await responses (for auditIfNotExists / deployIfNotExists policies).
@@ -382,11 +391,7 @@ fn yaml_test_impl(file: &str) -> Result<()> {
if let Some(rt) = effective_type {
inject_type_field(&mut raw, rt);
}
normalizer::normalize(
&raw,
Some(registry.as_ref()),
case.api_version.as_deref(),
)
normalizer::normalize(&raw, Some(registry), case.api_version.as_deref())
} else {
raw
}

View File

@@ -341,6 +341,35 @@ cases:
result: false
reasons: []
- note: default_rule_with_object_key
data: {}
input: {}
modules:
- |
package test
import rego.v1
default config["timeout"] := 30
config["timeout"] := val if {
val := input.val
}
query: data.test.config.timeout
want_result: 30
- note: default_rule_with_object_key_override
data: {}
input:
val: 60
modules:
- |
package test
import rego.v1
default config["timeout"] := 30
config["timeout"] := val if {
val := input.val
}
query: data.test.config.timeout
want_result: 60
- note: default_only_rule_with_package_query
data: {}
modules:

View File

@@ -0,0 +1,242 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
cases:
- note: partial_object_iteration_some_in_object_v1
data: {}
input:
x:
FOO: 1
BAR: 2
BAZ: 3
modules:
- |
package test
import rego.v1
violations[k] if {
some k, _ in input.x
}
query: data.test
want_result:
violations:
BAR: true
BAZ: true
FOO: true
- note: partial_object_iteration_some_in_array_v1
data: {}
input:
arr: ["FOO", "BAR", "BAZ"]
modules:
- |
package test
import rego.v1
violations[v] if {
some _, v in input.arr
}
query: data.test
want_result:
violations:
BAR: true
BAZ: true
FOO: true
- note: partial_object_iteration_with_filter_v1
data: {}
input:
x:
FOO: 1
BAR: 2
BAZ: 3
modules:
- |
package test
import rego.v1
violations[k] if {
some k, _ in input.x
k != "BAR"
}
query: data.test
want_result:
violations:
BAZ: true
FOO: true
- note: partial_object_iteration_input_lookup_future_keywords
data: {}
input:
x:
FOO: 1
BAR: 2
BAZ: 3
modules:
- |
package test
import future.keywords.if
violations[k] if {
input.x[k]
}
query: data.test
want_result:
violations:
BAR: true
BAZ: true
FOO: true
- note: partial_object_multiple_bodies_collect_all_keys_v1
data: {}
input:
primary:
FOO: 1
BAR: 2
secondary:
BAZ: 3
modules:
- |
package test
import rego.v1
violations[k] if {
some k, _ in input.primary
}
violations[k] if {
some k, _ in input.secondary
}
query: data.test
want_result:
violations:
BAR: true
BAZ: true
FOO: true
- note: constant_key_implicit_true_rule_is_complete_v1
data: {}
input:
enabled: true
other: false
modules:
- |
package test
import rego.v1
p["x"] if {
input.enabled
}
p["x"] if {
input.other
}
query: data.test.p.x
want_result: true
- note: partial_object_duplicate_keys_same_value_are_ok_v1
data: {}
input:
arr: ["FOO", "FOO", "BAR"]
modules:
- |
package test
import rego.v1
violations[v] if {
some _, v in input.arr
}
query: data.test
want_result:
violations:
BAR: true
FOO: true
- note: partial_object_duplicate_keys_different_values_error_v1
data: {}
input:
entries:
- k: "FOO"
v: 1
- k: "FOO"
v: 2
modules:
- |
package test
import rego.v1
violations[k] := v if {
some entry in input.entries
k := entry.k
v := entry.v
}
query: data.test.violations
error: "rules must not produce multiple outputs"
- note: partial_object_and_partial_set_iteration_coexist_v1
data: {}
input:
x:
FOO: 1
BAR: 2
BAZ: 3
modules:
- |
package test
import rego.v1
violations[k] if {
some k, _ in input.x
}
seen contains k if {
some k, _ in input.x
}
query: data.test
want_result:
seen:
set!: ["BAR", "BAZ", "FOO"]
violations:
BAR: true
BAZ: true
FOO: true
- note: partial_object_key_bound_in_outer_scope_v1
data: {}
input:
outer:
FOO: [1, 2]
BAR: [3]
BAZ: []
modules:
- |
package test
import rego.v1
violations[k] if {
some k, arr in input.outer
some _ in arr
}
query: data.test.violations
want_result:
BAR: true
FOO: true
- note: complete_rule_same_value_definitions_still_work_v1
data: {}
input:
role: "superuser"
modules:
- |
package test
import rego.v1
allowed if {
input.role == "admin"
}
allowed if {
input.role == "superuser"
}
query: data.test.allowed
want_result: true

View File

@@ -1,150 +0,0 @@
# Copyright (c) Microsoft Corporation.
# Licensed under the MIT License.
cases:
- note: constant_key_partial_object_v1
data: {}
input:
enabled: true
modules:
- |
package test
import rego.v1
p["fixed"] if {
input.enabled
}
query: data.test
want_result:
p:
fixed: true
- note: multilevel_partial_object_v1
data: {}
input:
nested:
app:
read: 1
write: 2
ops:
deploy: 3
modules:
- |
package test
import rego.v1
p[a][b] if {
some a, obj in input.nested
some b, _ in obj
}
query: data.test
want_result:
p:
app:
read: true
write: true
ops:
deploy: true
- note: constant_key_partial_object_explicit_value_v1
data: {}
input:
enabled: true
modules:
- |
package test
import rego.v1
p["fixed"] := 7 if {
input.enabled
}
query: data.test
want_result:
p:
fixed: 7
- note: multilevel_partial_object_explicit_value_v1
data: {}
input:
nested:
app:
read: 1
write: 2
ops:
deploy: 3
modules:
- |
package test
import rego.v1
p[a][b] := v if {
some a, obj in input.nested
some b, v in obj
}
query: data.test
want_result:
p:
app:
read: 1
write: 2
ops:
deploy: 3
- note: issue_712_reproducer_v0_partial_set
data: {}
input:
servers:
FOO: 1
BAR: 2
BAZ: 3
modules:
- |
package test
import future.keywords.in
violations[k] {
some k, _ in input.servers
}
query: data.test.violations
want_result:
set!: ["BAR", "BAZ", "FOO"]
- note: issue_712_reproducer_v1_partial_object
data: {}
input:
servers:
FOO: 1
BAR: 2
BAZ: 3
modules:
- |
package test
import rego.v1
violations[k] if {
some k, _ in input.servers
}
query: data.test.violations
want_result:
BAR: true
BAZ: true
FOO: true
- note: issue_712_reproducer_v1_contains_partial_set
data: {}
input:
servers:
FOO: 1
BAR: 2
BAZ: 3
modules:
- |
package test
import rego.v1
violations contains k if {
some k, _ in input.servers
}
query: data.test.violations
want_result:
set!: ["BAR", "BAZ", "FOO"]

View File

@@ -275,14 +275,6 @@ fn is_with_keyword_unsupported_error(err: &anyhow::Error) -> bool {
})
}
fn is_partial_object_unsupported_error(err: &anyhow::Error) -> bool {
err.chain().any(|cause| {
let msg = cause.to_string();
msg.contains("partial object rules with constant keys are not yet supported")
|| msg.contains("partial object rules with nested bracket keys are not yet supported")
})
}
fn maybe_verify_rvm_case(case: &TestCase, is_rego_v0_test: bool, actual: &Value) -> Result<()> {
if case.note == "defaultkeyword/function with var arg, ref head query" {
println!(
@@ -316,14 +308,6 @@ fn maybe_verify_rvm_case(case: &TestCase, is_rego_v0_test: bool, actual: &Value)
return Ok(());
}
if is_partial_object_unsupported_error(&err) {
println!(
" skipping RVM check for '{}' (partial object pattern unsupported)",
case.note
);
return Ok(());
}
return Err(err);
}
};

View File

@@ -48,18 +48,34 @@ cases:
want_result: true
- note: default_rule_with_object_key
skip: true # TODO: Fix rule type classification for config["timeout"] - should be Complete, not PartialObject
data: {}
input: {}
modules:
- |
package test
import rego.v1
default config["timeout"] := 30
config["timeout"] := 60 if {
false # This will fail
config["timeout"] := val if {
val := input.val
}
query: data.test.config.timeout
want_result: 30
- note: default_rule_with_object_key_override
data: {}
input:
val: 60
modules:
- |
package test
import rego.v1
default config["timeout"] := 30
config["timeout"] := val if {
val := input.val
}
query: data.test.config.timeout
want_result: 60
- note: default_rule_complex_value
data: {}
modules:

File diff suppressed because it is too large Load Diff

View File

@@ -6,9 +6,9 @@
# Covers dynamic keys, collisions, non-string keys, and template validation
cases:
- note: object_key_collision_overwrite
description: Setting same key twice should overwrite the value
example_rego: "{\"key\": 1, \"key\": 2}"
- note: object_key_collision_conflict
description: Setting same key twice with different values should raise a rule output conflict
example_rego: "p[\"key\"] = value { value := [1, 2][_] }"
literals:
- {}
- "key"
@@ -26,9 +26,31 @@ cases:
- "Load { dest: 2, literal_idx: 2 }" # value 1
- "ObjectSet { obj: 0, key: 1, value: 2 }"
- "Load { dest: 3, literal_idx: 3 }" # value 2
- "ObjectSet { obj: 0, key: 1, value: 3 }" # Overwrite
- "ObjectSet { obj: 0, key: 1, value: 3 }" # Conflict
- "Return { value: 0 }"
want_result: {"key": 2}
want_error: "multiple outputs"
- note: object_key_duplicate_same_value
description: Setting same key twice with the same value should succeed
example_rego: "p[\"key\"] := 1 if { some _ in [0, 1] }"
literals:
- {}
- "key"
- 1
instruction_params:
object_create_params:
- dest: 0
template_literal_idx: 0
literal_key_fields: []
fields: []
instructions:
- "ObjectCreate { params_index: 0 }"
- "Load { dest: 1, literal_idx: 1 }" # key
- "Load { dest: 2, literal_idx: 2 }" # value
- "ObjectSet { obj: 0, key: 1, value: 2 }"
- "ObjectSet { obj: 0, key: 1, value: 2 }"
- "Return { value: 0 }"
want_result: {"key": 1}
- note: object_dynamic_key_generation
description: Generate object keys dynamically from loop iteration