How to Route Jenkins Builds Through Chainsaw
Configure a Jenkins declarative pipeline to install packages through Chainsaw using a Username-with-password credential and job-local package-manager configuration.
Overview
Jenkins agents are typically long-lived with persistent workspaces, so it is
especially important to generate package-manager configuration inside each stage,
pull credentials from Jenkins Credentials with withCredentials, and clear local
caches on the first Chainsaw run. This page is the Jenkins-specific slice of How
to Integrate Chainsaw with CI/CD Pipelines; see that guide for GitHub
Actions and GitLab CI and for the cross-cutting cache-invalidation and policy
guidance.
Prerequisites
- A running Chainsaw instance reachable from your Jenkins agents
- A Chainsaw client credential with Client Type set to Service Token
- Repository scope set to only the ecosystems the pipeline needs
- The service token stored in Jenkins Credentials as a Username with password
credential named
chainsaw-service-token(Client ID as username, Client Secret as password)
node_modules, ~/.m2/repository, or ~/.gradle/caches populated will reuse
those packages without ever calling Chainsaw. Clear them on the first Chainsaw run
(the snippets below do this), and rotate the workspace if you are unsure.Declarative Pipeline
Each stage wraps its work in withCredentials so the Client ID and Secret are
injected as CHAINSAW_CLIENT_ID / CHAINSAW_CLIENT_SECRET only for that step.
pipeline {
agent any
stages {
stage('npm install') {
steps {
withCredentials([usernamePassword(credentialsId: 'chainsaw-service-token',
usernameVariable: 'CHAINSAW_CLIENT_ID', passwordVariable: 'CHAINSAW_CLIENT_SECRET')]) {
sh '''
rm -rf node_modules package-lock.json
CHAINSAW_NPM_AUTH="$(printf '%s' "$CHAINSAW_CLIENT_ID:$CHAINSAW_CLIENT_SECRET" | base64)"
cat > .npmrc <<EOF
registry=https://chain305.com/chainproxy/repository/@default/npmjs/
//chain305.com/chainproxy/repository/@default/npmjs/:_auth=${CHAINSAW_NPM_AUTH}
//chain305.com/chainproxy/repository/@default/npmjs/:always-auth=true
EOF
npm ci
'''
}
}
}
stage('maven build') {
steps {
withCredentials([usernamePassword(credentialsId: 'chainsaw-service-token',
usernameVariable: 'CHAINSAW_CLIENT_ID', passwordVariable: 'CHAINSAW_CLIENT_SECRET')]) {
sh '''
rm -rf ~/.m2/repository
mkdir -p ~/.m2
cat > ~/.m2/settings.xml <<'XML'
<settings>
<mirrors>
<mirror>
<id>chainsaw</id>
<url>https://chain305.com/chainproxy/repository/@default/maven-central/</url>
<mirrorOf>*</mirrorOf>
</mirror>
</mirrors>
<servers>
<server>
<id>chainsaw</id>
<username>${env.CHAINSAW_CLIENT_ID}</username>
<password>${env.CHAINSAW_CLIENT_SECRET}</password>
</server>
</servers>
</settings>
XML
mvn -B verify
'''
}
}
}
stage('docker pull') {
steps {
withCredentials([usernamePassword(credentialsId: 'chainsaw-service-token',
usernameVariable: 'CHAINSAW_CLIENT_ID', passwordVariable: 'CHAINSAW_CLIENT_SECRET')]) {
sh '''
echo "$CHAINSAW_CLIENT_SECRET" | docker login chain305.com --username "$CHAINSAW_CLIENT_ID" --password-stdin
docker pull chain305.com/library/alpine:3.21
'''
}
}
}
stage('gradle build') {
steps {
withCredentials([usernamePassword(credentialsId: 'chainsaw-service-token',
usernameVariable: 'CHAINSAW_CLIENT_ID', passwordVariable: 'CHAINSAW_CLIENT_SECRET')]) {
sh '''
rm -rf ~/.gradle/caches
mkdir -p ~/.gradle
cat > ~/.gradle/init.gradle <<'GRADLE'
allprojects {
repositories {
clear()
maven {
url "https://chain305.com/chainproxy/repository/@default/gradle-central/"
credentials {
username = System.getenv("CHAINSAW_CLIENT_ID")
password = System.getenv("CHAINSAW_CLIENT_SECRET")
}
}
maven {
url "https://chain305.com/chainproxy/repository/@default/google-maven/"
credentials {
username = System.getenv("CHAINSAW_CLIENT_ID")
password = System.getenv("CHAINSAW_CLIENT_SECRET")
}
}
}
}
GRADLE
./gradlew build
'''
}
}
}
}
}
A policy block returns HTTP 403, the install command exits non-zero, the stage fails, and the build is marked failed — the dependency never lands. Gate downstream promotion or deploy stages on this build’s success.
Verify Pipeline Activity
After the first run:
- Open Traffic in the Chainsaw dashboard.
- Filter by the service token’s Client ID.
- Confirm requests use the expected repository and outcome.
- Check the cache hit ratio after a warm run.
Next Steps
- How to Integrate Chainsaw with CI/CD Pipelines — full multi-CI reference, including CocoaPods
- Troubleshooting CI/CD Integration — common auth and policy-block failures
- How to Configure Your Package Manager to Use Chainsaw — per-ecosystem config reference