Skip to content

Core simplification, README/security overhaul, Dockerfile + coverage badge CI#3

Open
AlexandreCamillo wants to merge 3 commits into
Codeminer42:mainfrom
AlexandreCamillo:improvements/core-docs-ci
Open

Core simplification, README/security overhaul, Dockerfile + coverage badge CI#3
AlexandreCamillo wants to merge 3 commits into
Codeminer42:mainfrom
AlexandreCamillo:improvements/core-docs-ci

Conversation

@AlexandreCamillo
Copy link
Copy Markdown
Contributor

@AlexandreCamillo AlexandreCamillo commented May 22, 2026

Summary

Three independent improvements landed together for review:

  • chore(core): simplify hot paths, harden inputs, fix latent bugs (567005a)
  • docs: rewrite README, add security notice, refresh CHANGELOG (f80fdcd)
  • build, ci: Dockerfile for dev + auto-publish coverage badge (7c6580d)

Core (567005a)

  • Fix latent NoMethodError on SVGs without a viewBox (drop dev-only String#blank?).
  • Drop Tempfile round-trips; use Vips::Image.new_from_buffer for SVG and raster bytes. Remove the duplicate vips decode in Style.handle_image_path by surfacing source dimensions through FeatureMeasurer.
  • Move raster pixel loops from Array<Integer> (String#bytes) to binary String + String#getbyte to avoid per-call allocations in BackgroundDetector / PixelAnalyzer.
  • Validate LogoSoup.style inputs: warn on unknown option keys, raise ArgumentError for non-String/non-IO image_bytes, and transcode SVG bytes safely (encode("UTF-8", invalid: :replace, undef: :replace)) instead of a bare force_encoding.
  • Smaller cleanups: align-mode constants extracted to VisualCenterTransform, Comparable#clamp instead of nested min/max, case/when for img.bands, max_by for bucket argmax, Css.style_string(**styles) to match the call site.
  • Bump .rubocop.yml TargetRubyVersion to 3.1 to match the gemspec; relax dev-dep upper bounds (minitest, activesupport).
  • New regression specs cover the ArgumentError and warn-on-unknown-option behaviors.

Docs (f80fdcd)

  • README rewritten with TOC + dedicated sections: inputs, options reference, output, recipes (ERB / Rails helper / Phlex / caching), how-it-works (SVG + raster pipelines, sizing and visual-center math), performance, error handling, development.
  • Prominent Security — trusted inputs only section at the top: LogoSoup does not enforce size caps, strict MIME matching, or path validation. It is explicitly not intended for end-user uploads or any untrusted source. The section documents recommended usage (bundled assets, allowlisted internal sources) and the concrete attack vectors (decompression bombs, SVG payloads, path traversal).
  • CHANGELOG filled in for 0.1.1, 0.1.2, 0.1.3 from git history, and the current Unreleased work documented (Added / Changed / Fixed).

Build/CI (7c6580d)

  • Add a Dockerfile (Ruby 3.3-slim + libvips + librsvg) so contributors can run the full check suite without installing system deps. Gems are baked into the image via BUNDLE_PATH outside /app, so a bind-mounted working tree at runtime keeps gem lookup working without re-running bundle install.
  • Extend Coverage Main workflow to run on every push to main. After SimpleCov writes coverage/.last_run.json, generate a shields.io endpoint JSON reflecting line-coverage percentage, color-coded by bucket (>=90 brightgreen, >=75 green, >=60 yellow, >=40 orange, else red).
  • Publish the JSON to an orphan badges branch via native git (no third-party action). README badge URL points at shields.io/endpoint with the JSON hosted in the repo itself — no external coverage service required.

Test plan

  • bundle exec rake (RSpec + Rubocop) passes against the diff.
  • docker build -t logosoup . succeeds; docker run --rm -v "$PWD":/app logosoup rake runs the suite in-container.
  • Coverage workflow on main writes the badge JSON to badges branch and the README badge resolves.
  • Sanity-check the new ArgumentError / warn behavior against existing callers (only IO/String image_bytes, valid option keys).

- Replace `String#blank?` (ActiveSupport, dev-only) with stdlib in
  SvgDimensions to fix a latent NoMethodError on SVGs without a viewBox.
- Switch raster pixel loops from `Array<Integer>` (`String#bytes`) to
  binary `String` + `String#getbyte` to avoid per-call allocations in
  BackgroundDetector and PixelAnalyzer.
- Replace Tempfile round-trips with `Vips::Image.new_from_buffer` for
  SVG and raster bytes; remove the duplicate vips decode in
  `Style.handle_image_path` by surfacing `source_width`/`source_height`
  through FeatureMeasurer.
- Extract align-mode constants into VisualCenterTransform and centralize
  the visual-center? helper; collapse the four-line scaled-feature
  mutation into a hash-driven loop.
- Use `Comparable#clamp` in place of nested `[[v, hi].min, lo].max`,
  convert the `img.bands` if/elsif into a `case/when` (preserving the
  no-op for `bands == 0`), and use `max_by` for the bucket argmax in
  BackgroundDetector.
- Validate inputs in `LogoSoup.style`: warn on unknown option keys,
  raise `ArgumentError` for non-String/non-IO `image_bytes`, and
  safely transcode SVG bytes via `encode("UTF-8", invalid: :replace,
  undef: :replace)` instead of bare `force_encoding`.
- Declare `Css.style_string(**styles)` to match how it's called.
- Tidy `script/coverage_diff.rb` indentation and dedupe nil-init block.
- Bump `.rubocop.yml` TargetRubyVersion 2.7 -> 3.1 (aligns with the
  gemspec's `required_ruby_version >= 3.1`).
- Relax dev-dep upper bounds in the gemspec: drop `minitest < 5.26`,
  loosen `activesupport < 7.1` -> `< 8` to avoid future bundle-update
  breakage.
- Add regression specs for the new ArgumentError and warn-on-unknown
  option behaviors.
- README rewritten with TOC and dedicated sections for inputs, options
  reference, output, recipes (ERB / Rails helper / Phlex / caching),
  how-it-works (SVG and raster pipelines, sizing and visual-center
  math), performance, error handling, and development. Inspired by
  searchkick's README depth.
- Add a prominent "Security - trusted inputs only" section at the top:
  LogoSoup does not enforce size caps, strict MIME matching, or path
  validation on inputs, and is explicitly NOT intended for end-user
  uploads or any untrusted source. Document recommended usage
  (bundled assets, allowlisted internal sources) and the concrete
  attack vectors (decompression bombs, SVG payloads, path traversal).
- Update Development section with Docker workflow (build / test /
  shell / rake) and a project-layout tree.
- CHANGELOG: fill in 0.1.1, 0.1.2, 0.1.3 entries from git history and
  document the current Unreleased work (Added / Changed / Fixed),
  including the security notice, Docker image, input validation,
  encoding safety, internal refactors, and rubocop alignment.
- Add a Dockerfile (Ruby 3.3-slim + libvips + librsvg) so contributors
  can run the full check suite without installing system dependencies.
  Gems are baked into the image at build time via BUNDLE_PATH outside
  /app, so a bind-mounted working tree at runtime keeps gem lookup
  working without re-running bundle install.
- Extend `Coverage Main` workflow to run on every push to main (not
  just workflow_dispatch). After SimpleCov writes
  `coverage/.last_run.json`, generate a shields.io endpoint JSON
  reflecting the line-coverage percentage and color-coded by bucket
  (>=90 brightgreen, >=75 green, >=60 yellow, >=40 orange, else red).
- Publish the JSON to an orphan `badges` branch via native git (no
  third-party action), so the README badge URL points at
  shields.io/endpoint with the JSON hosted in the repo itself. No
  external coverage service or signup required.
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