Appearance
Vulcan v2.4.1
Released: 2026-08-26
A feature release centered on a redesigned comment-triage experience and the foundations for SRG authoring, plus security hardening on the login paths and a broad set of fixes. See the CHANGELOG for the complete list.
Highlights
- Three-column triage split-pane — triagers now work in a persistent layout: a rule sidebar (grouped, with pending/total counts, search, and keyboard navigation), the rule content, and the comment + triage form side by side, replacing the prev/next-plus-modal workflow. A triage progress bar above the table shows per-status counts with an "N of M resolved (X%)" summary and doubles as a click-to-filter control.
- Accessibility — the split-pane uses proper
nav/main/complementarylandmarks, skip links, content-first focus management on entry and after Save & Next, and a single-Tab-stop composite sidebar. Status color dots on the filter toggles all meet 3:1 contrast in light and dark mode. - SRG-authoring foundations — a persisted minted-identifier sequence makes authored-derivation requirement IDs immune to SRG rebases and abbreviation changes (never-renumber on re-release), plus SRG-viewer and source-picker refinements.
- Quality-of-life — a by-rule accordion view, 2D queue navigation, a "section updated since this comment" staleness badge, inline admin actions (force-withdraw, restore, move-to-rule, hard-delete with typed-ID confirmation), and shared InfoTooltip / InfoNotice components.
Security
- Login lockout and rate limiting on the JSON login path —
/api/auth/loginpreviously did a bare password check, bypassing Devise account lockout (STIG AC-07) and all login throttling. It now runs the full Devise checks, returns a distinctaccount_locked401, and both login paths share IP- and email-keyed throttles. - Local-login toggle enforced server-side — disabling local login previously only hid the form; a crafted POST could still authenticate with local credentials on an SSO-only instance. A shared guard now rejects both paths server-side.
Notable fixes
- Triage queue loads every comment past the server page cap — the queue silently dropped comments beyond the 100-per-page limit; it now pages until the full total is loaded.
- Comment moves carry the entire reply subtree — replies-to-replies at any depth now survive a comment's move between containers.
- Archive import preserves review edit timestamps instead of collapsing them to the creation time.
- Consent "I Agree" no longer looks like a dead button — a bodyless success response made the API client throw while parsing an empty body, leaving the modal open even though consent was recorded; empty responses now resolve cleanly and a genuine failure shows a visible error.
- Catalog and review N+1 queries removed for faster SRG catalog and component-review loads.
- Personal access token copy works in non-HTTPS deployments; admin token-revoke justification moved from
window.promptto a modal.
Upgrade notes
- Run migrations. Production deploys require
bundle exec rails db:migrate(the release/entrypoint flow runs it automatically). The SRG-authoring migration is safe for the release phase — its index builds concurrently and its constraints validate without blocking writes. - Self-hosted / Docker: database naming standardization. The 2.4 line standardizes database names to the Rails convention (
vulcan_development/vulcan_test/vulcan_production) and removes theDB_SUFFIXenvironment variable in favor ofDATABASE_NAME. The container entrypoint'supgrade:autostep detects and applies the rename on start; see the upgrade guide. Managed Postgres (e.g. Heroku viaDATABASE_URL) is unaffected. - Backup format is now 1.1 — exports declare
backup_format_version: "1.1"; older1.0archives remain importable.