diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index c799383f..a4b757b8 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -17,11 +17,16 @@ env: # public registry path. PUBLIC_REGISTRY: ${{ vars.SAMPLEWORKS_PUBLIC_REGISTRY || 'docker.io' }} PUBLIC_IMAGE_NAME: ${{ vars.SAMPLEWORKS_PUBLIC_IMAGE || 'diffuseproject/pixi-with-checkpoints' }} - CHECKPOINTS_SOURCE_IMAGE: ${{ vars.SAMPLEWORKS_CHECKPOINTS_SOURCE_IMAGE || 'harbor.astera.sh/library/sampleworks-checkpoints@sha256:ff1dd2b42c3afd593e034cf81df1bf1862c27ae491f46cc10e105629f1102781' }} CHECKPOINTS_DOCKERHUB_IMAGE: ${{ vars.SAMPLEWORKS_CHECKPOINTS_DOCKERHUB_IMAGE || 'docker.io/diffuseproject/sampleworks-checkpoints:latest' }} CUDA_BASE_IMAGE: ${{ vars.SAMPLEWORKS_CUDA_BASE_IMAGE || 'nvidia/cuda:12.4.1-devel-ubuntu22.04@sha256:da6791294b0b04d7e65d87b7451d6f2390b4d36225ab0701ee7dfec5769829f5' }} - ASTERA_REGISTRY: harbor.astera.sh + # Only the registry HOST is secret (repo secret ASTERA_REGISTRY); image paths + # and digests stay plain variables. This repo is public, so its Actions logs + # are public and only secrets are masked. Masking is substring-based, so + # keeping the secret to the bare host masks it inside every longer image ref + # while leaving digests readable when a build fails. It is set per job because + # workflow-level env cannot read the secrets context. + CHECKPOINTS_SOURCE_PATH: ${{ vars.SAMPLEWORKS_CHECKPOINTS_SOURCE_PATH }} ASTERA_IMAGE_NAME: library/pixi-with-checkpoints SKOPEO_IMAGE: quay.io/skopeo/stable@sha256:c7d3c512612f52805023cd38351081dad7e2729fc13d14b701e47c7c8bdd6615 @@ -33,6 +38,9 @@ jobs: runs-on: diffuse-sh-builder permissions: contents: read + env: + ASTERA_REGISTRY: ${{ secrets.ASTERA_REGISTRY }} + CHECKPOINTS_SOURCE_IMAGE: ${{ secrets.ASTERA_REGISTRY }}/${{ vars.SAMPLEWORKS_CHECKPOINTS_SOURCE_PATH }} outputs: checkpoints_digest: ${{ steps.verify_checkpoints.outputs.checkpoints_digest }} @@ -44,12 +52,26 @@ jobs: DOCKERHUB_USERNAME: ${{ secrets.DOCKERHUB_USERNAME }} DOCKERHUB_TOKEN: ${{ secrets.DOCKERHUB_TOKEN }} run: | - if [ -z "${CHECKPOINTS_SOURCE_IMAGE}" ] || [ -z "${CHECKPOINTS_DOCKERHUB_IMAGE}" ]; then - echo "Checkpoint source and Docker Hub destination image refs must be set." + # Check the parts, not the composed ref: an unset ASTERA_REGISTRY + # still yields a non-empty "/library/...@sha256:..." that would pass + # both the emptiness and the digest-pinned checks below. + if [ -z "${ASTERA_REGISTRY}" ] || [ -z "${CHECKPOINTS_SOURCE_PATH}" ]; then + echo "ASTERA_REGISTRY secret and SAMPLEWORKS_CHECKPOINTS_SOURCE_PATH variable must be set." exit 1 fi - if [ "${CHECKPOINTS_SOURCE_IMAGE}" = "${CHECKPOINTS_SOURCE_IMAGE%@*}" ]; then - echo "CHECKPOINTS_SOURCE_IMAGE must be digest-pinned." + # skopeo receives HARBOR_USERNAME/PASSWORD as --src-creds for this + # host, so a public registry here would leak them to a third party. + case "${ASTERA_REGISTRY}" in + docker.io|index.docker.io|registry-1.docker.io|"${PUBLIC_REGISTRY}") + echo "ASTERA_REGISTRY must be the internal registry, not a public one." + exit 1 ;; + esac + if [ -z "${CHECKPOINTS_DOCKERHUB_IMAGE}" ]; then + echo "Docker Hub destination image ref must be set." + exit 1 + fi + if [ "${CHECKPOINTS_SOURCE_PATH}" = "${CHECKPOINTS_SOURCE_PATH%@*}" ]; then + echo "SAMPLEWORKS_CHECKPOINTS_SOURCE_PATH must be digest-pinned." exit 1 fi if [ -z "${HARBOR_USERNAME}" ] || [ -z "${HARBOR_PASSWORD}" ]; then @@ -181,6 +203,8 @@ jobs: needs: public permissions: contents: read + env: + ASTERA_REGISTRY: ${{ secrets.ASTERA_REGISTRY }} steps: - name: Checkout code @@ -191,6 +215,21 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@d7f5e7f509e45cec5c76c4d5afdd7de93d0b3df5 # v4 + - name: Validate Astera registry configured + run: | + # The Harbor credentials are sent to whatever host this names, so an + # empty value (login-action then defaults to Docker Hub) or a public + # registry would hand them to a third party. Fail fast on both. + if [ -z "${ASTERA_REGISTRY}" ]; then + echo "ASTERA_REGISTRY repository secret must be set." + exit 1 + fi + case "${ASTERA_REGISTRY}" in + docker.io|index.docker.io|registry-1.docker.io|"${PUBLIC_REGISTRY}") + echo "ASTERA_REGISTRY must be the internal registry, not a public one." + exit 1 ;; + esac + - name: Login to Harbor uses: docker/login-action@650006c6eb7dba73a995cc03b0b2d7f5ca915bee # v4 with: diff --git a/Dockerfile.astera b/Dockerfile.astera index c159a837..c5da3c29 100644 --- a/Dockerfile.astera +++ b/Dockerfile.astera @@ -5,11 +5,12 @@ # private image adds Astera-only tooling (EXT, rsync, editor conveniences) and is # pushed to Harbor. It intentionally does not duplicate the public build. # -# Build locally: +# Build locally (ASTERA_REGISTRY = the internal registry host, same value as +# the CI repository secret): # docker build --platform linux/amd64 \ # -f Dockerfile.astera \ # --build-arg PIXI_WITH_CHECKPOINTS_IMAGE=diffuseproject/pixi-with-checkpoints:local \ -# -t harbor.astera.sh/library/pixi-with-checkpoints:local \ +# -t "${ASTERA_REGISTRY}/library/pixi-with-checkpoints:local" \ # . ARG PIXI_WITH_CHECKPOINTS_IMAGE diff --git a/README.md b/README.md index 7b901e09..cb529354 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ Currently, each structure prediction model has a different implementation, requi ## Citation If you use **sampleworks**, please cite: - + Chrispens, K., Collins, M., Mai, D., Wankowicz, S. A., Fraser, J. S., & van den Bedem, H. (2026). sampleworks: A Modular Platform for Experimentally Guided Biomolecular Ensemble Generation. https://doi.org/10.82153/jkxj-tw08 ## Installation @@ -167,10 +167,10 @@ setting equivalent local paths for `DATA_DIR`, `PROTEINS_CSV`, `RESULTS_DIR`, `MSA_CACHE_DIR`, and model checkpoints. Start an 8-GPU ACTL machine named `sampleworks` with the private Astera -`pixi-with-checkpoints:sampleworks` image and the shared data volume mounted: +`sampleworks` image alias and the shared data volume mounted: ```bash -actl pod up sampleworks --profile 8x --image harbor.astera.sh/library/pixi-with-checkpoints:sampleworks --storage shared --pvc-size 200Gi --mount diffuse-shared --yes +actl pod up sampleworks --profile 8x --image sampleworks --storage shared --pvc-size 200Gi --mount diffuse-shared --yes ``` Keep that terminal open; it maintains sync and SSH. From another terminal: @@ -299,8 +299,7 @@ Image names: | Purpose | Image | |---|---| | Public Sampleworks runtime | `diffuseproject/pixi-with-checkpoints` | -| Astera/ACTL runtime | `harbor.astera.sh/library/pixi-with-checkpoints` | -| ACTL scientist tag | `harbor.astera.sh/library/pixi-with-checkpoints:sampleworks` | +| Astera/ACTL runtime | `sampleworks` alias; run `actl pod images` for the resolved, digest-pinned ref | CI publishes these tags: @@ -319,9 +318,16 @@ CI configuration variables: |---|---| | `SAMPLEWORKS_PUBLIC_REGISTRY` | Public registry host; defaults to `docker.io` | | `SAMPLEWORKS_PUBLIC_IMAGE` | Public image path; defaults to `diffuseproject/pixi-with-checkpoints` | -| `SAMPLEWORKS_CHECKPOINTS_SOURCE_IMAGE` | Optional private/source checkpoint image that CI mirrors to Docker Hub; defaults to the current digest-pinned Harbor image | | `SAMPLEWORKS_CHECKPOINTS_DOCKERHUB_IMAGE` | Optional public Docker Hub checkpoint mirror destination tag; defaults to `docker.io/diffuseproject/sampleworks-checkpoints:latest` | | `SAMPLEWORKS_CUDA_BASE_IMAGE` | Optional digest-pinned CUDA base override | +| `SAMPLEWORKS_CHECKPOINTS_SOURCE_PATH` | **Required.** Digest-pinned path of the private checkpoint image CI mirrors to Docker Hub, without the registry host (e.g. `library/foo@sha256:...`) | + +One CI secret, `ASTERA_REGISTRY`, holds the internal registry host. It is a +secret rather than a variable because this repo is public, which makes its +Actions logs public, and only secrets are masked there. Log masking is +substring-based, so keeping the secret to the bare host masks it inside every +longer image ref while leaving paths and digests readable when a build fails. +The CI jobs fail fast when it is unset. Build the public image locally: @@ -332,13 +338,15 @@ docker build --platform linux/amd64 \ . ``` -Build the Astera overlay locally after a public image is available: +Build the Astera overlay locally after a public image is available. Set +`ASTERA_REGISTRY` to the internal registry host (same value as the CI +repository secret): ```bash docker build --platform linux/amd64 \ -f Dockerfile.astera \ --build-arg PIXI_WITH_CHECKPOINTS_IMAGE=diffuseproject/pixi-with-checkpoints:local \ - -t harbor.astera.sh/library/pixi-with-checkpoints:local \ + -t "${ASTERA_REGISTRY}/library/pixi-with-checkpoints:local" \ . ```