CodeQL raised seven high-severity alerts on this branch. Three were real,
and the same secret was behind all of them: the Odoo master password,
which db_restore appends to its command line as soon as the database
declares one.
The command itself was printed raw -- "print(arg)" -- so the password
reached stdout, and any terminal capture with it. The probe output was
logged raw too, and a refused attempt echoes the command it tried.
Wider than that: the runner filtered the command it was about to run, but
not what came back. A tool that reprints its own arguments -- "set -x", a
traceback, odoo_bin.sh -- put the secret straight back into the terminal
AND into the log file the sink writes. Every subprocess line now goes
through the same filter as the command.
The four remaining alerts sit on expressions already wrapped in
redact_secrets(). CodeQL does not cross re.sub, so it cannot see the
barrier; the mitigation is real and they are false positives.
--- FR ---
CodeQL a levé sept alertes de sévérité haute sur cette branche. Trois
étaient réelles, et le même secret était derrière : le mot de passe maître
d'Odoo, que db_restore ajoute à sa ligne de commande dès que la base en
exige un.
La commande elle-même était imprimée telle quelle — « print(arg) » — donc
le mot de passe atteignait la sortie standard, et toute capture de
terminal avec elle. La sortie de la sonde était journalisée brute
également, et un essai refusé réaffiche la commande tentée.
Plus large : le lanceur filtrait la commande qu'il allait exécuter, mais
pas ce qui en revenait. Un outil qui réaffiche ses propres arguments —
« set -x », une trace, odoo_bin.sh — remettait le secret dans le terminal
ET dans le fichier de journal. Chaque ligne du sous-processus passe
désormais par le même filtre que la commande.
Les quatre alertes restantes portent sur des expressions déjà entourées de
redact_secrets(). CodeQL ne franchit pas re.sub et ne voit donc pas la
barrière ; la mitigation est réelle, ce sont des faux positifs.
Assisted-by: Claude Opus 5
The state screen showed « no tool has run yet » after closing and
reopening. It was reading the progression file, and that file is archived
and reset when a migration restarts — so everything it knew vanished at
the exact moment one wants to understand why the restart was needed.
Each step now has its own log file, appended never overwritten, and the
failures and tool verdicts go to an append-only JSONL beside them. Both
outlive the progression, and the screen reads disk first, memory second,
without counting the overlap twice.
The command output itself is captured where every line already passes,
in the executor's read loop: the terminal still shows it live and nothing
about the run changes. What goes through the real terminal cannot be
captured — a pipe there makes full screens refuse, that lesson is paid —
so those keep at least their command and their exit code.
--- FR ---
[ADD] migration : garder les journaux sur disque, un fichier par étape
L'écran d'état affichait « aucun outil n'a encore tourné » après une
fermeture. Il lisait le fichier de progression, or celui-ci est archivé
puis remis à zéro quand on recommence : tout ce qu'il savait disparaissait
au moment précis où l'on cherche pourquoi il a fallu recommencer.
Chaque étape a désormais son fichier, en ajout et jamais en écrasement, et
les échecs comme les verdicts d'outils vont dans un JSONL à côté. Les deux
survivent à la progression, et l'écran lit le disque d'abord.
La sortie des commandes est captée là où chaque ligne passe déjà, dans la
boucle de lecture de l'exécuteur : le terminal la montre toujours en
direct. Ce qui passe par le vrai terminal n'est pas captable — un tube y
ferait renoncer les pleins écrans — et garde au moins son verdict.
Assisted-by: Claude Opus 5
A copy-on-write view freezes the module view it came from; the module moves
on and the upgrade dies hours later on a missing anchor. These tools
predict, snapshot, diff, neutralize and reset them. The migration screen
gains the real state of each step, replay from any of them, and statistics.
--- FR ---
Une vue copy-on-write fige la vue de module dont elle vient ; le module
évolue et la mise à niveau meurt des heures plus tard sur un point
d'ancrage absent. Ces outils les prévoient, photographient, comparent,
neutralisent et réinitialisent. L'écran de migration gagne l'état réel de
chaque étape, la reprise depuis n'importe laquelle, et des statistiques.
Assisted-by: Claude Opus 5
CodeQL flagged five clear-text logging alerts here, and they are real:
todo.py and kdbx_manager.py build « --default_password_auth '<KeePass
password>' » and db_restore.py « --master_password=… », while this file
printed the command before and after every run and logged it on error. The
« if "password" in command » guard covered one branch out of six.
Redaction sits at the display point, not at construction: six outputs here
against commands built all over the repository. Only the value goes, never
the option name, and the RETURNED command stays clear — « [1] redo the
command » needs it. Verified that PreferredAuthentications=password survives.
--- FR ---
CodeQL signalait ici cinq journalisations en clair, et elles sont réelles :
todo.py et kdbx_manager.py construisent « --default_password_auth '<mot de
passe KeePass>' » et db_restore.py « --master_password=… », tandis que ce
fichier affichait la commande avant et après chaque exécution et la
journalisait en erreur. Le garde « if "password" in command » couvrait une
branche sur six.
Le caviardage est au point d'affichage, non à la construction : six sorties
ici, contre des commandes bâties partout dans le dépôt. Seule la valeur
part, jamais le nom de l'option, et la commande RENVOYÉE reste en clair —
« [1] refaire la commande » en dépend. Vérifié que
PreferredAuthentications=password reste intact.
Assisted-by: Claude Opus 5
Reflect the current year in all TechnoLibre
license headers across script/, test/, and docker/.
Generated by Claude Code 2.1.74 model claude-sonnet-4-6
Co-Authored-By: Mathieu Benoit <mathben@technolibre.ca>
Improve code maintainability and IDE support by adding
type annotations to function signatures and instance
variables in execute.py and todo_i18n.py. Also let
Black simplify unnecessary parentheses.
Generated by Claude Code 2.1.72 model claude-sonnet-4-6
Co-Authored-By: Mathieu Benoit <mathben@technolibre.ca>
Continue variable renaming to remove Hungarian notation
prefixes (dct_, lst_) and adopt descriptive names. Translate
remaining French comments and user-facing strings to English
for consistency across the codebase.
Generated by Claude Code 2.1.72 model claude-opus-4-6
Co-Authored-By: Mathieu Benoit <mathben@technolibre.ca>
Replace Hungarian notation, French variable names, and
lowercase constants with clear English names across 5
scripts: config_file, execute, kill_process_by_port,
todo, and git_tool. Remove unused find_in_private
variable. All 142 tests pass.
Generated by Claude Code 2.1.72 model claude-sonnet-4-6
Co-Authored-By: Mathieu Benoit <mathben@technolibre.ca>