Download Latest Version OpenWhistle 2.1.0 source code.zip (4.7 MB) Google Add to Preferred Sources
Home / v1.4.0
Name Modified Size InfoDownloads / Week
Parent folder
README.md 2026-09-24 5.7 kB
v1.4.0 -- attachment privacy, tenancy, accessibility source code.tar.gz 2026-09-24 951.1 kB
v1.4.0 -- attachment privacy, tenancy, accessibility source code.zip 2026-09-24 1.1 MB
Totals: 3 Items   2.0 MB 0

Attachments no longer identify the whistleblower, multi-tenant installs keep organisations apart, and every page passes an automated contrast and layout check on a phone and in both themes. Found and verified with a mutation audit of every guard this release adds (28 of 28 caught).

Upgrade notes: migration 002 runs on start. The default BRAND_PRIMARY_COLOR is now #0c7253 (was #0e7c5a, 4.4:1 on tinted backgrounds); installs that set their own colour are unaffected. E2E and demo logins for the demo accounts use the static code 000000; real TOTP codes are single-use for every account.

Fixed

  • Cleaned PDFs still contained their XMP metadata. Unlinking it from the catalog left the stream in the file as an orphaned object; orphans are now removed. PDFs restricted by an owner password only are accepted and cleaned instead of refused.
  • Every page passes axe at impact serious and critical, in both themes. Fixed: accent colour on tinted backgrounds (4.4 → 5.0:1), white on amber in the dark demo badges (2.3:1), dark-theme secondary text (3.9 → 4.8:1), role badges (2.1 and 3.9:1), footer links distinguishable only by colour, inactive categories and locations faded below AA, an unlabelled role selector and link field, scrollable tables unreachable by keyboard.
  • Six more admin pages scrolled sideways on a phone (users, categories, locations, statistics, retention, system — up to 569 px), and long audit entries on the report view.
  • No page scrolls sideways on a phone any more. At 390 px the navigation (12 items in the admin) now wraps instead of running off-screen, the dashboard toolbar and the report view (two columns, no breakpoint) fit the width. An E2E test checks /submit, /status and /admin/login at 390 px.
  • Confidential mode works without JavaScript (Tor Browser "Safest"): the name/contact fields are shown by CSS :has() instead of a script.
  • The language picker works without JavaScript and no longer misuses listbox/option roles: it is a native <details> list of forms.
  • Contrast: input borders 1.25:1 → ≥ 3:1; a visible focus outline on inputs and on the submission-mode cards (focused and selected looked identical); secondary text 4.37:1 → 4.98:1 on cards; alert titles no longer dimmed.

Changed

  • Stricter tests. The axe checks fail on serious violations, not only critical ones (contrast failures used to ship green). A new UI check visits every public and admin page in both themes at 390 and 1440 px and fails on axe violations, console errors or sideways scrolling. Every guard of the release is mutation-tested (scripts/mutation_audit.py).
  • Maintainer documentation moved to docs-tech/ (release procedure, invariants, carried-forward findings, performance baseline); a test keeps it out of the published site.
  • Images are built once and published identically to all three registries. Each platform builds on a native runner (arm64 no longer under QEMU) and is pushed to GHCR by digest; one multi-arch index is then written under every tag to GHCR, Docker Hub and Quay.io. Docker Hub and Quay now get the same provenance, SBOM and cosign signature as GHCR (before: separate unsigned builds). The job fails unless every tag and every platform manifest behind it is pullable. Quay.io stays best-effort with a warning.
  • Dependencies are locked in uv.lock. The image, CI and the E2E/perf workflows install exactly the locked versions; CI fails if the lock is out of date. Dependabot now uses the uv ecosystem — the old pip entry only saw >= floors and had never opened a pull request.
  • The production image carries runtime dependencies only (no pytest, mypy or ruff), uv is taken from its official image (0.6.0 → 0.12.18), and the fonts are copied from docs/fonts instead of downloaded unverified at build time.
  • python-jose replaced by PyJWT, which drops ecdsa (PYSEC-2026-1325, no fix planned). Unused authlib and aiofiles removed; cryptography is now a declared dependency instead of an accidental transitive one.

Security

  • Multi-tenancy: an org admin now sees and manages only their own organisation. The users page, role changes, (de)activation, the assignment picker and target, the audit log and its CSV export, and the dashboard and statistics counts were unscoped; new users now join the creator's organisation. Single-organisation installs are unaffected.
  • DEMO_MODE no longer weakens a real installation. The static TOTP 000000 is accepted only for the seeded demo accounts, and demo data is not seeded into a database that completed the setup wizard and has no demo account.
  • Internal admin notes are encrypted at rest with the report's data key, like descriptions and messages. Existing notes are shown as stored.
  • Attachments no longer carry identifying metadata. EXIF/GPS and camera data (JPEG, PNG, WebP, GIF), PDF document info and XMP, and DOCX/XLSX author and company properties are removed on upload — before the file reaches the draft store. A file that cannot be parsed for cleaning is refused instead of stored as-is. The upload step tells the whistleblower what is and is not cleaned.
  • Attachments are encrypted at rest with the report's own data key, in PostgreSQL and in S3. Rows from before this release are served as stored (migration 002 adds attachments.encrypted).

Images (one signed multi-arch index, linux/amd64 + linux/arm64, identical in all three): ghcr.io/openwhistle/openwhistle:1.4.0, kermit1337/openwhistle:1.4.0, quay.io/jp1337/openwhistle:1.4.0.

Source: README.md, updated 2026-09-24