docker / build-push-action

GitHub Action to build and push Docker images with Buildx
https://github.com/marketplace/actions/build-and-push-docker-images
Apache License 2.0
4.24k stars 541 forks source link

Unable to use .npmrc file created with `actions/setup-node` when using `docker/build-push-action` #915

Closed varsnotwars closed 11 months ago

varsnotwars commented 1 year ago

Behaviour

Apologies if I've misunderstood the docs, but when combining actions/setup-node and docker/build-push-action and an image with a private npm package, a valid .npmrc file does not seem to be used, thus resulting in a 404 for the package. I have a suspicion the NODE_AUTH_TOKEN value is not being interpolated in the .npmrc file.

Steps to reproduce this issue

  1. Set a repository secret for your NPM token with the following naming convention. e.g., NPM_TOKEN=
  2. Create a step with actions/setup-node that will create the .npmrc file. Confirmed the following gets created at the /home/runner/work/_temp/ path:
    //registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}
    @<YOUR-NPM-ORG>:registry=https://registry.npmjs.org/
    always-auth=true
  3. Add a docker/build-push-action step that uses the secret-files param to set the npmrc secret and bind to file created by previous step. See action.yml file below.
  4. Run action

Expected behaviour

The private npm package is installed successfully using the .npmrc file.

Actual behaviour

A 404 is thrown when trying to install the private package

action.yml

jobs:
  push_to_registry:
    name: Push Docker image to Docker Hub
    runs-on: ubuntu-latest
    steps:
      - name: Check out the repo
        uses: actions/checkout@v3

      - name: Log in to Docker Hub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      - name: Extract metadata (tags, labels) for Docker
        id: meta
        uses: docker/metadata-action@v4
        with:
          images: <YOUR-ORG>/<IMAGE-NAME>

      - name: Use Node.js
        uses: actions/setup-node@v3
        with:
          always-auth: true
          node-version: "18.x"
          registry-url: https://registry.npmjs.org
          scope: "@<YOUR_NPM-ORG>"

      - name: Build and push Docker image
        uses: docker/build-push-action@v4
        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
        with:
          context: .
          file: ./Dockerfile
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          secret-files: |
            "npmrc=${{ runner.temp }}/.npmrc"

Dockerfile

FROM node:alpine

WORKDIR /app
COPY package.json .

RUN --mount=type=secret,id=npmrc,target=/app/.npmrc npm install --omit=dev

COPY . .

CMD ["npm","start"]
crazy-max commented 1 year ago

I have a similar use case but I just pass the NODE_AUTH_TOKEN as secret on my side and do the npm config within the build to publish packages: https://github.com/docker/actions-toolkit/blob/5b760c8b3a41b795b84bbb2d54191902b50c1cc1/dev.Dockerfile#L100

I use bake on my side though: https://github.com/docker/actions-toolkit/blob/5b760c8b3a41b795b84bbb2d54191902b50c1cc1/docker-bake.hcl#L77-L85 but would look like this using the build push action:

      - name: Build and push Docker image
        uses: docker/build-push-action@v4
        with:
          context: .
          file: ./Dockerfile
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          labels: ${{ steps.meta.outputs.labels }}
          secrets: |
            NODE_AUTH_TOKEN=${{ secrets.NPM_TOKEN }}

And in your Dockerfile I would assume smth like:

RUN --mount=type=secret,id=NODE_AUTH_TOKEN <<EOT
  set -e
  npm config set //registry.npmjs.org/:_authToken $(cat /run/secrets/NODE_AUTH_TOKEN)
  npm install --omit=dev
EOT

This way you can remove the Use Node.js step in your workflow.

Also be careful and use another stage when pulling dependencies to avoid having the .npmrc shipped in your image or just remove the file after operation.

        env:
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

What's the purpose of this?