diff --git a/CHANGELOG.md b/CHANGELOG.md index b8c8769..ef3cf6d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added - Public API stability policy — `README.md#versioning` documents what is and is not covered by semver guarantees from v1.0.0; `UPGRADING.md` cross-references the policy +- README: Security section covering authentication requirements, `allow_value_preview` caution, CSRF handling, and rate-limiting guidance +- README: Screenshots section with a single `docs/screenshots/demo.gif` slot (animated GIF showing a dashboard tour) +- README: `connects_to` added to the General configuration reference - Deprecation warning infrastructure — `SolidStackWeb.deprecator` exposes a gem-scoped `ActiveSupport::Deprecation` instance registered with `app.deprecators`; a private `deprecated_config` helper generates forwarding writers with warnings for any config keys renamed before 1.0 ### Changed diff --git a/README.md b/README.md index 6970ec9..202c3fa 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ [![Ruby](https://img.shields.io/badge/ruby-%3E%3D%203.3-ruby)](https://www.ruby-lang.org) [![codecov](https://codecov.io/gh/eclectic-coding/solid_stack_web/branch/main/graph/badge.svg)](https://codecov.io/gh/eclectic-coding/solid_stack_web) -A mountable Rails engine that provides a unified web dashboard for the full [Solid Stack](https://github.com/rails/solid_queue) — **Solid Queue**, **Solid Cache**, and **Solid Cable** — in a single interface with no asset pipeline dependency and no JavaScript runtime requirement. +A production-ready operations dashboard for the full Rails Solid Stack. Mount one engine to get deep visibility into **Solid Queue** (job browser, failed job retry, queue controls, recurring tasks, performance stats), **Solid Cache** (entry browser, size distribution, write timeline), and **Solid Cable** (channel browser, message list, purge controls) — with dark mode, CSV export, alert webhooks, and a JSON metrics endpoint, all with no asset pipeline dependency. ## Installation @@ -41,6 +41,12 @@ This creates `config/initializers/solid_stack_web.rb` with every configuration o --- +## Screenshots + +![SolidStackWeb dashboard](docs/screenshots/demo.gif) + +--- + ## Metrics endpoint `GET /metrics` (relative to your mount path) returns a JSON payload suitable for external monitoring tools, uptime checkers, or custom alerting: @@ -83,6 +89,10 @@ SolidStackWeb.configure do |config| config.authenticate do current_user&.admin? end + + # Multi-database — pass a connects_to hash when Solid Queue / Cache / Cable + # live on a separate database from your primary (default: nil, uses primary). + config.connects_to = { database: { writing: :queue, reading: :queue } } end ``` @@ -100,6 +110,44 @@ link_to "Queue Dashboard", SolidStackWeb.mount_path --- +## Security + +### Authentication + +**The dashboard is open to all visitors by default.** Any production deployment must configure an `authenticate` block or the dashboard will be publicly accessible. + +```ruby +SolidStackWeb.configure do |config| + # Devise + config.authenticate { current_user&.admin? } + + # HTTP Basic fallback (used when no authenticate block is set, or when + # the block returns false/nil and you want a browser credential prompt) + # Configure via HTTP_BASIC_AUTH_NAME / HTTP_BASIC_AUTH_PASSWORD env vars + # in your host app, or use a reverse proxy. +end +``` + +If the `authenticate` block returns `false` or `nil`, the engine falls back to HTTP Basic authentication. If no block is configured at all, the dashboard is open. + +### Sensitive cache values + +`allow_value_preview` is `false` by default. Enabling it renders the raw serialised cache value on the entry detail page. Do not enable this if your cache stores session tokens, PII, or other sensitive data. + +### CSRF protection + +All state-mutating actions (job discard, retry, queue pause/resume, cache flush) use form POST requests. Turbo handles CSRF tokens automatically for any standard Rails app with `protect_from_forgery`. + +### Rate limiting and network exposure + +The dashboard is designed to be mounted behind your application's existing authentication. For additional hardening, consider: + +- Mounting at a non-guessable path (e.g. `at: "/ops/#{Rails.application.credentials.dashboard_token}"`) +- Restricting access by IP at the reverse-proxy level +- Applying [Rack::Attack](https://github.com/rack/rack-attack) rules to the mount path + +--- + ## Solid Queue ### Features diff --git a/ROADMAP.md b/ROADMAP.md index fbb26c9..a3cdb98 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -10,8 +10,9 @@ The path to v1.0.0 is staged: first achieve feature parity with `solid_queue_das > _Declare a stable public API and commit to semantic versioning guarantees._ -### Added -- Complete README with configuration reference, screenshot gallery, and security guidance +### Remaining + +_All items complete._ --- diff --git a/docs/screenshots/.gitkeep b/docs/screenshots/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/docs/screenshots/demo.gif b/docs/screenshots/demo.gif new file mode 100644 index 0000000..373a376 Binary files /dev/null and b/docs/screenshots/demo.gif differ diff --git a/solid_stack_web.gemspec b/solid_stack_web.gemspec index 59de4e7..2a75926 100644 --- a/solid_stack_web.gemspec +++ b/solid_stack_web.gemspec @@ -7,9 +7,14 @@ Gem::Specification.new do |spec| spec.email = ["eclectic-coding@users.noreply.github.com"] spec.homepage = "https://github.com/eclectic-coding/solid_stack_web" spec.summary = "A unified Rails engine dashboard for Solid Queue, Solid Cache, and Solid Cable." - spec.description = "Mount SolidStackWeb in any Rails app using the Solid Stack to get a single " \ - "dashboard covering Solid Queue job monitoring, Solid Cache statistics, " \ - "and Solid Cable connection observability — all without leaving your app." + spec.description = "SolidStackWeb is a mountable Rails engine that provides a production-ready " \ + "operations dashboard for the full Solid Stack. It covers Solid Queue " \ + "(job browser, failed job retry with inline argument editing, queue pause/resume, " \ + "recurring tasks, performance stats, CSV export, and alert webhooks), " \ + "Solid Cache (entry browser, size distribution, 24-hour write timeline, " \ + "and optional value preview), and Solid Cable (channel browser, per-channel " \ + "message list, and purge controls). Ships with dark mode, Turbo Stream " \ + "responses, a JSON metrics endpoint, and no asset pipeline dependency." spec.license = "MIT" spec.metadata["homepage_uri"] = spec.homepage @@ -17,7 +22,7 @@ Gem::Specification.new do |spec| spec.metadata["changelog_uri"] = "https://github.com/eclectic-coding/solid_stack_web/blob/main/CHANGELOG.md" spec.files = Dir.chdir(File.expand_path(__dir__)) do - Dir["{app,config,db,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] + Dir["{app,config,db,docs,lib}/**/*", "MIT-LICENSE", "Rakefile", "README.md"] end spec.required_ruby_version = ">= 3.3"