Private npm registry access
skuba projects at SEEK often need to access private npm packages. SEEK’s internal Buildkite setup grants easy access to these packages, behind a GET_NPM_TOKEN
environment variable.
Historical setups involved private-npm
and aws-sm
. This document details how to simplify such a setup.
Use with docker-ecr-cache
This section of the document assumes use of pnpm. If using yarn
, some more work may be needed in some setups. skuba advises migrating to pnpm
if possible.
docker-ecr-cache
is very commonly used in SEEK skuba projects. Some skuba templates, like express-koa-api
, come with a docker-ecr-cache
setup that has this included. This will look like:
# .buildkite/pipeline.yml
configs:
plugins:
- &docker-ecr-cache
seek-oss/docker-ecr-cache#v2.2.1:
cache-on:
- .npmrc
- package.json#.packageManager
- pnpm-lock.yaml
dockerfile: Dockerfile.dev-deps
secrets:
# This mounts the provisioned .npmrc file and the NPM_TOKEN environment variable for use in `pnpm fetch`
- id=npm,src=/var/lib/buildkite-agent/.npmrc
- NPM_TOKEN
steps:
- label: Some step
commands:
# Private npm access is not needed here; it is only used by `pnpm fetch` in the Dockerfile
- pnpm install --offline
- echo "Hello world"
env:
# This tells our Buildkite setup to create the .npmrc file and provision the NPM_TOKEN environment variable
GET_NPM_TOKEN: please
plugins:
- *docker-ecr-cache
- docker-compose#v5.6.0:
run: app
environment:
# Don't pass NPM_TOKEN to the container. It's only needed in docker-ecr-cache.
- GITHUB_API_TOKEN
propagate-environment: true
...
WORKDIR /workdir
RUN --mount=type=bind,source=.npmrc,target=.npmrc \
--mount=type=bind,source=package.json,target=package.json \
--mount=type=bind,source=pnpm-lock.yaml,target=pnpm-lock.yaml \
# Store the .npmrc file out of the working directory
--mount=type=secret,id=npm,dst=/root/.npmrc,required=true \
# Mount the NPM_TOKEN environment variable
--mount=type=secret,id=NPM_TOKEN,env=NPM_TOKEN,required=true \
# This is the only place we need to use the NPM_TOKEN
pnpm fetch
Migrating
- Remove any references to
private-npm
oraws-sm
in your pipeline. If you are usingaws-sm
for other secrets, you can keep it (but remove any npm token references). -
Reconfigure
docker-ecr-cache
’ssecrets
section to include thenpm
andNPM_TOKEN
secrets.seek-oss/docker-ecr-cache#v2.2.1: cache-on: - .npmrc - package.json#.packageManager - pnpm-lock.yaml dockerfile: Dockerfile.dev-deps - secrets: id=npm,src=/tmp/.npmrc + secrets: + - id=npm,src=/var/lib/buildkite-agent/.npmrc + - NPM_TOKEN
-
Add the
GET_NPM_TOKEN
environment variable to any step which usesdocker-ecr-cache
.steps: - label: Some step plugins: - *docker-ecr-cache + env: + GET_NPM_TOKEN: please
🚨 Be wary of any steps which retrieve
env
variables via yaml anchors.An example of a mistake:
configs: prod: &prod plugins: [...] env: ENVIRONMENT: production steps: - label: Some step <<: *prod env: # 🚨🚨🚨 This will override the ENVIRONMENT variable from the prod anchor GET_NPM_TOKEN: please
In order to avoid this, you could:
- Reduce indirection with the YAML anchors, and put all environment variables inline in the step
- Put
GET_NPM_TOKEN
in theconfigs
section too
-
Update your Dockerfile to use the new secrets.
RUN --mount=type=bind,source=.npmrc,target=.npmrc \ --mount=type=bind,source=package.json,target=package.json \ --mount=type=bind,source=pnpm-lock.yaml,target=pnpm-lock.yaml \ --mount=type=secret,id=npm,dst=/root/.npmrc,required=true \ + --mount=type=secret,id=NPM_TOKEN,env=NPM_TOKEN,required=true \ + pnpm fetch
Other setups
Other setups are likely to look similar, but are not covered here. Review the internal npm documentation.