Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

no_std support #232

Merged
merged 1 commit into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .github/workflows/pr.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ jobs:
- uses: actions/checkout@v3
- name: Add musl target
run: rustup target add x86_64-unknown-linux-musl
- name: Add no_std target
run: rustup target add thumbv7m-none-eabi
- name: Install musl-gcc
run: sudo apt update && sudo apt install -y musl-tools
- name: Format Check
Expand All @@ -26,6 +28,12 @@ jobs:
run: cargo build -r --all-features --verbose
- name: Build
run: cargo build -r --verbose
- name: Build no_std
run: cd tests/ensure_no_std && cargo build -r --target thumbv7m-none-eabi
- name: Test no_std
run: cargo test -r --no-default-features
- name: Build only std
run: cargo build -r --example regorus --no-default-features --features "std"
- name: Doc Tests
run: cargo test -r --doc
- name: Run tests
Expand Down
71 changes: 50 additions & 21 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ members = [
"bindings/wasm",
"bindings/java",
"bindings/ruby/ext/regorusrb",
"tests/ensure_no_std",
]

[package]
Expand All @@ -15,7 +16,7 @@ version = "0.1.5"
edition = "2021"
license-file = "LICENSE"
repository = "https://github.com/microsoft/regorus"
keywords = ["interpreter", "opa", "policy-as-code", "rego"]
keywords = ["interpreter", "no_std", "opa", "policy-as-code", "rego"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

Expand All @@ -33,14 +34,15 @@ crypto = ["dep:constant_time_eq", "dep:hmac", "dep:hex", "dep:md-5", "dep:sha1",
deprecated = []
hex = ["dep:data-encoding"]
http = []
jwt = ["dep:jsonwebtoken", "dep:data-encoding"]
glob = ["dep:wax"]
graph = []
jsonschema = ["dep:jsonschema"]
jwt = ["dep:jsonwebtoken", "dep:data-encoding", "dep:itertools"]
no_std = ["lazy_static/spin_no_std"]
opa-runtime = []
regex = ["dep:regex"]
semver = ["dep:semver"]
std = ["serde_json/std"]
std = ["rand/std", "rand/std_rng", "serde_json/std"]
time = ["dep:chrono", "dep:chrono-tz"]
uuid = ["dep:uuid"]
urlquery = ["dep:url"]
Expand All @@ -67,41 +69,62 @@ full-opa = [
"yaml"
]

# Features that can be used in no_std environments.
# Note that: the spin_no_std feature in lazy_static must be specified.
opa-no-std = [
"arc",
"base64",
"base64url",
"coverage",
"crypto",
"deprecated",
"graph",
"hex",
"no_std",
"opa-runtime",
"regex",
"semver",
# Configure lazy_static to use spinlocks.
"lazy_static/spin_no_std"
]

# This feature enables some testing utils for OPA tests.
opa-testutil = []
rand = ["dep:rand"]

[dependencies]
anyhow = { version = "1.0.45", default-features=false }
anyhow = { version = "1.0.45", default-features = false }
serde = {version = "1.0.150", default-features = false, features = ["derive", "rc"] }
serde_json = { version = "1.0.89", default-features=false, features = ["alloc"] }
serde_yaml = {version = "0.9.16", optional = true }
lazy_static = "1.4.0"
rand = "0.8.5"
num = "0.4.1"
serde_json = { version = "1.0.89", default-features = false, features = ["alloc"] }
lazy_static = { version = "1.4.0", default-features = false }

# Crypto
constant_time_eq = {version = "0.3.0", optional = true}
hmac = {version = "0.12.1", optional = true}
sha2 = {version= "0.10.8", optional = true}
hex = {version = "0.4.3", optional = true}
sha1 = {version = "0.10.6", optional = true}
md-5 = {version = "0.10.6", optional = true}

data-encoding = { version = "2.4.0", optional = true }
constant_time_eq = {version = "0.3.0", optional = true, default-features = false }
hmac = {version = "0.12.1", optional = true, default-features = false}
sha2 = {version= "0.10.8", optional = true, default-features = false }
hex = {version = "0.4.3", optional = true, default-features = false, features = ["alloc"] }
sha1 = {version = "0.10.6", optional = true, default-features = false }
md-5 = {version = "0.10.6", optional = true, default-features = false }

data-encoding = { version = "2.4.0", optional = true, default-features=false, features = ["alloc"] }
scientific = { version = "0.5.2" }

regex = {version = "1.10.2", optional = true}
semver = {version = "1.0.20", optional = true}
regex = {version = "1.10.2", optional = true, default-features = false }
semver = {version = "1.0.20", optional = true, default-features = false }
wax = { version = "0.6.0", features = [], default-features = false, optional = true }
url = { version = "2.5.0", optional = true }
uuid = { version = "1.6.1", features = ["v4", "fast-rng"], optional = true }
uuid = { version = "1.6.1", default-features = false, features = ["v4", "fast-rng"], optional = true }
jsonschema = { version = "0.17.1", default-features = false, optional = true }
chrono = { version = "0.4.31", optional = true }
chrono-tz = { version = "0.8.5", optional = true }
jsonwebtoken = { version = "9.2.0", optional = true }
itertools = "0.12.1"
itertools = { version = "0.12.1", default-features = false, optional = true }

serde_yaml = {version = "0.9.16", default-features = false, optional = true }
rand = { version = "0.8.5", default-features = false, optional = true }

[dev-dependencies]
anyhow = "1.0.45"
cfg-if = "1.0.0"
clap = { version = "4.4.7", features = ["derive"] }
prettydiff = { version = "0.6.4", default-features = false }
Expand Down Expand Up @@ -131,6 +154,12 @@ name="kata"
harness=false
test=false

[[example]]
name="regorus"
harness=false
test=false
doctest=false

[package.metadata.docs.rs]
# To build locally:
# RUSTDOCFLAGS="--cfg docsrs" cargo +nightly doc --all-features --no-deps
Expand Down
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -88,14 +88,14 @@ features. By default all features are enabled.
The default build of regorus example program is 6.4M:
```bash
$ cargo build -r --example regorus; strip target/release/examples/regorus; ls -lh target/release/examples/regorus
-rwxr-xr-x 1 anand staff 6.4M Jan 19 11:23 target/release/examples/regorus*
-rwxr-xr-x 1 anand staff 6.3M May 11 22:03 target/release/examples/regorus*
```


When all features except for `yaml` are disabled, the binary size drops down to 2.9M.
When all default features are disabled, the binary size drops down to 1.9M.
```bash
$ cargo build -r --example regorus --features "yaml" --no-default-features; strip target/release/examples/regorus; ls -lh target/release/examples/regorus
-rwxr-xr-x 1 anand staff 2.9M Jan 19 11:26 target/release/examples/regorus*
$ cargo build -r --example regorus --no-default-features; strip target/release/examples/regorus; ls -lh target/release/examples/regorus
-rwxr-xr-x 1 anand staff 1.9M May 11 22:04 target/release/examples/regorus*
```

Regorus passes the [OPA v0.64.0 test-suite](https://www.openpolicyagent.org/docs/latest/ir/#test-suite) barring a few
Expand Down
54 changes: 46 additions & 8 deletions examples/regorus.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,37 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

use anyhow::{bail, Result};
use anyhow::{anyhow, bail, Result};

#[allow(dead_code)]
fn read_file(path: &String) -> Result<String> {
std::fs::read_to_string(path).map_err(|_| anyhow!("could not read {path}"))
}

#[allow(unused_variables)]
fn read_value_from_yaml_file(path: &String) -> Result<regorus::Value> {
#[cfg(feature = "yaml")]
return regorus::Value::from_yaml_file(path);

#[cfg(not(feature = "yaml"))]
bail!("regorus has not been built with yaml support");
}

fn read_value_from_json_file(path: &String) -> Result<regorus::Value> {
#[cfg(feature = "std")]
return regorus::Value::from_json_file(path);

#[cfg(not(feature = "std"))]
regorus::Value::from_json_str(&read_file(path)?)
}

fn add_policy_from_file(engine: &mut regorus::Engine, path: String) -> Result<()> {
#[cfg(feature = "std")]
return engine.add_policy_from_file(path);

#[cfg(not(feature = "std"))]
engine.add_policy(path.clone(), read_file(&path)?)
}

fn rego_eval(
bundles: &[String],
Expand Down Expand Up @@ -35,23 +65,23 @@ fn rego_eval(
_ => continue,
}

engine.add_policy_from_file(entry.path())?;
add_policy_from_file(&mut engine, entry.path().display().to_string())?;
}
}

// Load given files.
for file in files.iter() {
if file.ends_with(".rego") {
// Read policy file.
engine.add_policy_from_file(file)?;
add_policy_from_file(&mut engine, file.clone())?;
} else {
// Read data file.
let data = if file.ends_with(".json") {
regorus::Value::from_json_file(file)?
read_value_from_json_file(file)?
} else if file.ends_with(".yaml") {
regorus::Value::from_yaml_file(file)?
read_value_from_yaml_file(file)?
} else {
bail!("Unsupported data file `{file}`. Must be rego, json or yaml.")
bail!("Unsupported data file `{file}`. Must be rego, json or yaml.");
};

// Merge given data.
Expand All @@ -61,9 +91,9 @@ fn rego_eval(

if let Some(file) = input {
let input = if file.ends_with(".json") {
regorus::Value::from_json_file(&file)?
read_value_from_json_file(&file)?
} else if file.ends_with(".yaml") {
regorus::Value::from_yaml_file(&file)?
read_value_from_yaml_file(&file)?
} else {
bail!("Unsupported input file `{file}`. Must be json or yaml.")
};
Expand Down Expand Up @@ -95,8 +125,12 @@ fn rego_lex(file: String, verbose: bool) -> Result<()> {
use regorus::unstable::*;

// Create source.
#[cfg(feature = "std")]
let source = Source::from_file(file)?;

#[cfg(not(feature = "std"))]
let source = Source::from_contents(file.clone(), read_file(&file)?)?;

// Create lexer.
let mut lexer = Lexer::new(&source);

Expand All @@ -122,8 +156,12 @@ fn rego_parse(file: String) -> Result<()> {
use regorus::unstable::*;

// Create source.
#[cfg(feature = "std")]
let source = Source::from_file(file)?;

#[cfg(not(feature = "std"))]
let source = Source::from_contents(file.clone(), read_file(&file)?)?;

// Create a parser and parse the source.
let mut parser = Parser::new(&source)?;
let ast = parser.parse()?;
Expand Down
18 changes: 14 additions & 4 deletions scripts/pre-push
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,27 @@
set -eo pipefail

if [ -f Cargo.toml ]; then
# Run precommit checks
# Run precommit checks.
dir=$(dirname "${BASH_SOURCE[0]}")
"$dir/pre-commit"

# Ensure that the public API works
# Ensure that the public API works.
cargo test -r --doc

# Ensure that we can build with all features
# Ensure that no_std build succeeds.
# Build for a target that has no std available.
if command -v rustup > /dev/null; then
rustup target add thumbv7m-none-eabi
(cd tests/ensure_no_std; cargo build -r --target thumbv7m-none-eabi)
fi

# Ensure that we can build with only std.
cargo build -r --example regorus --no-default-features --features std

# Ensure that we can build with all features.
cargo build -r --all-features

# Ensure that all tests pass
# Ensure that all tests pass.
cargo test -r
cargo test -r --test aci
cargo test -r --test kata
Expand Down
53 changes: 0 additions & 53 deletions src/builtins/debugging.rs

This file was deleted.

Loading
Loading