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)
- Apply migration
20260331310000_policy_git_links.sql(e.g.supabase db push). - Ensure
NEXT_PUBLIC_APP_URLis the canonical HTTPS origin users and GitHub call (used to show the webhook URL in the dashboard). - As a workspace admin, open Dashboard → Policies → [policy] → Policy-as-Code (GitHub).
- Enter owner, repo, branch, and path to the JSON ruleset file (same schema as manual JSON in the editor).
- Click Create Git link. Copy the webhook secret (shown once).
- 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
pingon create — we respond OK).
- Payload URL: value shown in the dashboard (ends with
- Optional: add GitHub token on the link for private repositories or higher rate limits.
- 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, requirerefs/heads/{branch}, and ignore pushes that do not list your ruleset path in the commit file lists when GitHub sends a non-emptycommitsarray. - Ruleset validation: Fetched JSON must pass the same
safeParsePolicyRulesetchecks as the dashboard editor. Failures are stored inlast_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_jsonappends a row topolicy_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_namein 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