# Receivers

<!-- menuweight:30 -->

The `Receiver` API defines an incoming webhook receiver that triggers the
reconciliation for a group of Flux Custom Resources.

## Example

The following is an example of how to configure an incoming webhook for the
GitHub repository where Flux was bootstrapped with `flux bootstrap github`.
After a Git push, GitHub will send a push event to notification-controller,
which in turn tells Flux to pull and apply the latest changes from upstream.

**Note:** The following assumes an Ingress exposes the controller's
`webhook-receiver` Kubernetes Service. How to configure the Ingress is out of
scope for this example.

```yaml
---
apiVersion: notification.toolkit.fluxcd.io/v1
kind: Receiver
metadata:
  name: github-receiver
  namespace: flux-system
spec:
  type: github
  events:
    - "ping"
    - "push"
  secretRef:
    name: receiver-token
  resources:
    - apiVersion: source.toolkit.fluxcd.io/v1
      kind: GitRepository
      name: flux-system
```

In the above example:

- A Receiver named `github-receiver` is created, indicated by the
  `.metadata.name` field.
- The notification-controller generates a unique webhook path using the
  Receiver name, namespace and the token from the referenced
  `.spec.secretRef.name` secret.
- The incoming webhook path is reported in the `.status.webhookPath` field.
- When a GitHub push event is received, the controller verifies the payload's
  integrity and authenticity, using [HMAC][] and the `X-Hub-Signature` HTTP
  header.
- If the event type matches `.spec.events` and the payload is verified, then
  the controller triggers a reconciliation for the `flux-system` GitRepository
  which is listed under `.spec.resources`.

You can run this example by saving the manifest into `github-receiver.yaml`.

1. Generate a random string and create a Secret with a `token` field:

   ```sh
   TOKEN=$(head -c 12 /dev/urandom | shasum | cut -d ' ' -f1)

   kubectl -n flux-system create secret generic receiver-token \
     --from-literal=token=$TOKEN
   ```

2. Apply the resource on the cluster:

   ```sh
   kubectl -n flux-system apply -f github-receiver.yaml
   ```

3. Run `kubectl -n flux-system describe receiver github-receiver` to see its status:

   ```console
   ...
   Status:
     Conditions:
       Last Transition Time:  2022-11-16T23:43:38Z
       Message:               Receiver initialised for path: /hook/bed6d00b5555b1603e1f59b94d7fdbca58089cb5663633fb83f2815dc626d92b
       Observed Generation:   1
       Reason:                Succeeded
       Status:                True
       Type:                  Ready
     Observed Generation:     1
     Webhook Path:            /hook/bed6d00b5555b1603e1f59b94d7fdbca58089cb5663633fb83f2815dc626d92b
   Events:
     Type    Reason    Age   From                     Message
     ----    ------    ----  ----                     -------
     Normal  Succeeded 82s   notification-controller  Reconciliation finished, next run in 10m
   ```

4. Run `kubectl -n flux-system get receivers` to see the generated webhook path:

   ```console
   NAME              READY   STATUS                                                                        
   github-receiver   True    Receiver initialised for path: /hook/bed6d00b5555b1603e1f59b94d7fdbca58089cb5663633fb83f2815dc626d92b
   ```

5. On GitHub, navigate to your repository and click on the "Add webhook" button
   under "Settings/Webhooks". Fill the form with:

   - **Payload URL**: The composed address, consisting of the Ingress' hostname
     exposing the controller's `webhook-receiver` Kubernetes Service, and the
     generated path for the Receiver. For this example:
     `https://<hostname>/hook/bed6d00b5555b1603e1f59b94d7fdbca58089cb5663633fb83f2815dc626d92b`
   - **Secret**: The `token` string generated in step 1.

## Writing a Receiver spec

As with all other Kubernetes config, a Receiver needs `apiVersion`,
`kind`, and `metadata` fields. The name of a Receiver object must be a
valid <a href="https://kubernetes.io/docs/concepts/overview/working-with-objects/names#dns-subdomain-names" target="_blank" rel="noopener noreferrer">DNS subdomain name</a>.

A Receiver also needs a
<a href="https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#spec-and-status" target="_blank" rel="noopener noreferrer">`.spec` section</a>.

### Type

`.spec.type` is a required field that specifies how the controller should
handle the incoming webhook request.

#### Supported Receiver types

