fix(extensions): address #264 review follow-ups#1351
Conversation
…pers (swamp-club#264) Add a `binaries` field to the extension manifest so authors can declare executable host helpers (shell scripts, extensionless binaries) that ship alongside their extension. These files are exempt from the file-extension safety allowlist but still subject to all other checks (hidden files, symlinks, size limits, file count). Key changes: - Manifest schema: new optional `binaries: string[]` field - Safety analyzer: `exemptFromExtensionCheck` parameter skips the extension allowlist for declared binaries - Push: binary files packaged in archive with mode bits preserved - Pull: defensive chmod +x on POSIX, warning listing binary paths - Push metadata: binaries list sent to swamp-club for display Linux/macOS preserve executable bits through the publish/pull cycle. Windows: files are extracted and writable; executable invocation depends on file extension and shell behavior. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Condense the Before Starting checklist to a single sentence (each state already explains itself). Move State 7 failure remediation inline list to the reference file where the full safety rules live. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Add binaries to the belt-and-suspenders path traversal check in resolve_extension_files.ts (every other manifest field had both Zod validation and this fallback; binaries was missing) - Add cross-field dedup between additionalFiles and binaries — reject manifests that list the same path in both fields since both land in the same files/ directory - Narrow the pull-side chmod catch to only swallow NotFound errors and log other failures at debug level instead of silently discarding them Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
CLI UX Review
Blocking
None.
Suggestions
None.
Verdict
PASS — This PR makes no user-visible UX changes beyond adding a single new UserError. The new message (Path "${bf}" appears in both binaries and additionalFiles...) is clear, actionable, and consistent in tone and format with the surrounding error messages in resolve_extension_files.ts. The chmod catch narrowing in pull.ts is debug-level only and not visible to normal users. No commands, flags, help text, or JSON output shapes were changed.
There was a problem hiding this comment.
Adversarial Review
Critical / High
None.
Medium
None.
Low
-
src/cli/resolve_extension_files.ts:534— binaries not added toseenNormalized: The cross-field dedup checks binaries againstseenNormalized(additionalFiles map) but does not insert binaries intoseenNormalized. If a future field also lands infiles/and only checksseenNormalized, it would miss collisions with binaries. Not a bug today — only additionalFiles and binaries targetfiles/, and the check between them is complete — but worth noting for defensiveness. -
src/libswamp/extensions/pull.ts:970-971— non-NotFound chmod errors logged at debug, not warned: Ifchmodfails with e.g.PermissionDenied, the binary won't be executable at runtime, but this is only logged atdebuglevel. A user who doesn't run with debug logging would see no indication the binary won't work. The old code was strictly worse (silent catch-all), so this is an improvement, butwarnmight be more appropriate for non-NotFound chmod failures since they indicate the binary will be broken.
Verdict
PASS — Small, focused fix that plugs real gaps identified in prior review. The path-traversal belt-and-suspenders addition for binaries is correct and follows the established pattern. The cross-field dedup between additionalFiles and binaries is complete (additionalFiles fully populates seenNormalized before binaries checks against it). The chmod error narrowing is strictly better than the previous catch-all. No logic errors, no security issues, no missing edge cases.
There was a problem hiding this comment.
Code Review
All three changes are correct, well-scoped, and improve the security posture of the extension system.
Blocking Issues
None.
Suggestions
- Test coverage for the new cross-field dedup (
resolve_extension_files.ts:526-533): The new validation that rejects manifests listing the same path in bothbinariesandadditionalFilesis genuinely new logic with a distinct error path. The test file has 29 tests but none exercise anybinariesvalidation at all (a pre-existing gap). A test asserting that a manifest with a path in both fields throws the expectedUserErrorwould lock this down. Not blocking since the logic is straightforward and correct on inspection, but worth adding.
Notes
- Path traversal fix (line 153): Correctly closes the gap where
binarieswas the only manifest field missing from the belt-and-suspendersisSafeRelativePathcheck. Good security fix. - Cross-field dedup (lines 526-533): The one-directional check against
seenNormalizedis correct sinceadditionalFiles(step 15) is always processed beforebinaries(step 16). Error message is clear and actionable. - Narrowed chmod catch (
pull.ts:968-973): Good improvement — only swallowingNotFoundinstead of all errors, with debug logging for unexpected failures. Follows the LogTape tagged template convention from CLAUDE.md. - License headers present on both files. No libswamp import boundary violations. No
anytypes introduced.
Summary
binariesto the belt-and-suspenders path traversal check — every other manifest field had both Zod and fallback validation,binarieswas missedadditionalFilesandbinaries— reject manifests listing the same path in both since both land infiles/NotFoundand log other errors at debug levelAddresses review feedback from #1350.
Test plan
deno check— passesdeno lint— passesdeno fmt— passesdeno run test— 5731 pass, 0 failures🤖 Generated with Claude Code