Conversation
Multipart package publish stored the tarball and files before validation, and the handler catch returned 400 without deleting those Convex storage ids. Signed-off-by: Sebastien Tardif <SebTardif@ncf.ca>
|
🦞👀 Pull request received. I will update this pull request when review starts. ClawSweeper review completeClawSweeper finished reviewing this revision. The review result is being finalized. |
|
@SebTardif is attempting to deploy a commit to the OpenClaw Foundation Team on Vercel. A member of the Team first needs to authorize it. |
Existing handler tests mock store without delete. The unpublished-blob cleanup now skips when delete is absent, and accepts string storage ids so tsc matches the rest of the publish payload. Signed-off-by: Sebastien Tardif <SebTardif@ncf.ca>
|
Codex review: needs real behavior proof before merge. Reviewed September 11, 2026, 10:08 AM ET / 14:08 UTC (Revision 3). ClawSweeper reviewWhat this changesDeletes uploaded package files and tarballs after multipart storage or publication failures, and adds three handler regression tests. Regression provenancePossible regression — suspected (reviewed change). No predecessor PR is attributed. Merge readiness⛔ Blocked before merge - 11 items remain The cleanup remains necessary on current main, but both prior blocking findings remain: the patch can delete reused staged tarballs and blobs already owned by a release. The submitted trace uses in-memory storage and does not establish safe Convex deletion. Priority: P2 Review scores
Verification
How this fits togetherClawHub’s package publishing endpoint accepts loose files or a packaged tarball, stores them in Convex, and passes their storage IDs to the publication service. Releases and pending publication attempts then retain those blobs for scanning and downloads. flowchart TD
A[Authenticated package upload] --> B[Direct files or staged tarball]
B --> C[Parse and store files]
C --> D[Validate and publish]
D --> E[Release owns blobs]
C --> F[Failure cleanup]
D --> F
F --> G[Delete selected storage IDs]
Before merge
Findings
Agent review detailsSecurityNeeds attention: The new deletion path treats an old upload capability as authority to delete a release artifact after current publishing permission is denied. Review metrics
Root-cause clusterRelationship: Members:
Proposal only: this assessment does not dispatch repair, suppress jobs, mutate sibling items, close, or merge anything. Merge-risk optionsMaintainer options:
Technical reviewBest possible solution: Track request-created blobs separately from staged artifacts, and transfer cleanup responsibility to the publication owner once a release adopts them. Do we have a high-confidence way to reproduce the issue? Yes, source establishes the failure paths: replay a previously used staged ticket into a rejected publish, or throw after release insertion. These paths were not executed during this read-only review. Is this the best way to solve the issue? No. Waiting for concurrent stores to settle is appropriate, but the outer catch cannot infer that blobs are unpublished; ownership-aware cleanup is safer than deleting every payload ID. Full review comments:
Overall correctness: patch is incorrect AGENTS.md: found and applied where relevant. Codex review notes: model internal, reasoning medium; reviewed against cbfee7343ddc. LabelsLabel justifications:
EvidenceSecurity concerns:
What I checked:
Likely related people:
Rating scale
Overall follows the weaker of proof and patch quality. Workflow
HistoryReview history (2 earlier review cycles)
|
Signed-off-by: Sebastien Tardif <SebTardif@ncf.ca>
|
Closing this PR to free a barnacle slot for a higher-severity GitHub import unzip-limit fix (issue #3678). ClawSweeper left this change unranked with open deletion-safety P1s, so it is unlikely to merge as written. The leak itself stays tracked on issue #3673. That issue stays open. A later PR can pick it up after the P1s are addressed. |
What Problem This Solves
Fixes an issue where users publishing a package through authenticated
POST /api/v1/packageswithmultipart/form-datawould leave Convex storage blobs behind when publish failed. The request stored the ClawPack tarball and extracted files, or the loose uploaded files, then validated name, version, account age, and owner. A 400 from that validation, or a later extracted-file store failure, never deleted those ids. The blobs were not attached to a package release, so they stayed billed and unreferenced.Why This Change Was Made
Multipart package publish now follows the same cleanup contract as skill-scan upload. File and artifact storage ids are tracked. If parse fails after any store, or if publish throws after parse succeeds, those ids are deleted with
Promise.allSettledandstorage.delete. A successful publish keeps the blobs. The existing HTTP 400 mapping is unchanged; cleanup runs first, then the same error response is returned.User Impact
Failed CLI or API package publishes no longer leave orphaned upload blobs in Convex storage. Successful publishes are unchanged.
Evidence
Live
bunon Windows, worktreeC:/Users/sebta/.grok/tmp/pr-gate-batch/clawhub-f007. The script calls productionpublishPackageV1Handlerwith an in-memory storage stand-in. The old loop stores two loose files and never deletes them. The patched handler stores the same two ids and deletes both before returning 400. A ClawPack path that stores the tarball then fails on the first extracted-file store deletes the tarball id.The unpatched path leaves
storage:before-1,storage:before-2withbefore_deleted=-. The patched path printsafter_deleted=storage:after-1,storage:after-2andclawpack_deleted=storage:tarball.Real behavior proof
C:/Users/sebta/.grok/tmp/pr-gate-batch/clawhub-f007onfix/package-publish-blob-cleanup. Proof imported productionpublishPackageV1Handlerfromconvex/httpApiV1/packagesV1.ts.bun /tmp/clawhub-f007-proof.mjs. The script posted a multipart package publish with two loose files, first through the old store-then-throw loop, then through productionpublishPackageV1Handler. It also posted a ClawPack where the tarball store succeeded and the next store failed.after_stored=storage:after-1,storage:after-2andafter_deleted=storage:after-1,storage:after-2. The ClawPack path storedstorage:tarballand deletedstorage:tarball. Before the patch,before_stored=storage:before-1,storage:before-2andbefore_deleted=-.Notes
Same cleanup contract as skill multipart in #3549 and skill scan uploads in #2479. Multipart package store-without-cleanup landed in #2414 (2026-06-02, 95 days). The handler catch without delete dates to #1093 (2026-03-20, 169 days).
Allow edits from maintainers is enabled.
Tracker
Ref #3673
That issue stays open if this PR is closed without landing on main.