• v2026.8.16 9472d8d78b

    v2026.8.16
    All checks were successful
    CI / release-scripts (pull_request) Successful in 7s
    security-scan / SBOM (trivy) (pull_request) Successful in 10s
    security-scan / Filesystem scan (trivy fs) (pull_request) Successful in 15s
    security-scan / JS SCA (npm audit) (pull_request) Successful in 16s
    security-scan / Python SAST (bandit) (pull_request) Successful in 18s
    security-scan / Python SCA (pip-audit) (pull_request) Successful in 37s
    test-build / build (frontend) (pull_request) Successful in 56s
    CI / pre-commit (pull_request) Successful in 56s
    CI / frontend-test (pull_request) Successful in 1m1s
    test-build / build (backend) (pull_request) Successful in 1m28s
    test-build / build (pull_request) Successful in 0s
    CI / backend-test (pull_request) Successful in 2m20s
    CI / e2e (pull_request) Successful in 3m28s
    CI / release-scripts (push) Successful in 6s
    security-scan / SBOM (trivy) (push) Successful in 10s
    security-scan / Filesystem scan (trivy fs) (push) Successful in 14s
    security-scan / JS SCA (npm audit) (push) Successful in 15s
    security-scan / Python SAST (bandit) (push) Successful in 16s
    security-scan / Python SCA (pip-audit) (push) Successful in 34s
    CI / pre-commit (push) Successful in 56s
    publish-main / build (frontend) (push) Successful in 56s
    CI / frontend-test (push) Successful in 1m6s
    publish-main / build (backend) (push) Successful in 1m10s
    publish-main / build (push) Successful in 0s
    CI / backend-test (push) Successful in 2m19s
    CI / e2e (push) Successful in 3m26s
    release-and-deploy / release-scripts (push) Successful in 6s
    release-and-deploy / release (push) Successful in 18s
    release-and-deploy / pre-commit (push) Successful in 57s
    release-and-deploy / frontend-test (push) Successful in 58s
    release-and-deploy / build (frontend) (push) Successful in 1m9s
    release-and-deploy / build (backend) (push) Successful in 1m13s
    release-and-deploy / build (push) Successful in 0s
    release-and-deploy / backend-test (push) Successful in 2m19s
    release-and-deploy / e2e (push) Successful in 3m25s
    release-and-deploy / ci (push) Successful in 0s
    release-and-deploy / deploy (push) Successful in 1m49s
    Stable

    robbertbos released this 2026-08-16 21:02:14 +00:00 | 14 commits to main since this release

    Note when rolling out

    • The migration converts cards.source_data, cards.notes and
      outgoing_posts.content to encrypted bytea in place. Not rolling-safe:
      stop the old pod before the new one boots, and take a database backup
      first - reading the converted columns afterwards requires the
      WAGGLE_SECRET_KEY the migration ran with.
    • A second migration then strips the message, author and attachments out of
      cards.source_data. One-way by design: the downgrade cannot put them back.
    • Typing ~ offers your channels, most recently linked first, and inserts a
      reference to the one you pick.
    • Channels from your other teams are in the list too, marked with their team.
      They get a full link, because Mattermost only resolves a ~name inside the
      team of the message.
    • @ in a new message without a recipient now says "Kies eerst een kanaal bij
      Aan" rather than inviting you to keep typing.

    Release notes in the app

    • Returning users get a "Nieuw in Waggle" banner above every page, folded shut,
      listing the releases they missed by date. Dismissing it is permanent and
      follows the account, not the browser.
    • Every missed release is in that one expand. A button underneath fetches the
      releases before them, one at a time.
    • Notes are Dutch markdown per release in frontend/src/content/releases/; a
      release without a file shows no banner, and a new account sees nothing. The
      release job fails while unreleased.md has not been renamed to its version.

    Under the hood

    • Message snapshots, notes and outgoing drafts are encrypted at rest:
      Fernet under two new HKDF domains, covered by waggle rotate-keys.
    • A card stores references only - post, channel and permalink. The message,
      author and attachments come from Mattermost per request, so an edited post
      no longer needs a resync and nothing of it sits in the database.
    • A card whose post Mattermost no longer has reads "Bericht is niet meer
      beschikbaar in Mattermost" and keeps its status, planning and notes. If the
      fetch itself fails, the list says so once, with "Opnieuw proberen".
    • Cache and log hardening: API responses default to no-store, attachments cache
      only as inline images for an hour, typed search text moved from URLs into POST
      bodies, and the production access log is off.
    • Error paths stopped echoing content: database errors hide bind parameters,
      422 responses drop the submitted input, the rate limiter logs a hashed key.
    • Logout clears the browser's cache and storage (Clear-Site-Data) plus
      localStorage traces; sync_logs age out after 90 days.
    • The pod writes its own scrubbed request log (status, duration, pseudonymous
      user/session ids; no IPs or query strings) and sessions record
      last_seen_at for incident reconstruction.
    • NLDD design system 0.8.82. Enter submits the account forms again, the
      retention dropdowns are now named by the label above them instead of by a
      summary that shared no words with it, and the import success notice is an
      nldd-banner rather than a hand-rolled one.
    • Postgres 17 digest bumped to e384114.

    Container images