Configure registry: CI/CD

Route CI installs through the firewall with environment variables, so existing build commands don't change.

In CI, set the registry and certificate through environment variables. Your existing npm ci and pip install -r requirements.txt steps stay exactly as they are, and a blocked package fails the job.

Before you start: CI runners can reach sfw.example.com on 443, and you have the firewall's CA certificate (skip the CA steps if the firewall uses a certificate from a CA your runners already trust).

The four variables

VariableValueFor
NPM_CONFIG_REGISTRYhttps://sfw.example.com/npm/npm, pnpm, Yarn 1
NODE_EXTRA_CA_CERTSpath to sfw-ca.pemnpm and Node
PIP_INDEX_URLhttps://sfw.example.com/pypi/simple/pip
PIP_CERTpath to a CA bundle that includes the firewall CApip

Store the CA as a CI secret or file variable, write it to disk at the start of the job, and set the variables.

🚧

PIP_CERT replaces pip's whole bundle

Point PIP_CERT at the firewall CA alone and every other HTTPS fetch pip makes (git+https, an extra index) fails. Where you can run update-ca-certificates, add the firewall CA to the system store and point PIP_CERT at the system bundle (/etc/ssl/certs/ca-certificates.crt). NODE_EXTRA_CA_CERTS adds to Node's list, so it can point at the firewall CA alone.

GitHub Actions

jobs:
  build:
    runs-on: ubuntu-latest
    env:
      NPM_CONFIG_REGISTRY: https://sfw.example.com/npm/
      PIP_INDEX_URL: https://sfw.example.com/pypi/simple/
    steps:
      - uses: actions/checkout@v4
      - name: Install firewall CA
        run: |
          printf "%s\n" "$SFW_CA_PEM" | sudo tee /usr/local/share/ca-certificates/sfw-ca.crt > /dev/null
          sudo update-ca-certificates
          echo "NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/sfw-ca.crt" >> "$GITHUB_ENV"
          echo "PIP_CERT=/etc/ssl/certs/ca-certificates.crt" >> "$GITHUB_ENV"
        env:
          SFW_CA_PEM: ${{ secrets.SFW_CA_PEM }}
      - run: npm ci

The CA path is set through $GITHUB_ENV because job-level env can't reference the runner context, and the secret goes through env rather than being interpolated into the script.

GitLab CI

variables:
  NPM_CONFIG_REGISTRY: https://sfw.example.com/npm/
  PIP_INDEX_URL: https://sfw.example.com/pypi/simple/

build:
  script:
    # SFW_CA_PEM is a File-type CI/CD variable (its value is a path)
    - cp "$SFW_CA_PEM" /usr/local/share/ca-certificates/sfw-ca.crt && update-ca-certificates
    - export NODE_EXTRA_CA_CERTS="$SFW_CA_PEM" PIP_CERT=/etc/ssl/certs/ca-certificates.crt
    - npm ci

Container-based runners: bake it in once

If your builds run in your own image, put the CA and variables in the image and no pipeline changes at all:

COPY sfw-ca.pem /usr/local/share/ca-certificates/sfw-ca.crt
RUN update-ca-certificates
ENV NODE_EXTRA_CA_CERTS=/usr/local/share/ca-certificates/sfw-ca.crt \
    PIP_CERT=/etc/ssl/certs/ca-certificates.crt \
    NPM_CONFIG_REGISTRY=https://sfw.example.com/npm/ \
    PIP_INDEX_URL=https://sfw.example.com/pypi/simple/

Alpine and distroless bases need the ca-certificates package for update-ca-certificates to exist.

If runners can't resolve sfw.example.com through DNS, add it at runtime: docker run --add-host sfw.example.com:10.0.0.5 ....

Verify

Run one passing build, then add lodahs to a test branch's package.json and run again.

  • The clean build passes
  • The test build fails at install with E403 ... Blocked by Security Policy
  • The firewall logs show requests from the runner's IP

Notes

  • Lockfiles: package-lock.json records registry.npmjs.org URLs. Current npm versions swap that host for the configured registry automatically (replace-registry-host, default npmjs), so npm ci works without regenerating the lockfile.
  • Caches: a warm dependency cache on the runner skips the firewall entirely for cached packages. Clear it once when you switch.
  • Different from Socket scanning in CI: this blocks at install time. Pull request scanning with the Socket CLI or GitHub App is a separate integration.

Reference


Did this page help you?