fix(api): preserve latest across package backports (#3302)

This commit is contained in:
Vincent Koc
2026-07-30 17:45:25 +08:00
committed by GitHub
parent 9f037c1806
commit be94d781ae
3 changed files with 202 additions and 6 deletions
+1
View File
@@ -9,6 +9,7 @@
### Fixes
- API: keep older code-plugin and Claw backports from replacing the highest-semver `latest` release while preserving custom distribution tags.
- Integrations: truncate publisher-controlled Discord webhook titles to the platform's 256-character embed limit.
- Security: recover scheduled temporal publisher-abuse scans from strict Convex payload validation failures without leaving zombie running runs (thanks @jesse-merhi).
- CI: retry transient Convex preview provisioning failures under fresh deployment names during Vercel preview builds.
+126
View File
@@ -7915,6 +7915,7 @@ describe("packages public queries", () => {
expect(ctx.patch).toHaveBeenCalledWith("packageReleases:pending", {
publicationStatus: "published",
pendingPublication: undefined,
distTags: ["latest"],
verification: { scanStatus: "clean" },
});
await flushScheduledPackageReleaseTagCleanup(ctx);
@@ -7931,6 +7932,74 @@ describe("packages public queries", () => {
);
});
it("keeps the current latest when finalizing an older package release", async () => {
const existingPackage = makePackageDoc({
latestReleaseId: "packageReleases:latest",
latestVersionSummary: { version: "2.0.0" },
tags: { latest: "packageReleases:latest" },
summary: "current summary",
stats: { downloads: 0, installs: 0, stars: 0, versions: 1 },
});
const latestRelease = makeReleaseDoc({
_id: "packageReleases:latest",
version: "2.0.0",
distTags: ["latest"],
publicationStatus: "published",
});
const pendingRelease = makeReleaseDoc({
_id: "packageReleases:pending",
version: "1.0.1",
publicationStatus: "pending",
pendingPublication: {
displayName: "Demo Plugin v1",
tags: ["latest", "v1"],
channel: "community",
isOfficial: false,
},
distTags: ["latest", "v1"],
summary: "backport summary",
changelog: "backport",
integritySha256: "backport-sha",
verification: { scanStatus: "pending" },
llmAnalysis: {
status: "clean",
verdict: "clean",
checkedAt: 1_700_000_000_000,
},
});
const ctx = makeInsertReleaseCtx(existingPackage, [latestRelease, pendingRelease], {
"packageReleases:latest": latestRelease,
"packageReleases:pending": pendingRelease,
"packages:demo": existingPackage,
});
await publishPendingReleaseInternalHandler(ctx, {
releaseId: "packageReleases:pending",
});
expect(ctx.patch).toHaveBeenCalledWith(
"packageReleases:pending",
expect.objectContaining({
publicationStatus: "published",
distTags: ["v1"],
}),
);
expect(ctx.patch).toHaveBeenCalledWith(
"packages:demo",
expect.objectContaining({
latestReleaseId: "packageReleases:latest",
latestVersionSummary: { version: "2.0.0" },
summary: "current summary",
tags: {
latest: "packageReleases:latest",
v1: "packageReleases:pending",
},
stats: { downloads: 0, installs: 0, stars: 0, versions: 2 },
}),
);
expect(ctx.scheduler.runAfter).not.toHaveBeenCalled();
});
it("publishes a pending release without reading its file-heavy release history", async () => {
const priorRelease = makeReleaseDoc({
_id: "packageReleases:old",
@@ -8333,6 +8402,63 @@ describe("packages public queries", () => {
}
});
it("uses the latest tag when the version summary and release pointer are stale", async () => {
const existingPackage = makePackageDoc({
latestReleaseId: "packageReleases:stale",
latestVersionSummary: undefined,
tags: { latest: "packageReleases:latest" },
summary: "current summary",
stats: { downloads: 0, installs: 0, stars: 0, versions: 1 },
});
const staleRelease = makeReleaseDoc({
_id: "packageReleases:stale",
version: "1.0.0",
distTags: [],
});
const latestRelease = makeReleaseDoc({
_id: "packageReleases:latest",
version: "2.0.0",
distTags: ["latest"],
});
const ctx = makeInsertReleaseCtx(existingPackage, [staleRelease, latestRelease]);
await insertReleaseInternalHandler(ctx, {
actorUserId: "users:owner",
ownerUserId: "users:owner",
name: "demo-plugin",
displayName: "Demo Plugin v1",
family: "code-plugin",
version: "1.5.0",
changelog: "backport",
tags: ["latest", "v1"],
summary: "backport summary",
files: [],
integritySha256: "backport-sha",
});
expect(ctx.insert).toHaveBeenCalledWith(
"packageReleases",
expect.objectContaining({
version: "1.5.0",
distTags: ["v1"],
}),
);
expect(ctx.patch).toHaveBeenCalledWith(
"packages:demo",
expect.objectContaining({
latestReleaseId: "packageReleases:stale",
latestVersionSummary: undefined,
summary: "current summary",
tags: {
latest: "packageReleases:latest",
v1: "packageReleases:new",
},
stats: { downloads: 0, installs: 0, stars: 0, versions: 2 },
}),
);
expect(ctx.scheduler.runAfter).not.toHaveBeenCalled();
});
it("publishes suspicious prepublication plugin results with a suspicious scan status", async () => {
const ctx = makeInsertReleaseCtx(makePackageDoc());
const llmAnalysis = {
+75 -6
View File
@@ -10225,6 +10225,35 @@ type PackageReleaseTagCleanupAssignment = {
tags: string[];
};
function resolvePackageReleaseTagsForPublish(params: {
family: Doc<"packages">["family"];
currentLatestExists: boolean;
currentLatestVersion?: string;
candidateVersion: string;
requestedTags: string[];
}) {
const requestedLatest = params.requestedTags.some((tag) => tag.toLowerCase() === "latest");
const currentLatestSemver = params.currentLatestVersion
? semver.valid(params.currentLatestVersion)
: null;
const candidateSemver = semver.valid(params.candidateVersion);
const latestUsesSemver = params.family === "code-plugin" || params.family === "claw";
// `latest` is reserved for the highest semver on versioned package families.
// Callers default to this tag, so accepting it blindly would let backports roll the catalog back.
const shouldPromoteLatest =
requestedLatest &&
(!latestUsesSemver ||
!params.currentLatestExists ||
(currentLatestSemver !== null &&
candidateSemver !== null &&
semver.gt(candidateSemver, currentLatestSemver)));
const effectiveTags = [
...new Set(params.requestedTags.filter((tag) => tag.toLowerCase() !== "latest")),
];
if (shouldPromoteLatest) effectiveTags.push("latest");
return { effectiveTags, shouldPromoteLatest };
}
function getPackageTagReleaseId(
pkg: Pick<Doc<"packages">, "_id" | "latestReleaseId" | "tags">,
tag: string,
@@ -10232,6 +10261,32 @@ function getPackageTagReleaseId(
return tag === "latest" ? (pkg.tags.latest ?? pkg.latestReleaseId) : pkg.tags[tag];
}
async function resolvePackageCurrentLatestForPublish(
ctx: Pick<MutationCtx, "db">,
pkg: Pick<
Doc<"packages">,
"_id" | "family" | "latestReleaseId" | "latestVersionSummary" | "tags"
>,
) {
const latestReleaseId = getPackageTagReleaseId(pkg, "latest");
if (!latestReleaseId) return { exists: false, version: undefined };
if (pkg.family !== "code-plugin" && pkg.family !== "claw") {
return { exists: true, version: pkg.latestVersionSummary?.version };
}
const latestRelease = await ctx.db.get(latestReleaseId);
if (
latestRelease &&
latestRelease.packageId === pkg._id &&
isPublishedPackageRelease(latestRelease)
) {
return { exists: true, version: latestRelease.version };
}
// Keep the current pointer when its release row is missing or unusable.
// Promotion without a comparable version could roll installs back to a backport.
return { exists: true, version: pkg.latestVersionSummary?.version };
}
function planPackageReleaseTagReassignment(
pkg: Pick<Doc<"packages">, "_id" | "latestReleaseId" | "tags">,
releaseId: Id<"packageReleases">,
@@ -10399,8 +10454,14 @@ export const publishPendingReleaseInternal = internalMutation({
const now = Date.now();
const metadata = pendingPackagePublicationMetadata(release);
const effectiveTags = stringArrayPendingField(metadata, "tags") ?? release.distTags ?? [];
const shouldPromoteLatest = effectiveTags.includes("latest");
const currentLatest = await resolvePackageCurrentLatestForPublish(ctx, pkg);
const { effectiveTags, shouldPromoteLatest } = resolvePackageReleaseTagsForPublish({
family: pkg.family,
currentLatestExists: currentLatest.exists,
currentLatestVersion: currentLatest.version,
candidateVersion: release.version,
requestedTags: stringArrayPendingField(metadata, "tags") ?? release.distTags ?? [],
});
const scanStatus = resolvePackageReleaseScanStatus(release);
const releaseVerification = release.verification
? { ...release.verification, scanStatus }
@@ -10409,6 +10470,7 @@ export const publishPendingReleaseInternal = internalMutation({
...release,
publicationStatus: "published" as const,
pendingPublication: undefined,
distTags: effectiveTags,
verification: releaseVerification,
} as Doc<"packageReleases">;
@@ -10421,6 +10483,7 @@ export const publishPendingReleaseInternal = internalMutation({
await ctx.db.patch(release._id, {
publicationStatus: "published",
pendingPublication: undefined,
distTags: effectiveTags,
verification: releaseVerification,
});
@@ -10738,10 +10801,16 @@ export const insertReleaseInternal = internalMutation({
);
}
}
const shouldPromoteLatest = args.tags.includes("latest");
const effectiveTags = shouldPromoteLatest
? Array.from(new Set([...args.tags, "latest"]))
: args.tags;
const currentLatest = existing
? await resolvePackageCurrentLatestForPublish(ctx, existing)
: { exists: false, version: undefined };
const { effectiveTags, shouldPromoteLatest } = resolvePackageReleaseTagsForPublish({
family: args.family,
currentLatestExists: currentLatest.exists,
currentLatestVersion: currentLatest.version,
candidateVersion: args.version,
requestedTags: args.tags,
});
const releaseId = await ctx.db.insert("packageReleases", {
packageId: pkgId,