diff --git a/.github/workflows/dstack-ingress-release.yml b/.github/workflows/dstack-ingress-release.yml index 154fc2e..bd298d4 100644 --- a/.github/workflows/dstack-ingress-release.yml +++ b/.github/workflows/dstack-ingress-release.yml @@ -18,8 +18,7 @@ jobs: run: working-directory: custom-domain/dstack-ingress env: - IMAGE_REGISTRY: docker.io - IMAGE_REPOSITORY: ${{ vars.DOCKERHUB_ORG }}/dstack-ingress + IMAGE_REGISTRY: ghcr.io steps: - name: Checkout repository uses: actions/checkout@v4 @@ -49,7 +48,11 @@ jobs: exit 1 ;; esac + # GHCR rejects an uppercase path, and the owner is spelled + # Dstack-TEE, so derive the repository rather than hardcode it. + IMAGE_REPOSITORY=$(printf '%s/dstack-ingress' "${GITHUB_REPOSITORY_OWNER}" | tr '[:upper:]' '[:lower:]') echo "VERSION=${VERSION}" >> "$GITHUB_ENV" + echo "IMAGE_REPOSITORY=${IMAGE_REPOSITORY}" >> "$GITHUB_ENV" echo "IMAGE_REFERENCE=${IMAGE_REGISTRY}/${IMAGE_REPOSITORY}:${VERSION}" >> "$GITHUB_ENV" echo "Parsed version: ${VERSION}" @@ -58,12 +61,12 @@ jobs: sudo apt-get update sudo apt-get install -y skopeo jq - - name: Log in to Docker registry + - name: Log in to the container registry uses: docker/login-action@v3 with: registry: ${{ env.IMAGE_REGISTRY }} - username: ${{ vars.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - name: Build reproducible image and push env: @@ -84,7 +87,7 @@ jobs: - name: Generate artifact attestation uses: actions/attest-build-provenance@v1 with: - subject-name: docker.io/${{ env.IMAGE_REPOSITORY }} + subject-name: ${{ env.IMAGE_REGISTRY }}/${{ env.IMAGE_REPOSITORY }} subject-digest: ${{ steps.capture-digest.outputs.digest }} push-to-registry: true diff --git a/custom-domain/dstack-ingress/README.md b/custom-domain/dstack-ingress/README.md index 5f5d64e..251aebb 100644 --- a/custom-domain/dstack-ingress/README.md +++ b/custom-domain/dstack-ingress/README.md @@ -307,14 +307,18 @@ To disable the built-in evidence endpoint and serve evidence files only through The build script ensures reproducibility via pinned packages, deterministic timestamps, and specific buildkit version. Building the same commit from a clean checkout produces the same image digest; CI runs the same script with `--require-clean`. +### Where the images live + +Releases from 2.6 on are published to `ghcr.io/dstack-tee/dstack-ingress`, using the workflow's own `GITHUB_TOKEN`. 2.5 and earlier are on Docker Hub as `dstacktee/dstack-ingress` and stay there; they are not being mirrored. + ### Image metadata Every image records where it came from, using the standard [OCI image annotation keys](https://github.com/opencontainers/image-spec/blob/main/annotations.md). The values are derived from the git checkout only (commit, the `VERSION` file, the Dockerfile base image), so they do not disturb reproducibility. The same key/value set is written to three places: | Location | How to read it | |---|---| -| Image config labels | `skopeo inspect docker://dstacktee/dstack-ingress: \| jq .Labels` or `docker inspect --format '{{json .Config.Labels}}' ` | -| Image manifest annotations | `skopeo inspect --raw docker://dstacktee/dstack-ingress: \| jq .annotations` | +| Image config labels | `skopeo inspect docker://ghcr.io/dstack-tee/dstack-ingress: \| jq .Labels` or `docker inspect --format '{{json .Config.Labels}}' ` | +| Image manifest annotations | `skopeo inspect --raw docker://ghcr.io/dstack-tee/dstack-ingress: \| jq .annotations` | | `/etc/dstack-ingress/build-info` inside the image | `docker run --rm --entrypoint cat /etc/dstack-ingress/build-info`; also printed as the first line of the container log | | Key | Value | @@ -325,7 +329,7 @@ Every image records where it came from, using the standard [OCI image annotation | `org.opencontainers.image.url` / `.documentation` | This directory / README at that exact commit | | `org.opencontainers.image.base.name` / `.base.digest` | The pinned haproxy base image | -To reproduce a published image, check out the commit from its `revision` label and run `./build-image.sh` on a native Linux amd64 host with Docker Buildx, Skopeo, jq and Git installed; the digest printed at the end must match the registry. Releases are additionally signed with SLSA provenance, verifiable with `gh attestation verify oci://docker.io/dstacktee/dstack-ingress: --owner Dstack-TEE`. +To reproduce a published image, check out the commit from its `revision` label and run `./build-image.sh` on a native Linux amd64 host with Docker Buildx, Skopeo, jq and Git installed; the digest printed at the end must match the registry. Releases are additionally signed with SLSA provenance, verifiable with `gh attestation verify oci://ghcr.io/dstack-tee/dstack-ingress: --owner Dstack-TEE`. ### Releasing @@ -339,7 +343,7 @@ A release is not finished when the image is pushed. The compose files and the sn ```bash # from the repository root - grep -rn 'dstacktee/dstack-ingress:[0-9]' --include='*.yaml' --include='*.md' . + grep -rn 'dstack-ingress:[0-9]' --include='*.yaml' --include='*.md' . ``` Today that is `custom-domain/dstack-ingress/docker-compose.yaml`, `docker-compose.multi.yaml`, three snippets in this README, and `k3s/docker-compose.yaml`. @@ -366,7 +370,7 @@ at the cost of you creating three records by hand (or via a webhook). ```yaml services: dstack-ingress: - image: dstacktee/dstack-ingress: + image: ghcr.io/dstack-tee/dstack-ingress: environment: - CHALLENGE_TYPE=tls-alpn-01 - DOMAIN=app.example.com diff --git a/custom-domain/dstack-ingress/build-image.sh b/custom-domain/dstack-ingress/build-image.sh index f11c799..370851b 100755 --- a/custom-domain/dstack-ingress/build-image.sh +++ b/custom-domain/dstack-ingress/build-image.sh @@ -222,7 +222,7 @@ else echo "" echo " skopeo copy --insecure-policy oci-archive:./oci.tar docker://[:]" echo "" - echo " Pushing image to dstacktee org:" - echo " skopeo copy --insecure-policy oci-archive:./oci.tar docker://dstacktee/dstack-ingress:${VERSION} --authfile ~/.docker/config.json" + echo " Pushing image to the project registry:" + echo " skopeo copy --insecure-policy oci-archive:./oci.tar docker://ghcr.io/dstack-tee/dstack-ingress:${VERSION} --authfile ~/.docker/config.json" fi echo "" diff --git a/custom-domain/dstack-ingress/scripts/tests/e2e-test.sh b/custom-domain/dstack-ingress/scripts/tests/e2e-test.sh index 029eda4..be6f34b 100755 --- a/custom-domain/dstack-ingress/scripts/tests/e2e-test.sh +++ b/custom-domain/dstack-ingress/scripts/tests/e2e-test.sh @@ -12,7 +12,7 @@ # # Optional env vars: # GATEWAY_DOMAIN - dstack gateway domain (default: gateway.dstack-prod5.phala.network) -# IMAGE - dstack-ingress image (default: dstacktee/dstack-ingress:latest) +# IMAGE - dstack-ingress image (default: ghcr.io/dstack-tee/dstack-ingress:latest) # INSTANCE_TYPE - CVM instance type (default: tdx.small) # CERTBOT_STAGING - Use LE staging (default: true) # SKIP_CLEANUP - Don't delete CVM on exit (default: false) @@ -28,7 +28,7 @@ set -uo pipefail : "${CLOUDFLARE_API_TOKEN:?CLOUDFLARE_API_TOKEN is required}" : "${CERTBOT_EMAIL:?CERTBOT_EMAIL is required}" GATEWAY_DOMAIN="${GATEWAY_DOMAIN:-gateway.dstack-prod5.phala.network}" -IMAGE="${IMAGE:-dstacktee/dstack-ingress:latest}" +IMAGE="${IMAGE:-ghcr.io/dstack-tee/dstack-ingress:latest}" INSTANCE_TYPE="${INSTANCE_TYPE:-tdx.small}" CERTBOT_STAGING="${CERTBOT_STAGING:-true}" SKIP_CLEANUP="${SKIP_CLEANUP:-false}"