Package Registries webhooks

You can configure webhooks to be triggered in Package Registries when a package, image, chart, model, module, or file is created.

Webhooks are delivered to an HTTP POST endpoint of your choosing with a Content-Type: application/json header and a JSON encoded request body.

Add a webhook

To add a webhook for your package creation event:

  1. Select Package Registries in the global navigation > your registry to configure webhooks on.

  2. Select Settings tab > Notification Services page.

  3. Select the Add button on Webhook.

  4. Specifying your webhook's Description and Webhook URL.

  5. If you are using self-signed certificates for your webhooks, clear the Verify TLS Certificates checkbox.

  6. To allow the authenticity of your Package Registries webhook events to be verified, configure your webhook's Token value to be sent either as a plain text X-Buildkite-Token value or an encrypted X-Buildkite-Signature in the request header, bearing in mind that the latter provides the more secure verification method.

  7. In the Events section, ensure the package.created event has been selected.

  8. Select the Save Webhook Settings button to save these changes and add the webhook.

Package created

The webhook is triggered when a package is created by published through an ecosystem-native CLI or using the REST API.

Example payload:

{
  "event": "package.created",
  "package": {
    {
      "id": "0191e23a-4bc8-7683-bfa4-5f73bc9b7c44",
      "url": "https://api.buildkite.com/v2/packages/organizations/my_great_org/registries/my-registry/packages/0191e23a-4bc8-7683-bfa4-5f73bc9b7c44",
      "web_url": "https://buildkite.com/organizations/my_great_org/packages/registries/my-registry/packages/0191e23a-4bc8-7683-bfa4-5f73bc9b7c44",
      "name": "banana",
      "organization": {
        "id": "0190e784-eeb7-4ce4-9d2d-87f7aba85433",
        "slug": "my_great_org",
        "url": "https://api.buildkite.com/v2/organizations/my_great_org",
        "web_url": "https://buildkite.com/my_great_org"
      },
      "registry": {
        "id": "0191e238-e0a3-7b0b-bb34-beea0035a39d",
        "graphql_id": "UmVnaXN0cnktLS0wMTkxZTIzOC1lMGEzLTdiMGItYmIzNC1iZWVhMDAzNWEzOWQ=",
        "slug": "my-registry",
        "url": "https://api.buildkite.com/v2/packages/organizations/my_great_org/registries/my-registry",
        "web_url": "https://buildkite.com/organizations/my_great_org/packages/registries/my-registry"
      }
    }
  },
  "sender": {
    "id": "01989b9e-f7e2-4577-92e7-dcdf141598aa",
    "name": "Developer"
  }
}

HTTP headers

The following HTTP headers are present in every webhook request, which allow you to identify the event that took place, and to verify the authenticity of the request:

X-Buildkite-Event The type of event

Example: package.created

One of either the token or signature headers will be present in every webhook request. The token value and header setting can be found under Token in your Webhook Notification service.

Your selection in the Webhook Notification service will determine which is sent:

X-Buildkite-Token The webhook's token.

Example: 309c9c842g8565adecpd7469x6005989

X-Buildkite-Signature The signature created from your webhook payload, webhook token, and the SHA-256 hash function.

Example: timestamp=1619071700,signature=30222eb518dc3fb61ec9e64dd78d163f62cb134a6ldb768f1d40e0edbn6e43f0

Webhook token

By default, Buildkite will send a token with each webhook in the X-Buildkite-Token header.

The token value and header setting can be found under Token in your Webhook Notification service.

The token is passed in clear text.

Webhook signature

Buildkite can optionally send an HMAC signature in place of a webhook token.

The X-Buildkite-Signature header contains a timestamp and an HMAC signature. The timestamp is prefixed by timestamp= and the signature is prefixed by signature=.

Buildkite generates the signature using HMAC-SHA256; a hash-based message authentication code HMAC used with the SHA-256 hash function and a secret key. The webhook token value is used as the secret key. The timestamp is an integer representation of a UTC timestamp. The raw request body is the signed message.

The token value and header setting can be found under Token in your Webhook Notification service.

Verifying HMAC signatures

When using HMAC signatures, you'll want to verify that the signature is legitimate.

Using the token as the secret along with the timestamp from the webhook, compute the expected signature based on the raw request body. There should be a library available in the programming language you are using that can perform this operation.

Compare the code to the signature received in the webhook. If they do not match, your payload has been altered.

The below example in Ruby verifies the signature and timestamp using the OpenSSL gem's HMAC :

require 'openssl'

class BuildkiteWebhook
  def self.valid?(webhook_request_body, header, secret)
    timestamp, signature = get_timestamp_and_signatures(header)
    expected = OpenSSL::HMAC.hexdigest("sha256", secret, "#{timestamp}.#{webhook_request_body}")
    Rack::Utils.secure_compare(expected, signature)
  end

  def self.get_timestamp_and_signatures(header)
    parts = header.split(",").map { |kv| kv.split("=", 2).map(&:strip) }.to_h
    [parts["timestamp"], parts["signature"]]
  end
end

BuildkiteWebhook.valid?(
  request.body.read,
  request.headers["X-Buildkite-Signature"],
  ENV["BUILDKITE_WEBHOOK_SECRET"]
)

Defending against replay attacks

A replay attack is when an attacker intercepts a valid payload and its signature, then re-transmits them. One way to help mitigate such attacks is to send a timestamp with your payload and only accept them within a short window (for example, 5 minutes).

Buildkite sends a timestamp in the X-Buildkite-Signature header. The timestamp is part of the signed payload so that it is verified by the signature. An attacker will not be able to change the timestamp without invalidating the signature.

To help protect against a replay attack, upon receipt of a webhook:

  1. Verify the signature
  2. Check the timestamp against the current time

If the webhook's timestamp is within your chosen window of the current time, it can reasonably be assumed to be the original webhook.

Edit, disable, re-enable or delete a webhook

To do any of these actions a webhook:

  1. Select Package Registries in the global navigation > your registry with your configured webhooks.
  2. Select Settings tab > Notification Services to open its page.
  3. Select the webhook to open its page, and to:
    • Edit the webhook, alter the Description, Webhook URL, Verify TLS Certificates and Token fields as required (see Add a webhook for details), then select the Save Webhook Settings button.
    • Disable the webhook, select its Disable button and confirm the action. Disabled webhooks have a note at the top to indicate this state.
      • To re-enable the disabled webhook, select its Enable button.
    • Delete the webhook, select its Delete button and confirm the action. The webhook is removed from the Notification Services page.

Request logs

The last 20 webhook request and responses are saved, so you can debug and inspect your webhook. Each webhook's request logs are available on the bottom of their settings page.