Make stable versions immutable and allow soft-deletion / hiding of versions#1742
Conversation
7788a44 to
1b6cf76
Compare
glaubinix
left a comment
There was a problem hiding this comment.
Not fully through yet. Still missing the second half of the updater changes + tests and JS code
| SET updatedAt = :now, softDeletedAt = NULL, deletionReason = NULL, deletionReasonText = NULL | ||
| WHERE id IN (:ids) | ||
| AND softDeletedAt IS NOT NULL | ||
| AND (deletionReason IS NULL OR deletionReason = :autoReason)', |
There was a problem hiding this comment.
Just curious when would deletionReason by NULL here? Is this for versions soft deleted before merging this PR? Wonder if we should mark them as AutoDeletedMissing via migration? Would take it there aren't that many versions flagged as softDelete right now
There was a problem hiding this comment.
The migration file does set null ones to autodeleted missing actually, so once that ran through I guess we could simplify this condition yes.
And yeah there are 20K records with soft delete set right now, because some packages just never get updated for various reasons and then old branches are just left there dangling.
e34e37b to
767629f
Compare
Co-authored-by: Stephan <glaubinix@users.noreply.github.com>
e35b950 to
9dc3927
Compare
|
Ok this is ready to go I think, will deploy it tomorrow morning. |
Why
Today the Updater silently rewrites a stable version row whenever upstream changes the source/dist reference (re-tags, force-pushed annotated tags, etc.). For a published
v1.2.3this is wrong — downstream lock files, mirrors, and security scanners all assume a tagged release is a frozen snapshot. AndVersionRepository::remove()is the only way to pull a release: no recovery, no provenance, no way to distinguish maintainer cleanup from an admin takedown.This PR locks stable versions, adds a reason-aware soft-delete, and a separate admin-only version hiding capability.
Stable-version immutability gate (
Updater)source.referenceif present, elsedist.reference.DELETE_BEFOREnow only wipes dev versions; stable rows fall through to the immutability gate.UPDATE_EQUAL_REFSrenamed toUPDATE_SOURCE_DIST_URL. For stable rows, the URL rewrite only fires when both old and new refs are identical 40+ char hashes AND a driver-confirmed dist URL fetch verifies the new URL. Otherwise the version is skipped with a specific reason.Soft-delete with reasons (new
VersionDeletionReasonenum)AutoDeletedMissing— Updater soft-marks a row when upstream loses it; hard-purges after 1 day for dev versions only. Stable versions stay forever.DeletedByMaintainer— pulled via the per-version UI delete.DeletedByAdmin— pulled by an admin with an optional public reason.Hidden— admin took the version down with no public trace (used by the spam-cascade and selective takedowns). Visible to maintainers/admins, hidden from everyone else.V2 metadata + UI
V2Dumperfilters soft-deleted versions out of both<name>.jsonand<name>~dev.json. Composer can no longer resolve a pulled version.Deleted by maintainer on ...,Removed by admin on ...: <reason>,Hidden by admin on ...: <reason>,No longer found in upstream repository).lastBlockedReference IS NOT NULL, linking to the new doc page.Audit + notification
VersionSoftDeleted,VersionRecovered,VersionReferenceChangeBlocked./about/version-immutabilityexplaining the rule, what the maintainer sees, and the recommended remediation.Out of scope
PackageManager::deletePackage/CleanSpamPackagesCommand) is a separate concept (whole row cascades) and untouched.