Rule Cascade
Get started

5-minute quickstart

Try a rule in your browser with nothing installed, then get the command, write a rule with golden tests, check it, compile it and evaluate a request.

The first step needs nothing but this browser. For the rest:

You need the rcas command: one file with no dependencies, installed in the second step. Nothing else is installed.

Try it in your browser: nothing to install

The rule this page builds, with its schema and golden tests, is already loaded in the playground and evaluated: eleven items are denied with SHOP-ORD-001. Change the quantity to 3 and press Evaluate, then press Check to run the golden tests. The engine runs in the page: it is the TypeScript runtime, which passes the same conformance suite as the command, so it gives the same answer.

Try it in your browserThe quickstart's ruleset, schema and golden tests. Nothing to install.

The steps below do the same on your machine, where a CI job can run them.

Install the command

curl -fsSL https://rulescascade.com/install.sh | sh

The installer checks the download against SHA256SUMS (and its Sigstore signature with --verify cosign); Install has every option, and Download and verify does each step by hand. Then:

rcas version
rcas 1.0.0-alpha.5 (specification 1.0.0, bundle format 1.0.0)

Describe the data

A rule talks about an entity, and the entity's fields are checked against an OpenAPI schema, so a misspelt field fails to load instead of silently never matching. Create a working directory with a minimal schema:

mkdir -p quickstart && cd quickstart
cat > orders.openapi.yaml <<'EOF'
openapi: 3.1.0
info: { title: Orders API, version: 1.0.0 }
paths: {}
components:
  schemas:
    Order:
      type: object
      properties:
        id: { type: string }
        quantity: { type: integer }
EOF

Write a rule

One validation rule, its message, and two golden tests: one that passes the rule and one that breaks it.

orders.ruleset.yaml
ruleCascade: 1.0.0
kind: RuleSet

metadata:
  id: shop.orders
  version: 1.0.0
  title: Orders
  owner: shop-team
  status: active

scope:
  - { level: organization, id: shop }

entities:
  Order:
    schema: { $ref: "./orders.openapi.yaml#/components/schemas/Order" }

params:
  maxQuantity:
    type: integer
    default: 10

rules:
  - id: order.quantity.max
    kind: validation
    title: At most ten items per order
    target: { entity: Order, field: /quantity }
    operations: [create, update]
    triggers: [change, submit]
    when: { op: exists, args: [ { var: data.quantity } ] }
    assert: { op: lte, args: [ { var: data.quantity }, { var: params.maxQuantity } ] }
    severity: error
    finding:
      code: SHOP-ORD-001
      message: order.quantityTooHigh
      args: { max: { var: params.maxQuantity } }

messages:
  en:
    order.quantityTooHigh: "You can order at most {max} items."

tests:
  - name: ten items are allowed
    entity: Order
    operation: create
    given:
      data: { quantity: 10 }
    expect:
      decision: allow
      findings: []

  - name: eleven items are denied
    entity: Order
    operation: create
    given:
      data: { quantity: 11 }
    expect:
      decision: deny
      findings:
        - { rule: order.quantity.max, fields: [/quantity], message: You can order at most 10 items. }

Read it as: when the order has a quantity, assert that it is at most the parameter maxQuantity; otherwise raise the finding SHOP-ORD-001 with severity error on /quantity. The cookbook explains every member.

Check it

check validates the document, loads it, verifies every path against the schema and runs the golden tests:

rcas check orders.ruleset.yaml
shop.orders@1.0.0  sha256:d2f310e63f29...  1 rules (1 client-safe), 1 params
  2 golden tests, 0 failed

Break it on purpose: change data.quantity in the assert to data.quantty and run check again.

orders.ruleset.yaml: LOAD FAILED
  PATH_UNKNOWN: order.quantity.max path data.quantty is not in the Order schema

The exit status is 1, which is what fails a CI job. Change it back.

Compile and evaluate

Compile the ruleset into a bundle, then evaluate a request against it:

rcas compile orders.ruleset.yaml -o orders.bundle.json
echo '{"entity":"Order","operation":"create","data":{"quantity":12}}' |
  rcas evaluate --bundle orders.bundle.json -
{
  "ruleset": "shop.orders",
  "version": "1.0.0",
  "checksum": "sha256:d2f310e63f29e8307d5c1599589b4be1202bdf1a18be5503d7b4b0619527aace",
  "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": []
}

(The command prints each array member on its own line; the fields list is folded here.) Send "quantity": 3 instead and the decision is allow with no findings. evaluate exits with status 0 whatever the decision: the decision is in the output.

Done when rcas check prints 0 failed and evaluate returns deny for 12 items and allow for 3.

Where next

You want toRead
Evaluate the bundle in your serviceUsage by language
Show the findings in a formAdd rule enforcement to a React form
Enforce it in your APIEnforce in a backend API
Ship a change to the ruleAuthor and ship a rule change
See rules for every data type and severityCookbook

On this page