> ## Documentation Index
> Fetch the complete documentation index at: https://docs.backline.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Jenkins Integration

> Connect Jenkins so Backline can verify CI results on its remediation pull requests

## Overview

Backline connects to Jenkins **read-only** to find out whether its own remediation pull requests actually build. When Backline opens a fix PR, it locates the matching Jenkins build, reads the result, and — if the build failed — reads the failing stage's log so it can correct the fix and push an update.

Backline never starts, changes, or cancels a build, and never writes anything back to Jenkins.

<Note>
  Jenkins is a **verification** integration, not a scanner. It does not create findings. Its job is to decide whether Backline can honestly say a remediation PR passed your CI.
</Note>

## What You Can Do

With the Jenkins integration, Backline can:

* Read build results for its remediation pull requests
* Identify which stage failed, by name
* Read the failing stage's log and use it to push a corrected fix
* Connect several Jenkins servers, each with its own credentials
* Hold back a "CI verified" claim when a build result could not be read

## Prerequisites

Before connecting Jenkins, ensure you have:

* A Jenkins controller reachable either from Backline's cloud or from a Backline on-prem agent
* A dedicated Jenkins user with **Overall/Read** and **Job/Read** permissions
* An **API token** for that user

<Warning>
  Backline requires an API token, not an account password. Jenkins API tokens can be revoked individually and survive password changes, which makes them safe to hand to an integration.
</Warning>

## Network Requirements

Backline reaches Jenkins over one of two paths, and detects which one applies **automatically** when you connect:

| Path | How it works | What you need to do |
| - | - | - |
| **Cloud** | Backline connects to your Jenkins controller directly from its cloud | Allow-list Backline's egress to your Jenkins host |
| **On-prem agent** | The Backline agent already running inside your network connects to Jenkins on Backline's behalf | Nothing, if the agent is deployed and can reach the host |

Backline tries the cloud path first. If the server is unreachable that way, it retries through your on-prem agent and stores whichever path worked.

<Note>
  The on-prem agent needs **outbound** HTTPS only — to `app.backline.ai` and to your Jenkins host. No inbound firewall rules are required.
</Note>

