2026-02-13 01:27:38 -05:00
|
|
|
#!/usr/bin/env python3
|
2026-03-11 23:15:07 -04:00
|
|
|
# © 2021-2026 TechnoLibre (http://www.technolibre.ca)
|
2026-02-13 01:27:38 -05:00
|
|
|
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl)
|
|
|
|
|
|
|
|
|
|
import datetime
|
|
|
|
|
import logging
|
|
|
|
|
import os
|
[FIX] execute: redact the secrets before printing a command
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
2026-08-07 03:35:20 -04:00
|
|
|
import re
|
2026-02-13 01:27:38 -05:00
|
|
|
import shutil
|
|
|
|
|
import subprocess
|
|
|
|
|
import sys
|
|
|
|
|
import time
|
|
|
|
|
|
2026-02-14 05:53:31 -05:00
|
|
|
try:
|
|
|
|
|
import humanize
|
2026-02-19 12:27:35 -05:00
|
|
|
except ModuleNotFoundError as e:
|
2026-02-14 05:53:31 -05:00
|
|
|
humanize = None
|
2026-02-13 01:27:38 -05:00
|
|
|
|
2026-03-10 03:06:07 -04:00
|
|
|
VENV_ERPLIBRE = ".venv.erplibre"
|
2026-02-13 01:27:38 -05:00
|
|
|
|
[FIX] execute: redact the secrets before printing a command
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
2026-08-07 03:35:20 -04:00
|
|
|
# Une commande construite ailleurs peut porter un secret en clair : todo.py et
|
|
|
|
|
# kdbx_manager.py y mettent « --default_password_auth '<mot de passe KeePass>' »,
|
|
|
|
|
# db_restore.py « --master_password=… ». Cette commande est affichée avant et
|
|
|
|
|
# après l'exécution, et journalisée en erreur : le secret finissait donc dans le
|
|
|
|
|
# terminal, dans les journaux et dans toute sortie CI qui les capture.
|
|
|
|
|
#
|
|
|
|
|
# On caviarde la VALEUR, jamais le nom de l'option : la commande reste lisible et
|
|
|
|
|
# reproductible, il ne manque que ce qui ne doit pas être lu.
|
|
|
|
|
_SECRET_OPTION = re.compile(
|
|
|
|
|
r"(?P<opt>--?[\w-]*"
|
|
|
|
|
r"(?:password|passwd|pwd|secret|token|api[-_]?key)[\w-]*"
|
|
|
|
|
r"(?:\s+|=))"
|
|
|
|
|
r"(?P<val>'[^']*'|\"[^\"]*\"|\S+)",
|
|
|
|
|
re.IGNORECASE,
|
|
|
|
|
)
|
|
|
|
|
_SECRET_ENV = re.compile(
|
|
|
|
|
r"(?P<var>\b\w*(?:PASSWORD|PASSWD|SECRET|TOKEN)\w*=)"
|
|
|
|
|
r"(?P<val>'[^']*'|\"[^\"]*\"|\S+)"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def redact_secrets(text):
|
|
|
|
|
"""Remplace la valeur des options et variables porteuses de secret.
|
|
|
|
|
|
|
|
|
|
Appliqué à CHAQUE affichage d'une commande. Filtrer au point d'affichage
|
|
|
|
|
plutôt qu'à la construction est ce qui rend la garantie tenable : il n'y a
|
|
|
|
|
qu'une poignée de sorties ici, alors que les commandes se construisent
|
|
|
|
|
partout dans le dépôt.
|
|
|
|
|
"""
|
|
|
|
|
if not text:
|
|
|
|
|
return text
|
|
|
|
|
text = _SECRET_OPTION.sub(lambda m: m.group("opt") + "'***'", text)
|
|
|
|
|
return _SECRET_ENV.sub(lambda m: m.group("var") + "'***'", text)
|
|
|
|
|
|
|
|
|
|
|
2026-02-13 01:27:38 -05:00
|
|
|
new_path = os.path.normpath(
|
|
|
|
|
os.path.join(os.path.dirname(__file__), "..", "..")
|
|
|
|
|
)
|
|
|
|
|
sys.path.append(new_path)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logging.basicConfig(
|
|
|
|
|
format=(
|
|
|
|
|
"%(asctime)s,%(msecs)d %(levelname)-8s [%(filename)s:%(lineno)d]"
|
|
|
|
|
" %(message)s"
|
|
|
|
|
),
|
|
|
|
|
datefmt="%Y-%m-%d:%H:%M:%S",
|
|
|
|
|
level=logging.INFO,
|
|
|
|
|
)
|
|
|
|
|
_logger = logging.getLogger(__name__)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class Execute:
|
2026-03-10 04:07:38 -04:00
|
|
|
def __init__(self) -> None:
|
|
|
|
|
self.cmd_source_erplibre: str = ""
|
|
|
|
|
self.cmd_source_default: str = ""
|
2026-02-13 01:27:38 -05:00
|
|
|
exec_path_gnome_terminal = shutil.which("gnome-terminal")
|
|
|
|
|
if exec_path_gnome_terminal:
|
|
|
|
|
self.cmd_source_erplibre = (
|
|
|
|
|
f"gnome-terminal -- bash -c 'source"
|
2026-03-10 03:06:07 -04:00
|
|
|
f" ./{VENV_ERPLIBRE}/bin/activate;%s'"
|
2026-02-13 01:27:38 -05:00
|
|
|
)
|
|
|
|
|
self.cmd_source_default = "gnome-terminal -- bash -c '" f"%s'"
|
|
|
|
|
else:
|
|
|
|
|
exec_path_tell = shutil.which("osascript")
|
|
|
|
|
if exec_path_tell:
|
|
|
|
|
self.cmd_source_erplibre = (
|
|
|
|
|
"osascript -e 'tell application \"Terminal\"'"
|
|
|
|
|
)
|
|
|
|
|
self.cmd_source_erplibre += " -e 'tell application \"System Events\" to keystroke \"t\" using {command down}' -e 'delay 0.1' -e 'do script \""
|
2026-03-10 03:06:07 -04:00
|
|
|
self.cmd_source_erplibre += f"cd {os.getcwd()}; source ./{VENV_ERPLIBRE}/bin/activate; %s\" in front window'"
|
2026-02-13 01:27:38 -05:00
|
|
|
self.cmd_source_erplibre += " -e 'end tell'"
|
|
|
|
|
else:
|
|
|
|
|
self.cmd_source_erplibre = (
|
2026-03-10 03:06:07 -04:00
|
|
|
f"source ./{VENV_ERPLIBRE}/bin/activate;%s"
|
2026-02-13 01:27:38 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
|
|
def exec_command_live(
|
|
|
|
|
self,
|
2026-03-10 04:07:38 -04:00
|
|
|
command: str,
|
|
|
|
|
source_erplibre: bool = True,
|
|
|
|
|
quiet: bool = False,
|
|
|
|
|
single_source_erplibre: bool = False,
|
|
|
|
|
new_window: bool = False,
|
|
|
|
|
single_source_odoo: bool = False,
|
|
|
|
|
source_odoo: str = "",
|
|
|
|
|
new_env: dict | None = None,
|
|
|
|
|
return_status_and_command: bool = False,
|
|
|
|
|
return_status_and_output: bool = False,
|
|
|
|
|
return_status_and_output_and_command: bool = False,
|
|
|
|
|
) -> (
|
|
|
|
|
int
|
|
|
|
|
| tuple[int, str]
|
|
|
|
|
| tuple[int, list[str]]
|
|
|
|
|
| tuple[int, str, list[str]]
|
2026-02-13 01:27:38 -05:00
|
|
|
):
|
|
|
|
|
"""
|
2026-03-10 03:45:11 -04:00
|
|
|
Execute a command and display its output live.
|
2026-02-13 01:27:38 -05:00
|
|
|
|
|
|
|
|
Args:
|
2026-03-10 03:45:11 -04:00
|
|
|
command (str): The command to execute.
|
2026-02-13 01:27:38 -05:00
|
|
|
"""
|
|
|
|
|
|
|
|
|
|
my_env = os.environ.copy()
|
|
|
|
|
if new_env:
|
|
|
|
|
my_env.update(new_env)
|
|
|
|
|
|
|
|
|
|
process_start_time = time.time()
|
2026-03-10 03:06:07 -04:00
|
|
|
exit_code = None
|
2026-02-13 01:27:38 -05:00
|
|
|
if source_erplibre:
|
2026-03-10 03:06:07 -04:00
|
|
|
# command = f"source ./{VENV_ERPLIBRE}/bin/activate && " + command
|
2026-02-13 01:27:38 -05:00
|
|
|
# cmd = (
|
|
|
|
|
# f"gnome-terminal --tab -- bash -c 'source"
|
2026-03-10 03:06:07 -04:00
|
|
|
# f" ./{VENV_ERPLIBRE}/bin/activate;{command}'"
|
2026-02-13 01:27:38 -05:00
|
|
|
# )
|
2026-03-10 03:06:07 -04:00
|
|
|
command = self.cmd_source_erplibre % command
|
|
|
|
|
# os.system(f"./script/terminal/open_terminal.sh {command}")
|
2026-02-13 01:27:38 -05:00
|
|
|
elif single_source_erplibre:
|
2026-03-10 04:07:38 -04:00
|
|
|
command = f"source ./{VENV_ERPLIBRE}/bin/activate && %s" % command
|
2026-02-13 01:27:38 -05:00
|
|
|
elif single_source_odoo:
|
|
|
|
|
if not source_odoo and os.path.exists("./.erplibre-version"):
|
|
|
|
|
with open("./.erplibre-version") as f:
|
|
|
|
|
source_odoo = f.read()
|
|
|
|
|
if not source_odoo:
|
|
|
|
|
_logger.error(
|
[FIX] execute: redact the secrets before printing a command
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
2026-08-07 03:35:20 -04:00
|
|
|
"You cannot execute Odoo command if no version is"
|
|
|
|
|
f" installed. Command : {redact_secrets(command)}"
|
2026-02-13 01:27:38 -05:00
|
|
|
)
|
[ADD] migration: see and repair the website COW views
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
2026-08-10 03:10:50 -04:00
|
|
|
# Return the SAME shape the caller asked for. A bare int here
|
|
|
|
|
# made callers doing « status, cmd = exec_command_live(...) »
|
|
|
|
|
# crash with ValueError instead of seeing the failure.
|
|
|
|
|
if return_status_and_output_and_command:
|
|
|
|
|
return 1, command, []
|
|
|
|
|
if return_status_and_command:
|
|
|
|
|
return 1, command
|
|
|
|
|
if return_status_and_output:
|
|
|
|
|
return 1, []
|
|
|
|
|
return 1
|
2026-03-10 04:07:38 -04:00
|
|
|
command = f"source ./.venv.{source_odoo}/bin/activate && {command}"
|
2026-02-13 04:07:02 -05:00
|
|
|
if new_window and self.cmd_source_default:
|
2026-03-10 03:06:07 -04:00
|
|
|
command = self.cmd_source_default % command
|
2026-02-13 01:27:38 -05:00
|
|
|
|
|
|
|
|
if not quiet:
|
2026-03-12 05:20:32 -04:00
|
|
|
print("🏠 ⬇ Execute command :\n")
|
[FIX] execute: redact the secrets before printing a command
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
2026-08-07 03:35:20 -04:00
|
|
|
print(redact_secrets(command))
|
2026-03-10 03:06:07 -04:00
|
|
|
output_lines = []
|
2026-02-13 01:27:38 -05:00
|
|
|
|
|
|
|
|
try:
|
|
|
|
|
process = subprocess.Popen(
|
2026-03-10 03:06:07 -04:00
|
|
|
command,
|
2026-02-13 01:27:38 -05:00
|
|
|
shell=True,
|
|
|
|
|
executable="/bin/bash",
|
|
|
|
|
stdout=subprocess.PIPE,
|
|
|
|
|
stderr=subprocess.STDOUT,
|
|
|
|
|
text=True,
|
2026-03-10 03:45:11 -04:00
|
|
|
bufsize=1, # Disable buffering for live output
|
|
|
|
|
universal_newlines=True, # Handle line breaks correctly
|
2026-02-13 01:27:38 -05:00
|
|
|
env=my_env,
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
while True:
|
2026-03-10 03:06:07 -04:00
|
|
|
line = process.stdout.readline()
|
|
|
|
|
if not line:
|
2026-02-13 01:27:38 -05:00
|
|
|
break
|
|
|
|
|
if not quiet:
|
2026-03-10 03:06:07 -04:00
|
|
|
print(line, end="")
|
2026-02-13 01:27:38 -05:00
|
|
|
if (
|
|
|
|
|
return_status_and_output
|
|
|
|
|
or return_status_and_output_and_command
|
|
|
|
|
):
|
2026-02-13 03:46:27 -05:00
|
|
|
# Remove last \n char
|
2026-03-10 03:06:07 -04:00
|
|
|
output_lines.append(
|
|
|
|
|
line.removesuffix("\r\n")
|
2026-02-13 03:46:27 -05:00
|
|
|
.removesuffix("\n")
|
|
|
|
|
.removesuffix("\r")
|
|
|
|
|
)
|
2026-02-13 01:27:38 -05:00
|
|
|
|
2026-03-10 03:45:11 -04:00
|
|
|
process.wait()
|
2026-03-10 03:06:07 -04:00
|
|
|
exit_code = process.returncode
|
2026-02-13 01:27:38 -05:00
|
|
|
if process.returncode != 0 and not quiet:
|
2026-03-10 04:07:38 -04:00
|
|
|
print("Command returned error code:" f" {process.returncode}")
|
2026-02-13 01:27:38 -05:00
|
|
|
|
[ADD] migration: see and repair the website COW views
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
2026-08-10 03:10:50 -04:00
|
|
|
# An exception MUST report a failure. exit_code stays None otherwise,
|
|
|
|
|
# and None is falsy: callers testing « if not status: » would mark the
|
|
|
|
|
# step as done, and « if status and wait_at_error » would skip the error
|
|
|
|
|
# prompt. A crashed command was therefore recorded as a success.
|
2026-02-13 01:27:38 -05:00
|
|
|
except FileNotFoundError:
|
[ADD] migration: see and repair the website COW views
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
2026-08-10 03:10:50 -04:00
|
|
|
exit_code = 1
|
2026-02-13 01:27:38 -05:00
|
|
|
if not quiet:
|
[FIX] execute: redact the secrets before printing a command
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
2026-08-07 03:35:20 -04:00
|
|
|
print(f"Error: Command '{redact_secrets(command)}' not found.")
|
2026-02-13 01:27:38 -05:00
|
|
|
except Exception as e:
|
[ADD] migration: see and repair the website COW views
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
2026-08-10 03:10:50 -04:00
|
|
|
exit_code = 1
|
2026-02-13 01:27:38 -05:00
|
|
|
if not quiet:
|
[FIX] execute: redact the secrets before printing a command
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
2026-08-07 03:35:20 -04:00
|
|
|
print(f"An error occurred: {redact_secrets(str(e))}")
|
2026-02-13 01:27:38 -05:00
|
|
|
process_end_time = time.time()
|
|
|
|
|
duration_sec = process_end_time - process_start_time
|
|
|
|
|
if humanize:
|
|
|
|
|
duration_delta = datetime.timedelta(seconds=duration_sec)
|
2026-03-10 03:45:11 -04:00
|
|
|
human_time = humanize.precisedelta(duration_delta)
|
2026-02-13 01:27:38 -05:00
|
|
|
if not quiet:
|
2026-03-12 05:20:32 -04:00
|
|
|
print(f"🏠 ⬆ Executed ({human_time}) :\n")
|
2026-02-13 01:27:38 -05:00
|
|
|
else:
|
|
|
|
|
if not quiet:
|
2026-03-12 05:20:32 -04:00
|
|
|
print(f"🏠 ⬆ Executed ({duration_sec:.2f} sec.) :\n")
|
2026-02-13 01:27:38 -05:00
|
|
|
if not quiet:
|
[FIX] execute: redact the secrets before printing a command
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
2026-08-07 03:35:20 -04:00
|
|
|
print(redact_secrets(command))
|
2026-02-13 01:27:38 -05:00
|
|
|
print()
|
|
|
|
|
if return_status_and_output_and_command:
|
2026-03-10 03:06:07 -04:00
|
|
|
return exit_code, command, output_lines
|
2026-02-13 01:27:38 -05:00
|
|
|
if return_status_and_command:
|
2026-03-10 03:06:07 -04:00
|
|
|
return exit_code, command
|
2026-02-13 01:27:38 -05:00
|
|
|
if return_status_and_output:
|
2026-03-10 03:06:07 -04:00
|
|
|
return exit_code, output_lines
|
|
|
|
|
return exit_code
|