name: build on: push: branches: [main] tags: ['v*'] env: REGISTRY: harbor.pmagnus.cloud IMAGE: harbor.pmagnus.cloud/btcprice/btcprice jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-python@v5 with: python-version: '3.13' # act_runner's Actions cache endpoint is unreachable from job # containers and adds a five-minute timeout. Dependency install is # fast enough here without setup-python's cache integration. - name: Test run: | python -m pip install -r requirements-dev.txt python -m pytest tests/ - name: Generate immutable tags id: tags shell: bash run: | set -euo pipefail SHA=$(git rev-parse --short HEAD) case "$GITHUB_REF" in refs/tags/v*) VERSION="${GITHUB_REF_NAME#v}" ;; *) VERSION="main-$(date -u +%Y%m%d%H%M%S)" ;; esac echo "sha=$SHA" >> "$GITHUB_OUTPUT" echo "primary=$IMAGE:$VERSION" >> "$GITHUB_OUTPUT" echo "qualified=$IMAGE:$VERSION-$SHA" >> "$GITHUB_OUTPUT" # anvil is not a NetBird peer. Host networking makes BuildKit use the # runner host's pinned Harbor address; keep this until anvil is enrolled. - uses: docker/setup-buildx-action@v3 with: driver-opts: network=host - uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ secrets.HARBOR_ROBOT_USER }} password: ${{ secrets.HARBOR_ROBOT_TOKEN }} - uses: docker/build-push-action@v6 with: context: . platforms: linux/amd64 push: true # Harbor blocks manifest reads until Trivy has approved the image. # Push one tag first, then add the companion tag after the scan. tags: ${{ steps.tags.outputs.primary }} build-args: | BUILD_SHA=${{ steps.tags.outputs.sha }} cache-from: type=registry,ref=${{ env.IMAGE }}:buildcache cache-to: type=registry,ref=${{ env.IMAGE }}:buildcache,mode=max # The primary tag is already pushed and deployable by the time this runs: # the image policy selects `main-`, so a failure here costs the # SHA audit tag, not the rollout. - name: Wait for Harbor policy, then add SHA tag shell: bash env: PRIMARY: ${{ steps.tags.outputs.primary }} QUALIFIED: ${{ steps.tags.outputs.qualified }} run: | # Harbor's vulnerability policy blocks manifest reads while Trivy's scan # is still Running, and `imagetools create` copies the manifest. Retry # that copy itself rather than an `inspect` probe: a probe that passes is # no guarantee the copy will, and under the default `bash -e` the first # blocked copy aborted the step before its retries could run. for attempt in $(seq 1 60); do if docker buildx imagetools create --tag "$QUALIFIED" "$PRIMARY"; then echo "tagged $QUALIFIED on attempt $attempt" exit 0 fi echo "waiting for Harbor scan/pull policy ($attempt/60)" sleep 10 done echo "Harbor did not approve $PRIMARY within 10 minutes" >&2 exit 1 - name: Summary run: echo "pushed ${{ steps.tags.outputs.primary }} and ${{ steps.tags.outputs.qualified }}"