| Name | Modified | Size | Downloads / 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,/statusand/admin/loginat 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/optionroles: 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 theuvecosystem — the oldpipentry 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/fontsinstead of downloaded unverified at build time. python-josereplaced by PyJWT, which dropsecdsa(PYSEC-2026-1325, no fix planned). Unusedauthlibandaiofilesremoved;cryptographyis 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_MODEno longer weakens a real installation. The static TOTP000000is 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
002addsattachments.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.