build(deps): bump actions/download-artifact from 5.0.0 to 8.0.1 #293
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Build and Push Docker Image | |
| on: | |
| push: | |
| branches: [master] | |
| pull_request: | |
| branches: [master] | |
| workflow_dispatch: | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| # PR checks can be superseded. A publishing run must reach its source-head | |
| # checks so an older event can never cancel or overwrite a newer image. | |
| cancel-in-progress: ${{ github.event_name == 'pull_request' }} | |
| env: | |
| IMAGE_NAME: aethersailor/rule-bot | |
| permissions: | |
| contents: read | |
| jobs: | |
| validate: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| - name: Set up Python | |
| uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7 | |
| with: | |
| python-version: "3.14" | |
| cache: pip | |
| - name: Install dependencies | |
| run: pip install -r requirements.txt -r requirements-dev.txt | |
| - name: Run static checks | |
| run: | | |
| python -m compileall -q src tests | |
| ruff check src tests | |
| pip check | |
| - name: Run unit tests | |
| run: python -m unittest discover -s tests -v | |
| - name: Audit Python dependencies | |
| run: pip-audit -r requirements.txt | |
| build-and-push: | |
| needs: validate | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout repository | |
| uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7 | |
| - name: Set up QEMU | |
| uses: docker/setup-qemu-action@96fe6ef7f33517b61c61be40b68a1882f3264fb8 # v4 | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@bb05f3f5519dd87d3ba754cc423b652a5edd6d2c # v4 | |
| - name: Log in to Docker Hub | |
| if: github.event_name != 'pull_request' | |
| uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4 | |
| with: | |
| username: ${{ secrets.DOCKERHUB_USERNAME }} | |
| password: ${{ secrets.DOCKERHUB_TOKEN }} | |
| - name: Verify publish source is current master | |
| if: github.event_name != 'pull_request' | |
| shell: bash | |
| env: | |
| EXPECTED_SHA: ${{ github.sha }} | |
| run: | | |
| set -euo pipefail | |
| test "$GITHUB_REF" = "refs/heads/master" | |
| remote_sha="$(git ls-remote origin refs/heads/master | awk '{print $1}')" | |
| test -n "$remote_sha" | |
| if [[ "$remote_sha" != "$EXPECTED_SHA" ]]; then | |
| echo "refusing to publish stale source: expected $EXPECTED_SHA, master is $remote_sha" >&2 | |
| exit 1 | |
| fi | |
| - name: Extract image metadata | |
| id: meta | |
| uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6 | |
| with: | |
| images: ${{ env.IMAGE_NAME }} | |
| tags: type=raw,value=sha-${{ github.sha }} | |
| labels: | | |
| org.opencontainers.image.title=Rule Bot | |
| org.opencontainers.image.description=Telegram bot for rule management | |
| org.opencontainers.image.vendor=AetherSailor | |
| org.opencontainers.image.revision=${{ github.sha }} | |
| - name: Build and optionally push immutable multi-arch image | |
| uses: docker/build-push-action@53b7df96c91f9c12dcc8a07bcb9ccacbed38856a # v7 | |
| with: | |
| context: . | |
| platforms: linux/amd64,linux/arm64 | |
| push: ${{ github.event_name != 'pull_request' }} | |
| tags: ${{ env.IMAGE_NAME }}:sha-${{ github.sha }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| cache-from: type=gha | |
| cache-to: type=gha,mode=max | |
| provenance: mode=max | |
| sbom: true | |
| - name: Smoke test both published architectures | |
| if: github.event_name != 'pull_request' | |
| shell: bash | |
| env: | |
| CANDIDATE_IMAGE: ${{ env.IMAGE_NAME }}:sha-${{ github.sha }} | |
| run: | | |
| set -euo pipefail | |
| for platform in linux/amd64 linux/arm64; do | |
| docker run --rm --pull always --platform "$platform" \ | |
| --entrypoint python "$CANDIDATE_IMAGE" \ | |
| -c 'import aiohttp, github, maxminddb, telegram; import src.main' | |
| done | |
| - name: Promote current master to latest | |
| if: github.event_name != 'pull_request' | |
| shell: bash | |
| env: | |
| EXPECTED_SHA: ${{ github.sha }} | |
| CANDIDATE_IMAGE: ${{ env.IMAGE_NAME }}:sha-${{ github.sha }} | |
| run: | | |
| set -euo pipefail | |
| remote_sha="$(git ls-remote origin refs/heads/master | awk '{print $1}')" | |
| test -n "$remote_sha" | |
| if [[ "$remote_sha" != "$EXPECTED_SHA" ]]; then | |
| echo "master advanced during build; keeping candidate but not updating latest" >&2 | |
| exit 1 | |
| fi | |
| docker buildx imagetools create \ | |
| --tag "${IMAGE_NAME}:latest" \ | |
| "$CANDIDATE_IMAGE" | |
| - name: Verify latest platforms and source revision | |
| if: github.event_name != 'pull_request' | |
| shell: bash | |
| env: | |
| EXPECTED_SHA: ${{ github.sha }} | |
| run: | | |
| set -euo pipefail | |
| image="${IMAGE_NAME}:latest" | |
| for attempt in {1..12}; do | |
| manifest="$(docker buildx imagetools inspect "$image" \ | |
| --format '{{json .Manifest}}' 2>/dev/null || true)" | |
| if jq -e ' | |
| ([.manifests[]?.platform | select(.os == "linux") | .architecture] | index("amd64")) != null | |
| and | |
| ([.manifests[]?.platform | select(.os == "linux") | .architecture] | index("arm64")) != null | |
| ' <<<"$manifest" >/dev/null 2>&1; then | |
| verified=true | |
| for arch in amd64 arm64; do | |
| digest="$(jq -er --arg arch "$arch" ' | |
| .manifests[] | |
| | select(.platform.os == "linux" and .platform.architecture == $arch) | |
| | .digest | |
| ' <<<"$manifest")" | |
| image_config="$(docker buildx imagetools inspect \ | |
| "${IMAGE_NAME}@${digest}" --format '{{json .Image}}')" | |
| revision="$(jq -r '.config.Labels["org.opencontainers.image.revision"] // empty' \ | |
| <<<"$image_config")" | |
| if [[ "$revision" != "$EXPECTED_SHA" ]]; then | |
| verified=false | |
| break | |
| fi | |
| done | |
| if [[ "$verified" == true ]]; then | |
| exit 0 | |
| fi | |
| fi | |
| sleep 10 | |
| done | |
| echo "latest does not contain verified amd64/arm64 images for $EXPECTED_SHA" >&2 | |
| exit 1 |