Rule Cascade
LearnThe process, end to end

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

  1. 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.

  2. 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]
  3. 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.placed with its idempotency key.

Done when

  • You have shop.orders.bundle.json and its checksum.
  • Compiling twice gives identical files.
  • The client manifest holds no rule that must stay on the server.

Go deeper

Course overview

On this page