Compile to a checksummed bundle
rcas compile turns the ruleset and its parents into one JSON bundle with a checksum. Every runtime evaluates the bundle the same way.
Compiling runs every load check once and writes a bundle: one JSON file that holds a manifest for the server and a smaller one for the browser. The bundle carries a checksum of the resolved ruleset. The same source always gives the same checksum, in every runtime, so the checksum names exactly which rules made a decision.
Hands-on
-
Compile the organisation ruleset, look inside the bundle, and compile it again:
rcas compile (real output) $ rcas compile orders.ruleset.yaml -o shop.orders.bundle.json wrote shop.orders.bundle.json shop.orders@1.0.0 sha256:4583c90bbfcacb54bf78e11d9e8190ecc086ce4b69aade609b7a0928d452ea82 [exit status 0] $ jq '{ruleCascadeBundle, id, version, checksum, manifests: (.manifests | keys)}' shop.orders.bundle.json { "ruleCascadeBundle": "1.0.0", "id": "shop.orders", "version": "1.0.0", "checksum": "sha256:4583c90bbfcacb54bf78e11d9e8190ecc086ce4b69aade609b7a0928d452ea82", "manifests": [ "client", "server" ] } [exit status 0] $ rcas compile orders.ruleset.yaml -o again.bundle.json && cmp shop.orders.bundle.json again.bundle.json && echo identical wrote again.bundle.json shop.orders@1.0.0 sha256:4583c90bbfcacb54bf78e11d9e8190ecc086ce4b69aade609b7a0928d452ea82 identical [exit status 0]The two bundles are byte for byte identical. A rebuild never changes the checksum unless the rules changed.
-
Look at what the browser receives. The client manifest holds only the rules that may run in the browser: the action rule is
enforcement: server, so it is not there.rcas manifest (real output) $ rcas compile orders.ruleset.yaml -o shop.orders.bundle.json wrote shop.orders.bundle.json shop.orders@1.0.0 sha256:4583c90bbfcacb54bf78e11d9e8190ecc086ce4b69aade609b7a0928d452ea82 [exit status 0] $ rcas manifest shop.orders.bundle.json --channel client | jq '{id, version, checksum, channel, rules: [.rules[].id], params}' { "id": "shop.orders", "version": "1.0.0", "checksum": "sha256:4583c90bbfcacb54bf78e11d9e8190ecc086ce4b69aade609b7a0928d452ea82", "channel": "client", "rules": [ "order.quantity.max" ], "params": { "maxQuantity": 10 } } [exit status 0] -
Evaluate the bundle once, to see that it works without the YAML:
eleven-items.json { "entity": "Order", "operation": "create", "data": { "id": "o-2", "quantity": 11 } }rcas evaluate (real output) $ rcas compile orders.ruleset.yaml -o shop.orders.bundle.json wrote shop.orders.bundle.json shop.orders@1.0.0 sha256:4583c90bbfcacb54bf78e11d9e8190ecc086ce4b69aade609b7a0928d452ea82 [exit status 0] $ rcas evaluate --bundle shop.orders.bundle.json eleven-items.json | jq . { "ruleset": "shop.orders", "version": "1.0.0", "checksum": "sha256:4583c90bbfcacb54bf78e11d9e8190ecc086ce4b69aade609b7a0928d452ea82", "decision": "deny", "findings": [ { "rule": "order.quantity.max", "code": "SHOP-ORD-001", "severity": "error", "message": "You can order at most 10 items.", "fields": [ "/quantity" ], "blocking": true, "status": "open", "resolution": "none", "source": "shop.orders@1.0.0" } ], "effects": [], "commands": [] } [exit status 0] $ rcas evaluate --bundle shop.orders.bundle.json three-items.json | jq . { "ruleset": "shop.orders", "version": "1.0.0", "checksum": "sha256:4583c90bbfcacb54bf78e11d9e8190ecc086ce4b69aade609b7a0928d452ea82", "decision": "allow", "findings": [], "effects": [], "commands": [ { "name": "order.placed", "type": "event", "rule": "order.placed", "idempotencyKey": "order.placed:o-4", "payload": { "orderId": "o-4", "quantity": 3 }, "ref": "OrderPlaced" } ] } [exit status 0]The denied request returns no command. The allowed one returns
order.placedwith its idempotency key.
Done when
- You have
shop.orders.bundle.jsonand itschecksum. - Compiling twice gives identical files.
- The client manifest holds no rule that must stay on the server.
Go deeper
- Bundles and checksums: what the checksum covers.
- Ship a rule change, step "Store the bundle immutably".