Repository navigation
Conversation
…icy#313) Cedar's Rust API can build one schema from several fragments with Schema::from_schema_fragments, so teams can each own part of a large schema. CedarJava had no way to do this. Schema.fromFragments(List<Schema>) passes the fragments, in either format, to a new JNI function. The function checks them with Schema::from_schema_fragments, so conflicts and undeclared types are reported as Cedar reports them, and returns the combined schema in the JSON format. The result is an ordinary Schema, so it works for authorization (cached or not), validation and entity validation without any other changes. Signed-off-by: Ved Thakar <111605341+Vedthakar@users.noreply.github.com> Co-authored-by: Ved Thakar <111605341+Vedthakar@users.noreply.github.com>
Vedthakar
force-pushed
the
feat/313-schema-fragments
branch
from
October 16, 2026 03:07
7edd7b8 to
1b45023
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Issue #, if available: Fixes cedar-policy#313
Description of changes:
This solves issue cedar-policy#313: CedarJava can now build one schema from several schema fragments, as Cedar's Rust API does with
Schema::from_schema_fragments.Problem. The issue asks for a way to split a large schema (thousands of actions, many teams) into fragments and use them together as one schema.
Schemain CedarJava holds a single JSON or Cedar schema, and nothing inCedarJavaFFIcallsSchema::from_schema_fragments. Users had to concatenate schemas themselves, which is error-prone, especially across the two formats.Why a new API is needed. Every path that sends a schema to Rust (
AuthorizationOperation,ValidateOperation, entity validation, andSchema.cache()/preparseSchemaJni) takes onecedar_policy::ffi::Schema, which is a single JSON or Cedar schema.Change.
Schema.fromFragments(List<Schema> fragments)is a new public static method. Each fragment can be in the JSON or Cedar format. It returns an ordinarySchemain the JSON format, likeSchema.parse, so the result works with every existing API with no other changes: authorization (uncached and cached throughschema.cache()), request validation, policy validation, and entity validation.CedarJavaFFIhas a newfromFragmentsJni. The fragments go over JNI as a JSON array using the existingSchemaSerializer: an object for a JSON fragment, a string for a Cedar fragment. Rust parses each one into aSchemaFragmentand callsSchema::from_schema_fragments. That means cross-fragment references, duplicate declarations, undeclared types and RFC 70 shadowing are checked exactly as Cedar checks them, and the Rust error comes back as anInternalException. Warnings from Cedar-format fragments are dropped, as inSchema.parse.entityTypes,actions,commonTypes,annotations) into one JSON schema. Validation does not depend on how definitions are split across fragments, andfrom_schema_fragmentshas already rejected duplicate type and action definitions. The only remaining conflict is the same namespace annotation with two different values, which is reported as an error. The same value on both is fine. The merge is hand-written because the validated RustSchemacan't be serialized back to JSON or Cedar text, and every operation takes a singleffi::Schema. A code comment explains this, and a test round-trips every definition's contents.Schema(JSON format)InternalExceptionwith Cedar's errorInternalException(failed to resolve type: ...)InternalException{}nulllist ornullfragmentNullPointerExceptionExisting APIs are unchanged.
Alternatives considered.
preparseSchemaJnivariant that stores thefrom_schema_fragmentsresult under a cache key. It would only help cached authorization. Validation and uncached authorization still send the schema itself, so a fragments-onlySchemawould not work there.cedar_policy::ffi::Schemahas no fragments variant, so it would need a change incedarfirst.Since this is a new public API, I'm happy to rename it or change its shape (for example, varargs) if you prefer.
Tests
Rust (
CedarJavaFFI/src/interface.rs,schema_test):combine_schema_fragments_mixed_formats: a JSON and a Cedar fragment in the same namespace that refer to each othercombine_schema_fragments_matches_from_schema_fragments: the combined schema has the same entity types and actions asSchema::from_schema_fragments(common type, two namespaces, a namespace split across fragments)combine_schema_fragments_round_trips_contents: four fragments in two namespaces with common types, entity and attribute annotations, tags, an actionmemberOfacross fragments and context types. Every definition comes back unchanged in the combined schema, with nothing extra, and the combined schema keeps the cross-fragment action hierarchycombine_schema_fragments_single_and_emptycombine_schema_fragments_duplicate_entity_type,_undeclared_type,_conflicting_namespace_annotation(plus the same annotation value, which is allowed),_invalid_inputfrom_fragments_internal_valid,from_fragments_internal_null(JNI path, NPE on null)JUnit (
SchemaTests.FromFragmentsTests): combining JSON and Cedar fragments; policy validation against the combined schema (valid policy and unknown action); authorization with the combined schema, uncached and cached, plus request validation rejecting a principal type the schema doesn't allow; single and empty lists; duplicate declaration; undeclared type; malformed fragment; null inputs.On
mainthe new JUnit tests don't compile (cannot find symbol: fromFragments). With the Java change and themainnative library, 7 of 8 fail withUnsatisfiedLinkError: ... Schema.fromFragmentsJni. The null-input test passes because it throws before the JNI call. All pass with this change.Verification
cargo fmt --all --check(CedarJavaFFI): cleancargo test --all-features(CedarJavaFFI): 124 passedcargo clippy --all-features --all-targets: no new warnings compared withmain./gradlew build javadoc: BUILD SUCCESSFUL, 68,100 tests including the corpus tests. Checkstyle only reports the 3 existing warnings inpbt/IntegrationTests.java. I ran this locally against a native library built withcargo build --release --features partial-eval,tpeforx86_64-unknown-linux-gnu, throughCEDAR_JAVA_FFI_LIB, instead of the zigbuild cross-compile.Author: Ved Thakar (@Vedthakar)