If you already deployed the Backline agent for Bitbucket Data Center, the same agent serves Jenkins — but it must be recent enough to include Jenkins support. See [Upgrading the On-Prem Agent](#upgrading-the-on-prem-agent).

If your cluster reaches the internet through a corporate proxy, list your internal Jenkins host under `proxy.noProxy` in your Backline values so the agent reaches it **directly**. If your Jenkins certificate is signed by an internal or corporate CA, provide that CA to the agent. Both are configured exactly as described on the [Bitbucket Data Center page](/integrations/bitbucket-data-center).

## Creating a Read-Only Jenkins User

<Steps>
  <Step title="Create a dedicated user">
    In Jenkins, go to **Manage Jenkins → Users** and create a user for Backline (for example, `backline-reader`). Use a dedicated account rather than a shared or personal one, so its access can be reviewed and revoked on its own.
  </Step>

  <Step title="Grant read-only permissions">
    Under **Manage Jenkins → Security**, grant the user **Overall/Read** and **Job/Read**. These two are sufficient — Backline needs nothing else.

    <Note>
      Per-user permissions require an authorization strategy that supports them, such as **Matrix Authorization Strategy**. Granting the two Read permissions globally is enough; Backline only reads the jobs that build your repositories.
    </Note>
  </Step>

  <Step title="Generate an API token">
    Log in as that user, open **Configure** from the user menu, and under **API Token** click **Add new Token**. Copy the token — Jenkins shows it only once.
  </Step>
</Steps>

## Connecting Jenkins

<Steps>
  <Step title="Navigate to Integrations">
    In Backline, go to the Integration Hub from the main menu.
  </Step>

  <Step title="Select Jenkins">
    Open the **CI/CD** category and click **Connect** on the **Jenkins** card.
  </Step>

  <Step title="Enter Connection Details">
    Fill in the connection form:

    * **Server URL** — The base URL of your Jenkins controller (e.g., `https://jenkins.example.com:8443`). Include the context path if Jenkins runs under one.
    * **Username** — The read-only Jenkins user
    * **API Token** — The API token generated for that user
  </Step>

  <Step title="Connect">
    Click **Connect**. Backline tests the connection before saving it: it verifies the server answers, that the credentials are accepted, and that the user can read jobs. It also records which path reached the server — cloud or on-prem agent. If the check fails, the connection is not saved and you get a message explaining which of those three things went wrong.
  </Step>
</Steps>

## Connecting Multiple Servers

Jenkins supports more than one connection per Backline tenant, because credentials are per server: each Jenkins controller has its own user, its own API token, and possibly its own security configuration. Add one connection per server, repeating the steps above.

Backline normalizes server URLs before storing them, so the same controller cannot be added twice under different spellings — a trailing slash, a differently-cased host, or an explicit `:443` all resolve to the same server and the second attempt is rejected.

<Note>
  If you run a large fleet of Jenkins controllers, contact [support@backline.ai](mailto:support@backline.ai) before onboarding them — we will help you plan the rollout and how builds get matched to repositories.
</Note>

## After Connection

Once connected, Backline includes Jenkins in the CI check on every remediation pull request it opens. It waits for a build to finish, reads the result, and reports it alongside the pull request's own status checks. A failing build feeds Backline's analysis so it can push a corrected fix; a build Backline could not read is reported as such rather than assumed green.

## Managing the Integration

### Testing Connections

To verify that a connection is still valid:

1. Click **Configure** on the Jenkins integration card
2. Open the connection you want to check
3. Select **Test Connection**

Test runs the same probe as the original connect. It is safe to run at any time: it never disables, changes, or removes the connection, and it never changes the stored reachability path — a failing test only tells you something is wrong.

### Upgrading the On-Prem Agent

Jenkins support on the agent path requires a recent agent. If Backline reports that your agent needs an upgrade, update your Backline release:

```bash theme={null}
helm repo update
helm upgrade backline backline/backline \
  --namespace backline \
  --reuse-values
```

Then retry **Test Connection**.

## Known Limitations

* **Read-only** — Backline never triggers, retries, or cancels builds. It reads results and logs only.
* **Two-hour wait window** — Backline waits up to two hours for a build to finish, polling every 30 seconds. A build that has not finished within that window is reported as unverified rather than failed.
* **Unread results are reported, never assumed** — if Backline cannot read a Jenkins result (the server became unreachable, the build was deleted, the job never ran, the credentials stopped working), the pull request is marked **incomplete**. Backline does not claim CI verification it could not perform, and does not treat an unread result as a failure to fix either.
* **Logs must reach the Jenkins console** — Backline reads the console log of the failing stage. If a stage's real output lives somewhere else entirely — for example a build step that runs in an external container platform and writes to that platform's logs — Backline can see that the stage failed but cannot read why, and will classify the failure as not code-related.
* **One connection per server** — the same controller cannot be connected twice, even under a different URL spelling.

## Troubleshooting

<AccordionGroup>
  <Accordion title="Backline could not reach this Jenkins server from the cloud">
    Backline reached the network but got no usable answer from your controller on the cloud path.

    * Confirm the **Server URL** is correct, including scheme, port, and context path
    * Confirm the controller is running and answers on that URL
    * Allow-list Backline's egress to the Jenkins host, **or** deploy the Backline on-prem agent so the agent path can be used instead
  </Accordion>

  <Accordion title="Backline could not reach it from the cloud, and no on-prem agent responded">
    The cloud path failed and no Backline agent in your network answered.

    * If you intended to use the cloud path, allow-list Backline's egress to your Jenkins host
    * If you intended to use the agent path, verify the agent is installed and running:
      ```bash theme={null}
      kubectl get pods -n backline -l app=gitproxy
      ```
    * Confirm the agent has outbound access to `app.backline.ai`
  </Accordion>

  <Accordion title="Backline could not reach it from the cloud, and the agent could not reach it either">
    Both paths reached their destination but the Jenkins host itself did not answer.

    * Confirm the **Server URL** resolves and answers from inside your network
    * If your cluster uses an outbound proxy, add the Jenkins host to `proxy.noProxy` — otherwise the agent's request to an internal server is sent to the egress proxy and fails
    * If the controller uses an internal or corporate CA, provide that CA to the agent
    * Check the agent logs:
      ```bash theme={null}
      kubectl logs -n backline -l app=gitproxy --tail=200
      ```
  </Accordion>

  <Accordion title="Jenkins rejected those credentials">
    The server was reached, but it refused the username and API token.

    * Confirm the username matches the user the token belongs to
    * Regenerate the API token and re-enter it — tokens can be revoked in Jenkins
    * Confirm you used an **API token**, not the account password
  </Accordion>

  <Accordion title="The Jenkins user lacks Overall/Read or Job/Read">
    The credentials were accepted, but the user cannot read jobs.

    * Grant the user **Overall/Read** and **Job/Read**
    * Per-user permissions need an authorization strategy that supports them, such as Matrix Authorization Strategy
  </Accordion>

  <Accordion title="Your Backline on-prem agent needs an upgrade to support Jenkins">
    Your agent predates Jenkins support. Upgrade it as shown in [Upgrading the On-Prem Agent](#upgrading-the-on-prem-agent), then retry **Test Connection**.
  </Accordion>

  <Accordion title="An integration with that server URL already exists">
    That controller is already connected. Backline normalizes URLs, so a trailing slash or a differently-cased host still counts as the same server. Open the existing connection to edit its credentials instead of adding a second one.
  </Accordion>

  <Accordion title="Connected, but pull requests are reported as incomplete">
    Backline is reaching Jenkins but cannot read a result for the pull request.

    * Confirm the job that builds pull requests is enabled and actually ran for the Backline PR
    * Confirm the build finished within the two-hour window
    * Confirm the build still exists — a deleted build cannot be read
    * Confirm the read-only user can see that specific job
  </Accordion>
</AccordionGroup>

For additional help, contact [support@backline.ai](mailto:support@backline.ai).
