From e05cc8853391fbaf033f3f9a5ab39feec14f3c57 Mon Sep 17 00:00:00 2001 From: Luca Ghersi Date: Thu, 17 Sep 2026 18:14:54 +0200 Subject: [PATCH] feat(gar): publish to Artifact Registry Adds `actions/setup-artifact-registry`, which federates through the workload identity pool and configures Docker, npm and Maven from one step, and `.github/workflows/template_gitops_gar.yml`, which publishes images through it. A service calls the template and grants `id-token: write`; no registry credentials are passed. Images go to `images-publish`, deployments reference the `images` virtual repository in front of it, and that path is set in the GitOps repository once, by hand, so the template carries no GitOps file lists. `template_gitops.yml` is the Harbor equivalent and is untouched. Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/template_gitops_gar.yml | 350 +++++++++++++++++++++ README.md | 65 ++++ actions/setup-artifact-registry/README.md | 86 +++++ actions/setup-artifact-registry/action.yml | 100 ++++++ 4 files changed, 601 insertions(+) create mode 100644 .github/workflows/template_gitops_gar.yml create mode 100644 actions/setup-artifact-registry/README.md create mode 100644 actions/setup-artifact-registry/action.yml diff --git a/.github/workflows/template_gitops_gar.yml b/.github/workflows/template_gitops_gar.yml new file mode 100644 index 00000000..2c58f5d7 --- /dev/null +++ b/.github/workflows/template_gitops_gar.yml @@ -0,0 +1,350 @@ +# Publishes to Google Artifact Registry. +# +# The calling job must grant id-token: write. A called workflow cannot raise the +# caller's permissions, so that grant has to come from the caller or the token +# exchange fails before the build starts. +# +# gitops-github-action knows nothing about Google: setup-artifact-registry mints a +# token, and Artifact Registry accepts it as a basic-auth password under the fixed +# username oauth2accesstoken. +# +# A push is accepted only into images-publish, and deployments reference images, the +# virtual repository in front of it. That path is set in the GitOps repository once, +# by hand, and Flux image automation rolls the tag from there. +# +# So there are no gitops-dev / gitops-stage / gitops-prod inputs: they make the +# action rewrite the whole image reference on every build, which pins the deployment +# to images-publish. A caller that passes them fails with "invalid input". A service +# using the file lists moves to image automation before it moves here. +# +# template_gitops.yml is the Harbor equivalent. + +name: GitOps (Artifact Registry) + +on: + workflow_call: + inputs: + docker-registry: + required: false + type: string + default: "europe-docker.pkg.dev" + docker-registry-api: + required: false + type: string + default: "https://europe-docker.pkg.dev/v2/" + description: "Registry v2 API, used to retag a release without rebuilding. Must match docker-registry." + docker-build-args: + required: false + type: string + docker-build-target: + required: false + type: string + docker-build-outputs: + required: false + type: string + description: "Custom output destinations for docker build (e.g., type=registry,push=true,compression=gzip,force-compression=true). Required for DHI images." + docker-build-platform: + required: false + type: string + description: "A build platform (e.g., linux/amd64, linux/arm64). If multiple platforms are specified, the action will fail as it does not support cross-compilation." + default: "linux/amd64" + docker-build-provenance: + required: false + type: string + default: "false" + docker-disable-retagging: + required: false + type: string + default: "false" + docker-file: + required: false + type: string + default: "./Dockerfile" + docker-image: + required: false + type: string + default: sb-images/${{ github.event.repository.name }} + description: "Image path within the project, without the publish or pull repository in front of it. Both are composed from it." + docker-custom-tag: + required: false + type: string + docker-tag-timestamp: + required: false + type: string + default: "true" + description: "Insert a UTC timestamp into dev/main/master branch tags (e.g. dev-20260602143055-) to make them sortable for Flux image automation. Enabled by default; set to 'false' to use the legacy - format." + gitops-organization: + required: false + type: string + default: ${{ github.repository_owner }} + gitops-repository: + required: false + type: string + default: "mops" + gitops-user: + required: false + type: string + default: "staffbase-actions" + gitops-email: + required: false + type: string + default: "staffbase-actions[bot]@users.noreply.github.com" + upwind-client-id: + required: false + type: string + runs-on: + required: false + type: string + default: "ubuntu-24.04" + upwind-organization-id: + required: false + type: string + working-directory: + required: false + type: string + default: "." + create-deployment: + required: false + type: boolean + default: false + description: "Create GitHub Deployments on the source repository and write tracking annotations to the GitOps CRs" + multi-arch: + required: false + type: boolean + default: false + description: "Build linux/amd64 and linux/arm64 natively via a job matrix and merge them into one multi-arch image. Disabled by default (single-arch build using docker-build-platform). See gitops-github-action README 'Multi-Arch Images'." + multiarch-artifact-name: + required: false + type: string + default: "docker-digests" + description: "Base name of the artifact carrying the per-architecture digests between the build and merge jobs. Only needs changing when a workflow builds more than one multi-arch image, otherwise the digests get mixed up." + # waiting for: https://github.com/github-community/community/discussions/17554 + secrets: + docker-build-secrets: + required: false + docker-build-secret-files: + required: false + gitops-token: + required: false + gonosumdb: + required: false + client-id: + required: false + private-key: + required: false + upwind-client-secret: + required: false + +jobs: + gitops: + name: GitOps + runs-on: ${{ inputs.runs-on }} + if: inputs.multi-arch != true && (github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')) + permissions: + contents: read + deployments: write + # Federation needs this, and it cannot be granted from here: the calling job + # must grant it too, or the run fails before the build starts. + id-token: write + + env: + USING_APP_CREDENTIALS: ${{ secrets.client-id != '' && secrets.private-key != '' }} + + steps: + - name: Checkout + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + + - name: Get App Token + if: ${{ env.USING_APP_CREDENTIALS == 'true' }} + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 + id: get_token + with: + client-id: ${{ secrets.client-id }} + private-key: ${{ secrets.private-key }} + owner: ${{inputs.gitops-organization }} + + # configure is empty: gitops-github-action performs the registry login itself + # with the token passed below. + - name: Setup Artifact Registry + id: gar + uses: Staffbase/gha-workflows/actions/setup-artifact-registry@96e65ab81ccda77b8cdb26ed07946567a32263b2 # UNRELEASED + # Pinned by commit: a reusable workflow cannot reference an action by + # relative path, and a floating ref would hand a caller pinned to a tag + # whatever happens to sit on main. + with: + configure: "" + + - name: GitOps (build, push and deploy a new Docker image) + id: gitops + uses: Staffbase/gitops-github-action@158275454d56fd8fa923995220ee1b9eb1030032 # v8.2.1 + with: + docker-registry: ${{ inputs.docker-registry }} + docker-registry-api: ${{ inputs.docker-registry-api }} + docker-username: oauth2accesstoken + docker-password: ${{ steps.gar.outputs.access-token }} + docker-build-args: | + ${{ inputs.docker-build-args }} + GONOSUMDB=${{ vars.gonosumdb }} + # The token is always offered to the build as the secret "gar", so a + # Dockerfile installing npm or Maven dependencies from Artifact Registry + # can mount it. A build secret is only readable if the Dockerfile mounts + # it, so this costs nothing when unused. + docker-build-secrets: | + ${{ secrets.docker-build-secrets }} + gar=${{ steps.gar.outputs.access-token }} + docker-build-secret-files: ${{ secrets.docker-build-secret-files }} + docker-build-target: ${{ inputs.docker-build-target }} + docker-build-outputs: ${{ inputs.docker-build-outputs }} + docker-build-platforms: ${{ inputs.docker-build-platform }} + docker-build-provenance: ${{ inputs.docker-build-provenance }} + docker-disable-retagging: ${{ inputs.docker-disable-retagging }} + docker-file: ${{ inputs.docker-file }} + # images-publish is the only one of the two repositories that accepts a + # push. Deployments reference images, the virtual repository in front of + # it, which this workflow never writes: see the header. + docker-image: staffbase-artifacts/images-publish/${{ inputs.docker-image }} + docker-custom-tag: ${{ inputs.docker-custom-tag }} + docker-tag-timestamp: ${{ inputs.docker-tag-timestamp }} + gitops-organization: ${{ inputs.gitops-organization }} + gitops-repository: ${{ inputs.gitops-repository }} + gitops-user: ${{ inputs.gitops-user }} + gitops-email: ${{ inputs.gitops-email }} + gitops-token: ${{ env.USING_APP_CREDENTIALS == 'true' && steps.get_token.outputs.token || secrets.gitops-token }} + upwind-client-id: ${{ inputs.upwind-client-id }} + upwind-client-secret: ${{ secrets.upwind-client-secret }} + upwind-organization-id: ${{ inputs.upwind-organization-id }} + working-directory: ${{ inputs.working-directory }} + + gitops-build: + name: Build (${{ matrix.arch }}) + runs-on: ${{ matrix.runs-on }} + if: inputs.multi-arch == true && (github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')) + permissions: + contents: read + id-token: write + strategy: + fail-fast: false + matrix: + include: + - arch: amd64 + runs-on: ubuntu-24.04 + - arch: arm64 + runs-on: ubuntu-24.04-arm + + steps: + - name: Checkout + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + + - name: Setup Artifact Registry + id: gar + uses: Staffbase/gha-workflows/actions/setup-artifact-registry@96e65ab81ccda77b8cdb26ed07946567a32263b2 # UNRELEASED + with: + configure: "" + + - name: GitOps (build and push by digest) + uses: Staffbase/gitops-github-action@158275454d56fd8fa923995220ee1b9eb1030032 # v8.2.1 + with: + multiarch-mode: build + multiarch-artifact-name: ${{ inputs.multiarch-artifact-name }} + docker-registry: ${{ inputs.docker-registry }} + docker-registry-api: ${{ inputs.docker-registry-api }} + docker-username: oauth2accesstoken + docker-password: ${{ steps.gar.outputs.access-token }} + docker-build-args: | + ${{ inputs.docker-build-args }} + GONOSUMDB=${{ vars.gonosumdb }} + # The token is always offered to the build as the secret "gar", so a + # Dockerfile installing npm or Maven dependencies from Artifact Registry + # can mount it. A build secret is only readable if the Dockerfile mounts + # it, so this costs nothing when unused. + docker-build-secrets: | + ${{ secrets.docker-build-secrets }} + gar=${{ steps.gar.outputs.access-token }} + docker-build-secret-files: ${{ secrets.docker-build-secret-files }} + docker-build-target: ${{ inputs.docker-build-target }} + docker-build-provenance: ${{ inputs.docker-build-provenance }} + docker-disable-retagging: ${{ inputs.docker-disable-retagging }} + docker-file: ${{ inputs.docker-file }} + # images-publish is the only one of the two repositories that accepts a + # push. Deployments reference images, the virtual repository in front of + # it, which this workflow never writes: see the header. + docker-image: staffbase-artifacts/images-publish/${{ inputs.docker-image }} + docker-custom-tag: ${{ inputs.docker-custom-tag }} + docker-tag-timestamp: ${{ inputs.docker-tag-timestamp }} + working-directory: ${{ inputs.working-directory }} + + gitops-merge: + name: Merge and Deploy + needs: gitops-build + runs-on: ${{ inputs.runs-on }} + if: inputs.multi-arch == true && (github.ref == 'refs/heads/dev' || github.ref == 'refs/heads/main' || github.ref == 'refs/heads/master' || startsWith(github.ref, 'refs/tags/')) + permissions: + contents: read + deployments: write + # Federation needs this, and it cannot be granted from here: the calling job + # must grant it too, or the run fails before the build starts. + id-token: write + + env: + USING_APP_CREDENTIALS: ${{ secrets.client-id != '' && secrets.private-key != '' }} + + steps: + - name: Checkout + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + + - name: Get App Token + if: ${{ env.USING_APP_CREDENTIALS == 'true' }} + uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0 + id: get_token + with: + client-id: ${{ secrets.client-id }} + private-key: ${{ secrets.private-key }} + owner: ${{inputs.gitops-organization }} + + - name: Setup Artifact Registry + id: gar + uses: Staffbase/gha-workflows/actions/setup-artifact-registry@96e65ab81ccda77b8cdb26ed07946567a32263b2 # UNRELEASED + with: + configure: "" + + - name: GitOps (merge manifests and deploy) + id: gitops + uses: Staffbase/gitops-github-action@158275454d56fd8fa923995220ee1b9eb1030032 # v8.2.1 + with: + multiarch-mode: merge + multiarch-artifact-name: ${{ inputs.multiarch-artifact-name }} + docker-registry: ${{ inputs.docker-registry }} + docker-registry-api: ${{ inputs.docker-registry-api }} + docker-username: oauth2accesstoken + docker-password: ${{ steps.gar.outputs.access-token }} + docker-build-args: | + ${{ inputs.docker-build-args }} + GONOSUMDB=${{ vars.gonosumdb }} + # The token is always offered to the build as the secret "gar", so a + # Dockerfile installing npm or Maven dependencies from Artifact Registry + # can mount it. A build secret is only readable if the Dockerfile mounts + # it, so this costs nothing when unused. + docker-build-secrets: | + ${{ secrets.docker-build-secrets }} + gar=${{ steps.gar.outputs.access-token }} + docker-build-secret-files: ${{ secrets.docker-build-secret-files }} + docker-build-target: ${{ inputs.docker-build-target }} + docker-build-outputs: ${{ inputs.docker-build-outputs }} + docker-build-provenance: ${{ inputs.docker-build-provenance }} + docker-disable-retagging: ${{ inputs.docker-disable-retagging }} + docker-file: ${{ inputs.docker-file }} + # images-publish is the only one of the two repositories that accepts a + # push. Deployments reference images, the virtual repository in front of + # it, which this workflow never writes: see the header. + docker-image: staffbase-artifacts/images-publish/${{ inputs.docker-image }} + docker-custom-tag: ${{ inputs.docker-custom-tag }} + docker-tag-timestamp: ${{ inputs.docker-tag-timestamp }} + gitops-organization: ${{ inputs.gitops-organization }} + gitops-repository: ${{ inputs.gitops-repository }} + gitops-user: ${{ inputs.gitops-user }} + gitops-email: ${{ inputs.gitops-email }} + gitops-token: ${{ env.USING_APP_CREDENTIALS == 'true' && steps.get_token.outputs.token || secrets.gitops-token }} + upwind-client-id: ${{ inputs.upwind-client-id }} + upwind-client-secret: ${{ secrets.upwind-client-secret }} + upwind-organization-id: ${{ inputs.upwind-organization-id }} + working-directory: ${{ inputs.working-directory }} diff --git a/README.md b/README.md index 713c64a5..a7296f9a 100644 --- a/README.md +++ b/README.md @@ -321,6 +321,63 @@ jobs: +### GitOps (Artifact Registry) + +Publishes to Google Artifact Registry. The Harbor equivalent is [GitOps](#gitops), which this +replaces; migrate a service by switching the `uses:` line and adding `id-token: write`. + +```yaml +jobs: + gitops: + uses: Staffbase/gha-workflows/.github/workflows/template_gitops_gar.yml@1ad4ec63950c1dd36695bc073bc101f816dd8c06 # v17.0.2 + permissions: + contents: read + deployments: write + id-token: write + secrets: + client-id: ${{ vars.STAFFBASE_ACTIONS_CLIENT_ID }} + private-key: ${{ secrets.STAFFBASE_ACTIONS_PRIVATE_KEY }} +``` + +**The `permissions` block is required.** A called workflow cannot raise the caller's permissions, +so without `id-token: write` on the calling job the token exchange fails before the build starts. +The other two entries are needed because an explicit block replaces the default set: omitting +`contents: read` breaks the checkout. + +No registry credentials are passed. [`setup-artifact-registry`](actions/setup-artifact-registry) +mints a token per job, and Artifact Registry accepts it as a basic-auth password. + +Images are pushed to `images-publish`, the only one of the two repositories that accepts a push. +The path is composed from `docker-image`, which stays the short form `sb-images/`, so the +image lands at `staffbase-artifacts/images-publish/sb-images/`. + +**Deployments reference `images`, and this workflow never writes that path.** `images` is the +virtual repository in front of `images-publish`. It is set in the GitOps repository once, by hand, +and Flux image automation rolls the tag from there. + +There are therefore no `gitops-dev` / `gitops-stage` / `gitops-prod` inputs: they make the action +rewrite the whole image reference on every build, which pins the deployment to `images-publish`. +Passing them fails with `invalid input`. A service using the file lists moves to image automation +before it moves here. + +Pulls are unaffected while a service has not migrated, because `images` resolves `images-publish` +first and falls back to the `harbor` upstream, so an image that exists only on Harbor still +resolves through the same path. + +#### Installing dependencies during the build + +The token is always offered to the build as the secret `gar`, so a Dockerfile that installs npm or +Maven dependencies from Artifact Registry can mount it without the workflow passing anything: + +```dockerfile +RUN --mount=type=secret,id=gar,env=NODE_AUTH_TOKEN npm ci +``` + +with the project's `.npmrc` reading that variable. See +[`setup-artifact-registry`](actions/setup-artifact-registry) for the endpoint and the `.npmrc` +entries. A build secret is only readable if the Dockerfile mounts it, so this costs nothing when +unused. + ### Jira Ticket Tagging
@@ -712,6 +769,14 @@ jobs:
+## Actions 🧩 + +Composite actions in [`actions/`](actions), used from a job's `steps` rather than as a workflow. + +| Action | Purpose | +| ------ | ------- | +| [`setup-artifact-registry`](actions/setup-artifact-registry) | Federate into Google Artifact Registry and configure Docker, npm and Maven | + ## Limitations 🚧 With the current implementation of the reusable workflows from GitHub, we have some usage limitations. diff --git a/actions/setup-artifact-registry/README.md b/actions/setup-artifact-registry/README.md new file mode 100644 index 00000000..ac6d1699 --- /dev/null +++ b/actions/setup-artifact-registry/README.md @@ -0,0 +1,86 @@ +# Setup Artifact Registry + +Federates into Google Artifact Registry and configures the clients that need it. No credential is +stored anywhere: the job exchanges its OIDC token for a Google access token that lasts as long as +the run. + +## Usage + +```yaml +jobs: + build: + runs-on: ubuntu-24.04 + permissions: + contents: read + id-token: write + steps: + - uses: actions/checkout@v6 + + - uses: Staffbase/gha-workflows/actions/setup-artifact-registry@1ad4ec63950c1dd36695bc073bc101f816dd8c06 # v17.0.2 + id: gar + with: + configure: docker,npm +``` + +**The `permissions` block is required.** A composite action cannot request a permission for itself, +so without `id-token: write` on the calling job the token exchange fails. + +## Inputs + +| Name | Description | Default | +| ---- | ----------- | ------- | +| `configure` | Clients to configure: `docker`, `npm`, `maven`, comma-separated | `docker` | +| `workload-identity-provider` | Provider to federate through | the Staffbase pool | +| `service-account` | Account to impersonate | `github-artifact-publisher@global-iam-436113` | +| `docker-registry` | Registry host to log in to | `europe-docker.pkg.dev` | +| `npm-registry` | Endpoint the npm credential is written for | `https://europe-npm.pkg.dev/staffbase-artifacts/npm/` | +| `maven-registry` | Endpoint written into the generated `settings.xml` | `https://europe-maven.pkg.dev/staffbase-artifacts/maven` | + +## Outputs + +| Name | Description | +| ---- | ----------- | +| `access-token` | The access token, masked in logs. Pass it to a build that authenticates itself. | + +## What each client does + +**docker** logs in to `docker-registry`, so `docker build`, `docker push` and Jib all work. + +**npm** appends credentials for `npm-registry` to `~/.npmrc`. It writes the credential only: which +registry a project resolves from stays in the project's own `.npmrc`, so this never silently +repoints a build. + +**maven** writes `~/.m2/settings.xml` with a `server` entry under the id `artifact-registry`. +Reference that id from the project's `repository` definition. The step fails rather than +overwriting an existing `settings.xml`. + +## Installing inside a Docker build + +An `npm install` that runs in a `RUN` layer cannot see the runner's `~/.npmrc`. Pass the token as a +build secret instead: + +```yaml + - uses: Staffbase/gha-workflows/actions/setup-artifact-registry@1ad4ec63950c1dd36695bc073bc101f816dd8c06 # v17.0.2 + id: gar + + - uses: docker/build-push-action@v7 + with: + secrets: | + gar=${{ steps.gar.outputs.access-token }} +``` + +```dockerfile +RUN --mount=type=secret,id=gar,env=NODE_AUTH_TOKEN npm ci +``` + +with the project's `.npmrc` reading the token from that variable: + +```text +registry=https://europe-npm.pkg.dev/staffbase-artifacts/npm/ +//europe-npm.pkg.dev/staffbase-artifacts/npm/:_authToken=${NODE_AUTH_TOKEN} +//europe-npm.pkg.dev/staffbase-artifacts/npm/:always-auth=true +``` + +One endpoint serves public packages, Staffbase packages and the `@staffbase` scope, so a project +that migrates drops its `registry.npmjs.org` and `npm.pkg.github.com` entries and the GitHub token +behind them. diff --git a/actions/setup-artifact-registry/action.yml b/actions/setup-artifact-registry/action.yml new file mode 100644 index 00000000..5318e181 --- /dev/null +++ b/actions/setup-artifact-registry/action.yml @@ -0,0 +1,100 @@ +name: 'Setup Artifact Registry' +description: 'Federates into Google Artifact Registry and configures Docker, npm and Maven to use it.' +author: 'Staffbase SE' + +inputs: + configure: + description: 'Comma-separated list of clients to configure: docker, npm, maven. The access token is produced regardless, so a build that passes it on itself can leave this empty.' + required: false + default: 'docker' + workload-identity-provider: + description: 'Workload Identity Provider to federate through. The default is the Staffbase pool; overriding it is for testing only.' + required: false + default: 'projects/753004700074/locations/global/workloadIdentityPools/github/providers/github' + service-account: + description: 'Service account to impersonate. The default holds artifactregistry.writer on the publish repositories and reader on the project.' + required: false + default: 'github-artifact-publisher@global-iam-436113.iam.gserviceaccount.com' + docker-registry: + description: 'Docker registry host to log in to.' + required: false + default: 'europe-docker.pkg.dev' + npm-registry: + description: 'npm endpoint the credential is written for. Must match the registry the project resolves from.' + required: false + default: 'https://europe-npm.pkg.dev/staffbase-artifacts/npm/' + maven-registry: + description: 'Maven endpoint written into the generated settings.xml.' + required: false + default: 'https://europe-maven.pkg.dev/staffbase-artifacts/maven' + +outputs: + access-token: + description: 'Short-lived Google access token. Pass it to a build that authenticates itself, such as a Docker build secret for an npm install inside the image. Masked in logs, and valid for the length of the job.' + value: ${{ steps.auth.outputs.access_token }} + +runs: + using: 'composite' + steps: + # The calling job must grant id-token: write. A composite action cannot request + # a permission for itself, so without it this fails before anything is written. + - name: Authenticate to Google Cloud + id: auth + uses: google-github-actions/auth@7c6bc770dae815cd3e89ee6cdf493a5fab2cc093 # v3.0.0 + with: + workload_identity_provider: ${{ inputs.workload-identity-provider }} + service_account: ${{ inputs.service-account }} + token_format: access_token + + - name: Login to Artifact Registry + if: contains(inputs.configure, 'docker') + uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 + with: + registry: ${{ inputs.docker-registry }} + username: oauth2accesstoken + password: ${{ steps.auth.outputs.access_token }} + + # The credential only. Which registry a project resolves from stays in its own + # .npmrc, so this does not silently repoint a build. + - name: Configure npm + if: contains(inputs.configure, 'npm') + shell: bash + env: + NPM_REGISTRY: ${{ inputs.npm-registry }} + ACCESS_TOKEN: ${{ steps.auth.outputs.access_token }} + run: | + set -euo pipefail + # npm keys an entry by the registry URL without its scheme. + key="${NPM_REGISTRY#https:}" + { + echo "${key}:_authToken=${ACCESS_TOKEN}" + echo "${key}:always-auth=true" + } >> "${HOME}/.npmrc" + echo "::notice::Configured npm credentials for ${NPM_REGISTRY}" + + - name: Configure Maven + if: contains(inputs.configure, 'maven') + shell: bash + env: + MAVEN_REGISTRY: ${{ inputs.maven-registry }} + ACCESS_TOKEN: ${{ steps.auth.outputs.access_token }} + run: | + set -euo pipefail + settings="${HOME}/.m2/settings.xml" + if [[ -f "$settings" ]]; then + echo "::error::${settings} already exists. This action would overwrite it; configure Maven in the project instead." + exit 1 + fi + mkdir -p "${HOME}/.m2" + cat > "$settings" < + + + artifact-registry + oauth2accesstoken + ${ACCESS_TOKEN} + + + + XML + echo "::notice::Wrote Maven credentials for ${MAVEN_REGISTRY} to ${settings} under the server id 'artifact-registry'"