Skip to content

Commit 0fda046

Browse files
tomjwxfZeroXLaurenclaude
authored
feat: RequestGenerator WASM bindings for Cedar authorization requests (#73)
* feat: RequestGenerator WASM bindings for authorization requests Addresses #72. Per Victor's guidance: single crate, sync-only, camelCase. Extends `cedar-policy-mcp-schema-generator-wasm` (the crate from #64) with request-generation bindings that let JS/TS agent hosts construct Cedar authorization requests from MCP tool-call inputs. ## What this adds ### Generator crate (`cedar-policy-mcp-schema-generator`) - `AuthorizationComponents` struct — serializable principal/action/ resource/entities from a Cedar authorization request. - `RequestGenerator::get_action_uid_string(tool_name)` — returns the fully-qualified Cedar EntityUID string for a tool action. - `RequestGenerator::generate_request_components(input, principal, resource, context, entities, output)` — returns `AuthorizationComponents` ready for JSON serialization. ### WASM crate (`cedar-policy-mcp-schema-generator-wasm`) - `generateRequest(schemaStub, toolsJson, inputJson, principalType, principalId, resourceType, resourceId, configJson?)` — sync JS function that returns `{ principal, action, resource, entitiesJson, error, isOk }` in camelCase matching cedar-wasm conventions. - 6 unit tests (basic, invalid-input, invalid-stub, namespace qualification, entities JSON, error-field completeness). ## Why this matters Together with #64 (schema generation), this gives the complete build-time + runtime WASM toolchain for Cedar-based agent authorization: 1. **Schema generation** (#64): MCP tool descriptions → Cedar schema 2. **Request generation** (this PR): MCP tool call → Cedar request 3. **Authorization**: pass request + schema to `cedar-wasm` `isAuthorized()` for the decision All three steps now run in any JS/TS environment via WASM without a Rust toolchain. ## Verification - 237 tests passing (all workspace tests) - cargo clippy clean (workspace lints, `too_many_arguments` expected) - cargo fmt clean Signed-off-by: tommylauren <tfarley@utexas.edu> * test: add coverage for RequestGenerator WASM and generator-crate APIs Addresses CI coverage check failure (62.12% -> target 80%). WASM crate tests added (8): - Invalid config JSON returns error - Invalid tools JSON returns error - Empty config string uses defaults - Explicit config (numbersAsDecimal) passes through - Multi-tool schema resolves correct action - Resource ID appears in formatted EntityUID - req_err helper produces correct error shape - WasmRequestResult serializes with camelCase (isOk, entitiesJson) Generator crate tests added (3): - get_action_uid_string returns namespace-qualified action - get_action_uid_string distinguishes multiple tools - AuthorizationComponents is Clone + Debug with expected fields 312 tests passing, cargo clippy clean, cargo fmt clean. Signed-off-by: tommylauren <tfarley@utexas.edu> * test: comprehensive coverage for generate_request_components + all error paths Addresses CI coverage check (65.91% -> target 80%). Generator crate tests added (3): - generate_request_components basic: exercises the full serialization pipeline (EntityUID -> String, Entities -> JSON) - generate_request_components with output: covers the Output parameter path - generate_request_components entities serialization: validates the JSON array output format WASM crate tests added (4): - No-namespace schema: exercises the None branch for namespace qualification (principal/resource without NS:: prefix) - Explicit None config: confirms None config produces same results as omitted config - Action format: verifies namespace + tool name in action string - All error paths in generate_request_inner: exercises every early return (invalid config, invalid stub, invalid tools, invalid input, empty config string) in a single test function 319 tests passing, clippy clean, fmt clean. Signed-off-by: tommylauren <tfarley@utexas.edu> * refactor: propagate real entities + string-based request helper Addresses @chaluli's review feedback on #73: Q2 — entities bug (correctness) The WASM crate was hardcoding entities_json: "[]", which silently dropped entities the generator actually produces from MCP tool-call inputs containing nulls, floats, or nested objects. Fixed by routing the WASM entry point through the generator crate's real request- components pipeline — entity data now flows through unchanged. Q1 — API layering The old WASM code path duplicated namespace extraction and principal/ resource UID construction via format! strings. Replaced with a new string-based convenience method on RequestGenerator — generate_request_components_from_strings — which takes plain strings and builds correctly-namespaced EntityUIDs internally. The WASM crate now stays free of cedar-policy-core as a direct dep AND avoids the parallel implementation. The generator crate's public API is the single source of truth for request construction; WASM is a thin JSON-serialization wrapper around it. Tests - generator crate: +2 tests for the new string-based method (happy path + invalid principal type error surface). - WASM crate: +1 regression test that asserts entities_json parses as a real JSON array (not a hardcoded string literal) and that principal/action/resource are correctly namespaced against the schema. All 237+3 = 240 workspace tests pass. cargo clippy --all-features clean. cargo fmt clean. Co-Authored-By: Claude Opus 4 (1M context) <noreply@anthropic.com> Signed-off-by: tommylauren <tfarley@utexas.edu> * refactor: address all of @victornicolet's review comments Applies every point from the review on PR #73: 1. Remove duplicate / inconsistent doc block on `generateRequest`. The second block described the parameters as if they were a single JSON object, which contradicted the flat-argument signature. 2. Remove the explanatory "Previously this hardcoded [] -- see PR review" comment on the delegation call. The code is new to this PR; the comment belonged in the PR description, not the source. 3. Move `get_action_uid_string` out of the public API. It was only called from the two tests that tested it. Removing the method and its two standalone tests eliminates the dead export; namespace qualification of action UIDs stays covered by the full-pipeline tests against `generate_request_components`. 4. Delete every `#[expect(clippy::expect_used, reason = "Test assertion")]` (28 sites). Replace with one `#![allow(clippy::expect_used, clippy::panic, clippy::unwrap_used)]` per test module. Keeps test code noise-free. 5. Make `test_generate_request_no_namespace_schema` deterministic by removing the "might succeed or fail" branch. The Cedar schema parser at this version rejects unqualified `entity` declarations without a surrounding namespace block, so the test is retired; a comment records why and points at where namespace-absent coverage lives. 6. Surface the underlying `serde_json` error on invalid config, matching the schema-generation path (`"Invalid config: {}"` with the parser's own message) instead of the opaque `"failed to parse JSON"`. 7. Stop silencing `write_to_json` errors in `generate_request_components`. The call now uses `?` so a serializer failure surfaces as a `RequestGeneratorError` rather than producing a stale empty entity set. `String::from_utf8_lossy` handles the (unreachable in practice) non-UTF-8 path without an unwrap. 8. Strengthen the entities regression test. The previous version asserted `parsed.is_array()` and `starts_with('[')` / `ends_with(']')`, all of which a hardcoded `"[]"` would satisfy. The replacement test uses a tool input with a nested-object property plus a float that the schema generator must turn into a non-empty entity set, and asserts `!arr.is_empty()` with exact principal / action / resource UID equality. A regression to the old hardcoded behavior fails. 9. Consolidate duplicated happy-path tests. `test_generate_request_basic`, `test_generate_request_namespace_qualification`, `test_generate_request_action_contains_namespace_and_tool`, and `test_generate_request_with_none_config` all exercised subsets of the same success path with weaker assertions. Replaced by the single deeper `test_generate_request_entities_propagate_real_generator_output`. Verification: cargo test --workspace -> all pass (237 generator-crate, 44 wasm-crate, and adjacent) cargo clippy --workspace --all-features -> clean cargo fmt --check -> clean Thanks @victornicolet for the careful review; each comment improved the diff materially. Signed-off-by: tommylauren <tfarley@utexas.edu> --------- Signed-off-by: tommylauren <tfarley@utexas.edu> Co-authored-by: tommylauren <tfarley@utexas.edu> Co-authored-by: Claude Opus 4 (1M context) <noreply@anthropic.com>
1 parent 34b211a commit 0fda046

4 files changed

Lines changed: 948 additions & 17 deletions

File tree

0 commit comments

Comments
 (0)