Files
PaperClipAI/.github/workflows/docker-runner-check.yml
DottaandPaperclip c2f1d8471f Continue native Intel admission from retained Pi packages
Bind the original archive and receipt identities, preserve the cancelled attempt, and emit synchronous stage progress. No shipping source or provider input changes.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-10-07 18:10:21 -05:00

391 lines
18 KiB
YAML

name: Docker Runner check
on:
workflow_dispatch:
inputs:
target_branch:
description: "Branch in this repository to build; resolved to one immutable commit before checkout"
type: string
required: false
publish_eval_image:
description: "Publish an immutable Daytona qualification image on hosted Linux (no provider credentials)"
type: boolean
default: false
verify_source:
description: "Run broad source checks on hosted Linux"
type: boolean
default: false
verify_public_install:
description: "Build and verify clean public npm installation on hosted Linux (no provider credentials)"
type: boolean
default: false
verify_pi_macos_install:
description: "Verify frozen Pi shipping source on native hosted ARM and Intel Macs; no provider calls"
type: boolean
default: false
verify_pi_intel_continuation:
description: "Continue native Intel admission from immutable retained package artifact 11517098137; no provider calls"
type: boolean
default: false
build_eval_viewer:
description: "Build the canonical eval report viewer on hosted Linux"
type: boolean
default: false
pull_request:
paths:
- .github/workflows/docker-runner-check.yml
- Dockerfile
- .dockerignore
- scripts/check-docker-runner-cache.sh
- packages/paperclip-runner/rust-toolchain.toml
- packages/paperclip-runner/runner/**
- packages/paperclip-runner/protocol/**
permissions: {}
concurrency:
# Publishing a newer image must not discard an earlier verification's evidence.
group: docker-runner-check-${{ github.event.pull_request.number || github.ref }}-${{ (inputs.verify_pi_macos_install || inputs.verify_pi_intel_continuation) && 'mac-install' || inputs.verify_source && 'verification' || inputs.verify_public_install && 'public-install' || inputs.build_eval_viewer && 'viewer' || 'image' }}
cancel-in-progress: ${{ !inputs.verify_pi_macos_install && !inputs.verify_pi_intel_continuation }}
jobs:
runner:
if: github.event_name == 'pull_request'
name: Compile isolated native Runner
runs-on: ubuntu-latest
timeout-minutes: 20
permissions:
contents: read
steps:
- name: Checkout repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
persist-credentials: false
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4
# Compile the real target, then change source in a disposable context.
# A fresh builder must import dependencies and produce changed binary metadata.
# The baseline build anonymously seeds from the public BuildKit cache at
# ghcr.io/paperclipai/paperclip:buildcache-{amd64,arm64}; the verification
# build imports only this run's locally exported cache on a fresh builder.
# No registry credentials or image publication.
- name: Verify native build and dependency cache reuse
run: bash scripts/check-docker-runner-cache.sh
authorize_manual:
if: github.event_name == 'workflow_dispatch'
runs-on: ubuntu-latest
permissions:
contents: read
timeout-minutes: 5
outputs:
target_sha: ${{ steps.authorize.outputs.target_sha }}
steps:
- name: Authorize an explicit maintainer image build
id: authorize
env:
GH_TOKEN: ${{ github.token }}
REPOSITORY: ${{ github.repository }}
REPOSITORY_ID: ${{ github.repository_id }}
ACTOR_ID: ${{ github.actor_id }}
TRIGGERING_ACTOR: ${{ github.triggering_actor }}
ALLOWED_IDS: ${{ vars.AWS_CI_TRUSTED_USER_IDS }}
TARGET_BRANCH: ${{ inputs.target_branch || github.ref_name }}
run: |
set -euo pipefail
test "$REPOSITORY" = paperclipai/paperclip
test "$REPOSITORY_ID" = 1170821064
jq -e 'type == "array" and length > 0 and all(.[]; type == "number")' <<< "$ALLOWED_IDS" >/dev/null
triggering_id="$(gh api "users/$TRIGGERING_ACTOR" --jq .id)"
for id in "$ACTOR_ID" "$triggering_id"; do
jq -e --argjson id "$id" 'index($id) != null' <<< "$ALLOWED_IDS" >/dev/null
done
target_sha="$(gh api "repos/$REPOSITORY/git/ref/heads/$TARGET_BRANCH" --jq '.object.sha')"
[[ "$target_sha" =~ ^[0-9a-f]{40}$ ]]
echo "target_sha=$target_sha" >> "$GITHUB_OUTPUT"
manual_image:
if: ${{ !inputs.verify_pi_macos_install && !inputs.verify_pi_intel_continuation }}
name: Build and verify on Linux
needs: authorize_manual
# Keep maintainer authorization below; use a native hosted Linux builder.
runs-on: ubuntu-latest
timeout-minutes: 90
permissions:
contents: read
packages: write
steps:
- name: Authorize an explicit maintainer image build
env:
GH_TOKEN: ${{ github.token }}
REPOSITORY: ${{ github.repository }}
REPOSITORY_ID: ${{ github.repository_id }}
ACTOR_ID: ${{ github.actor_id }}
TRIGGERING_ACTOR: ${{ github.triggering_actor }}
ALLOWED_IDS: ${{ vars.AWS_CI_TRUSTED_USER_IDS }}
run: |
set -euo pipefail
test "$REPOSITORY" = paperclipai/paperclip
test "$REPOSITORY_ID" = 1170821064
jq -e 'type == "array" and length > 0 and all(.[]; type == "number")' <<< "$ALLOWED_IDS" >/dev/null
triggering_id="$(gh api "users/$TRIGGERING_ACTOR" --jq .id)"
for id in "$ACTOR_ID" "$triggering_id"; do
jq -e --argjson id "$id" 'index($id) != null' <<< "$ALLOWED_IDS" >/dev/null
done
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
ref: ${{ needs.authorize_manual.outputs.target_sha }}
persist-credentials: false
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6
with:
version: 9.15.4
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: 24
package-manager-cache: false
- name: Resolve source dependencies without lifecycle scripts
run: |
pnpm install --resolution-only --ignore-scripts --no-frozen-lockfile
mkdir -p remote-verification
sha256sum pnpm-lock.yaml > remote-verification/lock.sha256
git rev-parse HEAD > remote-verification/source.txt
- uses: docker/setup-buildx-action@37fe631027851001ddb9b187196cc803df7f5f0e # v4
- if: inputs.publish_eval_image
uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- name: Build checksum-verified Grok provider image
if: inputs.publish_eval_image
env:
SOURCE_SHA: ${{ needs.authorize_manual.outputs.target_sha }}
run: |
set -euo pipefail
image="ghcr.io/paperclipai/paperclip-daytona-runner:qualification-${SOURCE_SHA}-${GITHUB_RUN_ID}"
lock_sha="$(sha256sum pnpm-lock.yaml | cut -d ' ' -f 1)"
docker buildx build --platform linux/amd64 \
--file docker/daytona-runner/Dockerfile \
--build-arg "PAPERCLIP_RUNNER_SOURCE_REVISION=$SOURCE_SHA" \
--build-arg "PAPERCLIP_RUNNER_CONTENT_ID=qualification-$SOURCE_SHA" \
--build-arg "PAPERCLIP_RUNNER_LOCK_SHA256=$lock_sha" \
--cache-from type=registry,ref=ghcr.io/paperclipai/paperclip-daytona-runner:e2e-buildcache-amd64 \
--tag "$image" --metadata-file remote-verification/image.json --push .
digest="$(jq -r '."containerimage.digest"' remote-verification/image.json)"
[[ "$digest" =~ ^sha256:[0-9a-f]{64}$ ]]
immutable="${image%:*}@$digest"
docker logout ghcr.io
docker buildx imagetools inspect "$immutable" >/dev/null
echo "$immutable" > remote-verification/image.txt
echo "Image: $immutable" >> "$GITHUB_STEP_SUMMARY"
- name: Verify repository on hosted Linux
if: inputs.verify_source
# Leave time for artifact retention within the job deadline.
timeout-minutes: 38
run: |
set -uo pipefail
pnpm install --frozen-lockfile --ignore-scripts
status=0
for check in 'pnpm -r typecheck' 'pnpm test:run' 'pnpm check:token-gates' 'pnpm test:e2e:runner:typecheck' 'pnpm test:e2e:runner:unit' 'pnpm build' 'if [ -f scripts/verify-grok-npm-install.mjs ]; then node scripts/verify-grok-npm-install.mjs; fi'; do
label="$(echo "$check" | tr -cs 'a-zA-Z0-9' '-')"
echo "Starting $check"
check_status=0
timeout --signal=TERM --kill-after=15s 15m bash -c "$check" > "remote-verification/$label.log" 2>&1 || check_status=$?
printf '%s\t%s\n' "$check_status" "$check" >> remote-verification/check-status.tsv
if [ "$check_status" -ne 0 ]; then status=1; fi
echo "Finished $check (exit $check_status)"
done
exit "$status"
- name: Verify clean public npm installation
if: inputs.verify_public_install && !inputs.verify_source
timeout-minutes: 35
run: |
set -euo pipefail
test -f scripts/verify-grok-npm-install.mjs || { echo "Selected source does not provide the public-install verifier"; exit 1; }
pnpm install --frozen-lockfile --ignore-scripts > remote-verification/npm-setup.log 2>&1
pnpm build > remote-verification/npm-build.log 2>&1
node scripts/verify-grok-npm-install.mjs > remote-verification/public-npm-install.log 2>&1
- name: Build canonical eval report viewer
if: always() && (inputs.verify_source || inputs.build_eval_viewer)
run: |
set -euo pipefail
pnpm install --frozen-lockfile --ignore-scripts --filter '@paperclipai/paperclip-runner...'
pnpm --filter @paperclipai/paperclip-runner build:issue-thread > remote-verification/viewer-build.log 2>&1
tar -czf remote-verification/eval-viewer.tar.gz -C packages/paperclip-runner dist-issue-thread
sha256sum remote-verification/eval-viewer.tar.gz > remote-verification/eval-viewer.sha256
- name: Retain source, image and verification evidence
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: grok-remote-verification-${{ github.run_id }}
path: remote-verification/
retention-days: 7
pi_native_macos_install:
if: github.event_name == 'workflow_dispatch' && inputs.verify_pi_macos_install
name: Pi normal install (${{ matrix.arch }})
needs: authorize_manual
runs-on: ${{ matrix.host }}
timeout-minutes: 90
permissions:
contents: read
strategy:
fail-fast: false
matrix:
include:
- host: macos-15
arch: arm64
- host: macos-15-intel
arch: x64
steps:
- name: Authorize an explicit maintainer image build
env:
GH_TOKEN: ${{ github.token }}
REPOSITORY: ${{ github.repository }}
REPOSITORY_ID: ${{ github.repository_id }}
ACTOR_ID: ${{ github.actor_id }}
TRIGGERING_ACTOR: ${{ github.triggering_actor }}
ALLOWED_IDS: ${{ vars.AWS_CI_TRUSTED_USER_IDS }}
run: |
set -euo pipefail
test "$REPOSITORY" = paperclipai/paperclip
test "$REPOSITORY_ID" = 1170821064
jq -e 'type == "array" and length > 0 and all(.[]; type == "number")' <<< "$ALLOWED_IDS" >/dev/null
triggering_id="$(gh api "users/$TRIGGERING_ACTOR" --jq .id)"
for id in "$ACTOR_ID" "$triggering_id"; do
jq -e --argjson id "$id" 'index($id) != null' <<< "$ALLOWED_IDS" >/dev/null
done
- name: Checkout verification orchestration
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
ref: ${{ github.sha }}
path: orchestration
persist-credentials: false
- name: Checkout frozen shipping source
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
ref: 06a3d9739f402baa7f8be7aaa29dda6db7354bfb
path: source
fetch-depth: 0
persist-credentials: false
- name: Verify immutable source ancestry
env:
TARGET_SHA: ${{ needs.authorize_manual.outputs.target_sha }}
ORCHESTRATION_SHA: ${{ github.sha }}
run: |
set -euo pipefail
test "$(git -C source rev-parse HEAD)" = 06a3d9739f402baa7f8be7aaa29dda6db7354bfb
test "$(git -C orchestration rev-parse HEAD)" = "$ORCHESTRATION_SHA"
git -C source merge-base --is-ancestor 06a3d9739f402baa7f8be7aaa29dda6db7354bfb "$TARGET_SHA"
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6
with:
version: 9.15.4
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: 24.21.0
package-manager-cache: false
- name: Normal native public npm installation and Pi admission
env:
PI_QUALIFICATION_ORCHESTRATION_SHA: ${{ github.sha }}
EXPECTED_ARCH: ${{ matrix.arch }}
run: |
set -euo pipefail
node orchestration/scripts/pi-qualification-macos.mjs "$PWD/source" "$RUNNER_TEMP/pi-native-install-evidence" "$EXPECTED_ARCH"
- name: Retain native installation evidence and package archives
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: pi-native-install-${{ matrix.arch }}-${{ github.run_id }}
path: |
${{ runner.temp }}/pi-native-install-evidence/*.json
${{ runner.temp }}/pi-native-install-evidence/*.log
${{ runner.temp }}/pi-native-install-evidence/archives/*.tgz
retention-days: 14
if-no-files-found: error
pi_native_intel_continuation:
if: github.event_name == 'workflow_dispatch' && inputs.verify_pi_intel_continuation
name: Pi native Intel retained-package admission
needs: authorize_manual
runs-on: macos-15-intel
timeout-minutes: 35
permissions:
contents: read
actions: read
steps:
- name: Authorize an explicit maintainer image build
env:
GH_TOKEN: ${{ github.token }}
REPOSITORY: ${{ github.repository }}
REPOSITORY_ID: ${{ github.repository_id }}
ACTOR_ID: ${{ github.actor_id }}
TRIGGERING_ACTOR: ${{ github.triggering_actor }}
ALLOWED_IDS: ${{ vars.AWS_CI_TRUSTED_USER_IDS }}
run: |
set -euo pipefail
test "$REPOSITORY" = paperclipai/paperclip
test "$REPOSITORY_ID" = 1170821064
jq -e 'type == "array" and length > 0 and all(.[]; type == "number")' <<< "$ALLOWED_IDS" >/dev/null
triggering_id="$(gh api "users/$TRIGGERING_ACTOR" --jq .id)"
for id in "$ACTOR_ID" "$triggering_id"; do
jq -e --argjson id "$id" 'index($id) != null' <<< "$ALLOWED_IDS" >/dev/null
done
- name: Checkout verification orchestration
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
ref: ${{ github.sha }}
path: orchestration
persist-credentials: false
- name: Checkout frozen shipping source
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7
with:
ref: 06a3d9739f402baa7f8be7aaa29dda6db7354bfb
path: source
fetch-depth: 0
persist-credentials: false
- name: Verify immutable source ancestry
env:
TARGET_SHA: ${{ needs.authorize_manual.outputs.target_sha }}
ORCHESTRATION_SHA: ${{ github.sha }}
run: |
set -euo pipefail
test "$(git -C source rev-parse HEAD)" = 06a3d9739f402baa7f8be7aaa29dda6db7354bfb
test "$(git -C orchestration rev-parse HEAD)" = "$ORCHESTRATION_SHA"
git -C source merge-base --is-ancestor 06a3d9739f402baa7f8be7aaa29dda6db7354bfb "$TARGET_SHA"
- uses: pnpm/action-setup@0977fd99725f1db4007ccb2928dbb4e90d06cc86 # v6
with:
version: 9.15.4
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7
with:
node-version: 24.21.0
package-manager-cache: false
- name: Download immutable retained native Intel packages
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
gh api repos/paperclipai/paperclip/actions/artifacts/11517098137 > "$RUNNER_TEMP/pi-original-artifact.json"
jq -e '.name == "pi-native-install-x64-37694650556" and .expired == false and .digest == "sha256:b6923562c643ce7c970885692c2ce6d939c644ba66212870a7becfe9be454cac"' "$RUNNER_TEMP/pi-original-artifact.json" >/dev/null
gh run download 37694650556 --repo paperclipai/paperclip --name pi-native-install-x64-37694650556 --dir "$RUNNER_TEMP/pi-original-intel"
- name: Complete normal Intel package installation and Pi admission
timeout-minutes: 30
env:
PI_QUALIFICATION_ORCHESTRATION_SHA: ${{ github.sha }}
run: |
set -euo pipefail
node orchestration/scripts/pi-qualification-intel-continuation.mjs "$PWD/source" "$RUNNER_TEMP/pi-original-intel" "$RUNNER_TEMP/pi-native-install-evidence"
- name: Retain native installation evidence and package archives
if: always()
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: pi-native-install-x64-continuation-${{ github.run_id }}
path: |
${{ runner.temp }}/pi-native-install-evidence/*.json
${{ runner.temp }}/pi-native-install-evidence/*.log
${{ runner.temp }}/pi-native-install-evidence/archives/*.tgz
${{ runner.temp }}/pi-native-install-evidence/original-build/
${{ runner.temp }}/pi-original-artifact.json
retention-days: 14
if-no-files-found: error