diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6dcaece..8a89691 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,3 +1,7 @@ +# Release workflow: git tag v* builds sequencer tarballs, CM images, and pushes +# watchdog OCI images to ghcr.io + docker.io (requires DOCKERHUB_USERNAME / +# DOCKERHUB_TOKEN repo secrets, same as cartesi/cli). + name: Release on: @@ -18,6 +22,7 @@ on: permissions: contents: write + packages: write jobs: build-sequencer: @@ -161,23 +166,8 @@ jobs: path: dist/canonical-machine-image-*.tar.gz build-watchdog-image: - name: Build watchdog image (${{ matrix.arch }}) - # arm64 must build on an arm64 host — docker build --platform linux/arm64 on - # ubuntu-latest (amd64) without QEMU hits "exec format error" in RUN steps. - runs-on: ${{ matrix.runs_on }} - strategy: - fail-fast: false - matrix: - include: - - arch: amd64 - platform: linux/amd64 - runs_on: ubuntu-latest - deb_sha_env: CARTESI_MACHINE_SHA256_AMD64 - - arch: arm64 - platform: linux/arm64 - runs_on: ubuntu-24.04-arm - deb_sha_env: CARTESI_MACHINE_SHA256_ARM64 - + name: Build and push watchdog image + runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v5 @@ -185,34 +175,43 @@ jobs: - name: Load toolchain pins uses: ./.github/actions/load-toolchain-pins + - name: Set up QEMU + uses: docker/setup-qemu-action@v4 + - name: Set up Docker Buildx uses: docker/setup-buildx-action@v4 - - name: Build and export watchdog image - env: - TAG: ${{ inputs.tag || github.ref_name }} - DEB_SHA_ENV: ${{ matrix.deb_sha_env }} - run: | - set -euo pipefail - DEB_SHA="${!DEB_SHA_ENV}" - image="sequencer-watchdog:${TAG}" - docker build \ - --platform "${{ matrix.platform }}" \ - --build-arg "RELEASE_TAG=${TAG}" \ - --build-arg "GIT_COMMIT=${GITHUB_SHA}" \ - --build-arg "CARTESI_MACHINE_VERSION=${CARTESI_MACHINE_VERSION}" \ - --build-arg "CARTESI_MACHINE_DEB_SHA256=${DEB_SHA}" \ - -f watchdog/Dockerfile \ - -t "${image}" \ - . - mkdir -p dist - docker save "${image}" | gzip -9 > "dist/sequencer-watchdog-${TAG}-linux-${{ matrix.arch }}.tar.gz" + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} - - name: Upload artifact - uses: actions/upload-artifact@v6 + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + + - name: Build and push watchdog image + uses: docker/build-push-action@v6 with: - name: watchdog-image-linux-${{ matrix.arch }} - path: dist/sequencer-watchdog-*.tar.gz + context: . + file: watchdog/Dockerfile + platforms: linux/amd64,linux/arm64 + push: true + tags: | + ghcr.io/cartesi/sequencer-watchdog:${{ inputs.tag || github.ref_name }} + docker.io/cartesi/sequencer-watchdog:${{ inputs.tag || github.ref_name }} + build-args: | + RELEASE_TAG=${{ inputs.tag || github.ref_name }} + GIT_COMMIT=${{ github.sha }} + CARTESI_MACHINE_VERSION=${{ env.CARTESI_MACHINE_VERSION }} + CARTESI_MACHINE_DEB_SHA256_AMD64=${{ env.CARTESI_MACHINE_SHA256_AMD64 }} + CARTESI_MACHINE_DEB_SHA256_ARM64=${{ env.CARTESI_MACHINE_SHA256_ARM64 }} + cache-from: type=gha + cache-to: type=gha,mode=max publish: name: Publish GitHub Release diff --git a/docs/watchdog/operator-deployment.md b/docs/watchdog/operator-deployment.md index 6116eed..59ed1bb 100644 --- a/docs/watchdog/operator-deployment.md +++ b/docs/watchdog/operator-deployment.md @@ -46,12 +46,21 @@ curl -sS -o /dev/null -w "%{http_code}\n" "$WATCHDOG_SEQUENCER_URL/finalized_sta # expect 200 when a finalized snapshot exists (404 = not promoted yet or wrong host) ``` -### 2. Watchdog runtime (release bundle or local build) +### 2. Watchdog runtime (release image or local build) -**Production (recommended):** use the **release bundle** for tag `vX` — same +**Production (recommended):** pull the **release container image** for tag `vX` — same git tag as the sequencer binary and `canonical-machine-image-*-vX.tar.gz`. -Load `sequencer-watchdog-vX-linux-.tar.gz` (`docker load`) and verify -alignment via `release-manifest-vX.json` and `/opt/watchdog/RELEASE.json` + +**Container images (preferred for Dockerfile / Fly.io assembly):** + +| Registry | Image | +|----------|-------| +| GHCR | `ghcr.io/cartesi/sequencer-watchdog:vX` | +| Docker Hub | `docker.io/cartesi/sequencer-watchdog:vX` | + +Multi-arch manifest (`amd64` + `arm64`). + +Verify alignment via `release-manifest-vX.json` and `/opt/watchdog/RELEASE.json` inside the image. Toolchain pins live in [`toolchain-pins.env`](../../toolchain-pins.env). `cartesi-machine` in the watchdog image **must** match @@ -59,10 +68,38 @@ inside the image. Toolchain pins live in [`toolchain-pins.env`](../../toolchain- (the emulator that built the CM image tarball). Mismatch causes load failures or false `state_mismatch`. -Release image quick run: +**Compose a custom image (e.g. Fly.io rootfs)** — base on `debian:trixie-slim`, +install the same runtime packages as the release image, then copy from the +published watchdog image: + +```dockerfile +FROM debian:trixie-slim + +RUN apt-get update && apt-get install -y --no-install-recommends \ + lua5.4 libcurl4 libslirp0 libgomp1 ca-certificates util-linux \ + && rm -rf /var/lib/apt/lists/* + +COPY --from=ghcr.io/cartesi/sequencer-watchdog:vX /opt/watchdog /opt/watchdog +COPY --from=ghcr.io/cartesi/sequencer-watchdog:vX /usr/local/bin/sequencer-watchdog /usr/local/bin/sequencer-watchdog +COPY --from=ghcr.io/cartesi/sequencer-watchdog:vX /usr/local/bin/cartesi-machine /usr/local/bin/cartesi-machine +COPY --from=ghcr.io/cartesi/sequencer-watchdog:vX /usr/local/lib/ /usr/local/lib/ +COPY --from=ghcr.io/cartesi/sequencer-watchdog:vX /usr/local/lib/lua/ /usr/local/lib/lua/ +COPY --from=ghcr.io/cartesi/sequencer-watchdog:vX /usr/local/share/lua/ /usr/local/share/lua/ +COPY --from=ghcr.io/cartesi/sequencer-watchdog:vX /usr/local/share/cartesi-machine/ /usr/local/share/cartesi-machine/ + +ENV WATCHDOG_LUA_DEPS=/opt/watchdog/lib \ + LUA_PATH="/opt/watchdog/lua/?.lua;/opt/watchdog/lua/?/init.lua;/usr/local/share/lua/5.4/?.lua;/usr/local/share/lua/5.4/?/init.lua;;" \ + LUA_CPATH="/opt/watchdog/lib/?.so;/usr/local/lib/lua/5.4/?.so;;" \ + LD_LIBRARY_PATH="/usr/local/lib" \ + PATH="/usr/local/share/cartesi-machine:${PATH}" + +ENTRYPOINT ["/usr/local/bin/sequencer-watchdog"] +``` + +**Run from the published image:** ```bash -docker load < sequencer-watchdog-vX-linux-amd64.tar.gz +docker pull ghcr.io/cartesi/sequencer-watchdog:vX docker run --rm \ -e WATCHDOG_SEQUENCER_URL="https://" \ @@ -73,13 +110,13 @@ docker run --rm \ -e WATCHDOG_CM_SNAPSHOT_SAFE_BLOCK="" \ -v /var/lib/watchdog/state:/watchdog-state \ -v /var/lib/watchdog/cm-bootstrap:/cm-bootstrap:ro \ - sequencer-watchdog:vX init + ghcr.io/cartesi/sequencer-watchdog:vX init docker run --rm \ -e WATCHDOG_L1_RPC_URL="https://" \ -e WATCHDOG_STATE_DIR=/watchdog-state \ -v /var/lib/watchdog/state:/watchdog-state \ - sequencer-watchdog:vX tick + ghcr.io/cartesi/sequencer-watchdog:vX tick ``` **Local / dev build:** diff --git a/docs/watchdog/staging-drills.md b/docs/watchdog/staging-drills.md index 1db2288..fff4d80 100644 --- a/docs/watchdog/staging-drills.md +++ b/docs/watchdog/staging-drills.md @@ -9,7 +9,7 @@ This document covers staging and manual verification beyond the devnet tutorial. ## Prerequisites -- **Release bundle (staging/production):** deploy `sequencer-watchdog-vX` and `canonical-machine-image-*-vX` from the same git tag; toolchain pins live in [`toolchain-pins.env`](../../toolchain-pins.env). +- **Release (staging/production):** pull `ghcr.io/cartesi/sequencer-watchdog:vX` and deploy `canonical-machine-image-*-vX` from the same git tag; toolchain pins live in [`toolchain-pins.env`](../../toolchain-pins.env). - Built canonical machine image: `just canonical-build-machine-image` - `cartesi-machine`, `lua`, and `curl` on PATH - `just watchdog-lua-deps` — builds `lcurl.so` into `.deps/lua` (libcurl + Lua headers on host) diff --git a/examples/canonical-app/justfile b/examples/canonical-app/justfile index 5c5ecb6..74310db 100644 --- a/examples/canonical-app/justfile +++ b/examples/canonical-app/justfile @@ -1,10 +1,12 @@ set shell := ["bash", "-euo", "pipefail", "-c"] +pins := "../../toolchain-pins.env" +cartesi_machine_version := `sed -n 's/^CARTESI_MACHINE_VERSION=v//p' ../../toolchain-pins.env` +linux_image_release := `grep '^CARTESI_LINUX_IMAGE_RELEASE=' ../../toolchain-pins.env | cut -d= -f2` +linux_kernel_filename := `grep '^CARTESI_LINUX_KERNEL_FILENAME=' ../../toolchain-pins.env | cut -d= -f2` + out_dir := "out" source_date_epoch := "0" -cartesi_machine_version := "0.20.0" -linux_image_release := "v0.20.0" -linux_kernel_filename := "linux-6.5.13-ctsi-1-v0.20.0.bin" linux_kernel := out_dir + "/linux.bin" linux_kernel_sha512 := linux_kernel + ".sha512" linux_kernel_url := "https://github.com/cartesi/machine-linux-image/releases/download/" + linux_image_release + "/" + linux_kernel_filename diff --git a/scripts/ci-watchdog-docker-smoke.sh b/scripts/ci-watchdog-docker-smoke.sh index 49ddacf..a1ff03c 100755 --- a/scripts/ci-watchdog-docker-smoke.sh +++ b/scripts/ci-watchdog-docker-smoke.sh @@ -9,32 +9,13 @@ cd "${root}" source toolchain-pins.env image="sequencer-watchdog:ci-smoke" -if command -v dpkg >/dev/null 2>&1; then - arch="$(dpkg --print-architecture)" -else - case "$(uname -m)" in - x86_64) arch=amd64 ;; - aarch64 | arm64) arch=arm64 ;; - *) - echo "unsupported arch for watchdog docker smoke: $(uname -m)" >&2 - exit 1 - ;; - esac -fi -case "${arch}" in - amd64) deb_sha="${CARTESI_MACHINE_SHA256_AMD64}" ;; - arm64) deb_sha="${CARTESI_MACHINE_SHA256_ARM64}" ;; - *) - echo "unsupported arch for watchdog docker smoke: ${arch}" >&2 - exit 1 - ;; -esac docker build \ --build-arg "RELEASE_TAG=ci-smoke" \ --build-arg "GIT_COMMIT=local" \ --build-arg "CARTESI_MACHINE_VERSION=${CARTESI_MACHINE_VERSION}" \ - --build-arg "CARTESI_MACHINE_DEB_SHA256=${deb_sha}" \ + --build-arg "CARTESI_MACHINE_DEB_SHA256_AMD64=${CARTESI_MACHINE_SHA256_AMD64}" \ + --build-arg "CARTESI_MACHINE_DEB_SHA256_ARM64=${CARTESI_MACHINE_SHA256_ARM64}" \ -f watchdog/Dockerfile \ -t "${image}" \ . diff --git a/scripts/generate-release-manifest.sh b/scripts/generate-release-manifest.sh index 5bfb75f..5073d74 100755 --- a/scripts/generate-release-manifest.sh +++ b/scripts/generate-release-manifest.sh @@ -58,8 +58,8 @@ artifacts_json="$(cat <&2 + errors=$((errors + 1)) +} + rust_channel="$( grep -E '^\s*channel\s*=' "${root}/rust-toolchain.toml" \ | head -1 \ | sed -E 's/.*=[[:space:]]*"([^"]+)".*/\1/' )" if [[ "${rust_channel}" != "${RUST_TOOLCHAIN}" ]]; then - echo "rust-toolchain.toml channel=${rust_channel} != RUST_TOOLCHAIN=${RUST_TOOLCHAIN}" >&2 - errors=$((errors + 1)) + fail "rust-toolchain.toml channel=${rust_channel} != RUST_TOOLCHAIN=${RUST_TOOLCHAIN}" +fi + +if [[ "${CARTESI_LINUX_IMAGE_RELEASE}" != "${CARTESI_MACHINE_VERSION}" ]]; then + fail "CARTESI_LINUX_IMAGE_RELEASE=${CARTESI_LINUX_IMAGE_RELEASE} != CARTESI_MACHINE_VERSION=${CARTESI_MACHINE_VERSION}" +fi + +expected_assert_version="${CARTESI_MACHINE_VERSION#v}" +if [[ "${CARTESI_LINUX_KERNEL_FILENAME}" != *"${CARTESI_LINUX_IMAGE_RELEASE}"* ]]; then + fail "CARTESI_LINUX_KERNEL_FILENAME=${CARTESI_LINUX_KERNEL_FILENAME} does not include ${CARTESI_LINUX_IMAGE_RELEASE}" +fi + +canonical_just="${root}/examples/canonical-app/justfile" +if [[ ! -f "${canonical_just}" ]]; then + fail "missing ${canonical_just}" +else + resolved_assert_version="$( + sed -n 's/^CARTESI_MACHINE_VERSION=v//p' "${pins}" + )" + resolved_linux_release="$( + grep '^CARTESI_LINUX_IMAGE_RELEASE=' "${pins}" | cut -d= -f2 + )" + resolved_kernel_filename="$( + grep '^CARTESI_LINUX_KERNEL_FILENAME=' "${pins}" | cut -d= -f2 + )" + + if ! grep -q 'pins := "../../toolchain-pins.env"' "${canonical_just}"; then + fail "examples/canonical-app/justfile must read ../../toolchain-pins.env" + fi + + if [[ -z "${resolved_assert_version}" ]]; then + fail "could not resolve cartesi_machine_version from ${pins}" + elif [[ "${resolved_assert_version}" != "${expected_assert_version}" ]]; then + fail "resolved cartesi_machine_version=${resolved_assert_version} != ${expected_assert_version}" + fi + + if [[ "${resolved_linux_release}" != "${CARTESI_LINUX_IMAGE_RELEASE}" ]]; then + fail "resolved linux_image_release=${resolved_linux_release} != ${CARTESI_LINUX_IMAGE_RELEASE}" + fi + + if [[ "${resolved_kernel_filename}" != "${CARTESI_LINUX_KERNEL_FILENAME}" ]]; then + fail "resolved linux_kernel_filename=${resolved_kernel_filename} != ${CARTESI_LINUX_KERNEL_FILENAME}" + fi fi if [[ "${errors}" -ne 0 ]]; then diff --git a/toolchain-pins.env b/toolchain-pins.env index 98e745e..d4c8caf 100644 --- a/toolchain-pins.env +++ b/toolchain-pins.env @@ -10,9 +10,13 @@ XGENEXT2FS_SHA256_ARM64=e5aca81164b762bbe5447bacef41e4fa9e357fd9c8f44e519c520622 # Must match the cartesi-machine used to build canonical-machine-image-* tarballs # and the watchdog OCI image (in-process cartesi Lua module + CLI). -CARTESI_MACHINE_VERSION=v0.20.0-test2 -CARTESI_MACHINE_SHA256_AMD64=39bbfc96a6cc6606307294b719df65f4f2725e8d200d062bcbd8c22355b99b56 -CARTESI_MACHINE_SHA256_ARM64=787d823756000cdecd72da8a3494b4c08613087379035959e561bbaef7a220ba +CARTESI_MACHINE_VERSION=v0.20.0 +CARTESI_MACHINE_SHA256_AMD64=46b2f37b889091df3b89a8909467935f8dd4a1426eeb0491b6a346a12f0c341c +CARTESI_MACHINE_SHA256_ARM64=27ea10571335ad174b75388e7de54a3d3434bd607554d8c0bdf6abca47ceae0d + +# machine-linux-image release paired with CARTESI_MACHINE_VERSION (canonical-app justfile). +CARTESI_LINUX_IMAGE_RELEASE=v0.20.0 +CARTESI_LINUX_KERNEL_FILENAME=linux-6.5.13-ctsi-1-v0.20.0.bin # lua-cURLv3 is vendored in-tree under watchdog/third_party/lua-curl/src (no pin # to track -- the compiled bytes are the in-tree source). See its UPSTREAM file. diff --git a/watchdog/Dockerfile b/watchdog/Dockerfile index 85b847e..e697982 100644 --- a/watchdog/Dockerfile +++ b/watchdog/Dockerfile @@ -9,7 +9,8 @@ FROM debian:${DEBIAN_VERSION} AS build SHELL ["/bin/bash", "-o", "pipefail", "-c"] ARG CARTESI_MACHINE_VERSION -ARG CARTESI_MACHINE_DEB_SHA256 +ARG CARTESI_MACHINE_DEB_SHA256_AMD64 +ARG CARTESI_MACHINE_DEB_SHA256_ARM64 ARG TARGETARCH # wget + ca-certificates fetch the cartesi-machine .deb; gcc/pkg-config + Lua @@ -33,13 +34,13 @@ COPY watchdog/third_party watchdog/third_party RUN bash scripts/watchdog-lua-deps.sh RUN case "${TARGETARCH}" in \ - amd64) CM_ARCH=amd64 ;; \ - arm64) CM_ARCH=arm64 ;; \ + amd64) DEB_SHA="${CARTESI_MACHINE_DEB_SHA256_AMD64}"; CM_ARCH=amd64 ;; \ + arm64) DEB_SHA="${CARTESI_MACHINE_DEB_SHA256_ARM64}"; CM_ARCH=arm64 ;; \ *) echo "unsupported TARGETARCH=${TARGETARCH}" >&2; exit 1 ;; \ esac \ && wget -O /tmp/machine-emulator.deb \ "https://github.com/cartesi/machine-emulator/releases/download/${CARTESI_MACHINE_VERSION}/machine-emulator_${CM_ARCH}.deb" \ - && echo "${CARTESI_MACHINE_DEB_SHA256} /tmp/machine-emulator.deb" | sha256sum --check \ + && echo "${DEB_SHA} /tmp/machine-emulator.deb" | sha256sum --check \ && dpkg-deb -x /tmp/machine-emulator.deb /tmp/cm \ && mkdir -p /out/bin /out/lib /out/lib/lua/5.4 /out/share/cartesi-machine /out/share/lua/5.4 \ && cp -a /tmp/cm/usr/bin/cartesi-machine /out/bin/ \