Tekton’s GitHub webhook trigger doesn’t actually listen for pushes or PRs; it waits for a specific HTTP POST request from GitHub that describes a push or PR event.
Let’s see it in action. Imagine you have a GitHub repository. When you push a commit, GitHub’s webhook machinery kicks in. It bundles up details about that push—the commit SHA, the branch name, the files changed, who made the commit—into a JSON payload. This payload is then sent, via HTTP POST, to a pre-configured URL. This URL is usually an Ingress or a LoadBalancer pointing to your Tekton Triggers service.
Your Tekton TriggerTemplate and TriggerBinding are designed to receive this specific payload. The TriggerBinding is the crucial piece here; it’s configured to extract specific fields from the incoming JSON payload. For example, it might look for body.ref to get the Git ref (like refs/heads/main) and body.commits[0].id for the commit SHA.
These extracted values are then passed as parameters to your PipelineRun via the TriggerTemplate. So, when you push to GitHub, the flow is: GitHub Webhook -> Tekton Triggers Service -> TriggerBinding (extracts data) -> TriggerTemplate (uses data to create PipelineRun) -> PipelineRun (executes your Tekton Pipeline).
The core problem Tekton Triggers solves is decoupling your CI/CD execution from the event source. Instead of your CI system polling GitHub for changes (inefficient and slow), it passively waits for events. This event-driven model is far more scalable and responsive.
The EventListener is the Kubernetes custom resource that acts as the webhook server for Tekton. It defines the interceptors and the TriggerTemplate to be invoked. Interceptors are powerful; they can perform validations, mutations, or even transform the incoming payload before it reaches the TriggerBinding. A common interceptor is the GitHubInterceptor, which validates the incoming request’s signature using a shared secret, ensuring the request genuinely came from GitHub and not a malicious actor.
Here’s a simplified EventListener configuration:
apiVersion: tekton.dev/v1beta1
kind: EventListener
metadata:
name: github-listener
spec:
triggers:
- name: github-push-trigger
interceptors:
- github:
secretRef:
secretName: github-secret # Contains the GitHub webhook secret
eventTypes:
- "push"
# This is where the magic happens: linking the extracted data to a PipelineRun
template:
ref: github-push-template # Refers to a TriggerTemplate
params:
- name: git-repo-url
value: "$(body.repository.clone_url)"
- name: git-commit-sha
value: "$(body.commits[0].id)"
- name: git-ref
value: "$(body.ref)"
The TriggerTemplate then defines the PipelineRun that will be created:
apiVersion: tekton.dev/v1beta1
kind: TriggerTemplate
metadata:
name: github-push-template
spec:
params:
- name: git-repo-url
description: The Git repository URL
- name: git-commit-sha
description: The commit SHA to checkout
- name: git-ref
description: The Git ref to checkout
resourcetemplates:
- apiVersion: tekton.dev/v1beta1
kind: PipelineRun
metadata:
generateName: github-push-prerun- # A prefix for the PipelineRun name
spec:
pipelineRef:
name: my-pipeline # The name of your Tekton Pipeline
params:
- name: repo-url
value: "$(params.git-repo-url)"
- name: revision
value: "$(params.git-commit-sha)"
workspaces:
- name: source-workspace
persistentVolumeClaim:
claimName: shared-pvc # A PVC for the source code
The TriggerBinding is implicitly handled by the EventListener when you use $(body.some.field) directly in the template.params. If you needed more complex logic or wanted to bind to different event structures, you’d explicitly define a TriggerBinding resource and reference it in the EventListener.
Most people configure their GitHub webhook to send push events. However, the same mechanism works for pull_request events. You’d simply adjust the eventTypes in the EventListener’s GitHub interceptor to include "pull_request" and then modify your TriggerTemplate and TriggerBinding (or $(body.*) expressions) to extract data relevant to PRs, such as $(body.pull_request.html_url) or $(body.pull_request.head.sha).
The $(body.*) syntax is a powerful expression language used within Tekton Triggers. It allows you to dynamically inject data from the incoming webhook payload into your PipelineRun parameters. It’s not just limited to GitHub; this works for any webhook source that sends JSON payloads.
A common gotcha is that the secretRef in the EventListener’s GitHub interceptor needs to contain a token key holding your GitHub webhook secret. This secret is used to cryptographically verify that the incoming request actually originated from GitHub. If this verification fails, the EventListener will silently drop the request, leading you to believe your webhook isn’t firing.
When you’re setting up your GitHub webhook, ensure the "Content type" is set to application/json. If it’s application/x-www-form-urlencoded, the $(body.*) expressions won’t be able to parse the payload correctly.
The next challenge you’ll likely face is handling different event types (like issue_comment or release) or orchestrating multiple pipelines based on conditional logic within the webhook payload.