Documentation home

Build & integrate

Policy-as-Code (GitHub)

Sync ruleset JSON from Git on push; webhook URL, secrets, public vs private repos.

Policy-as-Code (GitHub sync)

Teams can keep policy rulesets in Git and sync them into AgentNexusAPI on push—aligned with infrastructure-as-code workflows. The evaluate API still uses the policy name configured in the product; Git only updates ruleset_json (and therefore policy_versions via the existing DB trigger).

What ships today

  • One GitHub link per policy (policy_git_links), managed by workspace admins on the policy edit page.
  • Inbound webhook (signed with a per-link secret): POST /api/webhooks/github/policy-git/[linkId]
  • Manual “Sync now” pulls the file from the configured branch using the GitHub Contents API.
  • Public repos work without a token (rate limits apply). Private repos need a GitHub token (fine-grained PAT with Contents read) stored on the link.

GitLab / self-hosted Git is not wired in this iteration; the same pattern (webhook + fetch) can be added later.

Setup (operators)

  1. Apply migration 20260331310000_policy_git_links.sql (e.g. supabase db push).
  2. Ensure NEXT_PUBLIC_APP_URL is the canonical HTTPS origin users and GitHub call (used to show the webhook URL in the dashboard).
  3. As a workspace admin, open Dashboard → Policies → [policy] → Policy-as-Code (GitHub).
  4. Enter owner, repo, branch, and path to the JSON ruleset file (same schema as manual JSON in the editor).
  5. Click Create Git link. Copy the webhook secret (shown once).
  6. In GitHub: Settings → Webhooks → Add webhook
    • Payload URL: value shown in the dashboard (ends with /api/webhooks/github/policy-git/{linkId}).
    • Content type: application/json
    • Secret: paste the webhook secret from step 5.
    • Events: “Just the push event” (plus GitHub will send ping on create — we respond OK).
  7. Optional: add GitHub token on the link for private repositories or higher rate limits.
  8. Use Sync now to test before the first push, or push a commit that touches the ruleset path.

Behavior

  • Push handling: We verify X-Hub-Signature-256, require refs/heads/{branch}, and ignore pushes that do not list your ruleset path in the commit file lists when GitHub sends a non-empty commits array.
  • Ruleset validation: Fetched JSON must pass the same safeParsePolicyRuleset checks as the dashboard editor. Failures are stored in last_error; the webhook returns 200 so GitHub does not infinite-retry on bad config (check the dashboard).
  • Version history: Each successful update to policies.ruleset_json appends a row to policy_versions (existing trigger).
  • Name vs file: The policy name in AgentNexusAPI is not read from the repo path. Rename policies in the dashboard if needed; keep policy_name in API calls aligned with that name.

Security notes

  • The webhook URL contains an opaque link id; without a valid HMAC signature, delivery is rejected (401).
  • PATs are sensitive — rotate in GitHub if exposed. Prefer fine-grained tokens scoped to the single repo.
  • Do not commit the webhook secret or PAT into your ruleset repo.

Code map

  • UI: app/dashboard/policies/PolicyGitPanel.tsx, app/dashboard/policies/[id]/page.tsx
  • Actions: app/dashboard/policies/policyGitActions.ts
  • Webhook: app/api/webhooks/github/policy-git/[linkId]/route.ts
  • Sync logic: lib/policy/githubPolicySync.ts