Skip to content

fix(eval): install /usr/bin/relearn-eval on the CUDA scoring image #9

fix(eval): install /usr/bin/relearn-eval on the CUDA scoring image

fix(eval): install /usr/bin/relearn-eval on the CUDA scoring image #9

name: publish-eval-image
# Publishes ghcr.io/cortexlm/relearn-eval and prints the pushed sha256 digest.
# That digest is what the control plane pins in `config/relearn-pin.toml` as
# `eval_image_digest`; a tag is never the pin.
#
# Two images, two Dockerfiles:
#
# :<sha> scoring — CUDA base + torch. Pin this, and only after
# this job has pulled THAT digest and run the harvest-PATH
# check against it.
# :<sha>-contract slim contract only. Fast, cannot score, not the pin.
#
# The contract image publishes first and independently, so a runtime build
# that runs out of runner disk cannot take the whole publish down with it.
on:
push:
branches: ["main", "cursor/**"]
workflow_dispatch:
permissions:
contents: read
packages: write
concurrency:
group: publish-${{ github.ref }}
cancel-in-progress: false
jobs:
contract:
runs-on: ubuntu-latest
outputs:
digest: ${{ steps.push.outputs.digest }}
steps:
- uses: actions/checkout@v4
- name: resolve the image name
# A registry repository must be lowercase; the owner is CortexLM.
run: echo "IMAGE=ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/relearn-eval" >> "${GITHUB_ENV}"
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: build and push the contract image
id: push
uses: docker/build-push-action@v6
with:
context: .
file: eval/Dockerfile
push: true
provenance: false
platforms: linux/amd64
tags: |
${{ env.IMAGE }}:${{ github.sha }}-contract
build-args: |
WITH_RUNTIME=0
RELEARN_GIT_SHA=${{ github.sha }}
cache-from: type=gha,scope=contract
cache-to: type=gha,mode=max,scope=contract
- name: report
run: |
{
echo "### relearn-eval (contract only)"
echo
echo '```'
echo "image = \"${IMAGE}\""
echo "digest = \"${{ steps.push.outputs.digest }}\""
echo '```'
echo
echo "Contract layer only: slim, no model runtime, so it refuses to score."
echo "Do not pin this digest."
} >> "${GITHUB_STEP_SUMMARY}"
runtime:
runs-on: ubuntu-latest
outputs:
digest: ${{ steps.push.outputs.digest }}
steps:
- uses: actions/checkout@v4
- name: resolve the image name
run: echo "IMAGE=ghcr.io/${GITHUB_REPOSITORY_OWNER,,}/relearn-eval" >> "${GITHUB_ENV}"
- name: free disk for the CUDA base and runtime wheels
run: |
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc \
/opt/hostedtoolcache /usr/local/share/boost \
/opt/hostedtoolcache/CodeQL || true
df -h /
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: build and push the scoring image
id: push
uses: docker/build-push-action@v6
with:
context: .
file: eval/Dockerfile.scoring
push: true
provenance: false
platforms: linux/amd64
tags: |
${{ env.IMAGE }}:${{ github.sha }}
build-args: |
WITH_RUNTIME=1
RELEARN_GIT_SHA=${{ github.sha }}
# No layer cache: the CUDA base plus wheels are several GiB, which
# is past what the Actions cache will hold, and a failed cache
# export would fail a build that otherwise produced a pinnable
# digest.
- name: pull the published digest and prove harvest PATH
# Live 127 on sha256:86240d76: the scoring image harvest booted did
# not contain a runnable /usr/bin/relearn-eval. CI's harvest-PATH
# check had only ever run against the slim contract image. This
# step pulls the digest we just pushed — the bytes a pod will get —
# and refuses to report a pin if the file is missing or 127s.
env:
DIGEST: ${{ steps.push.outputs.digest }}
run: |
set -eu
case "${DIGEST}" in
sha256:*) ;;
*) echo "no sha256 digest was published"; exit 1 ;;
esac
ref="${IMAGE}@${DIGEST}"
docker pull "${ref}"
docker run --rm --entrypoint /bin/sh "${ref}" -c \
'test -f /usr/bin/relearn-eval && test -x /usr/bin/relearn-eval && env -i PATH=/usr/bin:/bin /usr/bin/relearn-eval --help'
docker run --rm --entrypoint /bin/sh "${ref}" -c \
'test ! -L /usr/bin/relearn-eval'
docker run --rm --entrypoint /bin/sh "${ref}" -c \
'env -i PATH=/usr/bin:/bin /usr/bin/relearn-eval score --help'
- name: report the digest to pin
env:
DIGEST: ${{ steps.push.outputs.digest }}
run: |
set -eu
case "${DIGEST}" in
sha256:*) ;;
*) echo "no sha256 digest was published"; exit 1 ;;
esac
{
echo "### relearn-eval (scoring image, CUDA base)"
echo
echo "Pulled this digest after push and ran the harvest-PATH check."
echo "Paste into the control plane's \`config/relearn-pin.toml\`:"
echo
echo '```toml'
echo "eval_image = \"${IMAGE}\""
echo "eval_image_digest = \"${DIGEST}\""
echo "relearn_git_sha = \"${GITHUB_SHA}\""
echo '```'
} >> "${GITHUB_STEP_SUMMARY}"
echo "eval_image_digest = \"${DIGEST}\""