From 0f85832aa68e8958c790a5e17e2eb5b7b609b4d4 Mon Sep 17 00:00:00 2001 From: Nick Jordan Date: Tue, 15 Sep 2026 09:36:08 -0400 Subject: [PATCH] fix: back up with `aws s3 sync` instead of a Docker Hub pull MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Every backup since 2026-09-12 has failed, in this repository and in every repository that calls this workflow. The `S3 Backup` step was peter-evans/s3-backup, a Docker action whose Dockerfile starts `FROM minio/mc:RELEASE.2022-05-04T06-07-55Z`. The self-hosted runner rebuilds that image on every run, and Docker Hub now refuses the anonymous pull of that 2022 tag: ERROR: failed to build: failed to solve: minio/mc:RELEASE.2022-05-04T06-07-55Z: pull access denied, repository does not exist or may require authorization: insufficient_scope The build is step 3 of 8, so checkout, credentials and the backup itself all report `skipped` and no object is written. Nothing in any of these repositories changed on 2026-09-12 — the failure arrived without a commit, which is why it went unnoticed for days. Authenticating the pull would fix the symptom and leave the dependency. This removes it: the AWS CLI is already on these runners and already reads the credentials `Configure AWS credentials` exports two steps up, which is how narrative-marketplace-backend's `aws s3 cp` steps work on the same runners. `--delete` reproduces mc's `--remove`; the date-stamped prefix means each run writes into an empty one regardless. The trailing `aws s3 ls --summarize` prints an object count, so a reader can tell from the run log alone that the backup wrote something. That is the check `AUD-OPS-05` asks for and could not previously make without an AWS credential. Fixes narrative-io/mintlify-docs#824 Co-Authored-By: Claude Opus 5 (1M context) --- .github/workflows/backup.yml | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/.github/workflows/backup.yml b/.github/workflows/backup.yml index 0ef5cb3..b47e385 100644 --- a/.github/workflows/backup.yml +++ b/.github/workflows/backup.yml @@ -41,18 +41,24 @@ jobs: with: format: YYYY-MM-DD timezone: UTC + # This step was peter-evans/s3-backup, a Docker action built FROM a 2022 + # minio/mc tag. Around 2026-09-12 Docker Hub stopped serving that tag to + # anonymous pulls, so the self-hosted runner's image build started failing and + # every backup since has died before this step ran at all. The AWS CLI is + # already installed on these runners and already reads the credentials the + # step above exports, so `aws s3 sync` does the same work with no image to + # pull and no third-party action in the path. + # + # `--delete` is the old `--remove`. The old `--overwrite` has no counterpart: + # sync replaces anything whose size or mtime differs, and the target prefix is + # date-stamped, so each run writes into an empty prefix anyway. - name: S3 Backup (${{ steps.get-current-date.outputs.formattedTime }}) - uses: peter-evans/s3-backup@59efd330705d92805a44894668b6cf5c10dc740e # v1.1.1 env: - # All these outputs are supposed to be exposed, but when you run the configure-aws-credentials - # action with additional debug, the only output that is actually exposed is aws-account-id - # https://github.com/aws-actions/configure-aws-credentials/blob/main/action.yml - # ACCESS_KEY_ID: ${{ steps.configure-aws-credentials.outputs.aws-access-key-id }} - # SECRET_ACCESS_KEY: ${{ steps.configure-aws-credentials.outputs.aws-secret-access-key }} - # AWS_SESSION_TOKEN: ${{ steps.configure-aws-credentials.outputs.aws-session-token }} - ACCESS_KEY_ID: ${{ env.AWS_ACCESS_KEY_ID }} - SECRET_ACCESS_KEY: ${{ env.AWS_SECRET_ACCESS_KEY }} - # AWS_REGION already set - MIRROR_TARGET: narrative-backups-prod/github/${{ github.event.repository.name }}/${{ steps.get-current-date.outputs.formattedTime }} - with: - args: --overwrite --remove + # Interpolated into env rather than into the run block, which is what + # zizmor's template-injection rule asks for. + BACKUP_TARGET: s3://narrative-backups-prod/github/${{ github.event.repository.name }}/${{ steps.get-current-date.outputs.formattedTime }} + run: | + aws s3 sync . "$BACKUP_TARGET" --delete --no-progress + # An object count in the log is what makes "this backup actually wrote + # something" checkable from the run alone, with no AWS credential. + aws s3 ls --recursive --summarize "$BACKUP_TARGET/" | tail -n 2