diff --git a/.github/workflows/build-images.yml b/.github/workflows/build-images.yml index 544285b..b51cebc 100644 --- a/.github/workflows/build-images.yml +++ b/.github/workflows/build-images.yml @@ -1,16 +1,18 @@ name: Build & push md-workflows images -# Builds the three-stage image chain on the self-hosted diffuse builder and pushes to Harbor. +# Builds the three-stage image chain and publishes it. The ChimeraX-dependent base/gromacs +# builds run on GitHub-hosted runners (open egress reaches cgl.ucsf.edu + Docker Hub) and push +# the intermediates to a PRIVATE Docker Hub repo. Only the final actl assembly runs on the +# self-hosted diffuse builder, because only it pushes to Harbor (reachable over Tailscale). # -# Security: this workflow has NO pull_request trigger, so fork PRs can never reach the -# self-hosted runner or the Harbor credentials. Heavy builds run only on push to `astera` -# (path-filtered) and manual dispatch. Credentials live in the `harbor` GitHub Environment, -# which must be restricted to the `astera` deployment branch; the `diffuse-sh-builder` runner -# should sit in a runner group scoped to this repo. See the runbook in the PR description. +# Security: this workflow has NO pull_request trigger, so fork PRs can never reach the runners +# or the publish credentials. Heavy builds run only on push to `astera` (path-filtered) and +# manual dispatch. Credentials live in the `harbor` GitHub Environment (branch-restricted to +# `astera`, with required reviewers if configured). # -# NOTE: runs-on matches only the unique custom label `diffuse-sh-builder` (not `self-hosted`), -# because that runner was registered with --no-default-labels and so lacks the implicit -# `self-hosted` label. The custom label alone unambiguously targets it. +# NOTE: the actl job's runs-on matches only the unique custom label `diffuse-sh-builder` (not +# `self-hosted`), because that runner was registered with --no-default-labels and so lacks the +# implicit `self-hosted` label. The custom label alone unambiguously targets it. on: push: branches: [astera] @@ -31,10 +33,14 @@ concurrency: cancel-in-progress: true env: - REGISTRY: harbor.astera.sh - # base + gromacs (bake the non-redistributable ChimeraX) live in the proprietary project, - # distinguished by a stage tag prefix. The final consumable actl image lands in library. - PROPRIETARY_IMAGE: harbor.astera.sh/diffuse-proprietary/md-workflows + HARBOR_REGISTRY: harbor.astera.sh + # Docker Hub registry host for login + image refs. NOTE: it is `docker.io`, NOT the website + # `hub.docker.com` (that's the UI, not a registry endpoint). + DOCKERHUB_REGISTRY: docker.io + # base + gromacs bake the non-redistributable ChimeraX, so they publish to the PRIVATE Docker + # Hub repo (not public), distinguished by a stage tag prefix. The final consumable actl image + # lands in the Harbor library project. + DOCKERHUB_IMAGE: docker.io/diffuseproject/md LIBRARY_IMAGE: harbor.astera.sh/library/md-workflows jobs: @@ -62,19 +68,23 @@ jobs: base: name: Build base needs: version - runs-on: [diffuse-sh-builder] + runs-on: ubuntu-latest environment: harbor outputs: digest: ${{ steps.build.outputs.digest }} steps: - uses: actions/checkout@v4 + - name: Free disk space + run: | + sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/lib/android /opt/hostedtoolcache/CodeQL || true + docker system prune -af || true - uses: docker/setup-buildx-action@v3 - - name: Login to Harbor + - name: Login to Docker Hub uses: docker/login-action@v3 with: - registry: ${{ env.REGISTRY }} - username: ${{ secrets.HARBOR_USERNAME }} - password: ${{ secrets.HARBOR_PASSWORD }} + registry: ${{ env.DOCKERHUB_REGISTRY }} + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} - id: build uses: docker/build-push-action@v6 with: @@ -84,29 +94,33 @@ jobs: push: true provenance: false tags: | - ${{ env.PROPRIETARY_IMAGE }}:base-${{ needs.version.outputs.semver }} - ${{ env.PROPRIETARY_IMAGE }}:base-${{ needs.version.outputs.build }} - ${{ env.PROPRIETARY_IMAGE }}:base-${{ needs.version.outputs.sha }} - ${{ env.PROPRIETARY_IMAGE }}:base - cache-from: type=registry,ref=${{ env.PROPRIETARY_IMAGE }}:base-buildcache - cache-to: type=registry,ref=${{ env.PROPRIETARY_IMAGE }}:base-buildcache,mode=max + ${{ env.DOCKERHUB_IMAGE }}:base-${{ needs.version.outputs.semver }} + ${{ env.DOCKERHUB_IMAGE }}:base-${{ needs.version.outputs.build }} + ${{ env.DOCKERHUB_IMAGE }}:base-${{ needs.version.outputs.sha }} + ${{ env.DOCKERHUB_IMAGE }}:base + cache-from: type=registry,ref=${{ env.DOCKERHUB_IMAGE }}:base-buildcache + cache-to: type=registry,ref=${{ env.DOCKERHUB_IMAGE }}:base-buildcache,mode=max gromacs: name: Build gromacs needs: [version, base] - runs-on: [diffuse-sh-builder] + runs-on: ubuntu-latest environment: harbor outputs: digest: ${{ steps.build.outputs.digest }} steps: - uses: actions/checkout@v4 + - name: Free disk space + run: | + sudo rm -rf /usr/share/dotnet /opt/ghc /usr/local/lib/android /opt/hostedtoolcache/CodeQL || true + docker system prune -af || true - uses: docker/setup-buildx-action@v3 - - name: Login to Harbor + - name: Login to Docker Hub uses: docker/login-action@v3 with: - registry: ${{ env.REGISTRY }} - username: ${{ secrets.HARBOR_USERNAME }} - password: ${{ secrets.HARBOR_PASSWORD }} + registry: ${{ env.DOCKERHUB_REGISTRY }} + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} - id: build uses: docker/build-push-action@v6 with: @@ -116,14 +130,14 @@ jobs: push: true provenance: false build-args: | - BASE_IMAGE=${{ env.PROPRIETARY_IMAGE }}@${{ needs.base.outputs.digest }} + BASE_IMAGE=${{ env.DOCKERHUB_IMAGE }}@${{ needs.base.outputs.digest }} tags: | - ${{ env.PROPRIETARY_IMAGE }}:gromacs-${{ needs.version.outputs.semver }} - ${{ env.PROPRIETARY_IMAGE }}:gromacs-${{ needs.version.outputs.build }} - ${{ env.PROPRIETARY_IMAGE }}:gromacs-${{ needs.version.outputs.sha }} - ${{ env.PROPRIETARY_IMAGE }}:gromacs - cache-from: type=registry,ref=${{ env.PROPRIETARY_IMAGE }}:gromacs-buildcache - cache-to: type=registry,ref=${{ env.PROPRIETARY_IMAGE }}:gromacs-buildcache,mode=max + ${{ env.DOCKERHUB_IMAGE }}:gromacs-${{ needs.version.outputs.semver }} + ${{ env.DOCKERHUB_IMAGE }}:gromacs-${{ needs.version.outputs.build }} + ${{ env.DOCKERHUB_IMAGE }}:gromacs-${{ needs.version.outputs.sha }} + ${{ env.DOCKERHUB_IMAGE }}:gromacs + cache-from: type=registry,ref=${{ env.DOCKERHUB_IMAGE }}:gromacs-buildcache + cache-to: type=registry,ref=${{ env.DOCKERHUB_IMAGE }}:gromacs-buildcache,mode=max actl: name: Build actl (consumable) @@ -135,10 +149,16 @@ jobs: steps: - uses: actions/checkout@v4 - uses: docker/setup-buildx-action@v3 - - name: Login to Harbor + - name: Login to Docker Hub (pull private gromacs intermediate) + uses: docker/login-action@v3 + with: + registry: ${{ env.DOCKERHUB_REGISTRY }} + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Login to Harbor (push final image) uses: docker/login-action@v3 with: - registry: ${{ env.REGISTRY }} + registry: ${{ env.HARBOR_REGISTRY }} username: ${{ secrets.HARBOR_USERNAME }} password: ${{ secrets.HARBOR_PASSWORD }} - id: build @@ -150,7 +170,7 @@ jobs: push: true provenance: false build-args: | - GROMACS_IMAGE=${{ env.PROPRIETARY_IMAGE }}@${{ needs.gromacs.outputs.digest }} + GROMACS_IMAGE=${{ env.DOCKERHUB_IMAGE }}@${{ needs.gromacs.outputs.digest }} tags: | ${{ env.LIBRARY_IMAGE }}:${{ needs.version.outputs.semver }} ${{ env.LIBRARY_IMAGE }}:${{ needs.version.outputs.build }}