[UPD] docker : une seule base, bookworm, pour toutes les versions d'Odoo

Odoo 13, 14 et 15 bâtissaient encore sur bullseye, dont le dépôt de sécurité
est démantelé. Rien ne les y obligeait : la base est
« python:<version>-slim-<version Debian> », donc l'interpréteur vient de
l'image officielle et non de Debian — les variantes bookworm existent jusqu'à
3.7.17. L'aiguillage portait en outre une branche « buster » INATTEIGNABLE,
sa condition étant la négation de celle qui la précédait ; elle part avec le
reste. Le build de wkhtmltopdf suit la version : celui de bullseye réclame
libssl1.1, absente de bookworm.
Vérifié : les images 3.7.17 et 3.8.20 slim-bookworm existent, le .deb bookworm
rend l'empreinte déclarée, et ses quinze dépendances sont dans bookworm.

--- EN ---

Odoo 13, 14 and 15 still built on bullseye, whose security repository is
dismantled. Nothing required it: the base is
"python:<version>-slim-<suite>", so the interpreter comes from the official
image and not from Debian — the bookworm variants exist down to 3.7.17. The
switch also carried an UNREACHABLE "buster" branch, its condition being the
negation of the one before it; it goes with the rest. The wkhtmltopdf build
follows the suite: bullseye's requires libssl1.1, absent from bookworm.
Checked: the 3.7.17 and 3.8.20 slim-bookworm images exist, the bookworm .deb
matches the declared checksum, and its fifteen dependencies are in bookworm.

Assisted-by: Claude Opus 5
This commit is contained in:
Mathieu Benoit 2026-09-24 13:34:22 -04:00
parent e39221af01
commit a1f1065962
5 changed files with 97 additions and 18 deletions

View file

