[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
This commit is contained in:
parent
67e902e416
commit
18a6f064f5
1 changed files with 42 additions and 11 deletions
|
|
@ -5,6 +5,7 @@
|
||||||
import datetime
|
import datetime
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
import re
|
||||||
import shutil
|
import shutil
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
@ -17,6 +18,41 @@ except ModuleNotFoundError as e:
|
||||||
|
|
||||||
VENV_ERPLIBRE = ".venv.erplibre"
|
VENV_ERPLIBRE = ".venv.erplibre"
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
|
||||||
new_path = os.path.normpath(
|
new_path = os.path.normpath(
|
||||||
os.path.join(os.path.dirname(__file__), "..", "..")
|
os.path.join(os.path.dirname(__file__), "..", "..")
|
||||||
)
|
)
|
||||||
|
|
@ -107,7 +143,8 @@ class Execute:
|
||||||
source_odoo = f.read()
|
source_odoo = f.read()
|
||||||
if not source_odoo:
|
if not source_odoo:
|
||||||
_logger.error(
|
_logger.error(
|
||||||
f"You cannot execute Odoo command if no version is installed. Command : {command}"
|
"You cannot execute Odoo command if no version is"
|
||||||
|
f" installed. Command : {redact_secrets(command)}"
|
||||||
)
|
)
|
||||||
return -1
|
return -1
|
||||||
command = f"source ./.venv.{source_odoo}/bin/activate && {command}"
|
command = f"source ./.venv.{source_odoo}/bin/activate && {command}"
|
||||||
|
|
@ -116,7 +153,7 @@ class Execute:
|
||||||
|
|
||||||
if not quiet:
|
if not quiet:
|
||||||
print("🏠 ⬇ Execute command :\n")
|
print("🏠 ⬇ Execute command :\n")
|
||||||
print(command)
|
print(redact_secrets(command))
|
||||||
output_lines = []
|
output_lines = []
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
|
@ -156,16 +193,10 @@ class Execute:
|
||||||
|
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
if not quiet:
|
if not quiet:
|
||||||
if "password" in command:
|
print(f"Error: Command '{redact_secrets(command)}' not found.")
|
||||||
print(
|
|
||||||
f"Error: Command '{command.split(' ')[0]}'[...]"
|
|
||||||
" not found."
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
print(f"Error: Command '{command}' not found.")
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
if not quiet:
|
if not quiet:
|
||||||
print(f"An error occurred: {e}")
|
print(f"An error occurred: {redact_secrets(str(e))}")
|
||||||
process_end_time = time.time()
|
process_end_time = time.time()
|
||||||
duration_sec = process_end_time - process_start_time
|
duration_sec = process_end_time - process_start_time
|
||||||
if humanize:
|
if humanize:
|
||||||
|
|
@ -177,7 +208,7 @@ class Execute:
|
||||||
if not quiet:
|
if not quiet:
|
||||||
print(f"🏠 ⬆ Executed ({duration_sec:.2f} sec.) :\n")
|
print(f"🏠 ⬆ Executed ({duration_sec:.2f} sec.) :\n")
|
||||||
if not quiet:
|
if not quiet:
|
||||||
print(command)
|
print(redact_secrets(command))
|
||||||
print()
|
print()
|
||||||
if return_status_and_output_and_command:
|
if return_status_and_output_and_command:
|
||||||
return exit_code, command, output_lines
|
return exit_code, command, output_lines
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue