Skip to content
Open
51 changes: 45 additions & 6 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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 }}

Expand All @@ -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
Comment thread
coderabbitai[bot] marked this conversation as resolved.
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
Expand Down Expand Up @@ -181,6 +203,8 @@ jobs:
needs: public
permissions:
contents: read
env:
ASTERA_REGISTRY: ${{ secrets.ASTERA_REGISTRY }}

steps:
- name: Checkout code
Expand All @@ -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:
Expand Down
5 changes: 3 additions & 2 deletions Dockerfile.astera
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
24 changes: 16 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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:

Expand All @@ -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:

Expand All @@ -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" \
.
```

Expand Down