diff --git a/doc/plans/2026-10-03-cursor-production-readiness.md b/doc/plans/2026-10-03-cursor-production-readiness.md index 67f7abf8e9e..2009f936a61 100644 --- a/doc/plans/2026-10-03-cursor-production-readiness.md +++ b/doc/plans/2026-10-03-cursor-production-readiness.md @@ -151,6 +151,10 @@ compiled plugin in its own installed dependency directory; the affected repeat passed. A separate credential-free public probe exposed a development-only Runner import in the installed configuration check. The production fix uses the vendored boundary, and the stronger public verifier and both installed smokes pass. +The final fixture also checks the selected public plugin's release version and all +compiled entries. A credential-free repeat against the exact installed plugin +above passed; missing or mismatched version tests reject stale artifacts. This +adds an admission check without changing the certified plugin or provider behavior. Promotion checks passed: recursive typecheck, full build, token gates (1,129 files), Runner contract/replay checks, 164 focused Runner tests, executor/profile/runtime-mode coverage, diff --git a/tests/runner-e2e/README.md b/tests/runner-e2e/README.md index 67149629da9..0e97560f379 100644 --- a/tests/runner-e2e/README.md +++ b/tests/runner-e2e/README.md @@ -1609,6 +1609,15 @@ native binary overrides are removed from the server environment. Qualification admission is rejected, so this path requires production admission. Use the existing browser/API cases and encrypted company-secret fixture path. +Install the public `@paperclipai/plugin-daytona` package separately for a Daytona +smoke. Set `PAPERCLIP_RUNNER_E2E_INSTALLED_DAYTONA_PLUGIN` to its absolute installed +package directory when it has its own dependency root. The fixture checks its +compiled entries and release version before provisioning. The version must match +the installed CLI by default. If the release uses independent plugin versions, +set `PAPERCLIP_RUNNER_E2E_INSTALLED_DAYTONA_PLUGIN_VERSION` to the exact plugin +version in the release record. Record the plugin tarball SHA-256 with that version; +do not substitute a workspace build or an older installed plugin. + For a diagnosed failure campaign, `PAPERCLIP_RUNNER_E2E_KEEP_FAILED_PRIVATE=1` retains the attempt's owner-only private directory after a failed case even when owned cleanup passed. This does not alter the case or cleanup outcome. diff --git a/tests/runner-e2e/installed-release.test.ts b/tests/runner-e2e/installed-release.test.ts index 7982f9b6646..08f2d704da2 100644 --- a/tests/runner-e2e/installed-release.test.ts +++ b/tests/runner-e2e/installed-release.test.ts @@ -23,12 +23,17 @@ describe("ordinary installed release smoke", () => { mkdirSync(path.join(cliRoot, "dist"), { recursive: true }); mkdirSync(path.join(plugin, "dist"), { recursive: true }); const cli = path.join(cliRoot, "dist/index.js"); writeFileSync(cli, ""); writeFileSync(path.join(cliRoot, "package.json"), JSON.stringify({ name: "paperclipai", version: "0.0.0-verify" })); - const manifest = { name: "@paperclipai/plugin-daytona", paperclipPlugin: { manifest: "./dist/manifest.js", worker: "./dist/worker.js" }, exports: { ".": { import: "./dist/index.js" } } }; - for (const file of ["manifest.js", "worker.js"]) writeFileSync(path.join(plugin, "dist", file), ""); + const manifest = { name: "@paperclipai/plugin-daytona", version: "0.0.0-verify", paperclipPlugin: { manifest: "./dist/manifest.js", worker: "./dist/worker.js" }, exports: { ".": { import: "./dist/index.js" } } }; + for (const file of ["manifest.js", "worker.js", "index.js"]) writeFileSync(path.join(plugin, "dist", file), ""); writeFileSync(path.join(plugin, "package.json"), JSON.stringify(manifest)); expect(installedReleaseDaytonaPlugin(cli)).toBe(plugin); expect(installedReleaseDaytonaPlugin(cli, plugin)).toBe(plugin); expect(() => installedReleaseDaytonaPlugin(cli, "relative/plugin")).toThrow("absolute"); + writeFileSync(path.join(plugin, "package.json"), JSON.stringify({ ...manifest, version: "0.0.0-stale" })); + expect(() => installedReleaseDaytonaPlugin(cli, plugin)).toThrow("qualified release version 0.0.0-verify"); + expect(installedReleaseDaytonaPlugin(cli, plugin, "0.0.0-stale")).toBe(plugin); + writeFileSync(path.join(plugin, "package.json"), JSON.stringify({ ...manifest, version: undefined })); + expect(() => installedReleaseDaytonaPlugin(cli, plugin)).toThrow("qualified release version"); writeFileSync(path.join(plugin, "package.json"), JSON.stringify({ ...manifest, exports: { ".": "./src/index.ts" } })); expect(() => installedReleaseDaytonaPlugin(cli)).toThrow("public compiled Daytona"); writeFileSync(path.join(plugin, "package.json"), JSON.stringify(manifest)); diff --git a/tests/runner-e2e/installed-release.ts b/tests/runner-e2e/installed-release.ts index b07ed89c5cd..5f6cd19171f 100644 --- a/tests/runner-e2e/installed-release.ts +++ b/tests/runner-e2e/installed-release.ts @@ -14,8 +14,8 @@ export function installedReleaseLaunch(cliPath: string) { return { cli, cwd: root, args: [cli, "onboard", "--yes", "--run"], version: manifest.version }; } -/** Install the public plugin from the same consumer, without a workspace loader. */ -export function installedReleaseDaytonaPlugin(cliPath: string, installedPluginPath?: string): string { +/** Verify the selected public plugin belongs to the release being qualified. */ +export function installedReleaseDaytonaPlugin(cliPath: string, installedPluginPath?: string, expectedVersion?: string): string { const cli = installedReleaseLaunch(cliPath); if (installedPluginPath && !path.isAbsolute(installedPluginPath)) throw new Error("Installed Daytona plugin path must be absolute"); const plugin = realpathSync(installedPluginPath ?? path.join(path.dirname(cli.cwd), "@paperclipai/plugin-daytona")); @@ -26,8 +26,13 @@ export function installedReleaseDaytonaPlugin(cliPath: string, installedPluginPa manifest.exports?.["."]?.import !== "./dist/index.js") { throw new Error("Installed release requires the public compiled Daytona plugin package"); } + const releaseVersion = expectedVersion ?? cli.version; + if (!releaseVersion || manifest.version !== releaseVersion) { + throw new Error(`Installed Daytona plugin must match qualified release version ${releaseVersion}`); + } realpathSync(path.join(plugin, "dist/manifest.js")); realpathSync(path.join(plugin, "dist/worker.js")); + realpathSync(path.join(plugin, "dist/index.js")); return plugin; } diff --git a/tests/runner-e2e/live-fixtures.ts b/tests/runner-e2e/live-fixtures.ts index 4cfe762c653..ef2250f9ab0 100644 --- a/tests/runner-e2e/live-fixtures.ts +++ b/tests/runner-e2e/live-fixtures.ts @@ -117,7 +117,7 @@ export async function setupLiveFixtures(input: { async setup() { return api.post("/api/plugins/install", { packageName: process.env.PAPERCLIP_RUNNER_E2E_INSTALLED_CLI - ? installedReleaseDaytonaPlugin(process.env.PAPERCLIP_RUNNER_E2E_INSTALLED_CLI, process.env.PAPERCLIP_RUNNER_E2E_INSTALLED_DAYTONA_PLUGIN) + ? installedReleaseDaytonaPlugin(process.env.PAPERCLIP_RUNNER_E2E_INSTALLED_CLI, process.env.PAPERCLIP_RUNNER_E2E_INSTALLED_DAYTONA_PLUGIN, process.env.PAPERCLIP_RUNNER_E2E_INSTALLED_DAYTONA_PLUGIN_VERSION) : path.resolve( import.meta.dirname, "../../packages/plugins/sandbox-providers/daytona",