Skip to content
NFH Fabric Support home
NFH Fabric Support home

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: ECDSA

  • keyFormat: base64

  • publicKey: 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

  1. Update the policy files

  2. Build a new bundle

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