Contributing

This page describes how to set up a development environment for Loofah, run the test suite and linters, and how the project's CI is organized. It is based on the repository's Gemfile, Rakefile, and .github/workflows/ci.yml.

Getting the Source

git clone https://github.com/flavorjones/loofah.git
cd loofah
bundle install

The Gemfile uses the gemspec for runtime dependencies (nokogiri, crass) and adds development tools: minitest, rake, rdoc, json, and hoe-markdown. On Ruby 3.0 and newer it also installs pinned versions of RuboCop and the rubocop-minitest, rubocop-packaging, rubocop-performance, rubocop-rake, and rubocop-shopify plugins. On JRuby it pins jar-dependencies.

Running the Tests

bundle exec rake test

The test task (Rake's TestTask) runs every file under test/:

Directory Contents
test/unit/ API surface, scrubber traversal, helpers, encodings
test/integration/ End-to-end scrubbing of HTML and XML, ad-hoc regression cases, helpers
test/html5/ Sanitizer behavior, CSS and URI scrubbing, safelist properties
test/assets/ Fixtures such as msword.html and html5lib sanitizer test data

test/helper.rb prints the Nokogiri version info at startup and defines LOOFAH_HTML_VERSIONS, LOOFAH_HTML_DOCUMENT_CLASSES, and LOOFAH_HTML_DOCUMENT_FRAGMENT_CLASSES. These include the HTML5 variants only when Loofah.html5_support? is true, so most tests automatically run once per parser. On JRuby, the HTML5 cases are skipped and a separate test asserts that the html5_* methods raise NotImplementedError.

Tests use Minitest's spec syntax with context as an alias for describe.

When writing tests that depend on the parser, follow the existing pattern of branching on html5?, Nokogiri.jruby?, or Nokogiri.uses_libxml?("<2.9.11") rather than assuming one output.

Linting

bundle exec rake rubocop

RuboCop checks Gemfile, Rakefile, lib, loofah.gemspec, and test. To regenerate the todo file:

bundle exec rake rubocop:todo

If RuboCop cannot be loaded (for example on Ruby older than 3.0), the Rakefile prints NOTE: rubocop not available and skips the RuboCop tasks.

Rake Tasks

Task Description
rake test Run the test suite (the default task)
rake rubocop Run RuboCop (also part of the default task when RuboCop is available)
rake rubocop:todo Regenerate .rubocop_todo.yml
rake generate_safelists Load tasks/generate-safelists, a maintainer script for generating safelists from specifications
rake debug_manifest Print the files packaged into the gem

hoe-markdown also defines Markdown housekeeping tasks for the README and CHANGELOG.

Note: Much of tasks/generate-safelists is commented out, and the companion tasks/dompurify-to-json script expects a local DOMPurify checkout. Treat these as maintainer tooling rather than part of the normal workflow.

Benchmarks

The benchmark/ directory contains scripts that compare Loofah with other sanitizers (Rails' sanitizer, sanitize, html5lib, HTMLFilter) on sample pages. They require several old third-party gems that are not in the Gemfile, so they are not expected to run in a default setup.

Continuous Integration

The ci workflow runs on pushes to main and v*.*.x branches, on version tags, on pull requests, weekly on a schedule, and on manual dispatch. Jobs:

Job What it does
rubocop bundle exec rake rubocop on Ruby 3.4
GitHub Actions audit actionlint and zizmor on the workflow files
test bundle exec rake test on Ruby 2.5, 2.6, 2.7, 3.0, 3.1, 3.2, 3.3, 3.4, head, TruffleRuby head, JRuby 9.4, JRuby 10.0, and JRuby head
downstream Clones rails-html-sanitizer, points its bundle at the Loofah checkout, and runs its test suite

The downstream job is a good reminder: a change in Loofah's behavior can break rails-html-sanitizer and, through it, Rails applications. Run its tests locally if you change sanitizer behavior.

Project Files

File Purpose
CHANGELOG.md Release notes, with a "next / unreleased" section at the top
SECURITY.md Vulnerability reporting process
docs/2022-10-decision-on-cdata-nodes.md Design decision on escaping CDATA content
MIT-LICENSE.txt License

Reporting Security Issues

Do not open public issues for vulnerabilities. SECURITY.md asks reporters to use GitHub's private reporting. Reports are acknowledged within 24 hours, with a more detailed response within 72 hours. If there is no reply within 48 hours, you can contact the security coordinator, Mike Dalessio, or post on the loofah-talk mailing list without describing the issue.

See Also