Skip to main content
← Back to list
01Issue
FeatureClosedSwamp CLI
Assigneesstack72

Scorer should honour files/deno.json imports so bare specifiers resolve

Opened by stack72 · 4/24/2026

Problem

The extension tarball analyzer (lib/infrastructure/extension-tarball-analyzer.ts) strips the root deno.json and writes a controlled one with nodeModulesDir: "auto" and no imports map. Bare specifier imports like import { z } from "zod" therefore cannot resolve at score time, even when the publisher ships the import map via additionalFiles: [deno.json].

This creates a catch-22 for extension authors. Deno's no-import-prefix lint rule fires by default whenever a deno.json has an imports map — which is every swamp repo's default state — so:

  • Bare "zod" + repo deno.json: passes swamp extension fmt / swamp extension push, fails swamp extension quality and the registry scorer.
  • Inline "npm:zod@4": passes the scorer, fails swamp extension fmt / swamp extension push because of no-import-prefix.

The only escape today is disabling no-import-prefix in the repo's deno.json or scattering // deno-lint-ignore comments per import — documented as a workaround in swamp#1220, but the proper fix is server-side.

Proposed solution

Mirror the existing findReadme / findLicenseFile pattern (lines 598, 620 of the analyzer) for deno.json: check files/deno.json in the tarball and merge its imports map into the controlled deno.json the analyzer writes. The security argument for stripping the ROOT deno.json (line 394-409) doesn't apply to files/deno.json because it's a publisher-declared location, the merge can whitelist only imports, and each value can be validated against an allowlist.

Specifically:

  • Between stripHermeticityConfigs(logicalRoot) (line 123) and writeControlledDenoJson(logicalRoot) (line 124), read files/deno.json and extract ONLY the imports field (and possibly scopes). Ignore tasks, compilerOptions, lint, fmt, nodeModulesDir, unstable, workspace, everything else.
  • Validate each imports value: must match npm:*, jsr:*, https://<allowlisted host>, or a relative path that doesn't escape the tarball. Drop anything else.
  • Cap cardinality (e.g. 50 entries) and per-string length. Size-cap the file itself.
  • Merge the validated imports into the controlled { nodeModulesDir: "auto" } config that gets written to the root.

Back-compat: tarballs without files/deno.json behave exactly as today.

Test coverage needed

  1. Happy path: files/deno.json with { "imports": { "zod": "npm:zod@4" } } + entrypoint using bare "zod" → scores normally.
  2. Path traversal: value "../etc/passwd" → dropped.
  3. Disallowed scheme: value "data:..." → dropped.
  4. Oversized file → ignored.
  5. Malformed JSON → ignored, analyzer still runs.
  6. Key explosion (10k entries) → truncated to cap.
  7. Irrelevant keys (tasks, compilerOptions, etc.) → do NOT land in controlled config.
  8. No files/deno.json → behaves as today.

Alternatives considered

  • Leave as-is, document the catch-22. Done in swamp#1220 as the interim. Works but requires every author to disable no-import-prefix or use inline npm: — both inferior to shipping their import map.
  • Honour root deno.json in the tarball. Rejected by the existing security comment at line 394-409 — a root deno.json can shadow the entire analyzer environment. files/ is safer because the publisher explicitly opted in and we can whitelist fields.
  • Inline ONLY at bundle time, strip at publish. The swamp CLI would rewrite bare → inline before packaging. Rejected: invasive, changes publisher source semantics, and swamp#1218's swamp extension quality already mirrors server behaviour so the problem shows up locally anyway.

Downstream manual updates

After this ships, the following pages in this repo need updates:

  • content/manual/reference/extension-manifest.md (~line 520): the "bare from \"zod\" requires a deno.json import map" row is now accurate ONLY if deno.json is also in additionalFiles:. Split into bundle-time vs score-time resolution, or add the clause.
  • content/manual/how-to/improve-extension-score.md: add a section noting bare specifiers require shipping deno.json via additionalFiles:.
  • content/manual/how-to/create-and-publish-extension.md (~line 21): keep inline npm:zod@4 as the primary recommendation but add the bare + additionalFiles alternative.

Swamp-side cleanup (separate, in systeminit/swamp)

Once this ships, the gotcha block added by swamp#1220 in .claude/skills/swamp-extension-quality/SKILL.md becomes partly stale:

  • The no-import-prefix catch-22 goes away.
  • "Adding deno.json to additionalFiles: does not help" → flips to "is the supported way".
  • Remove the forward-looking sentence about the scorer honouring files/deno.json.

Origin

Surfaced during triage of swamp-club#161 and the corresponding interim fix in systeminit/swamp#1220. Issue 161's skill-level workaround is the band-aid; this is the proper fix.

02Bog Flow
OPENTRIAGEDIN PROGRESSCLOSED+ 1 MOREASSIGNED+ 4 MOREFINDINGS

Closed

4/24/2026, 11:27:52 PM

No activity in this phase yet.

03Sludge Pulse
stack72 assigned stack724/24/2026, 11:13:02 PM
Editable. Press Enter to edit.

stack72 commented 4/24/2026, 11:27:51 PM

Not doing this at this time - we will come back to it if we need to

Sign in to post a ripple.