Webhooks¶
Polling, the Tranche 1 default, has a median latency of about 30 seconds. For sub-second propagation — useful when your fleet operates under tight change-control windows — Ampora exposes an inbound webhook endpoint per Git source.
When webhooks help¶
- Median sync latency of well under 1 second.
- Avoids the
PollIntervalSecondsrace when a fast follow-up commit changes a file before the previous sweep has finished. - Keeps the cache cold path identical — webhook fires "go check the tip", the sweeper does the work.
When webhooks do NOT help¶
- The Git host cannot reach Ampora over HTTPS (air-gapped, NATted, privately exposed). Polling is the right answer.
- You have very few configurations; the polling latency is fine.
Endpoint shape¶
POST https://AMPORA_HOST/api/git/webhook/{sourceId}
Content-Type: application/json
X-Ampora-Webhook-Token: <per-source-secret>
{ /* upstream payload — currently the body is opaque to Ampora */ }
The body is opaque to Ampora today — we do not parse the upstream payload. The webhook is a "go check the tip" signal; the sweeper does the actual work. This means:
- Any Git host that fires any webhook works (GitLab, GitHub, Gitea, Bitbucket, self-hosted Gitolite, …).
- Replay-safe: hitting the endpoint many times is idempotent.
- Tamper-safe: even a faked payload cannot mislead the sweeper — the truth is the Git tree.
The X-Ampora-Webhook-Token header is the per-source secret. Generate it on GitOps → {source} → Webhook → Generate token, copy once, configure the upstream Git host with it.
Configuring on the Git host side¶
GitLab¶
Project → Settings → Webhooks:
- URL:
https://AMPORA_HOST/api/git/webhook/{sourceId} - Custom HTTP header:
X-Ampora-Webhook-Token: <token> - Trigger: Push events on the tracked branch only.
GitHub¶
Repository → Settings → Webhooks → Add webhook:
- Payload URL:
https://AMPORA_HOST/api/git/webhook/{sourceId} - Content type:
application/json - Secret: leave empty (the token goes in a custom header which GitHub does not natively support — use a Webhook Trigger via GitHub Actions if you need to inject the header).
Bitbucket¶
Repository → Repository settings → Webhooks:
- URL:
https://AMPORA_HOST/api/git/webhook/{sourceId}with the token appended as a query string is acceptable.
Verification¶
After configuring, push a trivial commit. GitOps → {source} → Sync runs should show a run within a second, attributed to webhook rather than poll.
If nothing happens:
- the inbound HTTPS endpoint is not reachable from the Git host (firewalls, no public DNS),
- the token mismatches — the audit log records every 401,
- the source is paused.
Falling back to polling¶
Even with webhooks configured, the polling timer still runs at the configured interval (default 60 s) as a backstop. A missed webhook delivery is masked by the next poll.
Rate limits¶
Ampora does not rate-limit webhooks — every request kicks the same underlying sweep, which deduplicates internally on the tip SHA. Spamming the endpoint a thousand times produces at most one sweep.
Security¶
- The token is hashed at rest, constant-time compared on every request.
- Endpoint requires HTTPS in production (
OpAmp:BootstrapPlaintextAllowed=falseand friends do not affect the webhook path; production rejects HTTP unconditionally). - Per-source token rotation: Webhook → Rotate token invalidates the old token immediately. Update upstream Git host config before rotating to avoid a delivery gap.