Skip to main content
← Back to list
01Issue
BugTriagedSwamp ClubPublic
Assigneeskeeb

Relationships

#1961 Extension version binaries never persisted — binaries security notice has never rendered

Opened by keeb · 9/2/2026

Description

binaries is accepted on publish, validated, and attached to the in-memory version record — then silently dropped before the insert. It has never been written to the database. The consequence is that the extension page's binaries security notice has never rendered for any extension on the registry.

Found while triaging #1951 (unrelated README/changelog bug); filing separately since it shares no code with that fix.

Where it breaks

MongoExtensionRepository.addVersion builds the document field by field and has no binaries key:

  • lib/infrastructure/mongo-extension-repository.ts:1402-1422 — the ExtensionVersionDocument literal. contentMetadata, releaseNotes and diff each get a conditional spread; binaries is absent entirely.

Everything on both sides of that line is correct, which is what makes it invisible:

  • routes/api/v1/extensions/confirm.ts:142 — accepted off the wire as binaries: body.binaries
  • lib/app/confirm-push.ts:268const binaries = validateBinaries(req.binaries);
  • lib/app/confirm-push.ts:324 — set on versionData
  • lib/infrastructure/mongo-extension-repository.ts:98 — declared on the document type (binaries?: string[])
  • lib/infrastructure/mongo-extension-repository.ts:157 — mapped on read (binaries: doc.binaries ?? [])

So the write path type-checks, the read path type-checks, and the ?? [] at the read makes the missing field indistinguishable from an extension that genuinely ships no binaries.

Verification

Queried prod Mongo (Atlas, test db) directly:

db.extension_versions.find({ binaries: { $exists: true } })  →  0 documents

Not "0 non-empty" — the field is absent from every version document in the registry. Nothing has ever been written.

Impact

  1. A security disclosure never renders. routes/extensions/[...name].tsx:761-778 is the "Security Notice" panel that warns "This extension includes executable binaries that run with your user permissions. Inspect before use." and lists the binary names. It is gated on hasBinaries ([...name].tsx:572, (latestVersion?.binaries.length ?? 0) > 0), which is permanently false. An extension that ships executable binaries is presented to installers identically to one that does not.

    Note the sibling hasExecutableScripts warning in the same panel derives from contentMetadata.skills, which is persisted — so that half still works, and the panel keeps appearing for skill-bearing extensions. That's part of why this went unnoticed: the section is not obviously dead.

  2. Version diffs can never report binary changes. lib/app/confirm-push.ts:293 feeds previousVersion.binaries ?? [] into computeVersionDiff, which always reads []. Adding or removing a binary produces no diff category, so it never appears in the auto-generated changelog.

Steps to reproduce

  1. Publish an extension whose manifest declares a binaries entry.
  2. Visit its page on swamp.club — no binary names are listed and no binaries security notice appears.
  3. Confirm in Mongo: the extension_versions document for that version has no binaries field.

When it broke

Dead since the feature shipped — 754cedac, "extensions: accept and display binaries field from push metadata (#303) (#519)". The commit added the wire format, the validation, the document type, the read mapping and the renderer, but not the write. Not a regression; it has never worked.

Related but distinct: #589 (extension push error for disallowed file types doesn't mention binaries field, shipped) is about the push-time error message, not persistence.

Suggested fix

Add binaries to the inserted document in addVersion. Prefer an unconditional binaries: version.binaries ?? [] over a truthiness spread — the read already normalizes with ?? [], and a conditional spread is what let this hide in the first place. Worth a round-trip test (write → read → rendered flag) rather than a document-shape assertion, since a shape assertion on the literal would have passed against the broken code.

Existing published versions cannot be backfilled from the request (the data was never captured), but binaries is re-derivable from the archives in S3 if a repair pass is wanted; otherwise it heals on next publish.

02Bog Flow
OPENTRIAGEDIN PROGRESSSHIPPED+ 1 MOREASSIGNED+ 14 MOREREVIEW

Triaged

9/2/2026, 4:39:55 PM

Click a lifecycle step above to view its details.

03Sludge Pulse
keeb assigned keeb9/2/2026, 4:37:00 PM

Sign in to post a ripple.