diff --git a/Cargo.lock b/Cargo.lock index 8771dfe..8a942ee 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1918,7 +1918,7 @@ dependencies = [ [[package]] name = "mybibli" -version = "1.18.0" +version = "1.19.0" dependencies = [ "argon2", "askama", diff --git a/Cargo.toml b/Cargo.toml index 5f2c792..878fe69 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mybibli" -version = "1.18.0" +version = "1.19.0" edition = "2024" license = "AGPL-3.0-or-later" diff --git a/README.md b/README.md index eb3f1fa..832f332 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ [![Version](https://img.shields.io/github/v/tag/guycorbaz/mybibli?label=version&sort=semver&color=blue)](https://github.com/guycorbaz/mybibli/releases) [![License: AGPL v3](https://img.shields.io/badge/license-AGPL--3.0--or--later-lightgrey)](LICENSE) [![Docker Pulls](https://img.shields.io/docker/pulls/gcorbaz/mybibli?logo=docker&label=docker%20pulls)](https://hub.docker.com/r/gcorbaz/mybibli) -[![Docker Image Size](https://img.shields.io/docker/image-size/gcorbaz/mybibli/1.18.0?logo=docker&label=image%20size)](https://hub.docker.com/r/gcorbaz/mybibli/tags) +[![Docker Image Size](https://img.shields.io/docker/image-size/gcorbaz/mybibli/1.19.0?logo=docker&label=image%20size)](https://hub.docker.com/r/gcorbaz/mybibli/tags) [![Open Issues](https://img.shields.io/github/issues/guycorbaz/mybibli?logo=github)](https://github.com/guycorbaz/mybibli/issues) [![Last Commit](https://img.shields.io/github/last-commit/guycorbaz/mybibli/main?logo=github)](https://github.com/guycorbaz/mybibli/commits/main) [![Stars](https://img.shields.io/github/stars/guycorbaz/mybibli?logo=github&style=flat)](https://github.com/guycorbaz/mybibli/stargazers) @@ -17,7 +17,7 @@ > Personal library cataloging for home collectors. -**Status:** in production since v1.1.1 (2026-05-14). 10 epics shipped; project is in GH-issue-driven polish mode. Current release: `v1.18.0`. Pre-built images on Docker Hub at [`gcorbaz/mybibli`](https://hub.docker.com/r/gcorbaz/mybibli). See [ROADMAP.md](ROADMAP.md) for what's coming next. +**Status:** in production since v1.1.1 (2026-05-14). 10 epics shipped; project is in GH-issue-driven polish mode. Current release: `v1.19.0`. Pre-built images on Docker Hub at [`gcorbaz/mybibli`](https://hub.docker.com/r/gcorbaz/mybibli). See [ROADMAP.md](ROADMAP.md) for what's coming next. ## What it is @@ -38,7 +38,7 @@ Built for collectors who want more than a spreadsheet: ## Screenshots -Live production install (`v1.18.0`, household NAS, 140+ volumes catalogued and growing): +Live production install (`v1.19.0`, household NAS, 140+ volumes catalogued and growing):

mybibli home page — search bar, genre filters, dashboard counters, and a recent-additions strip with cover thumbnails. @@ -411,7 +411,7 @@ Versioned under `_bmad-output/`: mybibli has been live in production since v1.1.1 (2026-05-14) on the household NAS that drove the project. v1.0.0 shipped after Epic 9 close (2026-05-10) as the first production-ready build; v1.1.0 added the seed-gate + audit trio (mandatory install floor — see "Installation notes" above); the themed minors v1.2 through v1.8 then delivered the original feature roadmap (browse & find, wishlist, HTTP API, valuation & stats, catalog hygiene, de/it locales + runtime logging, cover handling), each followed by production-driven patch trains. Since v1.8 the project runs in GH-issue-driven polish mode. -**Current release: `v1.18.0`** (2026-08-18) — management labels ([#443](https://github.com/guycorbaz/mybibli/issues/443)): an admin-defined vocabulary a librarian applies to titles *and* volumes from one shared list, with a `/labels` page that drills down to what carries each label. Labels stay internal — a visitor never sees them. One additive migration; the navigation bar now switches to its menu below 1024px, because the new entry no longer fitted on a tablet. +**Current release: `v1.19.0`** (2026-09-11) — the three change requests of a security review run against the 1.18.0 code, and the documentation work it made necessary. [#478](https://github.com/guycorbaz/mybibli/issues/478): the Trash panel's Restore button, which had pointed at an unregistered route since 1.2.0 and silently did nothing, now restores. [#480](https://github.com/guycorbaz/mybibli/issues/480): the seeded development accounts are deleted outright at first boot instead of being parked in the Trash with their published passwords intact — which #478 would otherwise have made restorable. [#479](https://github.com/guycorbaz/mybibli/issues/479): a cover decode runs under a fixed allocation budget, so an image that is small on the wire and enormous once decoded is refused rather than taking the container down. **No migration.** The preceding release, `v1.18.0` (2026-08-18), added management labels ([#443](https://github.com/guycorbaz/mybibli/issues/443)). **Release-by-release history lives in [ROADMAP.md](ROADMAP.md)** — one section per version, and the canonical copy. It is deliberately not repeated here: the [GitHub releases page](https://github.com/guycorbaz/mybibli/releases) carries the same notes as published artifacts, chapter 8 of the [user manual](docs/manual/) carries them offline, and the [website roadmap](https://guycorbaz.github.io/mybibli/roadmap.html) tells the same story for a different audience. See [`epics.md`](_bmad-output/planning-artifacts/epics.md) for the epic breakdown and [`sprint-status.yaml`](_bmad-output/implementation-artifacts/sprint-status.yaml) for the story-by-story state. diff --git a/ROADMAP.md b/ROADMAP.md index ec0f0b3..78aae81 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -32,28 +32,62 @@ mybibli follows [Semantic Versioning](https://semver.org/) 2.0. ## Now -**Current stable: [`v1.18.0`](https://github.com/guycorbaz/mybibli/releases/tag/v1.18.0)** -(2026-08-18) — management labels ([#443](https://github.com/guycorbaz/mybibli/issues/443)): -an admin-defined vocabulary a librarian applies to titles *and* volumes -from one shared list, with a `/labels` page of its own. One additive -migration. The section below has the detail; every release before it has -its own section further down, and this is the file that carries them — -the README quotes only the current release, and the website tells the +**Current stable: [`v1.19.0`](https://github.com/guycorbaz/mybibli/releases/tag/v1.19.0)** +(2026-09-11) — the three change requests of a security review run against +the 1.18.0 code, and the documentation work it made necessary. **No +migration.** The section below has the detail; every release before it +has its own section further down, and this is the file that carries them +— the README quotes only the current release, and the website tells the same story for a different audience. -**Merged on `main`, not yet released** — the three change requests from -the 2026-08-18 security review: -[#480](https://github.com/guycorbaz/mybibli/issues/480) the seed gate -hard-deletes its artefacts instead of parking them in the Trash, -[#478](https://github.com/guycorbaz/mybibli/issues/478) the Trash panel's -Restore button reaches a route that exists, and -[#479](https://github.com/guycorbaz/mybibli/issues/479) a cover decode -runs under an allocation budget. No migration. The version they ship -under is not decided yet. - **Open issues: none.** The tracker has been empty since the review closed. New work starts from a fresh report. +## v1.19.0 — the security review *(shipped)* + +Shipped 2026-09-11. Three change requests, **no migration**, one +documentation sweep. The review that produced them was run on 2026-08-18 +against the v1.18.0 code, with a stated attacker model: local network +plus a private tunnel, never a port forwarded to the internet. + +- [#478](https://github.com/guycorbaz/mybibli/issues/478) — **the Trash + panel's Restore button reaches a route that exists.** It had rendered + a link to `/admin/trash/{table}/{id}/restore` since story 8-6; that + route was never registered, so every click returned a 404 that HTMX + does not swap — no restore, no error, nothing at all. The route is + registered as POST rather than the GET the button emitted, so it rides + the CSRF layer; where restoring would clash with a relationship formed + since the deletion, a modal names the conflict before clearing it. + The suite had stayed green throughout because `TrashService::restore` + was only ever called from `#[cfg(test)]`. +- [#480](https://github.com/guycorbaz/mybibli/issues/480) — **the seed + gate hard-deletes its artefacts.** It had soft-deleted the seeded + `admin` / `librarian` rows, leaving them in the Trash for thirty days + with the passwords published in `SECURITY.md` intact, plus a session + row whose token is in the git history. Harmless while Restore was + broken; #478 is what made it urgent, and the two had to land in that + order. Upgrading instances purge whatever their old gate left behind. +- [#479](https://github.com/guycorbaz/mybibli/issues/479) — **a cover + decode runs under an allocation budget.** The 10 MiB cap bounded the + compressed bytes, not the memory: a few hundred bytes of PNG can + declare gigabytes of RGBA, and the OOM killer would take the container + down with every request in flight. 64 MiB and a 10 000 px per-side + ceiling; the download side now streams with a hard cap instead of + trusting `Content-Length`. The path that matters is the provider + chain, where the bytes are not ours. + +Also in this release: the CI actions are pinned by commit SHA with a +daily RustSec advisory scan ([#481](https://github.com/guycorbaz/mybibli/pull/481)), +the network posture is stated where an operator will actually read it +([#482](https://github.com/guycorbaz/mybibli/pull/482)), the +community-health files landed +([#477](https://github.com/guycorbaz/mybibli/pull/477)), and a +documentation audit closed fourteen findings across every surface +([#487](https://github.com/guycorbaz/mybibli/pull/487)) — K10plus finally +documented, the shelf-audit chapter describing the feature that shipped +three releases ago rather than a workaround, a route reference covering +all 148 routes instead of 82. + ## v1.18.0 — management labels *(shipped)* Shipped 2026-08-18. One issue, **one additive migration**, three reviewed tranches. diff --git a/_bmad-output/implementation-artifacts/sprint-status.yaml b/_bmad-output/implementation-artifacts/sprint-status.yaml index de8daef..bca23a8 100644 --- a/_bmad-output/implementation-artifacts/sprint-status.yaml +++ b/_bmad-output/implementation-artifacts/sprint-status.yaml @@ -1,5 +1,5 @@ # generated: 2026-03-29 -# last_updated: 2026-08-18 (v1.18.0 — minor on v1.17.0. #443 management labels: an admin-defined vocabulary applied to titles AND volumes from one shared list, with a /labels page and drill-down; Librarian+ only. One additive migration (labels, title_labels, volume_labels). Nav bar switches to the menu at lg instead of md. Release history: ROADMAP.md) +# last_updated: 2026-09-11 (v1.19.0 — minor on v1.18.0, no migration. The three change requests of the 2026-08-18 security review: #478 the Trash Restore button reaches a route that exists, #480 the seeded dev accounts are hard-deleted at first boot instead of parked in the Trash, #479 a cover decode runs under an allocation budget. Plus a documentation audit across every surface.) # project: mybibli # project_key: NOKEY # tracking_system: file-system diff --git a/docs/dockerhub-overview.md b/docs/dockerhub-overview.md index 1f649e2..6fbece9 100644 --- a/docs/dockerhub-overview.md +++ b/docs/dockerhub-overview.md @@ -118,7 +118,7 @@ Both `mybibli-covers` and `mybibli-logs` can be swapped from Docker-named volume ## Tags - `:latest` — tracks the highest semver release tag. -- `:1.18.0` (current), `:1.17.0`, `:1.16.0` and every prior release tag back to `:1.1.0` — specific releases. Pin to a specific tag in production-style setups; tracking `:latest` is reasonable for homelab. The full tag list is on the [Tags tab](https://hub.docker.com/r/gcorbaz/mybibli/tags). +- `:1.19.0` (current), `:1.18.0`, `:1.17.0` and every prior release tag back to `:1.1.0` — specific releases. Pin to a specific tag in production-style setups; tracking `:latest` is reasonable for homelab. The full tag list is on the [Tags tab](https://hub.docker.com/r/gcorbaz/mybibli/tags). - **No `:dev`, no `:main`, no `:beta` published** — tagged releases only. ## Docs diff --git a/docs/manual/en/01-installation.tex b/docs/manual/en/01-installation.tex index b54a0b2..925601b 100644 --- a/docs/manual/en/01-installation.tex +++ b/docs/manual/en/01-installation.tex @@ -108,8 +108,8 @@ \subsection*{1. Get the compose file and \texttt{.env}} \begin{lstlisting} mkdir -p /srv/mybibli && cd /srv/mybibli -curl -O https://raw.githubusercontent.com/guycorbaz/mybibli/v1.18.0/docker-compose.yml -curl -O https://raw.githubusercontent.com/guycorbaz/mybibli/v1.18.0/.env.example +curl -O https://raw.githubusercontent.com/guycorbaz/mybibli/v1.19.0/docker-compose.yml +curl -O https://raw.githubusercontent.com/guycorbaz/mybibli/v1.19.0/.env.example cp .env.example .env \end{lstlisting} diff --git a/docs/manual/en/08-upgrade-migration.tex b/docs/manual/en/08-upgrade-migration.tex index c93fb5d..bdf1335 100644 --- a/docs/manual/en/08-upgrade-migration.tex +++ b/docs/manual/en/08-upgrade-migration.tex @@ -132,13 +132,79 @@ \section{Reading the release notes} \item a one-paragraph summary of the change set; \item the migration impact (none / additive / breaking); \item a link to the diff against the previous tag; - \item attached PDFs of this manual (English + French) once the - release-time PDF build is wired into CI. + \item this manual as PDF, English and French, attached to the + release itself --- the copy that matches that exact version. \end{itemize} Read the notes before upgrading. Breaking changes are tagged with a prominent \emph{Breaking} label. +\section{What's new in 1.19.0}\label{sec:whats-new-1.19.0} + +Version 1.19.0 is a minor release on 1.18.0. \emph{No migration} --- +pull the image, restart, done. It carries the three change requests of +a security review conducted on the 1.18.0 code, plus the documentation +work that review made necessary. + +\begin{itemize} + \item \textbf{\#478 \string— the Trash can actually restore now.} + The Trash panel had shown a \emph{Restore} button since 1.2.0. + It pointed at an address the application never answered on, so + clicking it did nothing at all: no restore, no error message, + nothing. If you ever deleted a title by accident, opened the + Trash and wondered why the button seemed dead --- it was. + + It works. Deleted something by mistake, restore it, and it + returns where it was. When the record's relationships changed + while it sat in the trash --- a title reassigned to another + series, say --- mybibli asks before clearing the stale link + rather than deciding for you. + + \item \textbf{\#480 \string— the development accounts leave no + trace.} A fresh install has always shipped two development + accounts, \texttt{admin/admin} and + \texttt{librarian/librarian}, which the application removes at + first boot so the setup wizard can run (section + \ref{sec:upgrade-1.1.0}). Removed, until now, meant + \emph{moved to the Trash}: the rows sat there for thirty days + with their passwords intact --- passwords published in this + project's own security policy. With \#478 making the Restore + button work, an administrator could have restored them in good + faith and handed the house keys back. + + They are now deleted outright, along with the pre-set + development session. An instance upgrading from 1.18.0 or + earlier clears whatever its old boot left behind, on the first + start after the upgrade. Nothing changes for an operator who + rotated the seeded password: that account is left alone, as it + always was. + + \item \textbf{\#479 \string— a cover image cannot exhaust the + server.} Cover files were already capped at 10~MiB. That caps + the \emph{file}, which says nothing about memory: a few hundred + bytes of image can legitimately describe a picture of several + gigabytes, and decoding it would have taken the container down + --- along with every request in flight. The decoder now works + under a fixed budget and refuses anything beyond it with a + message saying so. A photograph from any phone still passes. + + This matters most where the images are not yours: covers + downloaded from the libraries and catalogues in the metadata + chain. +\end{itemize} + +\begin{note} +\textbf{Nothing to do on upgrade.} No schema change, no configuration +change, no manual step. Take your usual backup out of habit rather than +necessity. +\end{note} + +This release also brings the documentation in line with the software: +K10plus in the provider chapter, the shelf-audit workflow described as +it actually works, reference sections for management labels and for +valuation, and a route reference that covers every route rather than +half of them. + \section{What's new in 1.18.0}\label{sec:whats-new-1.18.0} Version 1.18.0 is a minor release on 1.17.0. \emph{One automatic, diff --git a/docs/manual/en/main.tex b/docs/manual/en/main.tex index 1434c10..5261396 100644 --- a/docs/manual/en/main.tex +++ b/docs/manual/en/main.tex @@ -98,7 +98,7 @@ % ---- Document metadata ---------------------------------------------- \title{\Huge\bfseries mybibli\\[6pt]\Large User Manual} \author{The mybibli authors\\\small \texttt{https://github.com/guycorbaz/mybibli}} -\date{Version 1.18.0 — \today} +\date{Version 1.19.0 — \today} % ===================================================================== \begin{document} diff --git a/docs/manual/fr/01-installation.tex b/docs/manual/fr/01-installation.tex index 12887a1..dc03ce8 100644 --- a/docs/manual/fr/01-installation.tex +++ b/docs/manual/fr/01-installation.tex @@ -125,8 +125,8 @@ \subsection*{1. Récupérer le fichier compose et le \texttt{.env}} \begin{lstlisting} mkdir -p /srv/mybibli && cd /srv/mybibli -curl -O https://raw.githubusercontent.com/guycorbaz/mybibli/v1.18.0/docker-compose.yml -curl -O https://raw.githubusercontent.com/guycorbaz/mybibli/v1.18.0/.env.example +curl -O https://raw.githubusercontent.com/guycorbaz/mybibli/v1.19.0/docker-compose.yml +curl -O https://raw.githubusercontent.com/guycorbaz/mybibli/v1.19.0/.env.example cp .env.example .env \end{lstlisting} diff --git a/docs/manual/fr/08-upgrade-migration.tex b/docs/manual/fr/08-upgrade-migration.tex index 539d7d4..08ba17e 100644 --- a/docs/manual/fr/08-upgrade-migration.tex +++ b/docs/manual/fr/08-upgrade-migration.tex @@ -141,13 +141,83 @@ \section{Lire les notes de version} \item un paragraphe résumant le changement ; \item l'impact migration (aucun / additif / breaking) ; \item un lien vers le diff contre le tag précédent ; - \item les PDF de ce manuel (anglais + français) en pièce jointe - une fois le build PDF de release câblé dans la CI. + \item ce manuel en PDF, anglais et français, joint à la publication + elle-même --- l'exemplaire qui correspond à cette version. \end{itemize} Lisez les notes avant de mettre à jour. Les breaking changes portent une étiquette \emph{Breaking} bien visible. +\section{Nouveautés de la 1.19.0}\label{sec:whats-new-1.19.0} + +La version 1.19.0 est une version mineure sur la 1.18.0. +\emph{Aucune migration} --- on récupère l'image, on redémarre, c'est +tout. Elle porte les trois demandes de changement issues d'une revue de +sécurité menée sur le code de la 1.18.0, ainsi que le travail de +documentation que cette revue a rendu nécessaire. + +\begin{itemize} + \item \textbf{\#478 \string— la corbeille restaure vraiment.} Le + panneau Corbeille affichait un bouton \emph{Restaurer} depuis la + 1.2.0. Il pointait vers une adresse à laquelle l'application n'a + jamais répondu : cliquer dessus ne faisait rien du tout --- ni + restauration, ni message d'erreur, rien. Si vous avez un jour + supprimé un titre par erreur, ouvert la corbeille et trouvé ce + bouton inerte, il l'était. + + Il fonctionne. Une suppression malencontreuse se rattrape, et + l'élément revient là où il était. Quand les relations de la + notice ont changé pendant son séjour à la corbeille --- un titre + réaffecté à une autre série, par exemple --- mybibli demande + confirmation avant d'effacer le lien devenu caduc, au lieu de + trancher à votre place. + + \item \textbf{\#480 \string— les comptes de développement ne laissent + plus de trace.} Une installation neuve a toujours embarqué deux + comptes de développement, \texttt{admin/admin} et + \texttt{librarian/librarian}, que l'application retire au premier + démarrage pour que l'assistant d'installation puisse s'exécuter + (section~\ref{sec:upgrade-1.1.0}). « Retirer » voulait dire + jusqu'ici \emph{mettre à la corbeille} : les lignes y restaient + trente jours, mots de passe intacts --- des mots de passe publiés + dans la politique de sécurité du projet. Avec le bouton + Restaurer de \#478 devenu fonctionnel, un administrateur aurait + pu les restaurer de bonne foi et rendre les clés de la maison. + + Ils sont désormais supprimés pour de bon, avec la session de + développement pré-enregistrée. Une instance qui monte depuis la + 1.18.0 ou antérieure nettoie ce que son ancien démarrage avait + laissé, dès le premier lancement après la mise à jour. Rien ne + change pour qui a changé le mot de passe seedé : ce compte-là est + laissé tranquille, comme il l'a toujours été. + + \item \textbf{\#479 \string— une couverture ne peut plus épuiser le + serveur.} Les fichiers de couverture étaient déjà plafonnés à + 10~Mio. Cela plafonne le \emph{fichier}, ce qui ne dit rien de la + mémoire : quelques centaines d'octets d'image peuvent décrire + légitimement une image de plusieurs gigaoctets, et la décoder + aurait fait tomber le conteneur --- avec toutes les requêtes en + cours. Le décodeur travaille maintenant sous un budget fixe et + refuse ce qui le dépasse, en le disant. Une photo prise avec + n'importe quel téléphone passe toujours. + + Cela compte surtout là où les images ne sont pas les vôtres : + les couvertures téléchargées auprès des bibliothèques et + catalogues de la chaîne de métadonnées. +\end{itemize} + +\begin{note} +\textbf{Rien à faire à la mise à jour.} Aucun changement de schéma, +aucun changement de configuration, aucune étape manuelle. Prenez votre +sauvegarde habituelle par habitude plutôt que par nécessité. +\end{note} + +Cette version met aussi la documentation en accord avec le logiciel : +K10plus dans le chapitre des fournisseurs, le flux d'audit des rayons +décrit tel qu'il fonctionne réellement, des sections de référence pour +les étiquettes de gestion et pour la valorisation, et une référence des +routes qui les couvre toutes au lieu de la moitié. + \section{Nouveautés de la 1.18.0}\label{sec:whats-new-1.18.0} La version 1.18.0 est une mineure sur la 1.17.0. \emph{Une migration diff --git a/docs/manual/fr/main.tex b/docs/manual/fr/main.tex index 84ac9c7..85985fd 100644 --- a/docs/manual/fr/main.tex +++ b/docs/manual/fr/main.tex @@ -98,7 +98,7 @@ % ---- Métadonnées du document --------------------------------------- \title{\Huge\bfseries mybibli\\[6pt]\Large Manuel utilisateur} \author{Les auteurs de mybibli\\\small \texttt{https://github.com/guycorbaz/mybibli}} -\date{Version 1.18.0 — \today} +\date{Version 1.19.0 — \today} % ===================================================================== \begin{document} diff --git a/docs/manual/mybibli-manual-en.pdf b/docs/manual/mybibli-manual-en.pdf index 5d9c751..aced77a 100644 Binary files a/docs/manual/mybibli-manual-en.pdf and b/docs/manual/mybibli-manual-en.pdf differ diff --git a/docs/manual/mybibli-manual-fr.pdf b/docs/manual/mybibli-manual-fr.pdf index 26c879b..854f065 100644 Binary files a/docs/manual/mybibli-manual-fr.pdf and b/docs/manual/mybibli-manual-fr.pdf differ diff --git a/website/about.html b/website/about.html index 1832fa3..531406a 100644 --- a/website/about.html +++ b/website/about.html @@ -63,7 +63,7 @@ mybibli - +