Skip to content

Commit

Permalink
Use Protobuf for DRT (#488)
Browse files Browse the repository at this point in the history
Signed-off-by: Craig Disselkoen <[email protected]>
  • Loading branch information
cdisselkoen authored Dec 10, 2024
1 parent 074952e commit 7f0c82b
Show file tree
Hide file tree
Showing 31 changed files with 521 additions and 10,859 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/build_and_test_drt_reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ jobs:
run: |
wget https://raw.githubusercontent.com/leanprover/elan/master/elan-init.sh
bash elan-init.sh -y
- name: Install protoc
run: sudo apt-get install protobuf-compiler
- name: Prepare Rust build
run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }}
- name: cargo fmt (cedar-policy-generators)
Expand Down
4 changes: 0 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,6 @@ jobs:
working-directory: ./cedar-lean
shell: bash
run: source ~/.profile && lake exe CedarUnitTests
- name: Test CLI
working-directory: ./cedar-lean
shell: bash
run: source ~/.profile && ./test_cli.sh
- name: Build docs
working-directory: ./cedar-lean
shell: bash
Expand Down
3 changes: 2 additions & 1 deletion .github/workflows/run_integration_tests_reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ jobs:
run: |
wget https://raw.githubusercontent.com/leanprover/elan/master/elan-init.sh
bash elan-init.sh -y
- name: Install protoc
run: sudo apt-get install protobuf-compiler
- name: Prepare Rust build
run: rustup update ${{ matrix.toolchain }} && rustup default ${{ matrix.toolchain }}
- name: Build Lean libraries
Expand All @@ -64,4 +66,3 @@ jobs:
working-directory: ./cedar-spec/cedar-drt
shell: bash
run: source ~/.profile && source set_env_vars.sh && cargo test --features "integration-testing" -- --nocapture

3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ RUN . ~/.profile; cargo install cargo-fuzz
# Install Lean
RUN wget https://raw.githubusercontent.com/leanprover/elan/master/elan-init.sh && sh elan-init.sh -y --default-toolchain none

# Install protoc
RUN wget https://github.com/protocolbuffers/protobuf/releases/download/v29.0/protoc-29.0-linux-x86_64.zip && unzip protoc-29.0-linux-x86_64.zip && rm protoc-29.0-linux-x86_64.zip

FROM prepare AS build

ENV CEDAR_SPEC_ROOT=/opt/src/cedar-spec
Expand Down
8 changes: 6 additions & 2 deletions cedar-drt/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ env_logger = "0.10"
log = "0.4"
libfuzzer-sys = "0.4"
cedar-policy = { path = "../cedar/cedar-policy", version = "4.*" }
cedar-policy-core = { path = "../cedar/cedar-policy-core", version = "4.*", features = ["arbitrary"] }
cedar-policy-validator = { path = "../cedar/cedar-policy-validator", version = "4.*", features = ["arbitrary"] }
cedar-policy-core = { path = "../cedar/cedar-policy-core", version = "4.*", features = ["arbitrary", "protobufs"] }
cedar-policy-validator = { path = "../cedar/cedar-policy-validator", version = "4.*", features = ["arbitrary", "protobufs"] }
cedar-policy-formatter = { path = "../cedar/cedar-policy-formatter", version = "4.*" }
cedar-testing = { path = "../cedar/cedar-testing", version = "4.*" }
lean-sys = { version = "0.0.7", features = ["small_allocator"], default-features = false }
Expand All @@ -19,6 +19,10 @@ serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"
lazy_static = "1.4"
smol_str = { version = "0.3", features = ["serde"] }
prost = "0.13"

[build-dependencies]
prost-build = "0.13"

[features]
integration-testing = []
Expand Down
17 changes: 15 additions & 2 deletions cedar-drt/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,10 @@
* limitations under the License.
*/

use std::env;
use std::path::Path;
const LEAN_BUILD_DIR: &'static str = "../cedar-lean/.lake/build/lib";
fn main() {
let lean_dir = env::var("LEAN_LIB_DIR").expect(
let lean_dir = std::env::var("LEAN_LIB_DIR").expect(
"`LEAN_LIB_DIR` environment variable is not set! Try running `source set_env_vars.sh`",
);
// We'll need to link against some files found here later, and it's nicer to
Expand All @@ -32,4 +31,18 @@ fn main() {
"cargo:rustc-link-search=native=../cedar-lean/.lake/packages/batteries/.lake/build/lib"
);
println!("cargo:rerun-if-changed={LEAN_BUILD_DIR}");

let mut config = prost_build::Config::new();
config.extern_path(".cedar_policy_core", "::cedar_policy_core::ast::proto");
config.extern_path(".cedar_policy_validator", "::cedar_policy_validator::proto");
config
.compile_protos(
&["./protobuf_schema/Messages.proto"],
&[
"./protobuf_schema",
"../cedar/cedar-policy-core/protobuf_schema",
"../cedar/cedar-policy-validator/protobuf_schema",
],
)
.unwrap();
}
2 changes: 1 addition & 1 deletion cedar-drt/build_lean_lib.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@

# Build command needed for linking Lean lib with Rust code
lake update
lake build Cedar:static DiffTest:static Batteries:static
lake build Cedar:static Protobuf:static CedarProto:static DiffTest:static Batteries:static
13 changes: 10 additions & 3 deletions cedar-drt/fuzz/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ libfuzzer-sys = "0.4"
serde = { version = "1.0", feature = ["derive"] }
serde_json = "1.0"
cedar-drt = { version = "4.0.0", path = ".." }
cedar-policy = { path = "../../cedar/cedar-policy", version = "4.*" }
cedar-policy-core = { path = "../../cedar/cedar-policy-core", version = "4.*", features = ["arbitrary"] }
cedar-policy-validator = { path = "../../cedar/cedar-policy-validator", version = "4.*", features = ["arbitrary", "entity-manifest"] }
cedar-policy = { path = "../../cedar/cedar-policy", version = "4.*", features = ["protobufs"] }
cedar-policy-core = { path = "../../cedar/cedar-policy-core", version = "4.*", features = ["arbitrary", "protobufs"] }
cedar-policy-validator = { path = "../../cedar/cedar-policy-validator", version = "4.*", features = ["arbitrary", "entity-manifest", "protobufs"] }
cedar-policy-formatter = { path = "../../cedar/cedar-policy-formatter", version = "4.*" }
cedar-testing = { path = "../../cedar/cedar-testing", version = "4.*" }
cedar-policy-generators = { path = "../../cedar-policy-generators", version = "4.*" }
Expand All @@ -30,6 +30,7 @@ rand_chacha = { version = "0.3", optional = true }
similar-asserts = "1.5.0"
thiserror = "2.0"
logos = "0.14.0"
prost = "0.13"
itertools = "0.13.0"

[dependencies.uuid]
Expand Down Expand Up @@ -188,6 +189,12 @@ path = "fuzz_targets/convert-policy-json-to-cedar.rs"
test = false
doc = false

[[bin]]
name = "protobuf-roundtrip"
path = "fuzz_targets/protobuf-roundtrip.rs"
test = false
doc = false

[[bin]]
name = "entity-validation"
path = "fuzz_targets/entity-validation.rs"
Expand Down
160 changes: 160 additions & 0 deletions cedar-drt/fuzz/fuzz_targets/protobuf-roundtrip.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/*
* Copyright Cedar Contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

#![no_main]

use libfuzzer_sys::arbitrary::{self, MaxRecursionReached};
use prost::Message;

use crate::arbitrary::Arbitrary;
use crate::arbitrary::Unstructured;
use cedar_drt::{AuthorizationRequestMsg, OwnedAuthorizationRequestMsg};
use cedar_drt_inner::{fuzz_target, schemas::Equiv};
use cedar_policy_core::{
ast, entities::Entities, entities::NoEntitiesSchema, entities::TCComputation,
extensions::Extensions,
};
use cedar_policy_generators::{
abac::ABACPolicy, abac::ABACRequest, hierarchy::HierarchyGenerator, schema::Schema,
settings::ABACSettings,
};

#[derive(Debug)]
struct FuzzTargetInput {
request: ABACRequest,
policy: ABACPolicy,
entities: Entities,
schema: cedar_policy_validator::ValidatorSchema,
}

// settings for this fuzz target
// copy-pasted from abac.rs
const SETTINGS: ABACSettings = ABACSettings {
match_types: false,
enable_extensions: true,
max_depth: 7,
max_width: 7,
enable_additional_attributes: true,
enable_like: true,
enable_action_groups_and_attrs: true,
enable_arbitrary_func_call: false,
enable_unknowns: false,
enable_action_in_constraints: true,
enable_unspecified_apply_spec: true,
};

impl<'a> Arbitrary<'a> for FuzzTargetInput {
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
let schema: Schema = Schema::arbitrary(SETTINGS.clone(), u)?;
let hierarchy = schema.arbitrary_hierarchy(u)?;
let request = schema.arbitrary_request(&hierarchy, u)?;
let policy = schema.arbitrary_policy(&hierarchy, u)?;

let entities: Entities = Entities::from_entities(
hierarchy.entities().map(|x| x.to_owned()),
None::<&NoEntitiesSchema>,
TCComputation::AssumeAlreadyComputed,
Extensions::none(),
)
.expect("Failed to create entities");

Ok(Self {
request,
policy,
entities,
schema: schema
.try_into()
.expect("Failed to convert schema to ValidatorSchema"),
})
}

fn try_size_hint(depth: usize) -> Result<(usize, Option<usize>), MaxRecursionReached> {
Ok(arbitrary::size_hint::and_all(&[
Schema::arbitrary_size_hint(depth)?,
HierarchyGenerator::size_hint(depth),
Schema::arbitrary_policy_size_hint(&SETTINGS, depth),
]))
}
}

fuzz_target!(|input: FuzzTargetInput| {
let s_policy: ast::StaticPolicy = input.policy.into();
let mut policies: ast::PolicySet = ast::PolicySet::new();
policies.add(s_policy.into()).expect("Failed to add policy");
roundtrip_authz_request_msg(AuthorizationRequestMsg {
request: &input.request.into(),
policies: &policies,
entities: &input.entities,
});
roundtrip_schema(input.schema);
});

fn roundtrip_authz_request_msg(auth_request: AuthorizationRequestMsg) {
// AST -> Protobuf
let auth_request_proto = cedar_drt::proto::AuthorizationRequestMsg::from(&auth_request);

// Protobuf -> Bytes
let buf = auth_request_proto.encode_to_vec();

// Bytes -> Protobuf
let roundtripped_proto = cedar_drt::proto::AuthorizationRequestMsg::decode(&buf[..])
.expect("Failed to deserialize AuthorizationRequestMsg from proto");

// Protobuf -> AST
let roundtripped = OwnedAuthorizationRequestMsg::from(roundtripped_proto);

// Checking request equality (ignores loc field)
assert_eq!(
auth_request.request.principal().uid(),
roundtripped.request.principal().uid()
);
assert_eq!(
auth_request.request.action().uid(),
roundtripped.request.action().uid()
);
assert_eq!(
auth_request.request.resource().uid(),
roundtripped.request.resource().uid()
);
assert_eq!(
auth_request.request.context(),
roundtripped.request.context()
);

// Checking policy set equality
assert_eq!(auth_request.policies, &roundtripped.policies);

// Checking entities equality
assert_eq!(auth_request.entities, &roundtripped.entities);
}

fn roundtrip_schema(schema: cedar_policy_validator::ValidatorSchema) {
// AST -> Protobuf bytes
let schema_proto = cedar_policy_validator::proto::ValidatorSchema::from(&schema);

// Protobuf -> Bytes
let buf = schema_proto.encode_to_vec();

// Bytes -> Protobuf
let roundtripped_proto = cedar_policy_validator::proto::ValidatorSchema::decode(&buf[..])
.expect("Failed to deserialize Schema from proto");

// Protobuf -> AST
let roundtripped = cedar_policy_validator::ValidatorSchema::from(&roundtripped_proto);

// Checking schema equivalence
Equiv::equiv(&schema, &roundtripped).unwrap();
}
16 changes: 16 additions & 0 deletions cedar-drt/protobuf_schema/Messages.proto
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
syntax = "proto3";
package cedar_drt;
import "AST.proto";
import "Validator.proto";

message AuthorizationRequestMsg {
cedar_policy_core.Request request = 1;
cedar_policy_core.LiteralPolicySet policies = 2;
cedar_policy_core.Entities entities = 3;
}

message ValidationRequestMsg {
cedar_policy_validator.ValidatorSchema schema = 1;
cedar_policy_core.LiteralPolicySet policies = 2;
cedar_policy_validator.ValidationMode mode = 3;
}
12 changes: 8 additions & 4 deletions cedar-drt/set_env_vars.sh
Original file line number Diff line number Diff line change
Expand Up @@ -16,14 +16,18 @@
# Set environment variables for Lean
if ! command -v lean &> /dev/null; then
echo "lean executable could not be found. is lean installed?"
return 1
else
export LEAN_LIB_DIR=$(lean --print-libdir)
export LD_LIBRARY_PATH=${LD_LIBRARY_PATH+$LD_LIBRARY_PATH:}$(lean --print-libdir)
export DYLD_LIBRARY_PATH=${DYLD_LIBRARY_PATH+$DYLD_LIBRARY_PATH:}$(lean --print-libdir)

# if the version of GLIBC is too old (< 2.27), then use the version of libm.so packaged with Lean
GLIBC_VERSION=`ldd --version | awk '/ldd/{print $NF}'`
if awk "BEGIN {exit !($GLIBC_VERSION < 2.27)}"; then
export LD_PRELOAD=${LD_PRELOAD+$LD_PRELOAD:}$(lean --print-prefix)/lib/glibc/libm.so
# Skip this check on macOS (darwin), which may not have `ldd`
if [[ "$OSTYPE" != "darwin"* ]]; then
GLIBC_VERSION=`ldd --version | awk '/ldd/{print $NF}'`
if awk "BEGIN {exit !($GLIBC_VERSION < 2.27)}"; then
export LD_PRELOAD=${LD_PRELOAD+$LD_PRELOAD:}$(lean --print-prefix)/lib/glibc/libm.so
fi
fi
fi
fi
Loading

0 comments on commit 7f0c82b

Please sign in to comment.