Skip to content

Customer publish-event trigger

This page is auto-generated from src/triggers/webhook.ts. Do not edit by hand — see docs/dev/docs-auto-sync.md.

Inbound webhook customers point at their private registry to trigger scans.

MethodPath
POST/api/v1/triggers/scan

Mechanism: HMAC-SHA256 (per-tenant Upwarden secret)

Transport: X-Vanguard-Signature header (sha256=<hex>)

Per-org HMAC-SHA256 of the raw request body, signed with the tenant’s webhook_secret and encoded as sha256=<hex>. Same shape as GitHub’s signature scheme; constant-time hex comparison. The tenant is resolved by the orgSlug field in the body (with slug-history fallback) — the (slug, signature) pair is the auth.

No explicit dedup gate at the receiver. The downstream action is naturally idempotent (e.g. unbind on an already-unbound row is a no-op).

Retry posture is governed by the upstream’s webhook delivery contract. Upwarden responds 2xx on accepted deliveries (including known-no-op events) so the upstream stops retrying; transient failures return 5xx so the upstream re-delivers within its retry budget.

FieldTypeOptional
orgSlugstringno
ecosystemstringno
packageNamestringno
versionstringno
sourcestringno
sourceRefstringyes
artifactUrlstringyes
  • npm
  • pypi
  • crates
  • rubygems
  • nuget
  • maven
  • go
  • customer-webhook
  • github-release
  • manual

The leading doc-comment block from the source file, reproduced verbatim. This is the canonical narrative explanation of the receiver — the auto-generated sections above are derived from it.

#149 trigger-on-publish — case 1 (customer-triggered) ingestion endpoint.
A customer who publishes a new (package, version) to their own private
registry — Artifactory, Nexus, GCP Artifact Registry — points a webhook
at this endpoint. We record the event in the `triggers` table so a
downstream consumer (SIEM export, notification fan-out, scan dispatch)
can react before the first customer install resolves the new version.
Auth model: per-org HMAC-SHA256 of the raw body, using the tenant's
`webhook_secret`. Header: `X-Vanguard-Signature: sha256=<hex>`. Same
shape as the GHSA webhook in src/blocklist/webhook.ts and as GitHub's
own webhook signature.
First-slice scope: record + audit. Scan dispatch off the trigger row
is the natural follow-up — same `dispatchQuarantineScans` shape the
existing quarantine path uses; deferred so the auth + recording surface
can land independently.
Tenant resolution: the body carries `orgSlug` and the signature proves
the sender holds that org's secret. So we don't need a `host`-based
resolver here — the (slug, secret) pair is the auth.