feat: optional Exoplanet.Sanitizer adapter (#24) - #26
Merged
Conversation
Behaviour + app-env activation that replaces the built-in sanitizer when set; html_sanitize_ex documented as the example adapter (no new dep). Refs #24 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Refs #24 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Optional adapter for delegating HTML sanitization to a comprehensive library (e.g. html_sanitize_ex). Activated via the :sanitizer_adapter application env key. Refs #24 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
When sanitize_html is true and an Exoplanet.Sanitizer adapter is set, it replaces the built-in tree-walk. strip_images/excerpt still apply. Refs #24 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Review follow-up: extract strip_only_opts/0 used by both the strip-images-only branch and strip_images_only/2; correct the comment that overclaimed a single fused walk now that the adapter path exists. Refs #24 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Refs #24 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
… test idiom) Refs #24 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Refs #24 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Refs #24 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Refs #24 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
strip_images rewrites <img> to <a href=src>. image_src/2 skipped the scheme allowlist when the pass ran with sanitize?: false (strip-only and post-adapter paths), so an <img src="javascript:..."> could become a clickable javascript: link. The generated <a href> is Exoplanet's own construct, so enforce safe_url?/1 unconditionally. Refs #24 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Addresses the sanitizer-hardening item in #24: let consumers delegate HTML sanitization to a comprehensive library (e.g.
html_sanitize_ex) for security-sensitive rendering — without making it a dependency.Exoplanet.Sanitizer— one callbacksanitize(html) :: html. Activated globally via app env (mirrorsExoplanet.Cache):sanitize_html: true, it replaces the built-in sanitize walk (single source of truth).strip_images/excerpt_lengthstill run after;sanitize_html: falsedisables sanitization entirely (adapter not called);nil/empty fields aren't passed to the adapter.@type t,@defaults,merge/2, andConfig.from_file/1are untouched.html_sanitize_exis the documented example adapter, not added tomix.exs.strip_imagesrewrites<img>to<a href=src>.image_src/2previously skipped the scheme allowlist when the pass ran withsanitize?: false(the strip-only and post-adapter paths), so an<img src="javascript:...">could become a clickablejavascript:link. The generated<a href>is Exoplanet's own construct, sosafe_url?/1is now enforced unconditionally. Regression tests added for both paths.Docs:
Exoplanet.Sanitizer+Exoplanet.Filtersmoduledocs, README "stronger sanitization" example, CHANGELOG, CLAUDE.md.Test Plan
mix precommit(compile, format, deps.unlock, docs, test) — 137 tests, 0 failurestest/exoplanet/filters_sanitizer_test.exs: replace, skip-when-false, per-field/empty-skip, strip-after-adapter ordering, no-adapter-unchanged, and thejavascript:-href regressiontest/exoplanet/filters_test.exsgreen)html_sanitize_exdependency added (mix.exs/mix.lockunchanged)Refs #24
🤖 Generated with Claude Code