mirror of
https://github.com/alkimake/paperclip.git
synced 2026-06-14 01:50:39 +09:00
Harden release flow with registry verification and dist-tag checks (#4800)
## Thinking Path > - Paperclip orchestrates AI agents for zero-human companies > - Paperclip is distributed as npm packages, including plugins like `plugin-e2b` > - The release process publishes canary and stable builds via npm dist-tags > - But there was no automated verification that published packages actually landed with the correct dist-tags, and broken canary publishes could silently ship to users > - This PR adds a registry verification script that checks published packages match their expected dist-tags, and wires it into PR CI so regressions are caught before merge > - The benefit is release integrity is verified automatically, and broken dist-tag states are caught early ## What Changed - Added `scripts/verify-release-registry-state.mjs` — verifies that published npm packages have correct dist-tag assignments and detects orphaned or mispointed tags - Added `scripts/verify-release-registry-state.test.mjs` — test coverage for the verification logic - Updated `scripts/release.sh` to include canary dist-tag safety checks before publishing - Updated `.github/workflows/pr.yml` to run registry verification as a CI step - Updated `doc/PUBLISHING.md` and `doc/RELEASING.md` with the new verification workflow ## Verification - `pnpm test` — all tests pass including new verification script tests - `node scripts/verify-release-registry-state.mjs` — runs against the live npm registry and reports current state - CI: the new PR workflow step runs on every PR push ## Risks - Low risk. This is additive CI and tooling — no runtime code changes. The registry verification is read-only (queries npm, does not publish). The release script changes add safety checks that abort before publishing if state is unexpected. ## Model Used Codex GPT 5.4 high via Paperclip. ## 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 run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] If this change affects the UI, I have included before/after screenshots - [x] I have updated relevant documentation to reflect my changes - [x] I have considered and documented any risks above - [x] I will address all Greptile and reviewer comments before requesting merge
This commit is contained in:
parent
367d4cab72
commit
a0f5cbffd7
7 changed files with 465 additions and 2 deletions
128
scripts/verify-release-registry-state.test.mjs
Normal file
128
scripts/verify-release-registry-state.test.mjs
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
import assert from "node:assert/strict";
|
||||
import test from "node:test";
|
||||
|
||||
import {
|
||||
collectInternalDependencyProblems,
|
||||
isCanaryVersion,
|
||||
verifyPackageRegistryState,
|
||||
} from "./verify-release-registry-state.mjs";
|
||||
|
||||
test("isCanaryVersion matches release canaries", () => {
|
||||
assert.equal(isCanaryVersion("2026.427.0-canary.3"), true);
|
||||
assert.equal(isCanaryVersion("2026.427.0"), false);
|
||||
});
|
||||
|
||||
test("collectInternalDependencyProblems flags missing internal versions", () => {
|
||||
const manifest = {
|
||||
dependencies: {
|
||||
"@paperclipai/plugin-sdk": "2026.425.0-canary.5",
|
||||
e2b: "^2.19.0",
|
||||
},
|
||||
};
|
||||
const packageDocsByName = new Map([
|
||||
[
|
||||
"@paperclipai/plugin-sdk",
|
||||
{
|
||||
versions: {
|
||||
"2026.427.0-canary.3": {},
|
||||
},
|
||||
},
|
||||
],
|
||||
]);
|
||||
|
||||
assert.deepEqual(collectInternalDependencyProblems(manifest, packageDocsByName), [
|
||||
"dependencies requires @paperclipai/plugin-sdk@2026.425.0-canary.5, but npm does not expose that version",
|
||||
]);
|
||||
});
|
||||
|
||||
test("verifyPackageRegistryState fails when canary latest is left in place by default", () => {
|
||||
const packageDocsByName = new Map([
|
||||
[
|
||||
"@paperclipai/plugin-e2b",
|
||||
{
|
||||
"dist-tags": {
|
||||
latest: "2026.425.0-canary.5",
|
||||
canary: "2026.427.0-canary.3",
|
||||
},
|
||||
versions: {
|
||||
"2026.425.0-canary.5": {
|
||||
dependencies: {
|
||||
"@paperclipai/plugin-sdk": "2026.425.0-canary.5",
|
||||
},
|
||||
},
|
||||
"2026.427.0-canary.3": {
|
||||
dependencies: {
|
||||
"@paperclipai/plugin-sdk": "2026.427.0-canary.3",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
"@paperclipai/plugin-sdk",
|
||||
{
|
||||
versions: {
|
||||
"2026.427.0-canary.3": {},
|
||||
},
|
||||
},
|
||||
],
|
||||
]);
|
||||
|
||||
assert.deepEqual(
|
||||
verifyPackageRegistryState({
|
||||
packageName: "@paperclipai/plugin-e2b",
|
||||
packageDoc: packageDocsByName.get("@paperclipai/plugin-e2b"),
|
||||
packageDocsByName,
|
||||
channel: "canary",
|
||||
distTag: "canary",
|
||||
targetVersion: "2026.427.0-canary.3",
|
||||
allowCanaryLatest: false,
|
||||
}),
|
||||
[
|
||||
"@paperclipai/plugin-e2b: latest dist-tag still resolves to canary 2026.425.0-canary.5; rerun with --allow-canary-latest only when that state is intentional",
|
||||
"@paperclipai/plugin-e2b@2026.425.0-canary.5 via latest: dependencies requires @paperclipai/plugin-sdk@2026.425.0-canary.5, but npm does not expose that version",
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
test("verifyPackageRegistryState allows intentional canary latest but still checks dependencies", () => {
|
||||
const packageDocsByName = new Map([
|
||||
[
|
||||
"paperclipai",
|
||||
{
|
||||
"dist-tags": {
|
||||
latest: "2026.427.0-canary.3",
|
||||
canary: "2026.427.0-canary.3",
|
||||
},
|
||||
versions: {
|
||||
"2026.427.0-canary.3": {
|
||||
dependencies: {
|
||||
"@paperclipai/server": "2026.427.0-canary.3",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
[
|
||||
"@paperclipai/server",
|
||||
{
|
||||
versions: {
|
||||
"2026.427.0-canary.3": {},
|
||||
},
|
||||
},
|
||||
],
|
||||
]);
|
||||
|
||||
assert.deepEqual(
|
||||
verifyPackageRegistryState({
|
||||
packageName: "paperclipai",
|
||||
packageDoc: packageDocsByName.get("paperclipai"),
|
||||
packageDocsByName,
|
||||
channel: "canary",
|
||||
distTag: "canary",
|
||||
targetVersion: "2026.427.0-canary.3",
|
||||
allowCanaryLatest: true,
|
||||
}),
|
||||
[],
|
||||
);
|
||||
});
|
||||
Loading…
Add table
Add a link
Reference in a new issue