| Receiver                                   | Type           | Supports filtering using [Events](#events) |
|--------------------------------------------|----------------|--------------------------------------------|
| [Generic webhook](#generic)                | `generic`      | ❌                                          |
| [Generic webhook with HMAC](#generic-hmac) | `generic-hmac` | ❌                                          |
| [GitHub](#github)                          | `github`       | ✅                                          |
| [Gitea](#github)                           | `github`       | ✅                                          |
| [GitLab](#gitlab)                          | `gitlab`       | ✅                                          |
| [Bitbucket server](#bitbucket-server)      | `bitbucket`    | ✅                                          |
| [Harbor](#harbor)                          | `harbor`       | ❌                                          |
| [DockerHub](#dockerhub)                    | `dockerhub`    | ❌                                          |
| [Quay](#quay)                              | `quay`         | ❌                                          |
| [Nexus](#nexus)                            | `nexus`        | ❌                                          |
| [Azure Container Registry](#acr)           | `acr`          | ❌                                          |
| [Google Container Registry](#gcr)          | `gcr`          | ❌                                          |
| [CDEvents](#cdevents)                      | `cdevents`     | ✅                                          |

#### Generic

When a Receiver's `.spec.type` is set to `generic`, the controller will respond
to any HTTP request to the generated [`.status.webhookPath` path](#webhook-path),
and request a reconciliation for all listed [Resources](#resources).

**Note:** This type of Receiver does not perform any validation on the incoming
request, and it does not support filtering using [Events](#events).

##### Generic example

```yaml
---
apiVersion: notification.toolkit.fluxcd.io/v1
kind: Receiver
metadata:
  name: generic-receiver
  namespace: default
spec:
  type: generic
  secretRef:
    name: webhook-token
  resources:
    - apiVersion: source.toolkit.fluxcd.io/v1
      kind: GitRepository
      name: webapp
      namespace: default
```

#### Generic HMAC

When a Receiver's `.spec.type` is set to `generic-hmac`, the controller will
respond to any HTTP request to the generated [`.status.webhookPath` path](#webhook-path),
while verifying the request's payload integrity and authenticity using [HMAC][].

The controller uses the `X-Signature` header to get the hash signature. This
signature should be prefixed with the hash function (`sha1`, `sha256` or
`sha512`) used to generate the signature, in the following format:
`<hash-function>=<hash>`.

To validate the HMAC signature, the controller will use the `token` string
from the [Secret reference](#secret-reference) to generate a hash signature
using the same hash function as the one specified in the `X-Signature` header.

If the generated hash signature matches the one specified in the `X-Signature`
header, the controller will request a reconciliation for all listed
[Resources](#resources).

**Note:** This type of Receiver does not support filtering using
[Events](#events).

##### Generic HMAC example

```yaml
---
apiVersion: notification.toolkit.fluxcd.io/v1
kind: Receiver
metadata:
  name: generic-hmac-receiver
  namespace: default
spec:
  type: generic-hmac
  secretRef:
    name: webhook-token
  resources:
    - apiVersion: source.toolkit.fluxcd.io/v1
      kind: GitRepository
      name: webapp
      namespace: default
```

##### HMAC signature generation example

1. Generate the HMAC hash for the request body using OpenSSL:

   ```sh
   printf '<request-body>' | openssl dgst -sha1 -r -hmac "<token>" | awk '{print $1}'
   ```

   You can replace the `-sha1` flag with `-sha256` or `-sha512` to use a
   different hash function.

2. Send an HTTP POST request with the body and the HMAC hash to the webhook URL:

   ```sh
   curl <webhook-url> -X POST -H "X-Signature: <hash-function>=<generated-hash>" -d '<request-body>'
   ```

#### GitHub

When a Receiver's `.spec.type` is set to `github`, the controller will respond
to an <a href="https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads" target="_blank" rel="noopener noreferrer">HTTP webhook event payload</a>
from GitHub to the generated [`.status.webhookPath` path](#webhook-path),
while verifying the payload using [HMAC][].

The controller uses the <a href="https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#delivery-headers" target="_blank" rel="noopener noreferrer">`X-Hub-Signature` header</a>
from the request made by GitHub to get the hash signature. To enable the
inclusion of this header, the `token` string from the [Secret reference](#secret-reference)
must be configured as the <a href="https://docs.github.com/en/developers/webhooks-and-events/webhooks/securing-your-webhooks#setting-your-secret-token" target="_blank" rel="noopener noreferrer">secret token for the
webhook</a>.

The controller will calculate the HMAC hash signature for the received request
payload using the same `token` string, and compare it with the one specified in
the header. If the two signatures match, the controller will request a
reconciliation for all listed [Resources](#resources).

This type of Receiver offers the ability to filter incoming events by comparing
the `X-GitHub-Event` header to the list of [Events](#events).
For a list of available events, see the <a href="https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads" target="_blank" rel="noopener noreferrer">GitHub
documentation</a>.

##### GitHub example

```yaml
---
apiVersion: notification.toolkit.fluxcd.io/v1
kind: Receiver
metadata:
  name: github-receiver
  namespace: default
spec:
  type: github
  events:
    - "ping"
    - "push"
  secretRef:
    name: webhook-token
  resources:
    - apiVersion: source.toolkit.fluxcd.io/v1
      kind: GitRepository
      name: webapp
```

The above example makes use of the [`.spec.events` field](#events) to filter
incoming events from GitHub, instructing the controller to only respond to
<a href="https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#ping" target="_blank" rel="noopener noreferrer">`ping`</a>
and <a href="https://docs.github.com/en/developers/webhooks-and-events/webhooks/webhook-events-and-payloads#push" target="_blank" rel="noopener noreferrer">`push`</a>
events.

#### Gitea

For Gitea, the `.spec.type` field can be set to `github` as it produces [GitHub
type](#github) compatible <a href="https://docs.gitea.io/en-us/webhooks/" target="_blank" rel="noopener noreferrer">webhook event payloads</a>.

**Note:** While the payloads are compatible with the GitHub type, the number of
available events may be limited and/or different from the ones available in
GitHub. Refer to the <a href="https://github.com/go-gitea/gitea/blob/v1.19.4/modules/webhook/type.go#L10" target="_blank" rel="noopener noreferrer">Gitea source code</a>
to see the list of available [events](#events).

#### GitLab

When a Receiver's `.spec.type` is set to `gitlab`, the controller will respond
to an <a href="https://docs.gitlab.com/ee/user/project/integrations/webhooks.html#events" target="_blank" rel="noopener noreferrer">HTTP webhook event payload</a>
from GitLab to the generated [`.status.webhookPath` path](#webhook-path).

The controller validates the payload's authenticity by comparing the
<a href="https://docs.gitlab.com/ee/user/project/integrations/webhooks.html#validate-payloads-by-using-a-secret-token" target="_blank" rel="noopener noreferrer">`X-Gitlab-Token` header</a>
from the request made by GitLab to the `token` string from the [Secret
reference](#secret-reference). To enable the inclusion of this header, the
`token` string must be configured as the "Secret token" while <a href="https://docs.gitlab.com/ee/user/project/integrations/webhooks.html#configure-a-webhook-in-gitlab" target="_blank" rel="noopener noreferrer">configuring a
webhook in GitLab</a>.

If the two tokens match, the controller will request a reconciliation for all
listed [Resources](#resources).

This type of Receiver offers the ability to filter incoming events by comparing
the `X-Gitlab-Event` header to the list of [Events](#events). For a list of
available webhook types, refer to the <a href="https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html" target="_blank" rel="noopener noreferrer">GitLab
documentation</a>.

##### GitLab example

```yaml
---
apiVersion: notification.toolkit.fluxcd.io/v1
kind: Receiver
metadata:
  name: gitlab-receiver
  namespace: default
spec:
  type: gitlab
  events:
    - "Push Hook"
    - "Tag Push Hook"
  secretRef:
    name: webhook-token
  resources:
    - apiVersion: source.toolkit.fluxcd.io/v1
      kind: GitRepository
      name: webapp-frontend
    - apiVersion: source.toolkit.fluxcd.io/v1
      kind: GitRepository
      name: webapp-backend
```

The above example makes use of the [`.spec.events` field](#events) to filter
incoming events from GitLab, instructing the controller to only respond to
<a href="https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#push-events" target="_blank" rel="noopener noreferrer">`Push Hook`</a>
and <a href="https://docs.gitlab.com/ee/user/project/integrations/webhook_events.html#tag-events" target="_blank" rel="noopener noreferrer">`Tag Push Hook`</a>
events.

#### Bitbucket Server

When a Receiver's `.spec.type` is set to `bitbucket`, the controller will
respond to an <a href="https://confluence.atlassian.com/bitbucketserver/event-payload-938025882.html" target="_blank" rel="noopener noreferrer">HTTP webhook event payload</a>
from Bitbucket Server to the generated [`.status.webhookPath` path](#webhook-path),
while verifying the payload's integrity and authenticity using [HMAC][].

The controller uses the <a href="https://confluence.atlassian.com/bitbucketserver/manage-webhooks-938025878.html#Managewebhooks-webhooksecrets" target="_blank" rel="noopener noreferrer">`X-Hub-Signature` header</a>
from the request made by BitBucket Server to get the hash signature. To enable
the inclusion of this header, the `token` string from the [Secret
reference](#secret-reference) must be configured as the "Secret" while creating
a webhook in Bitbucket Server.

The controller will calculate the HMAC hash signature for the received request
payload using the same `token` string, and compare it with the one specified in
the header. If the two signatures match, the controller will request a
reconciliation for all listed [Resources](#resources).

This type of Receiver offers the ability to filter incoming events by comparing
the `X-Event-Key` header to the list of [Events](#events). For a list of
available event keys, refer to the <a href="https://confluence.atlassian.com/bitbucketserver/event-payload-938025882.html#Eventpayload-Repositoryevents" target="_blank" rel="noopener noreferrer">Bitbucket Server
documentation</a>.

**Note:** Bitbucket Cloud does not support signing webhook requests
(<a href="https://jira.atlassian.com/browse/BCLOUD-14683" target="_blank" rel="noopener noreferrer">BCLOUD-14683</a>,
<a href="https://jira.atlassian.com/browse/BCLOUD-12195" target="_blank" rel="noopener noreferrer">BCLOUD-12195</a>). If your
repositories are on Bitbucket Cloud, you will need to use a [Generic
Receiver](#generic) instead.

##### Bitbucket Server example

```yaml
---
apiVersion: notification.toolkit.fluxcd.io/v1
kind: Receiver
metadata:
  name: bitbucket-receiver
  namespace: default
spec:
  type: bitbucket
  events:
    - "repo:refs_changed"
  secretRef:
    name: webhook-token
  resources:
    - apiVersion: source.toolkit.fluxcd.io/v1
      kind: GitRepository
      name: webapp
```

The above example makes use of the [`.spec.events` field](#events) to filter
incoming events from Bitbucket Server, instructing the controller to only
respond to <a href="https://confluence.atlassian.com/bitbucketserver/event-payload-938025882.html#Eventpayload-Push" target="_blank" rel="noopener noreferrer">`repo:refs_changed` (Push)</a>
events.

#### Harbor

When a Receiver's `.spec.type` is set to `harbor`, the controller will respond
to an <a href="https://goharbor.io/docs/latest/working-with-projects/project-configuration/configure-webhooks/#payload-format" target="_blank" rel="noopener noreferrer">HTTP webhook event payload</a>
from Harbor to the generated [`.status.webhookPath` path](#webhook-path).

The controller validates the payload's authenticity by comparing the
`Authorization` header from the request made by Harbor to the `token` string
from the [Secret reference](#secret-reference). To enable the inclusion of this
header, the `token` string must be configured as the "Auth Header" while
<a href="https://goharbor.io/docs/latest/working-with-projects/project-configuration/configure-webhooks/#configure-webhooks" target="_blank" rel="noopener noreferrer">configuring a webhook in
Harbor</a>.

If the two tokens match, the controller will request a reconciliation for all
listed [Resources](#resources).

**Note:** This type of Receiver does not support filtering using
[Events](#events). However, Harbor does support configuring event types for
which a webhook will be triggered.

##### Harbor example

```yaml
---
apiVersion: notification.toolkit.fluxcd.io/v1
kind: Receiver
metadata:
  name: harbor-receiver
  namespace: default
spec:
  type: harbor
  secretRef:
    name: webhook-token
  resources:
    - apiVersion: image.toolkit.fluxcd.io/v1
      kind: ImageRepository
      name: webapp
```

#### DockerHub

When a Receiver's `.spec.type` is set to `dockerhub`, the controller will
respond to an <a href="https://docs.docker.com/docker-hub/webhooks/" target="_blank" rel="noopener noreferrer">HTTP webhook event payload</a>
from DockerHub to the generated [`.status.webhookPath` path](#webhook-path).

The controller performs minimal validation of the payload by attempting to
unmarshal the <a href="https://docs.docker.com/docker-hub/webhooks/#example-webhook-payload" target="_blank" rel="noopener noreferrer">JSON request body</a>.
If the unmarshalling is successful, the controller will request a reconciliation
for all listed [Resources](#resources).

**Note:** This type of Receiver does not support filtering using
[Events](#events).

##### DockerHub example

```yaml
---
apiVersion: notification.toolkit.fluxcd.io/v1
kind: Receiver
metadata:
  name: dockerhub-receiver
  namespace: default
spec:
  type: dockerhub
  secretRef:
    name: webhook-token
  resources:
    - apiVersion: image.toolkit.fluxcd.io/v1
      kind: ImageRepository
      name: webapp
```

#### Quay

When a Receiver's `.spec.type` is set to `quay`, the controller will respond to
an HTTP <a href="https://docs.quay.io/guides/notifications.html#repository-push" target="_blank" rel="noopener noreferrer">Repository Push Notification payload</a>
from Quay to the generated [`.status.webhookPath` path](#webhook-path).

The controller performs minimal validation of the payload by attempting to
unmarshal the JSON request body to the expected format. If the unmarshalling is
successful, the controller will request a reconciliation for all listed
[Resources](#resources).

**Note:** This type of Receiver does not support filtering using
[Events](#events). In addition, it does not support any "Repository
Notification" other than "Repository Push".

##### Quay example

```yaml
---
apiVersion: notification.toolkit.fluxcd.io/v1
kind: Receiver
metadata:
  name: quay-receiver
  namespace: default
spec:
  type: quay
  secretRef:
    name: webhook-token
  resources:
    - apiVersion: image.toolkit.fluxcd.io/v1
      kind: ImageRepository
      name: webapp
```

#### Nexus

When a Receiver's `.spec.type` is set to `nexus`, the controller will respond
to an <a href="https://help.sonatype.com/repomanager3/integrations/webhooks/example-headers-and-payloads" target="_blank" rel="noopener noreferrer">HTTP webhook event payload</a>
from Nexus Repository Manager 3 to the generated [`.status.webhookPath`
path](#webhook-path), while verifying the payload's integrity and
authenticity using [HMAC][].

The controller validates the payload by comparing the
<a href="https://help.sonatype.com/repomanager3/integrations/webhooks/working-with-hmac-payloads" target="_blank" rel="noopener noreferrer">`X-Nexus-Webhook-Signature` header</a>
from the request made by Nexus to the `token` string from the [Secret
reference](#secret-reference). To enable the inclusion of this header, the
`token` string must be configured as the "Secret Key" while <a href="https://help.sonatype.com/repomanager3/integrations/webhooks/enabling-a-repository-webhook-capability" target="_blank" rel="noopener noreferrer">enabling a
repository webhook capability</a>.

The controller will calculate the HMAC hash signature for the received request
payload using the same `token` string, and compare it with the one specified in
the header. If the two signatures match, the controller will attempt to
unmarshal the request body to the expected format. If the unmarshalling is
successful, the controller will request a reconciliation for all listed
[Resources](#resources).

**Note:** This type of Receiver does not support filtering using
[Events](#events).

##### Nexus example

```yaml
---
apiVersion: notification.toolkit.fluxcd.io/v1
kind: Receiver
metadata:
  name: nexus-receiver
  namespace: default
spec:
  type: nexus
  secretRef:
    name: webhook-token
  resources:
    - apiVersion: image.toolkit.fluxcd.io/v1
      kind: ImageRepository
      name: webapp
```

#### GCR

When a Receiver's `.spec.type` is set to `gcr`, the controller will respond to
an <a href="https://cloud.google.com/artifact-registry/docs/configure-notifications" target="_blank" rel="noopener noreferrer">HTTP webhook event payload</a>
from Google Container Registry (GCR) or Google Artifact Registry (GAR) to the
generated [`.status.webhookPath`](#webhook-path), while verifying the payload is
legitimate using <a href="https://cloud.google.com/pubsub/docs/authenticate-push-subscriptions" target="_blank" rel="noopener noreferrer">OIDC ID token validation</a>.

The controller authenticates the request by performing the following checks on
the OIDC ID token from the `Authorization` header:

1. **Signature verification**: The token signature is validated against Google's
   public keys.
2. **Audience verification**: The `aud` claim is verified against the expected
   audience (see below).
3. **Issuer verification**: The `iss` claim must be `accounts.google.com` or
   `https://accounts.google.com`.
4. **Email verification**: The `email` claim must match the service account
   email specified in the referenced Secret's `email` key, and `email_verified`
   must be `true`.

For this to work, <a href="https://cloud.google.com/pubsub/docs/push#configure_for_push_authentication" target="_blank" rel="noopener noreferrer">authentication must be enabled on the Pub/Sub push
subscription</a>,
with the OIDC service account set to the same service account specified in the
Secret's `email` key.

##### Secret format for GCR

The Secret referenced by `.spec.secretRef.name` must contain the following keys:

| Key          | Required | Description                                                                                                                                                    |
|--------------|----------|----------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `token`      | Yes      | Random string used to salt the generated [webhook path](#webhook-path).                                                                                        |
| `email`      | Yes      | The email of the IAM service account configured on the Pub/Sub push subscription for OIDC authentication.                                                      |
| `audience`   | Yes      | The expected `aud` claim in the OIDC token.                                                                                                                    |

Example:

```yaml
---
apiVersion: v1
kind: Secret
metadata:
  name: gcr-webhook-token
  namespace: default
type: Opaque
stringData:
  token: <random token>
  email: <service-account>@<project>.iam.gserviceaccount.com
  # The default audience set by GCP is the full push endpoint URL, but
  # you can also choose a custom audience and configure it on the Pub/Sub
  # subscription.
  audience: https://<hostname>/hook/<sha256(token+name+namespace)>
```

When the verification succeeds, the request payload is unmarshalled to the
expected format. If this is successful, the controller will request a
reconciliation for all listed [Resources](#resources).

**Note:** This type of Receiver does not support filtering using
[Events](#events).

##### GCR example

```yaml
---
apiVersion: notification.toolkit.fluxcd.io/v1
kind: Receiver
metadata:
  name: gcr-receiver
  namespace: default
spec:
  type: gcr
  secretRef:
    name: gcr-webhook-token
  resources:
    - apiVersion: image.toolkit.fluxcd.io/v1
      kind: ImageRepository
      name: webapp
      namespace: default
```

#### ACR

When a Receiver's `.spec.type` is set to `acr`, the controller will respond to
an <a href="https://learn.microsoft.com/en-us/azure/container-registry/container-registry-webhook-reference" target="_blank" rel="noopener noreferrer">HTTP webhook event payload</a>,
from Azure Container Registry to the generated [`.status.webhookPath`](#webhook-path).

The controller performs minimal validation of the payload by attempting to
unmarshal the JSON request body. If the unmarshalling is successful, the
controller will request a reconciliation for all listed [Resources](#resources).

**Note:** This type of Receiver does not support filtering using
[Events](#events). However, Azure Container Registry does <a href="https://learn.microsoft.com/en-us/azure/container-registry/container-registry-webhook#create-webhook---azure-portal" target="_blank" rel="noopener noreferrer">support configuring
webhooks to only send events for specific actions</a>.

##### ACR example

```yaml
---
apiVersion: notification.toolkit.fluxcd.io/v1
kind: Receiver
metadata:
  name: acr-receiver
  namespace: default
spec:
  type: acr
  secretRef:
    name: webhook-token
  resources:
    - kind: ImageRepository
      name: webapp
```

#### CDEvents

When a Receiver's `.spec.type` is set to `cdevents`, the controller will respond to
a <a href="https://cdevents.dev/docs/" target="_blank" rel="noopener noreferrer">CDEvent Event Payload</a>. It will verify the CDEvent
using the <a href="https://github.com/cdevents/sdk-go" target="_blank" rel="noopener noreferrer">CDEvent Go-SDK</a>. 

This type of receiver supports filtering using [Events](#events) by comparing the
`type` header to the list of events. 

##### CDEvents example

```yaml
---
apiVersion: notification.toolkit.fluxcd.io/v1
kind: Receiver
metadata:
  name: cdevents-receiver
  namespace: flux-system
spec:
  type: cdevents
  events:
    - "dev.cdevents.change.merged"
  secretRef:
    name: receiver-token
  resources:
    - kind: GitRepository 
      name: webapp
```

### Events

`.spec.events` is an optional field to specify a list of webhook payload event
types this Receiver should act on. If left empty, no filtering is applied and
any (valid) payload is handled.

**Note:** Support for this field, and the entries in it, is dependent on the
Receiver type. See the [supported Receiver types](#supported-receiver-types)
section for more information.

### Resources

`.spec.resources` is a required field to specify which Flux Custom Resources
should be reconciled when the Receiver's [webhook path](#webhook-path) is
called.

A resource entry contains the following fields:

- `apiVersion` (Optional): The Flux Custom Resource API group and version, such as
  `source.toolkit.fluxcd.io/v1`.
- `kind`: The Flux Custom Resource kind, e.g. `Bucket`,
  `GitRepository`, `OCIRepository` or `ImageRepository`.
- `name`: The Flux Custom Resource `.metadata.name` or `*` (if `matchLabels` is specified)
- `namespace` (Optional): The Flux Custom Resource `.metadata.namespace`.
  When not specified, the Receiver's `.metadata.namespace` is used instead.
- `matchLabels` (Optional): Annotate Flux Custom Resources with specific labels.
   The `name` field must be set to `*` when using `matchLabels`

#### Reconcile objects by name

To reconcile a single object, set the `kind`, `name` and `namespace`:

```yaml
resources:
  - apiVersion: image.toolkit.fluxcd.io/v1
    kind: ImageRepository
    name: podinfo
```

#### Reconcile objects by label

To reconcile objects of a particular kind with specific labels:

```yaml
resources:
  - apiVersion: image.toolkit.fluxcd.io/v1
    kind: ImageRepository
    name: "*"
    matchLabels:
      app: podinfo
```

**Note:** Cross-namespace references [can be disabled for security
reasons](#disabling-cross-namespace-selectors).

#### Filtering reconciled objects with CEL

To filter the resources that are reconciled you can use <a href="https://cel.dev/" target="_blank" rel="noopener noreferrer">Common Expression Language (CEL)</a>.

For example, to trigger `ImageRepositories` on notifications from <a href="https://cloud.google.com/artifact-registry/docs/configure-notifications#examples" target="_blank" rel="noopener noreferrer">Google Artifact Registry</a> you can define the following receiver:

```yaml
apiVersion: notification.toolkit.fluxcd.io/v1
kind: Receiver
metadata:
  name: gar-receiver
  namespace: apps
spec:
  type: gcr
  secretRef:
    name: flux-gar-token
  resources:
    - apiVersion: image.toolkit.fluxcd.io/v1
      kind: ImageRepository
      name: "*"
      matchLabels:
        registry: gar
```

This will trigger the reconciliation of all `ImageRepositories` with the label `registry: gar`.

But if you want to only notify `ImageRepository` resources that are referenced from the incoming hook you can use CEL to filter the resources.

```yaml
apiVersion: notification.toolkit.fluxcd.io/v1
kind: Receiver
metadata:
  name: gar-receiver
  namespace: apps
spec:
  type: gcr
  secretRef:
    name: flux-gar-token
  resources:
    - apiVersion: image.toolkit.fluxcd.io/v1
      kind: ImageRepository
      name: "*"
      matchLabels:
        registry: gar
  resourceFilter: 'req.tag.contains(res.metadata.name)'
```

If the body of the incoming hook looks like this:

```json
{
  "action":"INSERT",
  "digest":"us-east1-docker.pkg.dev/my-project/my-repo/hello-world@sha256:6ec128e26cd5...",
  "tag":"us-east1-docker.pkg.dev/my-project/my-repo/hello-world:1.1"
}
```

This simple example would match `ImageRepositories` containing the name `hello-world`.

If you want to do more complex processing:

```yaml
  resourceFilter: has(res.metadata.annotations) && req.tag.split('/').last().value().split(":").first().value() == res.metadata.annotations['update-image']
```

This would look for an annotation "update-image" on the resource, and match it to the `hello-world` part of the tag name.

**Note:** Currently the `resource` value in the CEL expression only provides the object metadata, this means you can access things like `res.metadata.labels`, `res.metadata.annotations` and `res.metadata.name`.

### Secret reference

`.spec.secretRef.name` is a required field to specify a name reference to a
Secret in the same namespace as the Receiver. The Secret must contain a `token`
key, whose value is a string containing a (random) secret token.

This token is used to salt the generated [webhook path](#webhook-path), and
depending on the Receiver [type](#supported-receiver-types), to verify the
authenticity of a request.

**Note:** Some receiver types require additional keys in the Secret. For
example, the [GCR](#gcr) type requires an `email` key and optionally an
`audience` key. Refer to the documentation for the specific receiver type for
details.

Example:

```yaml
---
apiVersion: v1
kind: Secret
metadata:
  name: webhook-token
  namespace: default
type: Opaque
stringData:
  token: <random token>
```

To trigger a reconciliation of the Receiver when changes occur in
the referenced Secret, you can set the following label on the
Secret:

```yaml
metadata:
  labels:
    reconcile.fluxcd.io/watch: Enabled
```

An alternative to labeling every Secret is setting the
`--watch-configs-label-selector=owner!=helm` flag in
notification-controller, which allows watching all
Secrets except for Helm storage Secrets.

### Interval

`.spec.interval` is an optional field with a default of ten minutes that specifies
the time interval at which the controller reconciles the provider with its Secret
reference.

### Suspend

`.spec.suspend` is an optional field to suspend the Receiver.
When set to `true`, the controller will stop processing events for this Receiver.
When the field is set to `false` or removed, it will resume.

## Working with Receivers

### Disabling cross-namespace selectors

On multi-tenant clusters, platform admins can disable cross-namespace
references with the `--no-cross-namespace-refs=true` flag. When this flag is
set, Receivers can only refer to [Resources](#resources) in the same namespace
as the Receiver object, preventing tenants from triggering
reconciliations to another tenant's resources.

### Public Ingress considerations

Considerations should be made when exposing the controller's `webhook-receiver`
Kubernetes Service to the public internet. Each request to a Receiver [webhook
path](#webhook-path) will result in request to the Kubernetes API, as the
controller needs to fetch information about the resource. This endpoint may be
protected with a token, but this does not defend against a situation where a
legitimate webhook caller starts sending large amounts of requests, or the
token is somehow leaked. This may result in the controller, as it may get rate
limited by the Kubernetes API, degrading its functionality.

It is therefore a good idea to set rate limits on the Ingress which exposes
the Kubernetes Service. If you are using ingress-nginx, this can be done by
<a href="https://kubernetes.github.io/ingress-nginx/user-guide/nginx-configuration/annotations/#rate-limiting" target="_blank" rel="noopener noreferrer">adding annotations</a>.

### Triggering a reconcile

To manually tell the notification-controller to reconcile a Receiver outside
of the [specified interval window](#interval), a Receiver can be annotated with
`reconcile.fluxcd.io/requestedAt: <arbitrary value>`. Annotating the resource
queues the Receiver for reconciliation if the `<arbitrary-value>` differs from
the last value the controller acted on, as reported in
[`.status.lastHandledReconcileAt`](#last-handled-reconcile-at).

Using `kubectl`:

```sh
kubectl annotate --field-manager=flux-client-side-apply --overwrite  receiver/<receiver-name> reconcile.fluxcd.io/requestedAt="$(date +%s)"
```

Using `flux`:

```sh
flux reconcile source receiver <receiver-name>
```

### Waiting for `Ready`

When a change is applied, it is possible to wait for the Receiver to reach a
[ready state](#ready-receiver) using `kubectl`:

```sh
kubectl wait receiver/<receiver-name> --for=condition=ready --timeout=1m
```

### Suspending and resuming

When you find yourself in a situation where you temporarily want to pause the
reconciliation of a Receiver and the handling of requests, you can suspend it
using the [`.spec.suspend` field](#suspend).

#### Suspend a Receiver

In your YAML declaration:

```yaml
---
apiVersion: notification.toolkit.fluxcd.io/v1
kind: Receiver
metadata:
  name: <receiver-name>
spec:
  suspend: true
```

Using `kubectl`:

```sh
kubectl patch receiver <receiver-name> --field-manager=flux-client-side-apply -p '{\"spec\": {\"suspend\" : true }}'
```

Using `flux`:

```sh
flux suspend receiver <receiver-name>
```

#### Resume a Receiver

In your YAML declaration, comment out (or remove) the field:

```yaml
---
apiVersion: notification.toolkit.fluxcd.io/v1
kind: Receiver
metadata:
  name: <receiver-name>
spec:
  # suspend: true
```

**Note:** Setting the field value to `false` has the same effect as removing
it, but does not allow for "hot patching" using e.g. `kubectl` while practicing
GitOps; as the manually applied patch would be overwritten by the declared
state in Git.

Using `kubectl`:

```sh
kubectl patch receiver <receiver-name> --field-manager=flux-client-side-apply -p '{\"spec\" : {\"suspend\" : false }}'
```

Using `flux`:

```sh
flux resume receiver <receiver-name>
```

### Debugging a Receiver

There are several ways to gather information about a Receiver for debugging
purposes.

#### Describe the Receiver

Describing a Receiver using `kubectl describe receiver <receiver-name>` displays
the latest recorded information for the resource in the Status and Events
sections:

```console
...
Status:
...
Status:
  Conditions:
    Last Transition Time:  2022-11-21T12:41:48Z
    Message:               Reconciliation in progress
    Observed Generation:   1
    Reason:                ProgressingWithRetry
    Status:                True
    Type:                  Reconciling
    Last Transition Time:  2022-11-21T12:41:48Z
    Message:               unable to read token from secret 'default/webhook-token' error: Secret "webhook-token" not found
    Observed Generation:   1
    Reason:                TokenNotFound
    Status:                False
    Type:                  Ready
  Observed Generation:     -1
Events:
  Type     Reason  Age               From                     Message
  ----     ------  ----              ----                     -------
  Warning  Failed  5s (x4 over 16s)  notification-controller  unable to read token from secret 'default/webhook-token' error: Secret "webhook-token" not found
```

#### Trace emitted Events

To view events for specific Receiver(s), `kubectl events` can be used in
combination with `--for` to list the Events for specific objects.
For example, running

```sh
kubectl events --for=Receiver/<receiver-name>
```

lists

```console
LAST SEEN   TYPE      REASON   OBJECT                     MESSAGE
3m44s       Warning   Failed   receiver/<receiver-name>   unable to read token from secret 'default/webhook-token' error: Secret "webhook-token" not found
```

## Receiver Status

### Conditions

A Receiver enters various states during its lifecycle, reflected as
[Kubernetes Conditions][typical-status-properties].
It can be [ready](#ready-receiver), or it can [fail during
reconciliation](#failed-receiver).

The Receiver API is compatible with the [kstatus specification][kstatus-spec],
and reports the `Reconciling` condition where applicable.

#### Ready Receiver

The notification-controller marks a Receiver as _ready_ when it has the following
characteristics:

- The Receiver's Secret referenced in `.spec.secretRef.name` is found on the cluster.
- The Receiver's Secret contains a `token` key.

When the Receiver is "ready", the controller sets a Condition with the following
attributes in the Alert's `.status.conditions`:

- `type: Ready`
- `status: "True"`
- `reason: Succeeded`

#### Failed Receiver

The notification-controller may get stuck trying to reconcile a Receiver if its
secret token can not be found.

When this happens, the controller sets the `Ready` Condition status to `False`,
and adds a Condition with the following attributes:

- `type: Reconciling`
- `status: "True"`
- `reason: ProgressingWithRetry`

### Observed Generation

The notification-controller reports an
[observed generation][typical-status-properties]
in the Receiver's `.status.observedGeneration`. The observed generation is the
latest `.metadata.generation` which resulted in a [ready state](#ready-receiver).

### Last Handled Reconcile At

The notification-controller reports the last `reconcile.fluxcd.io/requestedAt`
annotation value it acted on in the `.status.lastHandledReconcileAt` field.

### Webhook Path

When a Receiver becomes [ready](#ready-receiver), the controller reports the
generated incoming webhook path under `.status.webhookPath`. The path format is
`/hook/sha256sum(token+name+namespace)`.

[typical-status-properties]: https://github.com/kubernetes/community/blob/master/contributors/devel/sig-architecture/api-conventions.md#typical-status-properties
[kstatus-spec]: https://github.com/kubernetes-sigs/cli-utils/tree/master/pkg/kstatus
[HMAC]: https://en.wikipedia.org/wiki/HMAC