mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-22 16:51:28 +02:00
Integrate Copilot production candidate with current master
This commit is contained in:
commit
9f14069246
700 files changed
+76916
-19908
No files matched your search
@@ -22,6 +22,8 @@
|
||||
FROM node:24-slim@sha256:ba849c60be29959425b8734d57b8b4b7d56f98edd9504c9af091d5281095a71e
|
||||
WORKDIR /context
|
||||
COPY . .
|
||||
# Verify ACPX release declarations against the exact Docker context.
|
||||
RUN node packages/paperclip-runner/scripts/generate-acpx-profiles.mjs --check
|
||||
# Committed artifacts the image build reads whose drift checks cannot run
|
||||
# here (they need the locked dependency tree or compiled dist/). Existence
|
||||
# in the context is the property this probe guards; content correctness is
|
||||
|
||||
@@ -38,14 +38,19 @@ test("parallel lanes cover check:all exactly once and never bypass verification"
|
||||
const scripts = JSON.parse(readFileSync(new URL("../../../packages/paperclip-runner/package.json", import.meta.url))).scripts;
|
||||
const checks = [...runner.matchAll(/^ checks: (.+)$/gm)].flatMap(([, value]) => value.split(" "));
|
||||
assert.deepEqual(checks, scripts["check:all"].split(" && ").map((command) => command.replace(/^pnpm run /, "")));
|
||||
assert.deepEqual([...runner.matchAll(/^ - lane: (.+)$/gm)].map(([, value]) => value), ["protocol", "rust"]);
|
||||
assert.deepEqual([...runner.matchAll(/^ - lane: (.+)$/gm)].map(([, value]) => value), ["protocol", "rust", "server-integration"]);
|
||||
assert.match(runner, /fail-fast: false/);
|
||||
assert.doesNotMatch(runner, /max-parallel: 1|^ needs:|continue-on-error:/m);
|
||||
const verify = runner.split(" - name: Verify Paperclip Runner\n")[1].split(" - name: Warm debug")[0];
|
||||
assert.match(verify, /RUNNER_CHECKS: \$\{\{ matrix.checks \}\}/);
|
||||
assert.match(verify, /set -euo pipefail/);
|
||||
assert.match(verify, /for check in \$RUNNER_CHECKS; do\s+pnpm --filter @paperclipai\/paperclip-runner "\$check"\s+done/);
|
||||
assert.doesNotMatch(verify, /if:|cache-hit/);
|
||||
const verifyIf = verify.match(/^\s*if: \$\{\{ (.+) \}\}$/m)?.[1];
|
||||
assert.equal(verifyIf, "matrix.lane != 'server-integration'");
|
||||
for (const lane of ["protocol", "rust", "server-integration"]) {
|
||||
assert.equal(runInNewContext(verifyIf, { matrix: { lane } }), lane !== "server-integration");
|
||||
}
|
||||
assert.doesNotMatch(verify, /cache-hit/);
|
||||
assert.doesNotMatch(runner, /id-token: write|packages: write|secrets: inherit/);
|
||||
});
|
||||
|
||||
@@ -57,7 +62,7 @@ test("only the trusted Rust lane writes, and warms both build profiles before sa
|
||||
assert.match(warm, /run: pnpm --filter @paperclipai\/paperclip-runner build:rust/);
|
||||
const sha = "a".repeat(40);
|
||||
const base = { repository: "paperclipai/paperclip", event_name: "push", ref: "refs/heads/master", sha };
|
||||
for (const lane of ["protocol", "rust"]) {
|
||||
for (const lane of ["protocol", "rust", "server-integration"]) {
|
||||
for (const [overrides, ref, trusted] of [
|
||||
[{}, sha, true],
|
||||
[{ event_name: "pull_request", ref: "refs/pull/1/merge" }, sha, false],
|
||||
|
||||
@@ -7,20 +7,24 @@ on:
|
||||
description: "Branch in this repository to build; resolved to one immutable commit before checkout"
|
||||
type: string
|
||||
required: false
|
||||
build_eval_image:
|
||||
description: "Build an immutable qualification image as an inspectable OCI artifact without publication"
|
||||
type: boolean
|
||||
default: false
|
||||
publish_eval_image:
|
||||
description: "Publish an immutable Daytona qualification image on the EC2 fleet (no provider credentials)"
|
||||
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 EC2"
|
||||
description: "Run broad source checks on hosted Linux"
|
||||
type: boolean
|
||||
default: false
|
||||
verify_public_install:
|
||||
description: "Build and verify clean public npm installation on EC2 (no provider credentials)"
|
||||
description: "Build and verify clean public npm installation on hosted Linux (no provider credentials)"
|
||||
type: boolean
|
||||
default: false
|
||||
build_eval_viewer:
|
||||
description: "Build the canonical eval report viewer on EC2"
|
||||
description: "Build the canonical eval report viewer on hosted Linux"
|
||||
type: boolean
|
||||
default: false
|
||||
pull_request:
|
||||
@@ -98,9 +102,10 @@ jobs:
|
||||
echo "target_sha=$target_sha" >> "$GITHUB_OUTPUT"
|
||||
|
||||
manual_image:
|
||||
name: Build and verify on EC2
|
||||
name: Build and verify on Linux
|
||||
needs: authorize_manual
|
||||
runs-on: runs-on/fleet=paperclip-public-pr-x64/env=public-ci
|
||||
# Keep maintainer authorization below; use a native hosted Linux builder.
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 90
|
||||
permissions:
|
||||
contents: read
|
||||
@@ -136,7 +141,11 @@ jobs:
|
||||
package-manager-cache: false
|
||||
- name: Resolve source dependencies without lifecycle scripts
|
||||
run: |
|
||||
pnpm install --resolution-only --ignore-scripts --no-frozen-lockfile
|
||||
if [[ "${{ inputs.build_eval_image || inputs.publish_eval_image }}" == true ]]; then
|
||||
pnpm install --frozen-lockfile --ignore-scripts
|
||||
else
|
||||
pnpm install --resolution-only --ignore-scripts --no-frozen-lockfile
|
||||
fi
|
||||
mkdir -p remote-verification
|
||||
sha256sum pnpm-lock.yaml > remote-verification/lock.sha256
|
||||
git rev-parse HEAD > remote-verification/source.txt
|
||||
@@ -147,31 +156,49 @@ jobs:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
- name: Build checksum-verified Grok provider image
|
||||
if: inputs.publish_eval_image
|
||||
- name: Prepare hosted image build capacity
|
||||
if: inputs.build_eval_image || inputs.publish_eval_image
|
||||
run: |
|
||||
# These preinstalled SDKs are absent from the image build context.
|
||||
sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc
|
||||
df -h .
|
||||
test "$(df --output=avail -BG . | tail -1 | tr -dc '0-9')" -ge 35
|
||||
- name: Build checksum-verified qualification image
|
||||
if: inputs.build_eval_image || 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)"
|
||||
content_id="$(node cli/node_modules/tsx/dist/cli.mjs tests/runner-e2e/daytona-image-content.ts)"
|
||||
[[ "$content_id" =~ ^[0-9a-f]{64}$ ]]
|
||||
printf '%s\n' "$content_id" > remote-verification/content-id.txt
|
||||
output_args=(--output type=oci,dest=remote-verification/image.oci.tar)
|
||||
if [[ "${{ inputs.publish_eval_image }}" == true ]]; then
|
||||
output_args=(--push)
|
||||
fi
|
||||
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_CONTENT_ID=$content_id" \
|
||||
--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 .
|
||||
--tag "$image" --metadata-file remote-verification/image.json "${output_args[@]}" .
|
||||
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
|
||||
if [[ "${{ inputs.publish_eval_image }}" == true ]]; then
|
||||
docker logout ghcr.io
|
||||
docker buildx imagetools inspect "$immutable" >/dev/null
|
||||
else
|
||||
sha256sum remote-verification/image.oci.tar > remote-verification/image-archive.sha256
|
||||
fi
|
||||
echo "$immutable" > remote-verification/image.txt
|
||||
echo "Image: $immutable" >> "$GITHUB_STEP_SUMMARY"
|
||||
- name: Verify repository on EC2
|
||||
echo "Image: $immutable; published: ${{ inputs.publish_eval_image }}" >> "$GITHUB_STEP_SUMMARY"
|
||||
- name: Verify repository on hosted Linux
|
||||
if: inputs.verify_source
|
||||
# Leave time for artifact retention before the fleet's one-hour lifetime.
|
||||
# Leave time for artifact retention within the job deadline.
|
||||
timeout-minutes: 38
|
||||
run: |
|
||||
set -uo pipefail
|
||||
@@ -193,9 +220,11 @@ jobs:
|
||||
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 install --resolution-only --ignore-scripts --no-frozen-lockfile > remote-verification/npm-setup.log 2>&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
|
||||
PAPERCLIP_RUNNER_QUALIFICATION_PACKAGES_DIR="$PWD/remote-verification/qualification-packages" \
|
||||
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: |
|
||||
@@ -210,4 +239,6 @@ jobs:
|
||||
with:
|
||||
name: grok-remote-verification-${{ github.run_id }}
|
||||
path: remote-verification/
|
||||
compression-level: 0
|
||||
retention-days: 1
|
||||
retention-days: 7
|
||||
@@ -384,7 +384,7 @@ jobs:
|
||||
echo "arch=$(node -p 'process.arch')" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Restore pnpm store (read only)
|
||||
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
with:
|
||||
path: ${{ steps.pnpm_store.outputs.path }}
|
||||
key: node-cache-${{ runner.os }}-${{ steps.pnpm_store.outputs.arch }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
@@ -609,7 +609,7 @@ jobs:
|
||||
echo "arch=$(node -p 'process.arch')" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Restore pnpm store (read only)
|
||||
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
with:
|
||||
path: ${{ steps.pnpm_store.outputs.path }}
|
||||
key: node-cache-${{ runner.os }}-${{ steps.pnpm_store.outputs.arch }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
@@ -767,7 +767,7 @@ jobs:
|
||||
echo "arch=$(node -p 'process.arch')" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Restore pnpm store (read only)
|
||||
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
with:
|
||||
path: ${{ steps.pnpm_store.outputs.path }}
|
||||
key: node-cache-${{ runner.os }}-${{ steps.pnpm_store.outputs.arch }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
@@ -905,7 +905,7 @@ jobs:
|
||||
echo "arch=$(node -p 'process.arch')" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Restore pnpm store (read only)
|
||||
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
with:
|
||||
path: ${{ steps.pnpm_store.outputs.path }}
|
||||
key: node-cache-${{ runner.os }}-${{ steps.pnpm_store.outputs.arch }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
@@ -1078,7 +1078,7 @@ jobs:
|
||||
echo "arch=$(node -p 'process.arch')" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Restore pnpm store (read only)
|
||||
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
with:
|
||||
path: ${{ steps.pnpm_store.outputs.path }}
|
||||
key: node-cache-${{ runner.os }}-${{ steps.pnpm_store.outputs.arch }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
@@ -1137,7 +1137,7 @@ jobs:
|
||||
echo "arch=$(node -p 'process.arch')" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Restore pnpm store (read only)
|
||||
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
with:
|
||||
path: ${{ steps.pnpm_store.outputs.path }}
|
||||
key: node-cache-${{ runner.os }}-${{ steps.pnpm_store.outputs.arch }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
@@ -1327,7 +1327,7 @@ jobs:
|
||||
echo "arch=$(node -p 'process.arch')" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Restore pnpm store (read only)
|
||||
uses: actions/cache/restore@caa296126883cff596d87d8935842f9db880ef25 # v5
|
||||
uses: actions/cache/restore@55cc8345863c7cc4c66a329aec7e433d2d1c52a9 # v6.1.0
|
||||
with:
|
||||
path: ${{ steps.pnpm_store.outputs.path }}
|
||||
key: node-cache-${{ runner.os }}-${{ steps.pnpm_store.outputs.arch }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }}
|
||||
|
||||
@@ -107,45 +107,46 @@ jobs:
|
||||
matrix:
|
||||
include:
|
||||
# Split the long chat file by collected test locations, and balance
|
||||
# the remaining server files across ten runners. Normal PR/local
|
||||
# invocations retain their complete general-server group.
|
||||
- group: general-server-without-chat
|
||||
# the remaining server files across ten runners. Rust-backed server
|
||||
# suites run in the cached Runner lane below. Local invocations retain
|
||||
# their complete general-server group.
|
||||
- group: general-server-without-chat-or-native-runner
|
||||
group_label: server (1/10)
|
||||
shard_index: 0
|
||||
shard_count: 10
|
||||
- group: general-server-without-chat
|
||||
- group: general-server-without-chat-or-native-runner
|
||||
group_label: server (2/10)
|
||||
shard_index: 1
|
||||
shard_count: 10
|
||||
- group: general-server-without-chat
|
||||
- group: general-server-without-chat-or-native-runner
|
||||
group_label: server (3/10)
|
||||
shard_index: 2
|
||||
shard_count: 10
|
||||
- group: general-server-without-chat
|
||||
- group: general-server-without-chat-or-native-runner
|
||||
group_label: server (4/10)
|
||||
shard_index: 3
|
||||
shard_count: 10
|
||||
- group: general-server-without-chat
|
||||
- group: general-server-without-chat-or-native-runner
|
||||
group_label: server (5/10)
|
||||
shard_index: 4
|
||||
shard_count: 10
|
||||
- group: general-server-without-chat
|
||||
- group: general-server-without-chat-or-native-runner
|
||||
group_label: server (6/10)
|
||||
shard_index: 5
|
||||
shard_count: 10
|
||||
- group: general-server-without-chat
|
||||
- group: general-server-without-chat-or-native-runner
|
||||
group_label: server (7/10)
|
||||
shard_index: 6
|
||||
shard_count: 10
|
||||
- group: general-server-without-chat
|
||||
- group: general-server-without-chat-or-native-runner
|
||||
group_label: server (8/10)
|
||||
shard_index: 7
|
||||
shard_count: 10
|
||||
- group: general-server-without-chat
|
||||
- group: general-server-without-chat-or-native-runner
|
||||
group_label: server (9/10)
|
||||
shard_index: 8
|
||||
shard_count: 10
|
||||
- group: general-server-without-chat
|
||||
- group: general-server-without-chat-or-native-runner
|
||||
group_label: server (10/10)
|
||||
shard_index: 9
|
||||
shard_count: 10
|
||||
@@ -297,6 +298,7 @@ jobs:
|
||||
checks: check:eval-kernel check:protocol
|
||||
- lane: rust
|
||||
checks: check:runner check:api-authority
|
||||
- lane: server-integration
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
@@ -373,14 +375,28 @@ jobs:
|
||||
# dependencies; never restore installed executables from cargo/bin.
|
||||
cache-workspace-crates: false
|
||||
cache-bin: false
|
||||
# Both lanes restore the existing dependency cache. Only the Rust
|
||||
# All lanes restore the existing dependency cache. Only the Rust
|
||||
# lane saves it, after warming both release and debug dependencies.
|
||||
save-if: ${{ matrix.lane == 'rust' && github.repository == 'paperclipai/paperclip' && github.event_name == 'push' && github.ref == 'refs/heads/master' && inputs.ref == github.sha }}
|
||||
|
||||
- name: Install dependencies
|
||||
run: pnpm install --no-frozen-lockfile
|
||||
|
||||
- name: Build native server test binaries
|
||||
if: ${{ matrix.lane == 'server-integration' }}
|
||||
timeout-minutes: 10
|
||||
working-directory: packages/paperclip-runner
|
||||
run: |
|
||||
set -euo pipefail
|
||||
pnpm build:rust
|
||||
cargo build --release --manifest-path runner/Cargo.toml --locked -p paperclip-runner-core --bin paperclip-runnerd --bin fake-codex-app-server
|
||||
|
||||
- name: Run native server integration suites
|
||||
if: ${{ matrix.lane == 'server-integration' }}
|
||||
run: pnpm test:run:general -- --group general-server-native-runner
|
||||
|
||||
- name: Verify Paperclip Runner
|
||||
if: ${{ matrix.lane != 'server-integration' }}
|
||||
env:
|
||||
RUNNER_CHECKS: ${{ matrix.checks }}
|
||||
run: |
|
||||
|
||||
Reference in new issue
Block a user