Skip to content

fix(extensions): address #264 review follow-ups#1351

Merged
stack72 merged 5 commits into
mainfrom
fix-264-followups
May 9, 2026
Merged

fix(extensions): address #264 review follow-ups#1351
stack72 merged 5 commits into
mainfrom
fix-264-followups

Conversation

@stack72
Copy link
Copy Markdown
Contributor

@stack72 stack72 commented May 9, 2026

Summary

  • Add binaries to the belt-and-suspenders path traversal check — every other manifest field had both Zod and fallback validation, binaries was missed
  • Add cross-field dedup between additionalFiles and binaries — reject manifests listing the same path in both since both land in files/
  • Narrow pull-side chmod catch to only swallow NotFound and log other errors at debug level

Addresses review feedback from #1350.

Test plan

  • deno check — passes
  • deno lint — passes
  • deno fmt — passes
  • deno run test — 5731 pass, 0 failures

🤖 Generated with Claude Code

stack72 and others added 5 commits May 9, 2026 22:21
…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>
Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adversarial Review

Critical / High

None.

Medium

None.

Low

  1. src/cli/resolve_extension_files.ts:534 — binaries not added to seenNormalized: The cross-field dedup checks binaries against seenNormalized (additionalFiles map) but does not insert binaries into seenNormalized. If a future field also lands in files/ and only checks seenNormalized, it would miss collisions with binaries. Not a bug today — only additionalFiles and binaries target files/, and the check between them is complete — but worth noting for defensiveness.

  2. src/libswamp/extensions/pull.ts:970-971 — non-NotFound chmod errors logged at debug, not warned: If chmod fails with e.g. PermissionDenied, the binary won't be executable at runtime, but this is only logged at debug level. 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, but warn might 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.

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

All three changes are correct, well-scoped, and improve the security posture of the extension system.

Blocking Issues

None.

Suggestions

  1. 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 both binaries and additionalFiles is genuinely new logic with a distinct error path. The test file has 29 tests but none exercise any binaries validation at all (a pre-existing gap). A test asserting that a manifest with a path in both fields throws the expected UserError would 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 binaries was the only manifest field missing from the belt-and-suspenders isSafeRelativePath check. Good security fix.
  • Cross-field dedup (lines 526-533): The one-directional check against seenNormalized is correct since additionalFiles (step 15) is always processed before binaries (step 16). Error message is clear and actionable.
  • Narrowed chmod catch (pull.ts:968-973): Good improvement — only swallowing NotFound instead 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 any types introduced.

@stack72 stack72 merged commit 2d3be9c into main May 9, 2026
11 checks passed
@stack72 stack72 deleted the fix-264-followups branch May 9, 2026 22:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant