Creating and publishing Rego policy artefacts
This guide explains how Network Facilitating Organizations (NFOs) can author policies in Rego, package them as OPA bundles, or a single rego file, publish them, and refer them in DeDi so that they can be discovered and evaluated for a specific networkId.
1. Overview
Policies in the network are distributed as OPA bundles or a single rego file.
Each bundle:
contains one or more Rego policy modules
may include policy data
exposes a decision rule that returns a validation result
is signed to ensure integrity
should be referenced in the network manifest by the NFO
For a given networkId, all applicable policy bundles are fetched and evaluated together.
A request is considered valid only if all applicable policies return valid=true.
2. Create Rego Policies and Decision Rule
Policies must be written in Rego and must expose a decision rule that returns the evaluation result.
Every policy bundle (or the rego file in case of a single rego file) must define a rule that returns:
{ "valid": true | false, "violations": ["string"] }
Field descriptions
Field | Description |
|---|---|
valid | Indicates whether the input satisfies the policy rules |
violations | List of violations detected during evaluation |
Example policy
The following example ensures that message.order.items.quantity.count is greater than zero.
package retail.policy
default result := { "valid": true, "violations": [] } result := { "valid": count(violations) == 0, "violations": violations } violations contains msg if { some item in input.message.order.items item.quantity.count <= 0 msg := "message.order.items.quantity.count must be greater than 0" }
Example query path
The rule path must be recorded in the registry:
data.retail.policy.result
This value must be configured as policyQueryPath.
3. Organize the Policy Repository
OPA does not require a fixed repository layout.
Example repository:
repo/ retail-policy/ validation.rego pricingRules.rego data.json prod-policy/ prodValidation.rego
Bundle files
File | Purpose |
|---|---|
.rego | Policy logic |
data.json | Optional structured data |
.manifest | Bundle metadata |
The .manifest file is automatically created when building bundles.
4. Build and Sign the OPA Bundle or Rego File
To sign a single rego file please follow the instructions in Signing a single file.
To sign an OPA bundle, download the OPA CLI from:
https://www.openpolicyagent.org/docs#1-download-opa
Once installed, build and sign a bundle:
opa build \ --bundle retail-policy/ \ --signing-key private.pem \ --signing-alg ES256 \ -o retail-bundle.tar.gz
This command:
packages policy modules and data
generates a .manifest
signs the bundle
creates .signatures.json inside the bundle
Reference: https://www.openpolicyagent.org/docs/management-bundles
You can use openssl to generate an ECDSA P-256 keypair compatible with ES256 for signing your bundle:
# GENERATE PRIVATE KEY openssl ecparam -name prime256v1 -genkey -noout -out private.pem # GENERATE PUBLIC KEY openssl pkey -in private.pem -pubout -out public.pem # Keys will be saved as private.pem and public.pem
5. Testing Policies Before Publishing
Before publishing bundles, authors must test the policies.
This ensures that:
bundles load correctly
there are no namespace conflicts
policies produce the expected results when evaluated together
Step 1 - Build the policy bundle (if using bundles)
Build the bundles you intend to publish:
opa build \ --bundle retail-policy/ \ --signing-key private.pem \ --signing-alg ES256 \ -o retail-bundle.tar.gz
Step 2 - Create sample input
Example input:
{ "message": { "order": { "items": [ { "id": "item1", "quantity": { "count": 0 } }, { "id": "item2", "quantity": { "count": 2 } } ] } } }
Save as input.json.
Step 3 - Evaluate the policy
Use the OPA CLI to load the built bundle or the single rego file and evaluate the decision rules.
In case of a bundle:
opa eval \ -b retail-bundle.tar.gz \ -i input.json \ --format=raw \ data.retail.validation.result
In case of a single file:
opa eval \ -d policy.rego \ -i input.json \ --format=raw \ data.retail.validation.result
Example output:
{ "valid": false, "violations": [ "message.order.items.quantity.count must be greater than 0" ] }
Testing bundles ensures that policies execute correctly before publishing them.
6. Publish the Policy
The policy must be published to a stable URL.
Example: https://github.com/nfo/policies/releases/download/v1/retail-bundle.tar.gz
Recommended hosting options:
GitHub Releases
Object storage
CDN
Immutable URLs are recommended.
esting directly without setting up network manifest: You can directly test the policy by configuring the OPA Policy Checker plugin in ONIX. For testing you can use type: bundle pointing to a local signed OPA bundle. Add it to your adapter's networkPolicyConfig YAML under your networkId or a default key so it applies to all requests regardless of networkId:
# config/opa-network-policies.yaml networkPolicies: nfo.com/production: type: bundle location: https://github.com/nfo/policies/releases/download/v1/retail-bundle.tar.gz query: "data.retail.policy.result" verification: enabled: true publicKeyLookupUrl: https://api.dedi.global/dedi/lookup/your-nfo.example.com/public_key_test/your-key-name
You can refer to Step 8 in this guide to see how to publish your public key.
Then reference it from your adapter config.
checkPolicy: id: opapolicychecker config: networkPolicyConfig: ./config/opa-network-policies.yaml # Also add checkPolicy to the handler's steps list.
7. Create or Update your manifest file to point to the bundle
manifestVersion: "1.0" manifestType: "network-manifest" networkId: "nfo.com/production" publisher: role: "NFO" domain: "nfo.example.org" policies: type: "rego" source: "bundle" bundle: id: "network-policy-bundle" url: "https://github.com/nfo/policies/releases/download/v1/retail-bundle.tar.gz" policyQueryPath: "data.retail.policy.result" observability: enabled: true config: url: "https://nfo.example.org/observ/fields.yaml" signatureUrl: "https://nfo.example.org/observ/fields.yaml.sig" collector: url: "https://telemetry.nfo.example.org/v1/network/events" governance: effectiveFrom: "2026-03-10T00:00:00Z" effectiveUntil: "2027-03-10T00:00:00Z" signed: true signatureUrl: "https://nfo.example.org/network-runtime-manifest.sig"
8. Ensure the registry metadata for the network references the manifest file and the public key is published
Publishing signing public key
Login to DeDi.Global. In your namespace, you can create a public key registry to publish your public key. Click on the new registry button and select the Public Key schema.
When publishing the public key in DeDi for bundles signed with ES256, use:
keyType:ECDSAkeyFormat:base64publicKey: the Base64-encoded contents of the public key (excluding the-----BEGIN PUBLIC KEY-----and-----END PUBLIC KEY-----lines), copied into the corresponding field in DeDi
Once the record is published and it's status is live, you can go to the record to copy its lookup URL from the widget on the page.
Referencing the network manifest
Go to the NFO reference registry where the reference to NP registries are added in DeDi Global. Once you have located the registry click on the 3 dots on the card:
Click on update.
Ensure the following fields are present as metadata for the registry:
Field Name | Description |
|---|---|
manifestUrl | The URL pointing to the network's policy manifest file. |
signingPublicKeyLookupUrl | The lookup URL of the public key published in DeDi. |
manifestSignatureUrl | The URL pointing to the signature of the network manifest file. |
Referencing the policy using network ID in beckn ONIX: To resolve policies automatically from a verified network manifest set for a network in the OPA Policy Checker plugin, set type: manifest for the network entry in your networkPolicyConfig file, using the networkId as the key. Also configure the manifestLoader plugin in the same handler — the OPA plugin uses it to fetch and verify the manifest at startup:
# config/opa-network-policies.yaml networkPolicies: nfo.com/production: type: manifest
manifestLoader: id: manifestloader config: cacheTTL: 24h checkPolicy: id: opapolicychecker config: networkPolicyConfig: ./config/opa-network-policies.yaml
The policy source, query path, and signing details are all read from the manifest — no location, query, or verification block is needed in the config.
9. Updating Policies
There are two ways to update policies.
Option 1 — Publish a new version
Update the policy files
Build a new bundle
Update the manifest file
Option 2 — Update the bundle at the same URL
Policies can also be updated at the same static URL. It is recommended to update the release number in the network manifest when you do so.
Example:
https://github.com/nfo/policies/releases/download/latest/retail-bundle.tar.gz
When the bundle content changes:
the updated bundle will be fetched automatically
the updated policies will be applied
no restart is required
If using a mutable URL, ensure the path remains stable.
10. Best Practices
Always sign policy bundles or files
Prefer immutable artifact URLs
Use clear package naming
Version policies explicitly
Test all policies for the same networkId together before publishing