> For the complete documentation index, see [llms.txt](https://docs.gomboc.ai/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.gomboc.ai/policy-management/policy-sets/policy-sets-backup-and-version-control-via-api.md).

# Policy Sets: Backup & Version Control via API

Gomboc's Policy Sets can be fully managed through the **Rules Service API**, giving you programmatic access to export, back up, and restore your policy configuration. This is useful for:

* **Disaster recovery** — quickly restore your configuration after accidental changes.
* **Environment promotion** — copy policy sets from a staging org to production.
* **Audit trails** — track every change to your policy configuration in Git history.
* **GitOps workflows** — store the desired state of your policy sets in a repository and reconcile it on a schedule.

***

### Prerequisites

#### Personal Access Token (PAT)

All Rules Service API calls require a Bearer token. Generate one from the Gomboc Portal:

1. Open the account dropdown (top-right corner) → **Settings**.
2. Select **Personal Access Tokens**.
3. Click **Generate Token**, give it a name and an expiry, then click **Create**.
4. Copy the token somewhere safe — it is shown only once.

Set it as an environment variable for the examples below:

```bash
export GOMBOC_TOKEN="<your-personal-access-token>"
```

The scripts on this page also require [`jq`](https://stedolan.github.io/jq/) and `curl`.

#### API Base URL

All Rules Service endpoints are served at:

```
https://rules.app.gomboc.ai
```

***

### Concepts

In the Gomboc Portal, a **Policy Set** is shown under **Policy Management → Policy Sets**.

Internally — and through the API — each policy set is a **Channel**: a named, saved search over the policy library that determines which rules are applied to your workspaces.

A channel has the following fields:

| Field         | Type              | Description                                               |
| ------------- | ----------------- | --------------------------------------------------------- |
| `name`        | string            | Unique identifier (also used as the human-readable label) |
| `query`       | string (optional) | ORL search query that selects rules                       |
| `filters`     | array of strings  | Additional filter expressions                             |
| `annotations` | object (optional) | Arbitrary key/value metadata tags                         |

***

### Exporting Policy Sets (Backup)

Use `GET /api/v1/channels/search` to retrieve all policy sets defined in your account. The endpoint supports pagination — iterate over pages until you have collected every record.

#### Shell export script

```bash
#!/usr/bin/env bash
# export-policy-sets.sh — exports all policy sets to policy-sets-<date>.json
set -euo pipefail

BASE_URL="https://rules.app.gomboc.ai"
PER_PAGE=1
USE_DATE=1

usage() {
  cat <<EOF
Usage: $(basename "$0") [--no-date]

Exports all policy sets to policy-sets-YYYY-MM-DD.json by default.
Use --no-date to write policy-sets.json instead.
EOF
}

while [ $# -gt 0 ]; do
  case "$1" in
    --no-date)
      USE_DATE=0
      shift
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "Error: unknown option: $1" >&2
      usage >&2
      exit 1
      ;;
  esac
done

if [ "$USE_DATE" -eq 1 ]; then
  OUTPUT="policy-sets-$(date +%Y-%m-%d).json"
else
  OUTPUT="policy-sets.json"
fi

if [ -z "${GOMBOC_TOKEN:-}" ]; then
  echo "Error: GOMBOC_TOKEN is not set" >&2
  exit 1
fi

decode_jwt_payload() {
  local token="$1"
  local payload padded rem

  payload=$(printf '%s' "$token" | cut -d. -f2)
  if [ -z "$payload" ]; then
    return 1
  fi

  padded="$payload"
  rem=$((${#padded} % 4))
  case "$rem" in
    2) padded="${padded}==" ;;
    3) padded="${padded}=" ;;
  esac

  printf '%s' "$padded" | tr '_-' '/+' | base64 -d 2>/dev/null
}

ACCOUNT_ID=$(decode_jwt_payload "$GOMBOC_TOKEN" | jq -er '.tenantId // .accountId // empty' 2>/dev/null || true)
if [ -z "$ACCOUNT_ID" ]; then
  echo "Error: could not extract accountId from GOMBOC_TOKEN" >&2
  exit 1
fi

page=1
echo "[]" > "$OUTPUT"

while :; do
  resp=$(curl -sS "${BASE_URL}/api/v1/channels/search?page=${page}&perPage=${PER_PAGE}" \
    -H "Authorization: Bearer ${GOMBOC_TOKEN}")

  if [ "$(jq -r '.status' <<<"$resp")" != "success" ]; then
    echo "Error: $resp" >&2
    exit 1
  fi

  jq -s --arg accountId "$ACCOUNT_ID" \
    '.[0] + (.[1].data.channels | map(select(.accountId == $accountId)))' \
    "$OUTPUT" <(echo "$resp") > "${OUTPUT}.tmp"
  mv "${OUTPUT}.tmp" "$OUTPUT"

  count=$(jq -r '.data.channels | length' <<<"$resp")
  [ "$count" -lt "$PER_PAGE" ] && break
  page=$((page + 1))
done

echo "Exported $(jq 'length' "$OUTPUT") policy sets for account $ACCOUNT_ID to $OUTPUT"
```

#### Example output (`policy-sets.json`)

```json
[
  {
    "id": "a1b2c3d4-...",
    "accountId": "f0e1d2c3-...",
    "name": "default",
    "query": "",
    "filters": ["provider:aws", "risk:high"],
    "annotations": { "env": "production" },
    "createdAt": "2025-01-10T14:23:00.000Z",
    "updatedAt": "2025-04-03T09:01:00.000Z"
  },
  {
    "id": "e5f6a7b8-...",
    "accountId": "f0e1d2c3-...",
    "name": "cis-aws-hardening",
    "query": "classification:cis-aws",
    "filters": [],
    "annotations": { "framework": "CIS", "env": "all" },
    "createdAt": "2025-02-18T11:00:00.000Z",
    "updatedAt": "2025-05-01T16:30:00.000Z"
  }
]
```

***

### Restoring Policy Sets

Use `POST /api/v1/channels/batch/upsert` to restore from a backup file. This endpoint **creates or updates** up to 200 channels in a single request.

> **Note:** Only `name`, `query`, `filters`, and `annotations` are writable. The `id`, `accountId`, `createdAt`, and `updatedAt` fields are read-only and are stripped automatically by the script below.

#### Shell restore script

```bash
#!/usr/bin/env bash
# restore-policy-sets.sh — restores policy sets from a backup file
set -euo pipefail

BASE_URL="https://rules.app.gomboc.ai"
INPUT="${1:-policy-sets.json}"

payload=$(jq '{channels: [.[] | {name, query, filters, annotations}]}' "$INPUT")

curl -sS -X POST "${BASE_URL}/api/v1/channels/batch/upsert" \
  -H "Authorization: Bearer ${GOMBOC_TOKEN}" \
  -H "Content-Type: application/json" \
  -d "$payload" | jq .
```

If the backup file contains more than 200 policy sets, split it into chunks of 200 and call the script once per chunk.

***

### Version Control with Git

Combine the export script with a Git repository to maintain a full history of every change to your policy configuration.

#### Recommended repository layout

```
policy-config/
├── policy-sets.json      ← exported channels (policy sets)
├── export.sh             ← export script
├── restore.sh            ← restore script
└── .github/
    └── workflows/
        └── backup.yml    ← automated daily backup
```

#### GitHub Actions: automated daily backup

```yaml
name: Backup Gomboc Policy Sets

on:
  schedule:
    - cron: "0 3 * * *"   # every day at 03:00 UTC
  workflow_dispatch:

permissions:
  contents: write

jobs:
  backup:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Install jq
        run: sudo apt-get update && sudo apt-get install -y jq

      - name: Export policy sets
        env:
          GOMBOC_TOKEN: ${{ secrets.GOMBOC_TOKEN }}
        run: bash export.sh

      - name: Commit if changed
        run: |
          git config user.name  "github-actions[bot]"
          git config user.email "github-actions[bot]@users.noreply.github.com"
          git add policy-sets.json
          if git diff --cached --quiet; then
            echo "No changes — policy sets are up to date."
          else
            git commit -m "chore: update policy sets backup $(date -u +%Y-%m-%d)"
            git push
          fi
```

Add `GOMBOC_TOKEN` as a repository secret in your GitHub repository settings.

***

### Restoring to a Different Environment

You can use the same backup file to copy policy sets across Gomboc organizations (e.g., from staging to production):

```bash
export GOMBOC_TOKEN="<production-org-token>"
bash restore.sh policy-sets.json
```

***

### API Quick Reference

All endpoints are on `https://rules.app.gomboc.ai`. Authentication: `Authorization: Bearer <PAT>`.

| Operation                  | Method   | Path                            | Key parameters                            |
| -------------------------- | -------- | ------------------------------- | ----------------------------------------- |
| List all policy sets       | `GET`    | `/api/v1/channels/search`       | `page`, `perPage`, `query`                |
| Get one policy set         | `GET`    | `/api/v1/channels/get`          | `name` (query param)                      |
| Create a policy set        | `POST`   | `/api/v1/channels/create`       | `name`, `query`, `filters`, `annotations` |
| Update a policy set        | `PUT`    | `/api/v1/channels/update`       | `name`, `query`, `filters`, `annotations` |
| Batch create               | `POST`   | `/api/v1/channels/batch/create` | array of channels, `onConflict`           |
| Batch upsert (restore)     | `POST`   | `/api/v1/channels/batch/upsert` | array of channels                         |
| Delete a policy set        | `DELETE` | `/api/v1/channels/delete`       | `name` (query param)                      |
| List rules in a policy set | `GET`    | `/api/v1/channels/rules`        | `name`, `page`, `perPage`                 |

For the full OpenAPI specification, see the Rule Service API reference.

***

### FAQ

**Will restoring a policy set overwrite the existing one?** Yes. `batch/upsert` updates existing channels matched by `name` and creates any that do not exist yet. To add new channels without touching existing ones, use `batch/create` with `"onConflict": "skip"` instead.

**Do I need to back up the rules themselves?** Built-in Gomboc rules are managed by Gomboc and do not need to be backed up. If you have published custom ORL rules, those can be exported separately using the `/api/v1/rules/search` endpoint — see the Rule Service API documentation.

**What happens to workspaces if I delete and re-create a policy set?** Workspace assignments are stored separately. Deleting and re-creating a policy set with the same `name` may require you to re-assign it to workspaces in the Portal. Use `batch/upsert` (update-in-place) to avoid this.


---

# 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 dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.gomboc.ai/policy-management/policy-sets/policy-sets-backup-and-version-control-via-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
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.
