> For the complete documentation index, see [llms.txt](https://docs.nfh.global/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.nfh.global/build/creating-a-network/network-policies/rego-policies.md).

# Creating and publishing Rego policy artifacts

This guide explains how Network Facilitating Organizations (NFOs) can author policies in Rego, package them as OPA bundles, or a single rego file, publish…

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](/build/creating-a-network/network-policies/signing-files.md).

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](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.policy.result
```

In case of a single file:

```
opa eval \
-d policy.rego \
-i input.json \
--format=raw \
data.retail.policy.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.

{% hint style="info" icon="lightbulb" %}
**Testing directly without setting up network manifest**: You can directly test the policy by configuring the [OPA Policy Checker plugin](https://github.com/beckn/beckn-onix/tree/main/pkg/plugin/implementation/opapolicychecker) 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`:

```yaml
# 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.

```yaml
checkPolicy:
  id: opapolicychecker
  config:
    networkPolicyConfig: ./config/opa-network-policies.yaml

# Also add checkPolicy to the handler's steps list.
```

{% endhint %}

### 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](https://publish.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. |

{% hint style="info" icon="lightbulb" %}
**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](https://github.com/beckn/beckn-onix/tree/main/pkg/plugin/implementation/opapolicychecker), 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:

```yaml
# config/opa-network-policies.yaml
networkPolicies:
  nfo.com/production:
    type: manifest
```

```yaml
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.
{% endhint %}

### 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


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.nfh.global/build/creating-a-network/network-policies/rego-policies.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
