Skip to content

Webhooks

Patchwire accepts push events from four SCM providers. A scan fires within ~1 second of the push and finishes in under a minute for typical repositories.

URL pattern

ProviderURL
Forgejohttps://api.patchwire.app/v1/hooks/forgejo
GitHubhttps://api.patchwire.app/v1/hooks/github
GitLabhttps://api.patchwire.app/v1/hooks/gitlab
Bitbucket Cloudhttps://api.patchwire.app/v1/hooks/bitbucket

All four endpoints reject requests whose HMAC signature does not verify against your installation's PATCHWIRE_WEBHOOK_SECRET.

Getting your secret

Open any project's page → Webhook setup card. Each provider tab shows:

  • The full URL to paste
  • The shared secret to paste
  • The exact header / event filter to set

Copy directly from there. The secret rotates on the server side only; the UI always shows the current value.

Per-provider setup

Forgejo

  1. Repo → SettingsWebhooksAdd webhook → choose Forgejo.
  2. URL: https://api.patchwire.app/v1/hooks/forgejo.
  3. HTTP method: POST.
  4. Content type: application/json.
  5. Secret: paste from the setup card.
  6. Trigger: select Push events (the default).
  7. Branch filter: leave blank to fire on every branch, or set to your default branch.
  8. Save. Click Test delivery — you should see a green checkmark and an HTTP 200.

GitHub

  1. Repo → SettingsWebhooksAdd webhook.
  2. Payload URL: https://api.patchwire.app/v1/hooks/github.
  3. Content type: application/json.
  4. Secret: paste from the setup card.
  5. SSL verification: leave enabled (your endpoint uses Let's Encrypt).
  6. Which events? Select Just the push event.
  7. Active: ✅. Save.
  8. Open the new webhook → Recent DeliveriesRedeliver to test.

GitLab

  1. Project → SettingsWebhooksAdd new webhook.
  2. URL: https://api.patchwire.app/v1/hooks/gitlab.
  3. Secret token: paste from the setup card. Note: GitLab sends this in the X-Gitlab-Token header verbatim, not as an HMAC; Patchwire compares it against the configured secret in constant time.
  4. Trigger: enable Push events.
  5. Save.
  6. Click TestPush events.

Bitbucket Cloud

  1. Repository → Repository settingsWebhooksAdd webhook.
  2. Title: anything (e.g. "Patchwire").
  3. URL: https://api.patchwire.app/v1/hooks/bitbucket.
  4. Status: Active.
  5. Triggers: Repository push.
  6. Save. Bitbucket does not have a built-in test button — push a commit to trigger.

Bitbucket Cloud signature

Bitbucket Cloud's webhook signing differs from GitHub/Forgejo's. Patchwire verifies the X-Hub-Signature-256 header only if Bitbucket sends it — older payloads fall back to checking the request's source IP range. For high-trust setups, prefer the GitHub/GitLab/Forgejo paths.

How the org and project are resolved

The webhook body carries the repository's full_name (e.g. acme/web). Patchwire splits on / to get:

  • owner → resolved as the organisation slug
  • name → resolved as the project slug

So if your Patchwire org is acme and you register a project with slug web, the webhook for acme/web lands correctly.

If either resolution fails, the webhook returns HTTP 200 with "status":"ignored" — this is deliberate. Returning a 4xx would make the SCM retry indefinitely.

Watching a webhook fire

API logs (via SSH):

bash
ssh hostinger "sudo kubectl logs -n patchwire deploy/patchwire-api --tail=50 | grep -E 'cloning|scan complete|scan-bg'"

You'll see:

INFO cloning repo url=… branch=main target=/tmp/.tmpXXX
INFO running semgrep path=/tmp/.tmpXXX
INFO running gitleaks path=/tmp/.tmpXXX
INFO scan-bg: scan complete scan_id=… status=completed findings=2 raw_findings=3

Total time: clone (~10s) + semgrep (~30s) + gitleaks (~10s) + DB writes (~few seconds) ≈ 50–60s end-to-end.

Released under a proprietary licence.