Skip to main content
Test at every layer before you deploy: unit-test your Rego rules with opa test, run your WASM oracle in isolation, then simulate the full policy end-to-end against the Newton network. This guide covers all three. For diagnosing failures after deployment, see Testing & Debugging.

Unit-test your Rego with opa test

Rego rules are pure functions of input, data.params, and data.wasm, which makes them easy to unit-test without the network. Write a companion policy_test.rego and mock the data with with. Given a policy like this:
package vault_risk_rating

import future.keywords

default allow := false

t := data.params

# Each oracle's output is namespaced under its pack id.
v := data.wasm.vaultsfyi

deny contains "apy_spike" if v.apy_z_score > t.apy_z_max

deny contains "risk_score_below_floor" if {
    v.risk_score != null
    v.risk_score < t.risk_score_floor
}

allow if count(deny) == 0
Write policy_test.rego alongside it. Mock data.params and data.wasm with with, and assert on both allow and membership in the deny set:
package vault_risk_rating_test

import data.vault_risk_rating

default_params := {
    "apy_z_max": 4,
    "risk_score_floor": 60,
}

clean_data := {
    "apy_z_score": 0.5,
    "risk_score": 90,
}

# The policy reads data.wasm.vaultsfyi.*, so wrap fixtures under the pack id.
wrap(inner) := {"vaultsfyi": inner}

with_data(overrides) := wrap(object.union(clean_data, overrides))

test_allow_when_all_clean if {
    d := wrap(clean_data)
    vault_risk_rating.allow with data.params as default_params with data.wasm as d
}

test_deny_apy_spike if {
    d := with_data({"apy_z_score": 5})
    "apy_spike" in vault_risk_rating.deny with data.params as default_params with data.wasm as d
    not vault_risk_rating.allow with data.params as default_params with data.wasm as d
}

test_deny_risk_score_below_floor if {
    d := with_data({"risk_score": 30})
    "risk_score_below_floor" in vault_risk_rating.deny with data.params as default_params with data.wasm as d
}

# A null risk score must not deny — guards against a fail-closed regression.
test_risk_score_null_does_not_deny if {
    d := with_data({"risk_score": null})
    not "risk_score_below_floor" in vault_risk_rating.deny with data.params as default_params with data.wasm as d
}

# Two simultaneous failures must coexist in the deny set, not fail open.
test_multiple_denies_do_not_fail_open if {
    d := with_data({"apy_z_score": 99, "risk_score": 10})
    deny := vault_risk_rating.deny with data.params as default_params with data.wasm as d
    count(deny) >= 2
    not vault_risk_rating.allow with data.params as default_params with data.wasm as d
}
Run the tests:
opa test ./policy.rego ./policy_test.rego -v
Recommended coverage:
  • Happy path — clean data allows.
  • Each deny rule — one test per rule, asserting the expected reason is in deny and allow is false.
  • Param toggles — a deny flag set to false does not deny.
  • Edge valuesnull, empty, and out-of-range fields behave as intended.
  • No fail-open under multiple failures — two deny conditions at once still denies.
  • Multi-oracle — for chained oracles, wrap each fixture under its own pack id ({"vaultsfyi": {...}, "webacy": {...}}) and assert deny rules from each namespace fire independently.

Quick local checks with the CLI

The CLI bundles a Rego engine with Newton’s crypto and identity built-ins. Use it to evaluate a query or validate syntax:
# Evaluate a query against policy + data + input files
newton-cli regorus eval \
  -d policy.rego \
  -d data.json \
  -i intent.json \
  --non-strict \
  "data.vault_risk_rating.allow"

# Validate syntax / inspect the policy
newton-cli regorus parse policy.rego
newton-cli regorus lex policy.rego
Pass --non-strict for OPA-compatible evaluation. -d (data/policy) can be repeated; -i is the input (intent) file. See the CLI Reference.

Test your WASM oracle

Run the compiled oracle in isolation to confirm it produces the data shape your Rego expects.
# Local execution in a sandbox with the Newton HTTP host
newton-cli --chain-id 11155111 policy-data simulate \
  --wasm-file ./dist/policy.wasm \
  --input-json '{"network":"mainnet","vaultAddress":"0x..."}'
For an oracle that needs secrets, test through the Gateway:
MethodSecrets sourceOwnership
newt_simulatePolicyDataProvided inline by the callerNone required
newt_simulatePolicyDataWithClientRead from stored, uploaded secretsPolicyClient owner
curl -X POST https://gateway.testnet.newton.xyz/rpc \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $NEWTON_API_KEY" \
  -d '{
    "jsonrpc": "2.0",
    "method": "newt_simulatePolicyData",
    "params": {
      "policy_data_address": "0xYourPolicyData",
      "wasm_args": "0x7b226e6574776f726b223a226d61696e6e6574227d"
    },
    "id": "7ca6621b-7aa4-4bb7-a896-1f2b58a18c78"
  }'
See Uploading & Accessing Secrets in Oracles for the secrets lifecycle.

Simulate the full policy

The final step before deploying: evaluate the complete policy (Rego + every oracle + merged data) against a sample intent with newt_simulatePolicy. Pass one entry per oracle in policy_data and namespaced policy_params:
curl -X POST https://gateway.testnet.newton.xyz/rpc \
  -H "Content-Type: application/json" \
  -H "Authorization: Bearer $NEWTON_API_KEY" \
  -d '{
    "jsonrpc": "2.0",
    "method": "newt_simulatePolicy",
    "params": {
      "policy_client": "0xYourPolicyClient",
      "policy": "package vault_risk_rating\n...",
      "entrypoint": "vault_risk_rating.allow",
      "intent": {
        "from": "0xf39Fd6e51aad88F6F4ce6aB8827279cffFb92266",
        "to": "0xb1aD5f82407bC0f19f42b2614fb9083035a36b69",
        "value": "0x0",
        "data": "0x",
        "chain_id": "0xaa36a7",
        "function_signature": "0x"
      },
      "policy_data": [
        { "policy_data_address": "0xYourPolicyData" }
      ],
      "policy_params": { "vaultsfyi": { "apy_z_max": 4, "risk_score_floor": 60 } }
    },
    "id": "7ca6621b-7aa4-4bb7-a896-1f2b58a18c78"
  }'
Inspect evaluation_result.policy_params_and_data in the response to confirm the merged data.wasm shape, and evaluation_result.result for the allow/deny decision. For multi-oracle policies, see Chaining Multiple Data Oracles.
  1. opa test your Rego rules.
  2. policy-data simulate each oracle locally.
  3. Upload secrets, then newt_simulatePolicyDataWithClient to verify they resolve.
  4. newt_simulatePolicy for the full end-to-end decision.
  5. Deploy, then submit production tasks.

Next Steps

Testing & Debugging

Diagnose failures after deployment

Chaining Data Oracles

Simulate and test multi-oracle policies

Deployment Checklist

Pre-launch verification steps

Rego Syntax Guide

Rego language reference