rvm: switch binary serialization to postcard (#582)

Move RVM binary encoding from bincode to postcard and bump the format version. Update test helpers, docs, changelog, and refresh lockfiles after the swap.

Closes #575

Signed-off-by: Anand Krishnamoorthi <anakrish@microsoft.com>
This commit is contained in:
Anand Krishnamoorthi
2026-03-03 15:09:45 -06:00
committed by GitHub
parent b6f11c5602
commit 006e819d52
13 changed files with 261 additions and 268 deletions

View File

@@ -49,9 +49,9 @@ jobs:
- name: Run rust-clippy
run: cargo xtask clippy --sarif rust-clippy-results.sarif
continue-on-error: true
- name: Upload analysis results to GitHub
if: ${{ hashFiles('rust-clippy-results.sarif') != '' }}
uses: github/codeql-action/upload-sarif@89a39a4e59826350b863aa6b6252a07ad50cf83e # v3.29.11
with:
sarif_file: rust-clippy-results.sarif

View File

@@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Azure RBAC condition interpreter with builtin evaluation coverage and YAML test suite, including quantifier (ForAnyOfAnyValues/ForAllOfAllValues), datetime (DateTimeEquals), IP (IpInRange), GUID (GuidEquals), list (ListContains), and string (StringEquals) semantics.
- FFI surface for Azure RBAC condition evaluation (see bindings changelog for language-specific wrappers).
### Changed
- [**breaking**] Switch RVM binary serialization to postcard, bump the format to v4, and mark v1-3 loads as partial (recompile required).
## [0.9.1](https://github.com/microsoft/regorus/compare/regorus-v0.9.0...regorus-v0.9.1) - 2026-02-06
### Fixed

51
Cargo.lock generated
View File

@@ -123,16 +123,6 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bincode"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740"
dependencies = [
"serde",
"unty",
]
[[package]]
name = "bit-set"
version = "0.8.0"
@@ -300,6 +290,15 @@ version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
[[package]]
name = "cobs"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1"
dependencies = [
"thiserror",
]
[[package]]
name = "colorchoice"
version = "1.0.4"
@@ -433,6 +432,18 @@ dependencies = [
"serde",
]
[[package]]
name = "embedded-io"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
[[package]]
name = "embedded-io"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
[[package]]
name = "ensure_no_std"
version = "0.1.0"
@@ -1035,6 +1046,18 @@ dependencies = [
"plotters-backend",
]
[[package]]
name = "postcard"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24"
dependencies = [
"cobs",
"embedded-io 0.4.0",
"embedded-io 0.6.1",
"serde",
]
[[package]]
name = "potential_utf"
version = "0.1.4"
@@ -1230,7 +1253,6 @@ name = "regorus"
version = "0.9.1"
dependencies = [
"anyhow",
"bincode",
"cfg-if",
"chrono",
"chrono-tz",
@@ -1247,6 +1269,7 @@ dependencies = [
"num-bigint",
"num-traits",
"num_cpus",
"postcard",
"prettydiff",
"rand",
"regex",
@@ -1535,12 +1558,6 @@ version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
[[package]]
name = "unty"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae"
[[package]]
name = "url"
version = "2.5.8"

View File

@@ -39,7 +39,7 @@ net = ["dep:ipnet"]
no_std = ["lazy_static/spin_no_std"]
opa-runtime = []
regex = ["dep:regex"]
rvm = ["dep:bincode", "dep:indexmap"]
rvm = ["dep:postcard", "dep:indexmap"]
semver = ["dep:semver"]
allocator-memory-limits = ["std", "mimalloc", "mimalloc/allocator-memory-limits"]
std = ["rand/std", "rand/std_rng", "serde_json/std", "msvc_spectre_libs" ]
@@ -128,7 +128,7 @@ mimalloc = { package = "regorus-mimalloc", path = "mimalloc", version = "2.2.6",
# rvm related deps
indexmap = { version = "2.12.1", default-features = false, features = ["serde"], optional = true }
bincode = { version = "2.0.1", default-features = false, features = ["alloc", "serde"], optional = true }
postcard = { version = "1.1.3", default-features = false, features = ["alloc"], optional = true }
[dev-dependencies]
anyhow = "1.0.45"

View File

@@ -102,16 +102,6 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bincode"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740"
dependencies = [
"serde",
"unty",
]
[[package]]
name = "bit-set"
version = "0.8.0"
@@ -246,6 +236,15 @@ version = "0.7.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c3e64b0cc0439b12df2fa678eae89a1c56a529fd067a9115f7827f1fffd22b32"
[[package]]
name = "cobs"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1"
dependencies = [
"thiserror",
]
[[package]]
name = "colorchoice"
version = "1.0.4"
@@ -304,6 +303,18 @@ dependencies = [
"serde",
]
[[package]]
name = "embedded-io"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
[[package]]
name = "embedded-io"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
[[package]]
name = "equivalent"
version = "1.0.2"
@@ -805,6 +816,18 @@ dependencies = [
"siphasher",
]
[[package]]
name = "postcard"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24"
dependencies = [
"cobs",
"embedded-io 0.4.0",
"embedded-io 0.6.1",
"serde",
]
[[package]]
name = "potential_utf"
version = "0.1.4"
@@ -953,7 +976,6 @@ name = "regorus"
version = "0.9.1"
dependencies = [
"anyhow",
"bincode",
"chrono",
"chrono-tz",
"dashmap",
@@ -966,6 +988,7 @@ dependencies = [
"msvc_spectre_libs",
"num-bigint",
"num-traits",
"postcard",
"rand",
"regex",
"regorus-mimalloc",
@@ -1258,12 +1281,6 @@ version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
[[package]]
name = "unty"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae"
[[package]]
name = "url"
version = "2.5.8"

View File

@@ -52,16 +52,6 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bincode"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740"
dependencies = [
"serde",
"unty",
]
[[package]]
name = "bit-set"
version = "0.8.0"
@@ -162,6 +152,15 @@ dependencies = [
"phf",
]
[[package]]
name = "cobs"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1"
dependencies = [
"thiserror 2.0.18",
]
[[package]]
name = "combine"
version = "4.6.7"
@@ -204,6 +203,18 @@ dependencies = [
"serde",
]
[[package]]
name = "embedded-io"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
[[package]]
name = "embedded-io"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
[[package]]
name = "equivalent"
version = "1.0.2"
@@ -681,6 +692,18 @@ dependencies = [
"siphasher",
]
[[package]]
name = "postcard"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24"
dependencies = [
"cobs",
"embedded-io 0.4.0",
"embedded-io 0.6.1",
"serde",
]
[[package]]
name = "potential_utf"
version = "0.1.4"
@@ -829,7 +852,6 @@ name = "regorus"
version = "0.9.1"
dependencies = [
"anyhow",
"bincode",
"chrono",
"chrono-tz",
"data-encoding",
@@ -841,6 +863,7 @@ dependencies = [
"msvc_spectre_libs",
"num-bigint",
"num-traits",
"postcard",
"rand",
"regex",
"regorus-mimalloc",
@@ -1081,12 +1104,6 @@ version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
[[package]]
name = "unty"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae"
[[package]]
name = "url"
version = "2.5.8"

View File

@@ -52,16 +52,6 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bincode"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740"
dependencies = [
"serde",
"unty",
]
[[package]]
name = "bit-set"
version = "0.8.0"
@@ -150,6 +140,15 @@ dependencies = [
"phf",
]
[[package]]
name = "cobs"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1"
dependencies = [
"thiserror",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
@@ -182,6 +181,18 @@ dependencies = [
"serde",
]
[[package]]
name = "embedded-io"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
[[package]]
name = "embedded-io"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
[[package]]
name = "equivalent"
version = "1.0.2"
@@ -676,6 +687,18 @@ version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950"
[[package]]
name = "postcard"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24"
dependencies = [
"cobs",
"embedded-io 0.4.0",
"embedded-io 0.6.1",
"serde",
]
[[package]]
name = "potential_utf"
version = "0.1.4"
@@ -888,7 +911,6 @@ name = "regorus"
version = "0.9.1"
dependencies = [
"anyhow",
"bincode",
"chrono",
"chrono-tz",
"data-encoding",
@@ -900,6 +922,7 @@ dependencies = [
"msvc_spectre_libs",
"num-bigint",
"num-traits",
"postcard",
"rand",
"regex",
"regorus-mimalloc",
@@ -1124,12 +1147,6 @@ version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
[[package]]
name = "unty"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae"
[[package]]
name = "url"
version = "2.5.8"

View File

@@ -63,16 +63,6 @@ version = "0.22.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6"
[[package]]
name = "bincode"
version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "36eaf5d7b090263e8150820482d5d93cd964a81e4019913c972f4edcc6edb740"
dependencies = [
"serde",
"unty",
]
[[package]]
name = "bit-set"
version = "0.8.0"
@@ -167,6 +157,15 @@ dependencies = [
"phf",
]
[[package]]
name = "cobs"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fa961b519f0b462e3a3b4a34b64d119eeaca1d59af726fe450bbba07a9fc0a1"
dependencies = [
"thiserror",
]
[[package]]
name = "core-foundation-sys"
version = "0.8.7"
@@ -199,6 +198,18 @@ dependencies = [
"serde",
]
[[package]]
name = "embedded-io"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
[[package]]
name = "embedded-io"
version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "edd0f118536f44f5ccd48bcb8b111bdc3de888b58c74639dfb034a357d0f206d"
[[package]]
name = "equivalent"
version = "1.0.2"
@@ -738,6 +749,18 @@ version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184"
[[package]]
name = "postcard"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6764c3b5dd454e283a30e6dfe78e9b31096d9e32036b5d1eaac7a6119ccb9a24"
dependencies = [
"cobs",
"embedded-io 0.4.0",
"embedded-io 0.6.1",
"serde",
]
[[package]]
name = "potential_utf"
version = "0.1.4"
@@ -886,7 +909,6 @@ name = "regorus"
version = "0.9.1"
dependencies = [
"anyhow",
"bincode",
"chrono",
"chrono-tz",
"data-encoding",
@@ -898,6 +920,7 @@ dependencies = [
"msvc_spectre_libs",
"num-bigint",
"num-traits",
"postcard",
"rand",
"regex",
"semver",
@@ -1113,12 +1136,6 @@ version = "0.2.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861"
[[package]]
name = "unty"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d49784317cd0d1ee7ec5c716dd598ec5b4483ea832a2dced265471cc0f690ae"
[[package]]
name = "url"
version = "2.5.8"

View File

@@ -90,11 +90,11 @@ version:
`3`).
2. **Section manifest**: four little-endian `u32` lengths for entry points,
sources, literals, and the rule tree, plus a single-byte `rego_v0` flag.
3. **Preamble payloads**: each section is encoded with `bincode` using helper
3. **Preamble payloads**: each section is encoded with `postcard` using helper
wrappers (`BinaryValueSlice`, `BinaryValueRef`) to stream complex `Value`
graphs without cloning.
4. **Program core**: the remaining `Program` struct is serialized once more via
`bincode`; fields skipped by serde (entry points, literals, sources,
`postcard`; fields skipped by serde (entry points, literals, sources,
rule_tree, resolved builtins) are re-inserted from the preamble when the
program is reconstructed.

View File

@@ -85,7 +85,7 @@ pub struct Program {
impl Program {
/// Current serialization format version
pub const SERIALIZATION_VERSION: u32 = 3;
pub const SERIALIZATION_VERSION: u32 = 4;
/// Magic bytes to identify Regorus program files
pub const MAGIC: [u8; 4] = *b"REGO";
/// Maximum instructions supported (matches u16 jump targets)

View File

@@ -4,8 +4,7 @@
use alloc::format;
use alloc::string::{String, ToString as _};
use alloc::vec::Vec;
use bincode::config::standard;
use bincode::serde::{decode_from_slice, encode_to_vec};
use postcard::{from_bytes, to_allocvec};
use super::{DeserializationResult, Program};
use crate::value::Value;
@@ -70,7 +69,7 @@ impl Program {
}
/// Serialize program to binary format.
/// Uses pure bincode for all sections now that `Value` supports serde.
/// Uses postcard for all sections now that `Value` supports serde.
pub fn serialize_binary(&self) -> Result<Vec<u8>, String> {
self.validate_limits()?;
@@ -79,19 +78,19 @@ impl Program {
buffer.extend_from_slice(&Self::MAGIC);
buffer.extend_from_slice(&Self::SERIALIZATION_VERSION.to_le_bytes());
let entry_points_bin = encode_to_vec(&self.entry_points, standard())
.map_err(|e| format!("Entry points bincode serialization failed: {}", e))?;
let entry_points_bin = to_allocvec(&self.entry_points)
.map_err(|e| format!("Entry points postcard serialization failed: {}", e))?;
let sources_bin = encode_to_vec(&self.sources, standard())
.map_err(|e| format!("Sources bincode serialization failed: {}", e))?;
let sources_bin = to_allocvec(&self.sources)
.map_err(|e| format!("Sources postcard serialization failed: {}", e))?;
let literals_bin = encode_to_vec(BinaryValueSlice(self.literals.as_slice()), standard())
.map_err(|e| format!("Literals bincode serialization failed: {}", e))?;
let literals_bin = to_allocvec(&BinaryValueSlice(self.literals.as_slice()))
.map_err(|e| format!("Literals postcard serialization failed: {}", e))?;
let rule_tree_bin = encode_to_vec(BinaryValueRef(&self.rule_tree), standard())
.map_err(|e| format!("Rule tree bincode serialization failed: {}", e))?;
let rule_tree_bin = to_allocvec(&BinaryValueRef(&self.rule_tree))
.map_err(|e| format!("Rule tree postcard serialization failed: {}", e))?;
let binary_data = encode_to_vec(self, standard())
let binary_data = to_allocvec(self)
.map_err(|e| format!("Program structure binary serialization failed: {}", e))?;
buffer.extend_from_slice(
@@ -152,128 +151,13 @@ impl Program {
}
match version {
1 => {
if data.len() < 25 {
return Err("Data too short for header".to_string());
}
let entry_points_len = Self::read_u32_as_usize(data, 8)?;
let sources_len = Self::read_u32_as_usize(data, 12)?;
let rego_v0 = Self::read_byte(data, 16)? != 0;
let mut offset = OffsetTracker::new(17);
let entry_points_start = offset.advance(entry_points_len)?;
let sources_start = offset.advance(sources_len)?;
let binary_len_start = offset.current();
if data.len() < binary_len_start.checked_add(4).ok_or("Offset overflow")? {
return Err("Data too short for binary length".to_string());
}
let binary_len = Self::read_u32_as_usize(data, binary_len_start)?;
let mut binary_offset = OffsetTracker::new(binary_len_start);
binary_offset.advance(4)?; // Skip the binary_len u32
let binary_start = binary_offset.advance(binary_len)?;
let json_start = binary_offset.current();
if data.len() < json_start.checked_add(4).ok_or("Offset overflow")? {
return Err("Data too short for JSON length".to_string());
}
let json_len = Self::read_u32_as_usize(data, json_start)?;
let total_expected = json_start
.checked_add(4)
.and_then(|v| v.checked_add(json_len))
.ok_or("Offset overflow")?;
if data.len() < total_expected {
return Err("Data truncated".to_string());
}
let json_end = json_start
.checked_add(4)
.and_then(|v| v.checked_add(json_len))
.ok_or("Offset overflow")?;
let entry_points = decode_from_slice(
Self::get_slice(data, entry_points_start, sources_start)?,
standard(),
)
.map(|(value, _)| value)
.map_err(|e| format!("Entry points deserialization failed: {}", e))?;
let sources = decode_from_slice(
Self::get_slice(data, sources_start, binary_len_start)?,
standard(),
)
.map(|(value, _)| value)
.map_err(|e| format!("Sources deserialization failed: {}", e))?;
let mut needs_recompilation = false;
let mut program = match decode_from_slice::<Program, _>(
Self::get_slice(data, binary_start, json_start)?,
standard(),
) {
Ok((prog, _)) => prog,
Err(_e) => {
needs_recompilation = true;
Program::new()
}
};
let (literals, rule_tree) =
match serde_json::from_slice::<serde_json::Value>(Self::get_slice(
data,
json_start.checked_add(4).ok_or("Offset overflow")?,
json_end,
)?) {
Ok(combined) => {
let literals = combined
.get("literals")
.and_then(|v| serde_json::from_value::<Vec<Value>>(v.clone()).ok())
.unwrap_or_else(|| {
needs_recompilation = true;
Vec::new()
});
let rule_tree = combined
.get("rule_tree")
.and_then(|v| serde_json::from_value::<Value>(v.clone()).ok())
.unwrap_or_else(|| {
needs_recompilation = true;
Value::new_object()
});
(literals, rule_tree)
}
Err(_e) => {
needs_recompilation = true;
(Vec::new(), Value::new_object())
}
};
program.entry_points = entry_points;
program.sources = sources;
program.literals = literals;
program.rule_tree = rule_tree;
program.rego_v0 = rego_v0;
program.needs_recompilation = needs_recompilation;
if !program.builtin_info_table.is_empty() {
if let Err(_e) = program.initialize_resolved_builtins() {
program.needs_recompilation = true;
}
}
if program.needs_recompilation {
Ok(DeserializationResult::Partial(program))
} else {
Ok(DeserializationResult::Complete(program))
}
1..=3 => {
let mut program = Program::new();
program.needs_recompilation = true;
program.rego_v0 = Self::legacy_rego_v0(data, version).unwrap_or(false);
Ok(DeserializationResult::Partial(program))
}
2 | 3 => {
4 => {
if data.len() < 29 {
return Err("Data too short for header".to_string());
}
@@ -306,27 +190,21 @@ impl Program {
return Err("Data truncated".to_string());
}
let entry_points = decode_from_slice(
Self::get_slice(data, entry_points_start, sources_start)?,
standard(),
)
.map(|(value, _)| value)
.map_err(|e| format!("Entry points deserialization failed: {}", e))?;
let entry_points =
from_bytes(Self::get_slice(data, entry_points_start, sources_start)?)
.map_err(|e| format!("Entry points deserialization failed: {}", e))?;
let sources = decode_from_slice(
Self::get_slice(data, sources_start, literals_start)?,
standard(),
)
.map(|(value, _)| value)
.map_err(|e| format!("Sources deserialization failed: {}", e))?;
let sources = from_bytes(Self::get_slice(data, sources_start, literals_start)?)
.map_err(|e| format!("Sources deserialization failed: {}", e))?;
let mut needs_recompilation = false;
let literals = match decode_from_slice::<Vec<BinaryValue>, _>(
Self::get_slice(data, literals_start, rule_tree_start)?,
standard(),
) {
Ok((binary_literals, _)) => match binaries_to_values(binary_literals) {
let literals = match from_bytes::<Vec<BinaryValue>>(Self::get_slice(
data,
literals_start,
rule_tree_start,
)?) {
Ok(binary_literals) => match binaries_to_values(binary_literals) {
Ok(values) => values,
Err(_e) => {
needs_recompilation = true;
@@ -339,11 +217,12 @@ impl Program {
}
};
let rule_tree = match decode_from_slice::<BinaryValue, _>(
Self::get_slice(data, rule_tree_start, binary_len_start)?,
standard(),
) {
Ok((binary_tree, _)) => match binary_to_value(binary_tree) {
let rule_tree = match from_bytes::<BinaryValue>(Self::get_slice(
data,
rule_tree_start,
binary_len_start,
)?) {
Ok(binary_tree) => match binary_to_value(binary_tree) {
Ok(value) => value,
Err(_e) => {
needs_recompilation = true;
@@ -356,16 +235,14 @@ impl Program {
}
};
let mut program = match decode_from_slice::<Program, _>(
Self::get_slice(data, binary_start, binary_end)?,
standard(),
) {
Ok((prog, _)) => prog,
Err(_e) => {
needs_recompilation = true;
Program::new()
}
};
let mut program =
match from_bytes::<Program>(Self::get_slice(data, binary_start, binary_end)?) {
Ok(prog) => prog,
Err(_e) => {
needs_recompilation = true;
Program::new()
}
};
program.entry_points = entry_points;
program.sources = sources;
@@ -404,8 +281,16 @@ impl Program {
let version = Self::read_u32(data, 4).ok();
match version {
Some(1..=3) => Ok(true),
Some(1..=4) => Ok(true),
_ => Ok(false),
}
}
fn legacy_rego_v0(data: &[u8], version: u32) -> Option<bool> {
match version {
1 => data.get(16).map(|value| *value != 0),
2 | 3 => data.get(24).map(|value| *value != 0),
_ => None,
}
}
}

View File

@@ -13,8 +13,7 @@ use crate::rvm::program::{binaries_to_values, BinaryValue, Program};
use alloc::format;
use alloc::string::String;
use alloc::vec::Vec;
use bincode::config::standard;
use bincode::serde::decode_from_slice;
use postcard::from_bytes;
/// Test utility function for round-trip serialization
/// Serializes program, deserializes it, and serializes again to check for consistency
@@ -31,7 +30,7 @@ pub fn test_round_trip_serialization(program: &Program) -> Result<(), String> {
serialized1[7],
]);
if version == 2 && serialized1.len() >= 25 {
if version == Program::SERIALIZATION_VERSION && serialized1.len() >= 25 {
let entry_points_len = u32::from_le_bytes([
serialized1[8],
serialized1[9],
@@ -56,11 +55,9 @@ pub fn test_round_trip_serialization(program: &Program) -> Result<(), String> {
let rule_tree_start = literals_start + literals_len;
if literals_len > 0 && serialized1.len() >= rule_tree_start {
match decode_from_slice::<Vec<BinaryValue>, _>(
&serialized1[literals_start..rule_tree_start],
standard(),
) {
Ok((decoded_literals, _)) => {
match from_bytes::<Vec<BinaryValue>>(&serialized1[literals_start..rule_tree_start])
{
Ok(decoded_literals) => {
if binaries_to_values(decoded_literals).is_err() {
return Err(
"Failed to convert literal table from binary representation".into(),
@@ -69,7 +66,7 @@ pub fn test_round_trip_serialization(program: &Program) -> Result<(), String> {
}
Err(err) => {
return Err(format!(
"Failed to decode literal table with bincode: {}",
"Failed to decode literal table with postcard: {}",
err
));
}

View File

@@ -1,7 +1,7 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
use std::fs::File;
use std::fs::{self, File};
use std::path::{Path, PathBuf};
use std::process::{Command, Stdio};
@@ -131,10 +131,33 @@ fn run_clippy_with_sarif(workspace: &Path, sarif: &Path) -> Result<()> {
sarif_cmd.stdout(Stdio::from(sarif_file));
run_command(sarif_cmd, "clippy-sarif")?;
let formatted_path = sarif_path.with_extension("sarif.tmp");
let sarif_input = File::open(&sarif_path)
.with_context(|| format!("failed to reopen SARIF output at {}", sarif_path.display()))?;
let sarif_output = File::create(&formatted_path).with_context(|| {
format!(
"failed to create SARIF output at {}",
formatted_path.display()
)
})?;
let mut fmt = Command::new("sarif-fmt");
fmt.arg(&sarif_path);
fmt.stdin(Stdio::from(sarif_input));
fmt.stdout(Stdio::from(sarif_output));
run_command(fmt, "sarif-fmt")?;
let formatted_len = fs::metadata(&formatted_path)
.map(|metadata| metadata.len())
.unwrap_or(0);
if formatted_len == 0 {
let _ = fs::remove_file(&formatted_path);
println!("sarif-fmt produced empty output, keeping original SARIF");
} else {
fs::rename(&formatted_path, &sarif_path).with_context(|| {
format!("failed to replace SARIF output at {}", sarif_path.display())
})?;
}
println!("SARIF report written to {}", sarif_path.display());
Ok(())