From 9b9d4f0577b6cbd516082e97a6413e8a9d349826 Mon Sep 17 00:00:00 2001 From: Maxim Shulga Date: Sun, 2 Aug 2026 16:18:03 -0700 Subject: [PATCH] Publish one release image digest from a modernised workflow The push job called build-push-action twice, once for the ref tag and once for latest. Two builds meant the two tags could resolve to different manifest digests. Build once and let docker/metadata-action supply both tags and the OCI labels for that single build. Replace the deprecated actions/checkout@v2 and docker/build-push-action@v1, default workflow permissions to contents: read so pull requests cannot reach publication credentials, and authenticate with a scoped DOCKER_TOKEN through docker/login-action instead of DOCKER_PASSWORD. The test job's docker-compose.test.yml branch was dead; that file does not exist in the repository. Co-Authored-By: Claude Opus 5 --- .github/workflows/docker-publish.yml | 59 +++++++++++++++++----------- IMPROVEMENTS.md | 13 +++--- 2 files changed, 44 insertions(+), 28 deletions(-) diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index b3ad039..559d12e 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -9,24 +9,29 @@ on: pull_request: +permissions: + contents: read + +env: + IMAGE: snegov/seafile-client + jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - name: Validate compose example run: docker compose --file compose.example.yaml config --quiet - - name: Run tests - run: | - if [ -f docker-compose.test.yml ]; then - docker-compose --file docker-compose.test.yml build - docker-compose --file docker-compose.test.yml run sut - else - docker build . --file Dockerfile - fi + - name: Build image + uses: docker/build-push-action@v6 + with: + context: . + push: false + load: true + tags: ${{ env.IMAGE }}:ci push: needs: test @@ -35,22 +40,30 @@ jobs: if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/') steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - - uses: docker/build-push-action@v1 + # Every tag of a release must resolve to one manifest digest, so the + # image is built once and all tags are attached to that single build. + - name: Collect tags and labels + id: meta + uses: docker/metadata-action@v5 + with: + images: ${{ env.IMAGE }} + tags: | + type=ref,event=tag + flavor: | + latest=true + + - name: Log in to Docker Hub + uses: docker/login-action@v3 with: username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - repository: snegov/seafile-client - tag_with_ref: true - add_git_labels: true - push: ${{ startsWith(github.ref, 'refs/tags/') }} + password: ${{ secrets.DOCKER_TOKEN }} - - uses: docker/build-push-action@v1 + - name: Build and push + uses: docker/build-push-action@v6 with: - username: ${{ secrets.DOCKER_USERNAME }} - password: ${{ secrets.DOCKER_PASSWORD }} - repository: snegov/seafile-client - tags: latest - add_git_labels: true - push: ${{ startsWith(github.ref, 'refs/tags/') }} + context: . + push: true + tags: ${{ steps.meta.outputs.tags }} + labels: ${{ steps.meta.outputs.labels }} diff --git a/IMPROVEMENTS.md b/IMPROVEMENTS.md index 960eaf0..7143150 100644 --- a/IMPROVEMENTS.md +++ b/IMPROVEMENTS.md @@ -147,12 +147,15 @@ Acceptance criteria: ### CI and release pipeline -- [ ] Replace `actions/checkout@v2` and `docker/build-push-action@v1`. -- [ ] Set workflow permissions explicitly to `contents: read` by default. -- [ ] Use a scoped Docker Hub access token. -- [ ] Build a release image once and attach all version and `latest` tags to +- [x] Replace `actions/checkout@v2` and `docker/build-push-action@v1`. +- [x] Set workflow permissions explicitly to `contents: read` by default. +- [x] Use a scoped Docker Hub access token. The workflow now reads + `secrets.DOCKER_TOKEN`; the repository secret still has to be created from a + scoped Docker Hub token before the next tag is pushed. +- [x] Build a release image once and attach all version and `latest` tags to the same manifest digest. -- [ ] Add OCI labels, an SBOM, provenance, and image signing. +- [x] Add OCI labels via `docker/metadata-action`. +- [ ] Add an SBOM, provenance, and image signing. - [ ] Add dependency updates for Python, Docker, and GitHub Actions. - [ ] Run dependency and image scans on pull requests and on a schedule.