Skip to main content

Triggering Jenkins using webhooks

In this guide, you will learn how to trigger your Jenkins Pipelines from Port, using Webhook Actions.

Illustration

The steps shown in the image above are as follows:

  1. An action is invoked in Port;

  2. Port signs the action payload using SHA-1 with the clientSecret value and puts it in the X-Port-Signature request header.

    info

    Verifying the webhook request using the request headers provides the following benefits:

    • Ensures that the request payload has not been tampered with
    • Ensures that the sender of the message is Port
    • Ensures that the received message is not a replay of an older message
  3. Port publishes an invoked WEBHOOK via a POST request to https://{JENKINS_URL}/generic-webhook-trigger/invoke

    An example flow would be:

    1. A developer asks to run a Jenkins pipeline;
    2. Port sends a POST request with the action payload to the Jenkins webhook URL;
    3. The Jenkins webhook receives the new action request;
    4. The Jenkins webhook triggers the pipeline;

Prerequisites

Jenkins required plugins:

Setting up the webhook

Enabling webhook trigger for a pipeline

To enable triggering a Jenkins pipeline using a webhook invocation, you will need to add "Generic Webhook Trigger" as a build trigger to your pipeline.

In your job's page, enter the Configuration tab, and scroll down to the Build Triggers section. Check the Generic Webhook Trigger box:

Enable generic webhook

By default, when enabling the webhook trigger for a job, it can be triggered by sending an event to http://JENKINS_URL/generic-webhook-trigger/invoke. This means that, if not configured otherwise, all jobs will be triggered when sending an event to this route. It is recommended to set up a job token to avoid running unwanted jobs.

Defining variables

After checking the box, look for the Post content parameters section. This is where you will define the variables which will be passed to your pipeline run.

  • The Variable field value should match the name of the variable that is defined in your job configuration and expected by the job run.
  • The Expression field should be set to JSONPath and be directed to the relevant property sent by the Port action.


tip

Here is part of the JSON scheme of the Port action, which shows the inputs sent by Port when triggering the action:

[
{
"identifier": "runPipeline",
"title": "Run Pipeline",
"icon": "Jenkins",
"userInputs": {
"properties": {
"input1": {
"type": "string"
}
}
}
... # Port Action configuration
]

Here is a sample payload that is generated when the action is triggered and sent to Jenkins:

{
... # Event metadata
"payload": {
"properties": {
"input1": "input1_value"
}

}

}

For example, the JSONPath for input1 would be:

$.payload.properties.input1

Port Action - The full Port action definition can be found here.

Token setup

The token parameter allows triggering a specific (or a group) of jobs.

To set up a token for you job, scroll down to the Token section, and provide a job token:

Configure Token

After saving, you will be able to specifically trigger this job job, using the following URL:

http://JENKINS_URL/generic-webhook-trigger/invoke?token=<JOB_TOKEN>
tip

For advanced configuration of your Jenkins webhook trigger, check out the Generic webhook trigger plugin page!

Setting up the Port action

To trigger the Jenkins pipeline, you will setup a Port Webhook Action.

Here is an example for an action that will trigger the webhook you just set up:

[
{
"identifier": "runPipeline",
"title": "Run Pipeline",
"icon": "Jenkins",
"userInputs": {
"properties": {
"input1": {
"type": "string"
}
}
},
"invocationMethod": {
"type": "WEBHOOK",
"url": "http://JENKINS_URL/generic-webhook-trigger/invoke?token=<JOB_TOKEN>"
},
"trigger": "CREATE",
"description": "Run Jenkins pipeline"
}
]

Securing your webhook

It is possible to add a protection layer to your exposed pipelines by configuring whitelisting.

Whitelisting gives you the following security options:

  • Limit the list of IP addresses that can send a request that triggers the pipeline;
  • Add validation for the webhook payload content to verify that it really originated from Port.

Here is an example of the required configuration:

Webhook Validation

note
  • The IP field should be set to 3.251.12.205, which is our hosted outbound WEBHOOK Gateway;
    • For more information about Port's outbound calls, check out Port's actions security page.
  • In the HMAC Secret field, choose a secret containing your port-client-secret.

If this secret doesn't already exist, create a secret text type secret using this guide. The value of the secret should be your Port Client Secret which can be found by following the guide here.

Report Jenkins action run status to Port

Once you have triggered your Jenkins pipeline successfully, it is essential to update the status of the run action in Port.

In order to update the action, you'll need to create the RUN_ID variable, and to set it to be fetched from the action payload:

RUN_ID variable

The code snippet below demonstrates how you can report the progress of your pipeline to Port:

Click here to see the code
import groovy.json.JsonSlurper

pipeline {
agent any

environment {
PORT_CLIENT_ID="YOUR_CLIENT_ID"
PORT_CLIENT_SECRET="YOUR_CLIENT_SECRET"
ACCESS_TOKEN = ""
}

stages {
stage('Get access token') {
steps {
script {
// Execute the curl command and capture the output
def result = sh(returnStdout: true, script: """
accessTokenPayload=\$(curl -X POST \
-H "Content-Type: application/json" \
-d '{"clientId": "${PORT_CLIENT_ID}", "clientSecret": "${PORT_CLIENT_SECRET}"}' \
-s "https://api.getport.io/v1/auth/access_token")
echo \$accessTokenPayload
""")

// Parse the JSON response using JsonSlurper
def jsonSlurper = new JsonSlurper()
def payloadJson = jsonSlurper.parseText(result.trim())

// Access the desired data from the payload
ACCESS_TOKEN = payloadJson.accessToken
}
}
}

stage('Send logs example') {
steps {
script {
def logs_report_response = sh(script: """
curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-d '{"message": "this is a log test message example"}' \
"https://api.getport.io/v1/actions/runs/$RUN_ID/logs"
""", returnStdout: true)

println(logs_report_response)
}
}
}

stage('Update status example') {
steps {
script {
def status_report_response = sh(script: """
curl -X PATCH \
-H "Content-Type: application/json" \
-H "Authorization: Bearer ${ACCESS_TOKEN}" \
-d '{"status":"SUCCESS", "message": {"run_status": "Jenkins CI/CD Run completed successfully!"}}' \
"https://api.getport.io/v1/actions/runs/${RUN_ID}"
""", returnStdout: true)

println(status_report_response)
}
}
}
}
}