Rule Cascade
Get started

5-minute quickstart

Build the command, write a rule with golden tests, check it, compile it and evaluate a request.

You need Git and Go 1.22 or later. The command is one file with no dependencies; nothing else is installed. (Without Go, every command below also exists in Python: see the end of the page.)

Build the command

git clone https://github.com/YarlisAISolutions/rule-cascade.git && cd rule-cascade
(cd packages/go && go build -o dist/rule-cascade ./cmd/rule-cascade)
alias rule-cascade=$PWD/packages/go/dist/rule-cascade
rule-cascade version
rule-cascade 1.0.0-alpha.2 (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:

rule-cascade 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:

rule-cascade compile orders.ruleset.yaml -o orders.bundle.json
echo '{"entity":"Order","operation":"create","data":{"quantity":12}}' |
  rule-cascade 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 rule-cascade check prints 0 failed and evaluate returns deny for 12 items and allow for 3.

Without Go

The reference implementation has the same commands. From the repository root, with Python 3.10 or later:

pip install -r tools/requirements.txt
python tools/rulecheck.py check quickstart/orders.ruleset.yaml
python tools/rulecheck.py compile quickstart/orders.ruleset.yaml -o quickstart/orders.bundle.json

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

Source: site/content/docs/get-started/quickstart.mdx

On this page