From ac854a9b59f9c0520cd91148c9acb3609ff65a6f Mon Sep 17 00:00:00 2001 From: Dotta <34892728+cryppadotta@users.noreply.github.com> Date: Tue, 22 Sep 2026 19:30:09 -0700 Subject: [PATCH] ci: build Daytona eval images on the authorized fleet (#13847) ## Thinking Path > - Paperclip manages AI agents and their work. > - Product E2E campaigns test the browser, server, and runner together. > - The trusted workflow selects an authorized execution fleet. > - Daytona image builds still use a fixed GitHub-hosted runner. > - This pull request applies the existing fleet selection to image builds. > - Campaign builds and tests then use the configured EC2 fleet. ## Linked Issues or Issue Description Refs: https://github.com/paperclipai/paperclip/pull/13845 **What existing behavior does this improve?** The location of Daytona Product E2E image builds. **Current behavior** The image job uses ubuntu-latest even when RUNNER_E2E_AWS_ENABLED selects EC2 for the rest of the campaign. **Proposed behavior** Use the existing authorized runner output for the image job. Preserve the GitHub-hosted fallback when the EC2 switch is off. ## What Changed - Route Daytona image builds through the existing authorized runner selection. - Assert that the image job depends on authorization and receives no provider credentials. - Document the build routing and credential boundary. ## Verification - Product E2E workflow security: 11 tests passed. - git diff --check passed. - Reviewed actor checks, workflow triggers, target commit selection, signing, and package permissions. They are unchanged. - Required CI checks pass on the latest head. The first CI attempt had failures in unchanged chat tests; one diagnostic rerun passed. Both attempts remain in Actions. - Greptile reviewed the latest head at 5/5 with no inline findings. - Live EC2 image verification follows after this trusted workflow change is merged. No local Docker execution. ## Risks EC2 image builds depend on the fleet having working Docker and sufficient disk space. Existing authorization, image digest checks, signing, and the GitHub-hosted fallback remain in place. No provider secrets are added to the image job. No application or database changes. ## Model Used OpenAI Codex, GPT-6 family, with reasoning, code editing, and tool execution. The exact deployment model ID and context-window size are not exposed in this session. ## Checklist - [x] I have included a thinking path that traces from project context to this change - [x] I have specified the model used (with version and capability details) - [x] I have checked ROADMAP.md and confirmed this PR does not duplicate planned core work - [x] I have searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have not referenced internal/instance-local Paperclip issues or links (only public GitHub `#NNN` / `github.com/paperclipai/paperclip` URLs) - [x] My branch name describes the change (e.g. `docs/...`, `fix/...`) and contains no internal Paperclip ticket id or instance-derived details - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] All Paperclip CI gates are green - [x] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge Co-authored-by: Paperclip --- .github/workflows/runner-full-stack-e2e.yml | 3 ++- tests/runner-e2e/SECURITY.md | 7 ++++++- tests/runner-e2e/workflow-security.test.ts | 8 ++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/.github/workflows/runner-full-stack-e2e.yml b/.github/workflows/runner-full-stack-e2e.yml index 5556752cbc4..d689e073068 100644 --- a/.github/workflows/runner-full-stack-e2e.yml +++ b/.github/workflows/runner-full-stack-e2e.yml @@ -363,7 +363,8 @@ jobs: daytona_image: name: Publish verified Daytona image needs: [authorize, target_lock, catalog] - runs-on: ubuntu-latest + # Keep image builds on the same authorized fleet as campaign execution. + runs-on: ${{ needs.authorize.outputs.test_runner }} timeout-minutes: 45 permissions: contents: read diff --git a/tests/runner-e2e/SECURITY.md b/tests/runner-e2e/SECURITY.md index e781d54fc63..e499f638d1e 100644 --- a/tests/runner-e2e/SECURITY.md +++ b/tests/runner-e2e/SECURITY.md @@ -98,7 +98,8 @@ the actor gate, environment branch restriction, and protected default branch. ## Runner fleet isolation -When `RUNNER_E2E_AWS_ENABLED=true`, paid matrix cells use the exact RunsOn fleet +When `RUNNER_E2E_AWS_ENABLED=true`, paid matrix cells, reusable runner builds, +and Daytona image builds use the exact RunsOn fleet selector `runs-on/fleet=paperclip-public-pr-x64/env=public-ci`, matching the AWS fleet selected by `pr-trusted.yml` only after its stable numeric-ID trust gate. Any other or missing toggle value falls back to the GitHub-hosted @@ -106,6 +107,10 @@ Any other or missing toggle value falls back to the GitHub-hosted between those two reviewed literal labels; it never evaluates a configured runner label. +Daytona image builds depend on successful campaign authorization and keep the +existing GHCR publication and signing permissions. They receive no provider +credentials and do not enter the `runner-e2e-paid` environment. + Keep both runner targets restricted to `paperclipai/paperclip` and workflows that independently authorize trusted source revisions. Never let a fork or untrusted pull-request workflow target them. The RunsOn fleet must launch a diff --git a/tests/runner-e2e/workflow-security.test.ts b/tests/runner-e2e/workflow-security.test.ts index 5e3fd4084f9..dc0ef205f85 100644 --- a/tests/runner-e2e/workflow-security.test.ts +++ b/tests/runner-e2e/workflow-security.test.ts @@ -200,6 +200,14 @@ describe("public repository paid workflow security", () => { fullStack.indexOf(" daytona_image:"), fullStack.indexOf(" build_runner_artifacts:"), ); + expect(daytonaImageJob).toMatch(buildRunnerNeeds); + expect(daytonaImageJob).toContain( + "runs-on: ${{ needs.authorize.outputs.test_runner }}", + ); + expect(daytonaImageJob).not.toContain("name: runner-e2e-paid"); + expect(daytonaImageJob).not.toMatch( + /(?:OPENAI|ANTHROPIC|OPENROUTER|DAYTONA|XAI)_API_KEY/, + ); expect(authorizeJob).toContain( "aws_runner='runs-on/fleet=paperclip-public-pr-x64/env=public-ci'", );