From a3fcd59e82b81fd60711794c0a0edcde3fdda3eb Mon Sep 17 00:00:00 2001 From: John McLear Date: Mon, 20 Apr 2026 10:00:02 +0100 Subject: [PATCH 1/2] ci: publish Docker images to GHCR alongside Docker Hub Adds ghcr.io/ether/etherpad as a second publish target on release tags, reusing the existing docker/metadata-action step so the same SemVer tags (e.g. 2.6.1, 2.6, 2, latest) are pushed to both registries. Motivation: downstream consumers (Helm charts in particular) hit Docker Hub anonymous pull rate limits. GHCR has no such limits and the workflow already runs with GITHUB_TOKEN, so this is additive with no new secrets required. Docker Hub remains the primary/canonical source; GHCR is a mirror. Note: this only affects future release tags. The 2.6.1 tag already on Docker Hub will need to be mirrored separately (e.g. via skopeo) if downstream needs it on GHCR before the next release. --- .github/workflows/docker.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 3f668384868..02b42a0d611 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -14,6 +14,7 @@ env: TEST_TAG: etherpad/etherpad:test permissions: contents: read + packages: write jobs: docker: @@ -84,7 +85,9 @@ jobs: id: meta uses: docker/metadata-action@v6 with: - images: etherpad/etherpad + images: | + etherpad/etherpad + ghcr.io/ether/etherpad tags: | type=ref,event=branch type=semver,pattern={{version}} @@ -97,6 +100,14 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} + - + name: Log in to GHCR + if: github.event_name == 'push' + uses: docker/login-action@v4 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - name: Build and push id: build-docker From 8b7b2aabc3f0f1aec16b029c1708f7be0d26c44b Mon Sep 17 00:00:00 2001 From: John McLear Date: Mon, 20 Apr 2026 10:13:17 +0100 Subject: [PATCH 2/2] address qodo review: scope packages:write to publish job, document GHCR Two fixes from the qodo code review on #7569: 1. Overprivileged PR token (security). The original change set 'packages: write' at workflow level, which meant pull_request runs (whose Test step executes PR-controlled code) also inherited push access to GHCR. Splits the workflow into two jobs: - build-test: runs on pull_request and push with contents:read only. Does the single-arch load+test as before. - publish: needs build-test, runs only on push with packages:write. Does the multi-arch build-and-push, Docker Hub description update, and ether-charts bump. Docker Hub login is also now gated by job-level 'if' (same effect as the previous step-level 'if'). 2. Docs miss GHCR option. Updates doc/docker.md and README.md to document the GHCR mirror alongside Docker Hub with equivalent pull examples, so downstream users discovering via docs can choose the mirror to avoid Docker Hub rate limits. --- .github/workflows/docker.yml | 40 ++++++++++++++++++++++++------------ README.md | 4 +++- doc/docker.md | 18 ++++++++++------ 3 files changed, 42 insertions(+), 20 deletions(-) diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 02b42a0d611..156a14d239b 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -12,13 +12,15 @@ on: - 'v?[0-9]+.[0-9]+.[0-9]+' env: TEST_TAG: etherpad/etherpad:test + permissions: contents: read - packages: write jobs: - docker: + build-test: runs-on: ubuntu-latest + permissions: + contents: read env: PNPM_HOME: ~/.pnpm-store steps: @@ -27,11 +29,6 @@ jobs: uses: actions/checkout@v6 with: path: etherpad - - - - name: Set up QEMU - if: github.event_name == 'push' - uses: docker/setup-qemu-action@v4 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 @@ -79,9 +76,28 @@ jobs: done (cd src && gnpm run test-container) git clean -dxf . + + publish: + needs: build-test + if: github.event_name == 'push' + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + steps: + - + name: Check out + uses: actions/checkout@v6 + with: + path: etherpad + - + name: Set up QEMU + uses: docker/setup-qemu-action@v4 + - + name: Set up Docker Buildx + uses: docker/setup-buildx-action@v4 - name: Docker meta - if: github.event_name == 'push' id: meta uses: docker/metadata-action@v6 with: @@ -95,14 +111,12 @@ jobs: type=semver,pattern={{major}} - name: Log in to Docker Hub - if: github.event_name == 'push' uses: docker/login-action@v4 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Log in to GHCR - if: github.event_name == 'push' uses: docker/login-action@v4 with: registry: ghcr.io @@ -111,7 +125,6 @@ jobs: - name: Build and push id: build-docker - if: github.event_name == 'push' uses: docker/build-push-action@v7 with: context: ./etherpad @@ -120,6 +133,7 @@ jobs: push: true tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} + cache-from: type=gha - name: Update repo description uses: peter-evans/dockerhub-description@v5 if: github.ref == 'refs/heads/master' @@ -129,8 +143,8 @@ jobs: password: ${{ secrets.DOCKERHUB_TOKEN }} repository: etherpad/etherpad enable-url-completion: true - - name: Check out - if: github.event_name == 'push' && github.ref == 'refs/heads/develop' + - name: Check out ether-charts + if: github.ref == 'refs/heads/develop' uses: actions/checkout@v6 with: path: ether-charts diff --git a/README.md b/README.md index 635ae688925..259dddc7980 100644 --- a/README.md +++ b/README.md @@ -103,11 +103,13 @@ $env:ETHERPAD_RUN=1; irm https://raw.githubusercontent.com/ether/etherpad/master ### Docker-Compose +The official image is published to both Docker Hub (`etherpad/etherpad`) and GitHub Container Registry (`ghcr.io/ether/etherpad`) with identical tags. Use whichever suits your environment; GHCR avoids Docker Hub's anonymous pull rate limits. + ```yaml services: app: user: "0:0" - image: etherpad/etherpad:latest + image: etherpad/etherpad:latest # or: ghcr.io/ether/etherpad:latest tty: true stdin_open: true volumes: diff --git a/doc/docker.md b/doc/docker.md index 71af392360f..fe31ea031ab 100644 --- a/doc/docker.md +++ b/doc/docker.md @@ -1,15 +1,21 @@ # Docker -The official Docker image is available on https://hub.docker.com/r/etherpad/etherpad. +The official Docker image is published to two registries with identical tags: -## Downloading from Docker Hub -If you are ok downloading a [prebuilt image from Docker Hub](https://hub.docker.com/r/etherpad/etherpad), these are the commands: +- Docker Hub (canonical): https://hub.docker.com/r/etherpad/etherpad +- GitHub Container Registry (mirror): https://github.com/ether/etherpad/pkgs/container/etherpad + +The GHCR mirror is useful if you are hitting Docker Hub anonymous pull rate limits (for example on Kubernetes clusters). + +## Downloading a prebuilt image ```bash -# gets the latest published version +# from Docker Hub docker pull etherpad/etherpad - -# gets a specific version docker pull etherpad/etherpad:2.6.1 + +# from GHCR (same image, same tags) +docker pull ghcr.io/ether/etherpad +docker pull ghcr.io/ether/etherpad:2.6.1 ``` ## Build a personalized container