How to Route GitLab CI Builds Through Chainsaw
Configure GitLab CI to install packages through Chainsaw using a Service Token, masked CI/CD variables, and job-local package-manager configuration, with a merge-request gating example.
Overview
GitLab CI jobs run on shared or persistent runners, so generate package-manager configuration inside each job, read credentials from masked CI/CD variables, and avoid persistent global runner state. This page is the GitLab-CI-specific slice of How to Integrate Chainsaw with CI/CD Pipelines; see that guide for GitHub Actions and Jenkins and for the cross-cutting cache-invalidation and policy guidance.
Prerequisites
- A running Chainsaw instance reachable from your GitLab runners
- A Chainsaw client credential with Client Type set to Service Token
- Repository scope set to only the ecosystems the pipeline needs
CHAINSAW_CLIENT_IDandCHAINSAW_CLIENT_SECRETdefined as masked CI/CD variables (Settings → CI/CD → Variables)
npm
stages: [build]
variables:
NPM_CONFIG_USERCONFIG: "$CI_PROJECT_DIR/.npmrc"
build_node:
image: node:20
stage: build
before_script:
- rm -rf node_modules package-lock.json
- CHAINSAW_NPM_AUTH="$(printf '%s' "$CHAINSAW_CLIENT_ID:$CHAINSAW_CLIENT_SECRET" | base64)"
- printf "registry=https://chain305.com/chainproxy/repository/@default/npmjs/\n//chain305.com/chainproxy/repository/@default/npmjs/:_auth=%s\n//chain305.com/chainproxy/repository/@default/npmjs/:always-auth=true\n" "$CHAINSAW_NPM_AUTH" > .npmrc
script:
- npm ci
- npm test
pip
stages: [test]
variables:
PIP_INDEX_URL: "https://chain305.com/chainproxy/repository/@default/pypi/simple/"
PIP_RETRIES: "5"
PIP_TIMEOUT: "60"
test_python:
image: python:3.13
stage: test
before_script:
- printf "machine chain305.com\n login %s\n password %s\n" "$CHAINSAW_CLIENT_ID" "$CHAINSAW_CLIENT_SECRET" > "$HOME/.netrc"
- chmod 600 "$HOME/.netrc"
- pip cache purge
script:
- python -m pip install -U pip
- pip install -r requirements.txt
- pytest -q
Maven
build_maven:
image: maven:3.9-eclipse-temurin-21
stage: build
script:
- 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
Docker / OCI
build_container:
image: docker:24-cli
services:
- docker:24-dind
before_script:
- echo "$CHAINSAW_CLIENT_SECRET" | docker login chain305.com --username "$CHAINSAW_CLIENT_ID" --password-stdin
script:
- docker pull chain305.com/library/alpine:3.21
Gating Merge Requests
Run the install/build job on merge-request pipelines and make it a required pipeline so the merge is blocked when a package is denied. A policy block returns HTTP 403, the install step exits non-zero, and the merge request cannot merge.
stages: [firewall]
firewall_install:
image: node:20
stage: firewall
rules:
- if: '$CI_PIPELINE_SOURCE == "merge_request_event"'
before_script:
- rm -rf node_modules package-lock.json
- CHAINSAW_NPM_AUTH="$(printf '%s' "$CHAINSAW_CLIENT_ID:$CHAINSAW_CLIENT_SECRET" | base64)"
- printf "registry=https://chain305.com/chainproxy/repository/@default/npmjs/\n//chain305.com/chainproxy/repository/@default/npmjs/:_auth=%s\n//chain305.com/chainproxy/repository/@default/npmjs/:always-auth=true\n" "$CHAINSAW_NPM_AUTH" > .npmrc
script:
# A policy block (e.g. CHW-2002 vulnerability, CHW-2004 typosquat)
# returns HTTP 403, npm ci exits non-zero, and this job fails the MR.
- npm ci
Then enable Pipelines must succeed under Settings → Merge requests so a failed firewall job blocks the merge. Scope a stricter policy to the merge-request service token so MRs are gated more aggressively than scheduled builds.
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 Gradle and CocoaPods
- Troubleshooting CI/CD Integration — common auth and policy-block failures
- How to Configure Your Package Manager to Use Chainsaw — per-ecosystem config reference