> Markdown version of https://docs.laavat.io/isg/integration/jenkins/ from the LAAVAT PKI and Signing Platform documentation. All pages: https://docs.laavat.io/llms.txt

# Jenkins Integration

## Jenkins integration

This integration guide has instructions for Jenkins integration with LAAVAT PKI and Signing Platform.

In order to use Jenkins, a cloud-native Service Principal needs to be added to Azure AD as a registered application.
By registering an application, the client ID and client secret are obtained, and they are used to retrieve an access token for the LAAVAT PKI and Signing Platform.

Since the LAAVAT PKI and Signing Platform uses AD group information to grant access for specific operation(e.g., digest signing), a Azure native group needs to be created. This cloud native Service Principal is added to that group.
The Azure group ids need to be present in the LAAVAT PKI and Signing Platform.

### Integration environment

These integration instructions are tested with the following Jenkins and Jenkins plugin versions

1. Jenkins version 2.222.3
2. Jenkins Plugins:
    1. HTTP Request Plugin 1.8.26
    2. Pipeline Utility Steps 2.5.0

### Common settings to enable communication to LAAVAT PKI and Signing Platform

#### Service Principal clientid and client secret

Credentials need to be added to the Jenkins credential store before you can access LAAVAT PKI and Signing Platform on the Jenkins pipeline.
The credentials in Jenkins case are Azure AD `Application (client) ID` and `client secret`.

1. Open credentials view
2. Click add credentials
  [image: Add Credentials](https://docs.laavat.io/isg/images/addcredentialsarrow.png)
3. Select Username password
  [image: Select Username password](https://docs.laavat.io/isg/images/selectusernamepassword.png)
4. Type the clientid
5. Type the client secret
6. Fill in an ID for this credential
7. Optional: Add a description of this credential
  [image: Filled username password](https://docs.laavat.io/isg/images/credentialsinformationfilled.png)

### Jenkins pipeline examples

#### Jenkins pipeline to send digest signing

This is an example setup to show how to do digest signing.

This is an example setup to show how to submit digests for signing to the LAAVAT PKI and Signing Platform from Jenkins pipeline.

1. Parameters required for the pipeline
  [image: Params 1](https://docs.laavat.io/isg/images/parameters_1.png)
  [image: Params 2](https://docs.laavat.io/isg/images/parameters_2.png)
  [image: Params 3](https://docs.laavat.io/isg/images/parameters_3.png)
  [image: Params 4](https://docs.laavat.io/isg/images/parameters_4.png)
  [image: Params 5](https://docs.laavat.io/isg/images/parameters_5.png)
  [image: Params 6](https://docs.laavat.io/isg/images/parameters_6.png)
  [image: Params 7](https://docs.laavat.io/isg/images/parameters_7.png)
  [image: Params 8](https://docs.laavat.io/isg/images/parameters_8.png)
  [image: Params 9](https://docs.laavat.io/isg/images/parameters_9.png)
  [image: Params 10](https://docs.laavat.io/isg/images/parameters_10.png)
  [image: Params 11](https://docs.laavat.io/isg/images/parameters_11.png)
  [image: Params 12](https://docs.laavat.io/isg/images/parameters_12.png)
  [image: Params 13](https://docs.laavat.io/isg/images/parameters_13.png)
  [image: Params 14](https://docs.laavat.io/isg/images/parameters_14.png)
  [image: Params 15](https://docs.laavat.io/isg/images/parameters_15.png)
  [image: Params 16](https://docs.laavat.io/isg/images/parameters_16.png)
  [image: Params 17](https://docs.laavat.io/isg/images/parameters_17.png)
  [image: Params 18](https://docs.laavat.io/isg/images/parameters_18.png)
2. The shell script is below as an example in text format.

The `signing-tool` client is published on PyPI, so a CI job installs it with `pip install signing-tool` — no repository
checkout or `setup.py` step is needed. The example below also shows the automation-oriented features of the client:

- **Token via stdin (`-t @-`).** The access token is piped into the client instead of being placed on the command line,
  so it never appears in the process list or the build log. A token file (`-t @/path`) works the same way.
- **`--json` for machine-readable output.** The request ID is parsed from JSON with `jq` (JSON keys are `snake_case`).
- **Exit codes.** The client returns `0` on success and non-zero on failure (`1` general error, `2` usage error, `3`
  not ready — `--wait` timed out with the request still pending, `4` the request is `Rejected` or `Failed`, `130`
  interrupted), so `set -e` fails the build automatically on any error.
- **`--wait` with a completed download.** `imagesigning get --wait` blocks until the request finishes and then writes the
  output, so the job doesn't need a poll loop.

```bash
#!/bin/bash
set -euo pipefail

# 1. Install the published client into a clean virtualenv
python3 -m venv venv
source venv/bin/activate
pip install --upgrade pip
pip install signing-tool

# 2. Obtain an access token (client-credentials flow) into a variable
TOKEN=$(curl --silent --location --request GET \
  "https://login.microsoftonline.com/${addirectorytenantid}/oauth2/v2.0/token" \
  --form 'grant_type=client_credentials' \
  --form "client_secret=${SECRET}" \
  --form "client_id=${CLIENTID}" \
  --form "scope=${resourceAPI}/.default" | jq -r '.access_token')

# 3. Submit the digest for signing. The token is piped in via -t @- (stdin),
#    so it is never on the command line. --json makes the output parseable.
# RSA-PSS: add --padding PSS; raw ECDSA r||s: add --encoding RAW (for JWS or COSE, use imagesigning envelope)
REQUEST_ID=$(printf '%s' "$TOKEN" | signing-tool --json -c -t @- -a "${DevBaseURL}" \
  imagesigning add "${operationType}" \
  -P "${productid}" --operid "${operid}" \
  -p "${payload}" -H "${hashalgorithm}" | jq -r '.id')

# 4. Wait for completion and download the signed digest in one step.
printf '%s' "$TOKEN" | signing-tool -c -t @- -a "${DevBaseURL}" \
  imagesigning get -I "${REQUEST_ID}" --wait -O signeddig.test
```

> **Note**
> `--wait` uses a socket-timeout grace period rather than a hard overall bound; for a strict ceiling combine it with
> `--wait-timeout`. To also verify the digest you submitted matches what was signed, pass `--expect-input` on the
> `get` step. See [Reference Client › Usage](https://docs.laavat.io/democlient/usage/) for the full automation surface (exit codes,
> `--json` keys, the two digests, and proxy/CA settings).
