mirror of
https://github.com/paperclipai/paperclip.git
synced 2026-10-21 08:22:20 +02:00
Fix Docker dependency installation for Copilot lifecycle hooks (#16983)
## Thinking Path > - Paperclip manages AI agents and their work. > - The standard Docker image contains the server and Runner. > - Its dependency stage installs packages before copying application source. > - New Copilot postinstall hooks need files absent from that stage. > - Both image architectures stop before compilation. > - This change supplies the lifecycle inputs and tests both entrypoints. ## Linked Issues or Issue Description **What happened?** Master Docker builds fail with a missing `packages/paperclip-runner/scripts/install-copilot-assets.mjs`. The server postinstall also needs its bootstrap script and source marker. See the failed public [Docker build](https://github.com/paperclipai/paperclip/actions/runs/39450988012). **Expected behavior** Dependency installation recognizes the existing source workspace. The later build compiles and verifies provider assets through the existing path. **Steps to reproduce** 1. Build the standard Docker image from master. 2. Reach `pnpm install` in the `deps` stage. 3. Observe the missing lifecycle-script error before compilation. **Paperclip version or commit** Reproduced in the Docker build for `24758b9da129a5e424fb7ba6b423d748ce23f3bc`. This PR starts at `33cc567f75ae8a3fecf4442d20772e62944f1552`. **Deployment mode** Docker, Linux amd64 and arm64. No database is involved. Searched open PRs and issues for Docker, Copilot, installer and the exact missing script. No matching fix was found. ## What Changed - Copy the Runner installer and its two helper modules into the dependency layer. - Copy the server installer and both existing source-workspace markers. - Execute both real postinstall entrypoints in a temporary fixture populated from the relevant Docker COPY inputs. - Run the fixture in the existing trusted PR dependency-stage check. ## Verification - `node --test scripts/docker-deps-postinstall.test.mjs` passed. - The same test fails with the original Dockerfile because the installer is missing. The fixed Dockerfile was restored and the test passed again. - `node scripts/check-docker-deps-stage.mjs` passed. - The fixture passed through the existing timing wrapper in default and `PAPERCLIP_CI_PROFILE=true` modes. The latter wrote test timing records. - `pnpm install --frozen-lockfile` passed. - All three `node --test packages/paperclip-runner/scripts/install-copilot-assets.test.mjs` cases passed. These test fresh Runner/server assets, source bootstrap and published-package failure. - Full workspace `pnpm -r typecheck` and `pnpm build` passed. The full local test command is running. All 55 checks passed on exact head `8ab57339cb9a0dcefa3ae9c2c0f92dc4f6210a23`, with one neutral security scan and four conditional skips. This includes full server, browser, Runner, typecheck, build, package-smoke and dependency-stage checks. Apex reviewed the same head at 5/5 with its prior timing finding resolved. No review thread remains unresolved. - The local Docker daemon does not respond to an info probe. A complete local image build has not been run. The post-merge canonical image build must pass before any deployment uses this change. ## Risks The dependency cache now includes these small lifecycle inputs. Source edits to the two marker files invalidate that cache. The existing source-workspace detection and compiled asset verification remain in place. This does not add an installer bypass, change provider pins or alter runtime behavior. No schema change is included. ## Model Used OpenAI GPT-6 through Codex, with source inspection, code execution and GitHub tools. The exact served 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 focused tests locally and recorded the results above - [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 <noreply@paperclip.ing>
This commit is contained in:
1 parent
2c96f76780
commit
6b804bfeba
3 files changed
+52
-1
No files matched your search
@@ -90,7 +90,9 @@ jobs:
|
||||
"${{ github.event.pull_request.head.sha }}"
|
||||
|
||||
- name: Validate Dockerfile deps stage
|
||||
run: node ./scripts/check-docker-deps-stage.mjs
|
||||
run: |
|
||||
node ./scripts/check-docker-deps-stage.mjs
|
||||
node "$CI_NODE_TEST" ./scripts/docker-deps-postinstall.test.mjs
|
||||
|
||||
- name: Validate Node version policy
|
||||
run: pnpm check:node-version
|
||||
|
||||
@@ -48,6 +48,10 @@ COPY packages/plugins/plugin-llm-wiki/package.json packages/plugins/plugin-llm-w
|
||||
COPY packages/plugins/plugin-workspace-diff/package.json packages/plugins/plugin-workspace-diff/
|
||||
COPY patches/ patches/
|
||||
COPY scripts/link-plugin-dev-sdk.mjs scripts/
|
||||
COPY packages/paperclip-runner/scripts/install-copilot-assets.mjs packages/paperclip-runner/scripts/materialize-copilot-binary.mjs packages/paperclip-runner/scripts/copilot-inner-distribution.mjs packages/paperclip-runner/scripts/
|
||||
COPY packages/paperclip-runner/src/drivers/acpx/copilot-installation.ts packages/paperclip-runner/src/drivers/acpx/
|
||||
COPY server/scripts/install-copilot-assets.mjs server/scripts/
|
||||
COPY server/src/services/copilot-connection-probe.ts server/src/services/
|
||||
|
||||
# CI owns repository lock updates. Resolve manifest changes in the image's
|
||||
# private build tree, then install from that exact generated lock.
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
import assert from "node:assert/strict";
|
||||
import { execFileSync } from "node:child_process";
|
||||
import { cp, mkdtemp, mkdir, readFile, rm } from "node:fs/promises";
|
||||
import { tmpdir } from "node:os";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { test } from "node:test";
|
||||
|
||||
const repo = fileURLToPath(new URL("../", import.meta.url));
|
||||
|
||||
test("dependency-layer inputs can run both Copilot postinstall entrypoints before compilation", async () => {
|
||||
const dockerfile = await readFile(path.join(repo, "Dockerfile"), "utf8");
|
||||
const stage = dockerfile.split(/^FROM .* AS deps\s*$/im)[1]?.split(/^FROM /im)[0];
|
||||
assert.ok(stage, "dependency stage exists");
|
||||
const beforeInstall = stage.split(/^RUN pnpm install/m)[0];
|
||||
const fixture = await mkdtemp(path.join(tmpdir(), "paperclip-docker-postinstall-"));
|
||||
try {
|
||||
for (const line of beforeInstall.split("\n")) {
|
||||
if (!line.startsWith("COPY ") || line.includes("--")) continue;
|
||||
const args = line.trim().split(/\s+/).slice(1);
|
||||
const destination = args.pop();
|
||||
for (const source of args) {
|
||||
if (source !== "pnpm-workspace.yaml"
|
||||
&& !source.startsWith("packages/paperclip-runner/")
|
||||
&& !source.startsWith("server/")) continue;
|
||||
assert.ok(destination.endsWith("/"), "fixture supports directory COPY destinations");
|
||||
const target = path.join(fixture, destination, path.basename(source));
|
||||
await mkdir(path.dirname(target), { recursive: true });
|
||||
await cp(path.join(repo, source), target, { recursive: true });
|
||||
}
|
||||
}
|
||||
for (const owner of ["packages/paperclip-runner", "server"]) {
|
||||
const cwd = path.join(fixture, owner);
|
||||
const manifest = JSON.parse(await readFile(path.join(cwd, "package.json"), "utf8"));
|
||||
assert.equal(manifest.scripts.postinstall, "node scripts/install-copilot-assets.mjs");
|
||||
const output = execFileSync(process.execPath, ["scripts/install-copilot-assets.mjs"], {
|
||||
cwd, encoding: "utf8", timeout: 10_000,
|
||||
});
|
||||
assert.match(output, /Copilot runtime assets: (source-workspace-pending-build|unsupported-platform)/);
|
||||
await assert.rejects(readFile(path.join(cwd, "provider-assets/copilot")), { code: "ENOENT" });
|
||||
}
|
||||
} finally {
|
||||
await rm(fixture, { recursive: true, force: true });
|
||||
}
|
||||
});
|
||||
Reference in new issue
Block a user