@ -161,6 +161,7 @@ au [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
- `make` and `make todo` go through `install.sh`, which picks an interpreter able to READ the code before running it: `.venv.erplibre` on the right version, else a recent enough system `python3`, else the install. A system older than `conf/python-erplibre-version` would otherwise stop on a syntax error raised before any guard could name the command to type. TODO then relaunches itself in `.venv.erplibre`, or offers to run `install_erplibre.sh` in a terminal
- The production Docker image builds `.venv.erplibre` on Odoo's Python and stops when that Python cannot parse `script/`
- Debian 11 is dropped from the deployment catalogue: its LTS ended, and its security suite is neither served nor archived — the index it still publishes names packages whose pool no longer holds the file, so apt stops before installing git. Debian 13 takes its place, its cloud image always being the latest point release
- Every container image is built on bookworm, whatever the Odoo version. The base is `python:<version>-slim-<suite>`: the interpreter comes from the official image, never from Debian, and the bookworm variants exist down to 3.7.17. The wkhtmltopdf build follows the suite — bullseye's requires libssl1.1, absent from bookworm
- The PATCH bounds only Odoo's venv, whose pyproject requires `>=3.12.10,<3.13`. For the tooling one, the major.minor is enough: requiring the patch turned away a distribution's Python one step behind — NixOS 25.11 ships 3.14.2 where conf asks 3.14.7 — and made pyenv COMPILE CPython for a difference nothing needs
- `make format` picks the formatter from each file's context: an Odoo module keeps isort and black on `py37`, the series still supported going down that far, while this repository's own tooling goes through ruff, configured once in `.ruff.toml`. ruff follows CPython's versions, where black 24.8.0 stops at `py313`, and its import sorting replaces isort; it is also what the OCA standard uses since it left black
- The repositories that Google Repo checks out under `script/` are excluded from that formatting, a named path included: reformatting them would write in someone else's history. `target-version` stays at `py310` there, because the git hooks carry `#!/usr/bin/env python3` and a distribution still ships 3.10 — from 3.14 on, ruff would write `except A, B:` without parentheses
@ -185,6 +186,7 @@ au [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
- `make` et `make todo` passent par `install.sh`, qui choisit un interpréteur capable de LIRE le code avant de le lancer : `.venv.erplibre` s'il porte la bonne version, sinon le `python3` du système s'il est assez récent, sinon l'installation. Un système plus ancien que `conf/python-erplibre-version` s'arrêterait autrement sur une erreur de syntaxe levée avant qu'aucun garde puisse nommer la commande à taper. TODO se relance ensuite dans `.venv.erplibre`, ou propose de lancer `install_erplibre.sh` en terminal
- L'image Docker de production bâtit `.venv.erplibre` sur le Python d'Odoo et s'arrête quand ce Python ne sait pas lire `script/`
- Debian 11 quitte le catalogue de déploiement : son LTS est terminé, et sa suite de sécurité n'est ni servie ni archivée — l'index qu'elle publie encore nomme des paquets dont le pool ne porte plus le fichier, et apt s'arrête avant d'installer git. Debian 13 la remplace, son image cloud étant toujours le dernier point de version
- Toutes les images de conteneur reposent sur bookworm, quelle que soit la version d'Odoo. La base est `python:<version>-slim-<version Debian>` : l'interpréteur vient de l'image officielle, jamais de Debian, et les variantes bookworm existent jusqu'à 3.7.17. Le build de wkhtmltopdf suit la version — celui de bullseye réclame libssl1.1, absente de bookworm
- Le PATCH ne borne que le venv d'Odoo, dont le pyproject exige `>=3.12.10,<3.13`. Pour celui de l'outillage, la majeure.mineure suffit : exiger le patch écartait le Python d'une distribution d'un cran en retard — NixOS 25.11 livre 3.14.2 quand conf demande 3.14.7 — et faisait COMPILER CPython à pyenv pour une différence que rien ne réclame
- `make format` choisit le formateur d'après le contexte de chaque fichier : un module Odoo garde isort et black en `py37`, la série la plus ancienne encore supportée, quand l'outillage de ce dépôt passe par ruff, réglé une fois dans `.ruff.toml`. ruff suit les versions de CPython, là où black 24.8.0 s'arrête à `py313`, et son tri d'imports remplace isort ; c'est aussi ce qu'emploie la norme OCA depuis qu'elle a quitté black
- Les dépôts que Google Repo rapatrie sous `script/` sont écartés de ce formatage, chemin nommé compris : les reformater écrirait dans l'historique d'autrui. `target-version` y reste à `py310`, parce que les hooks git portent `#!/usr/bin/env python3` et qu'une distribution livre encore 3.10 — à partir de 3.14, ruff écrirait `except A, B:` sans parenthèses

View file

@ -83,6 +83,7 @@ au [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
- `make` et `make todo` passent par `install.sh`, qui choisit un interpréteur capable de LIRE le code avant de le lancer : `.venv.erplibre` s'il porte la bonne version, sinon le `python3` du système s'il est assez récent, sinon l'installation. Un système plus ancien que `conf/python-erplibre-version` s'arrêterait autrement sur une erreur de syntaxe levée avant qu'aucun garde puisse nommer la commande à taper. TODO se relance ensuite dans `.venv.erplibre`, ou propose de lancer `install_erplibre.sh` en terminal
- L'image Docker de production bâtit `.venv.erplibre` sur le Python d'Odoo et s'arrête quand ce Python ne sait pas lire `script/`
- Debian 11 quitte le catalogue de déploiement : son LTS est terminé, et sa suite de sécurité n'est ni servie ni archivée — l'index qu'elle publie encore nomme des paquets dont le pool ne porte plus le fichier, et apt s'arrête avant d'installer git. Debian 13 la remplace, son image cloud étant toujours le dernier point de version
- Toutes les images de conteneur reposent sur bookworm, quelle que soit la version d'Odoo. La base est `python:<version>-slim-<version Debian>` : l'interpréteur vient de l'image officielle, jamais de Debian, et les variantes bookworm existent jusqu'à 3.7.17. Le build de wkhtmltopdf suit la version — celui de bullseye réclame libssl1.1, absente de bookworm
- Le PATCH ne borne que le venv d'Odoo, dont le pyproject exige `>=3.12.10,<3.13`. Pour celui de l'outillage, la majeure.mineure suffit : exiger le patch écartait le Python d'une distribution d'un cran en retard — NixOS 25.11 livre 3.14.2 quand conf demande 3.14.7 — et faisait COMPILER CPython à pyenv pour une différence que rien ne réclame
- `make format` choisit le formateur d'après le contexte de chaque fichier : un module Odoo garde isort et black en `py37`, la série la plus ancienne encore supportée, quand l'outillage de ce dépôt passe par ruff, réglé une fois dans `.ruff.toml`. ruff suit les versions de CPython, là où black 24.8.0 s'arrête à `py313`, et son tri d'imports remplace isort ; c'est aussi ce qu'emploie la norme OCA depuis qu'elle a quitté black
- Les dépôts que Google Repo rapatrie sous `script/` sont écartés de ce formatage, chemin nommé compris : les reformater écrirait dans l'historique d'autrui. `target-version` y reste à `py310`, parce que les hooks git portent `#!/usr/bin/env python3` et qu'une distribution livre encore 3.10 — à partir de 3.14, ruff écrirait `except A, B:` sans parenthèses

View file

@ -83,6 +83,7 @@ to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
- `make` and `make todo` go through `install.sh`, which picks an interpreter able to READ the code before running it: `.venv.erplibre` on the right version, else a recent enough system `python3`, else the install. A system older than `conf/python-erplibre-version` would otherwise stop on a syntax error raised before any guard could name the command to type. TODO then relaunches itself in `.venv.erplibre`, or offers to run `install_erplibre.sh` in a terminal
- The production Docker image builds `.venv.erplibre` on Odoo's Python and stops when that Python cannot parse `script/`
- Debian 11 is dropped from the deployment catalogue: its LTS ended, and its security suite is neither served nor archived — the index it still publishes names packages whose pool no longer holds the file, so apt stops before installing git. Debian 13 takes its place, its cloud image always being the latest point release
- Every container image is built on bookworm, whatever the Odoo version. The base is `python:<version>-slim-<suite>`: the interpreter comes from the official image, never from Debian, and the bookworm variants exist down to 3.7.17. The wkhtmltopdf build follows the suite — bullseye's requires libssl1.1, absent from bookworm
- The PATCH bounds only Odoo's venv, whose pyproject requires `>=3.12.10,<3.13`. For the tooling one, the major.minor is enough: requiring the patch turned away a distribution's Python one step behind — NixOS 25.11 ships 3.14.2 where conf asks 3.14.7 — and made pyenv COMPILE CPython for a difference nothing needs
- `make format` picks the formatter from each file's context: an Odoo module keeps isort and black on `py37`, the series still supported going down that far, while this repository's own tooling goes through ruff, configured once in `.ruff.toml`. ruff follows CPython's versions, where black 24.8.0 stops at `py313`, and its import sorting replaces isort; it is also what the OCA standard uses since it left black
- The repositories that Google Repo checks out under `script/` are excluded from that formatting, a named path included: reformatting them would write in someone else's history. `target-version` stays at `py310` there, because the git hooks carry `#!/usr/bin/env python3` and a distribution still ships 3.10 — from 3.14 on, ruff would write `except A, B:` without parentheses

View file

@ -9,9 +9,6 @@ ODOO_VERSION=$(cat .odoo-version | xargs)
PYTHON_VERSION=$(cat .python-odoo-version | xargs)
POETRY_VERSION=$(cat .poetry-version | xargs)
IS_DEBIAN_BOOKWORM=true
IS_DEBIAN_BULLSEYE=true
# or IS_DEBIAN_BUSTER
ARGS=""
IS_RELEASE=false
IS_RELEASE_ALPHA=false
@ -37,20 +34,12 @@ for arg in "$@"; do
elif [ "$arg" == "--odoo_16" ]; then
output_version=$(python ./script/version/get_version.py --odoo_version 16.0)
elif [ "$arg" == "--odoo_15" ]; then
IS_DEBIAN_BOOKWORM=false
IS_DEBIAN_BULLSEYE=false
output_version=$(python ./script/version/get_version.py --odoo_version 15.0)
elif [ "$arg" == "--odoo_14" ]; then
IS_DEBIAN_BOOKWORM=false
IS_DEBIAN_BULLSEYE=false
output_version=$(python ./script/version/get_version.py --odoo_version 14.0)
elif [ "$arg" == "--odoo_13" ]; then
IS_DEBIAN_BOOKWORM=false
IS_DEBIAN_BULLSEYE=false
output_version=$(python ./script/version/get_version.py --odoo_version 13.0)
elif [ "$arg" == "--odoo_12" ]; then
IS_DEBIAN_BOOKWORM=false
IS_DEBIAN_BULLSEYE=false
output_version=$(python ./script/version/get_version.py --odoo_version 12.0)
fi
done
@ -100,13 +89,18 @@ cd docker
ARGS="${ARGS} --build-arg WORKING_BRANCH=$(git rev-parse --abbrev-ref HEAD) --build-arg WORKING_HASH=$(git rev-parse --verify HEAD)"
if [ "$IS_DEBIAN_BOOKWORM" == true ]; then
ARGS="${ARGS} --build-arg DEBIAN_NAME=bookworm --build-arg URL_WKHTMLTOX=github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-3/wkhtmltox_0.12.6.1-3.bookworm_amd64.deb --build-arg SHA1SUM_WKTHMLTOX=e9f95436298c77cc9406bd4bbd242f4771d0a4b2"
elif [ "$IS_DEBIAN_BOOKWORM" != true ]; then
ARGS="${ARGS} --build-arg DEBIAN_NAME=bullseye --build-arg URL_WKHTMLTOX=github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-2/wkhtmltox_0.12.6.1-2.bullseye_amd64.deb --build-arg SHA1SUM_WKTHMLTOX=cecbf5a6abbd68d324a7cd6c51ec843d71e98951"
elif [ "$IS_DEBIAN_BULLSEYE" != true ]; then
ARGS="${ARGS} --build-arg DEBIAN_NAME=buster --build-arg URL_WKHTMLTOX=github.com/wkhtmltopdf/packaging/releases/download/0.12.6-1/wkhtmltox_0.12.6-1.buster_amd64.deb --build-arg SHA1SUM_WKTHMLTOX=d9f259a67e05e1c221d48b504453645e6c491fab"
fi
# UNE seule base, bookworm, pour toutes les versions d'Odoo.
#
# La base est « python:<version>-slim-<nom> » : le Python vient de l'image
# officielle, jamais de Debian. Changer de nom de version ne change donc pas
# l'interpréteur, et les variantes bookworm existent jusqu'à 3.7.17 — vérifié
# sur le registre. Rien n'obligeait les vieux Odoo à rester sur bullseye, dont
# le dépôt de sécurité est aujourd'hui démantelé.
#
# Le build de wkhtmltopdf suit la version : celui de bullseye réclame
# libssl1.1, absente de bookworm ; celui de bookworm réclame libssl3, et ses
# quinze dépendances y sont toutes — vérifié dans l'index.
ARGS="${ARGS} --build-arg DEBIAN_NAME=bookworm --build-arg URL_WKHTMLTOX=github.com/wkhtmltopdf/packaging/releases/download/0.12.6.1-3/wkhtmltox_0.12.6.1-3.bookworm_amd64.deb --build-arg SHA1SUM_WKTHMLTOX=e9f95436298c77cc9406bd4bbd242f4771d0a4b2"
set -e
# Build base

View file

@ -0,0 +1,81 @@
#!/usr/bin/env python3
# © 2026 TechnoLibre (http://www.technolibre.ca)
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
"""Les conteneurs reposent-ils tous sur la même base ?
La base est « python:<version>-slim-<nom de version Debian> » : le Python vient
de l'image officielle, jamais de Debian. Changer de nom de version ne change
donc pas l'interpréteur, et rien n'obligeait les vieux Odoo à rester sur
bullseye — dont le dépôt de sécurité est aujourd'hui démantelé.
Ce que ces tests gardent :
- une seule base, pour toutes les versions d'Odoo. L'aiguillage précédent
portait une branche « buster » INATTEIGNABLE : sa condition était la
négation de celle qui la précédait ;
- le build de wkhtmltopdf suit la version. Celui de bullseye réclame
libssl1.1, absente de bookworm : un .deb mal apparié s'installe puis ne se
lance pas, et l'impression PDF échoue à l'exécution, pas à la construction ;
- l'empreinte accompagne l'URL. Le Dockerfile la vérifie avant d'installer,
et une URL changée sans son empreinte ferait échouer la construction.
"""
import re
import unittest
from pathlib import Path
RACINE = Path(__file__).resolve().parents[1]
SCRIPT = (RACINE / "script/docker/docker_build.sh").read_text(encoding="utf-8")
DOCKERFILE = (RACINE / "docker/Dockerfile.base").read_text(encoding="utf-8")
class TestUneSeuleBase(unittest.TestCase):
def test_aucune_version_debian_anterieure(self):
for ancienne in ("bullseye", "buster", "stretch"):
with self.subTest(version=ancienne):
self.assertNotIn(f"DEBIAN_NAME={ancienne}", SCRIPT)
def test_la_base_est_bookworm(self):
self.assertIn("--build-arg DEBIAN_NAME=bookworm", SCRIPT)
def test_elle_est_posee_une_seule_fois(self):
"""Plusieurs branches redonneraient un aiguillage à entretenir."""
self.assertEqual(1, SCRIPT.count("--build-arg DEBIAN_NAME="))
def test_plus_aucun_drapeau_de_version(self):
self.assertNotIn("IS_DEBIAN_", SCRIPT)
class TestWkhtmltopdf(unittest.TestCase):
def test_le_build_suit_la_version_de_la_base(self):
"""Le .deb de bullseye réclame libssl1.1, absente de bookworm."""
urls = re.findall(r"URL_WKHTMLTOX=(\S+)", SCRIPT)
self.assertTrue(urls)
for url in urls:
with self.subTest(url=url):
self.assertIn("bookworm", url)
def test_l_empreinte_accompagne_l_url(self):
self.assertEqual(
SCRIPT.count("URL_WKHTMLTOX="),
SCRIPT.count("SHA1SUM_WKTHMLTOX="),
)
def test_le_dockerfile_verifie_l_empreinte_avant_d_installer(self):
"""Sans ce contrôle, une page d'erreur HTML s'installerait comme
un paquet."""
verif = DOCKERFILE.index("sha1sum -c -")
pose = DOCKERFILE.index(
"apt-get install -y --no-install-recommends ./wkhtmltox.deb"
)
self.assertLess(verif, pose)
def test_le_defaut_du_dockerfile_s_accorde_au_script(self):
"""Une construction lancée sans argument ne doit pas changer de base."""
self.assertIn("ARG DEBIAN_NAME=bookworm", DOCKERFILE)
attendue = re.search(r"URL_WKHTMLTOX=(\S+)", SCRIPT).group(1)
self.assertIn(attendue, DOCKERFILE)
if __name__ == "__main__":
unittest.main()