restauration : lire aussi l archive en clair, pas seulement la chiffree

`--support-chiffre` ecrit un tar clair quand le support est deja chiffre au repos.
Ajoute cote EXPORT le 12 septembre, et pas cote RESTAURATION : `restaurer_cles.py`,
qui est ce qui rend la cle USB autonome, ne savait lire que du GPG.

Constate en EPROUVANT l export, pas en le supposant reussi. Et le message etait le
pire possible :

    gpg: aucune donnee OpenPGP valable n a ete trouvee.
    ECHEC du dechiffrement. Phrase de passe erronee, ou archive abimee.

Il accusait une phrase de passe qu on n avait jamais posee, sur une archive saine. Il
envoyait chercher la faute la ou elle n est pas — au moment ou l on restaure, c est-a
-dire au moment ou l on sait le moins.

`tarfile.is_tarfile` reconnait la forme. Pas de drapeau a passer : ce serait une chose
de plus a savoir le jour ou tout a brule.

Verifie sur la cle reelle : l archive du 13 se liste, dix fichiers, chacun avec sa
destination. Le garde-fou a par ailleurs refuse d ecraser celle du 12 — « on n ecrase
pas une sauvegarde de cles : elle est peut-etre la seule » — donc la nouvelle est
datee et l ancienne reste.

make prouver : 72 OK, 0 echec, 1 saute.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Crgis8CxCWkAGFA1ecBz3q
This commit is contained in:
Daniel Allaire 2026-09-13 16:32:07 -04:00
parent 025776064a
commit a154893fc1
2 changed files with 60 additions and 10 deletions

View file

@ -1,5 +1,36 @@
# CHANGELOG — Set-OPS
## 2026-09-13 (4) — La cle USB ne savait pas relire ce qu'on venait d'y ecrire
`exporter_cles --support-chiffre` ecrit un TAR CLAIR quand le support est deja chiffre au
repos : empiler GPG par-dessus ajouterait une phrase de passe a perdre sans rien proteger
de plus. Cette capacite a ete ajoutee cote EXPORT le 2026-09-12, et **pas cote
RESTAURATION**.
`restaurer_cles.py` — le script qui rend la cle autonome — ne savait lire que du GPG.
Constate en eprouvant l'export, pas en le supposant reussi :
```
gpg: aucune donnée OpenPGP valable n'a été trouvée.
ECHEC du dechiffrement.
Phrase de passe erronee, ou archive abimee.
```
**Le message accusait une phrase de passe qu'on n'avait jamais posee**, sur une archive
parfaitement saine. C'est le pire genre de diagnostic : il envoie chercher la faute la ou
elle n'est pas, au moment ou l'on restaure — c'est-a-dire au moment ou l'on sait le moins.
`tarfile.is_tarfile` reconnait la forme ; les deux sont desormais lues. On ne demande pas
un drapeau : ce serait une chose de plus a savoir le jour ou tout a brule.
### Ce que l'export a aussi montre de bon
Le garde-fou a REFUSE d'ecraser l'archive du 12 — « on n'ecrase pas une sauvegarde de
cles : elle est peut-etre la seule ». La nouvelle est datee, l'ancienne reste.
Dix cles sortent desormais, dont `setops-vault-site-technolibre`, creee le jour meme.
## 2026-09-13 (3) — Un site expose ce dont ses locataires ont besoin pour l'habiter
### Le constat

View file

@ -50,7 +50,7 @@ def _destination(nom: str) -> Path:
def main() -> int:
ap = argparse.ArgumentParser()
ap.add_argument("archive", help="Chemin de l'archive .tar.gpg")
ap.add_argument("archive", help="Chemin de l'archive (.tar ou .tar.gpg)")
ap.add_argument("--lister", action="store_true",
help="Montrer ce que l'archive contient, sans rien ecrire")
ap.add_argument("--forcer", action="store_true",
@ -61,16 +61,35 @@ def main() -> int:
if not arch.is_file():
raise SystemExit(f"REFUS : {arch} introuvable.")
# DEUX FORMES D'ARCHIVE, ET IL FAUT LES DEUX (mesure du 2026-09-13).
#
# `exporter_cles --support-chiffre` ecrit un TAR CLAIR quand le support est deja
# chiffre au repos (LUKS) : empiler GPG par-dessus ajouterait une phrase de passe a
# perdre sans rien proteger de plus. Cette capacite a ete ajoutee cote EXPORT sans
# l'etre cote RESTAURATION — et ce script, qui est ce qui rend la cle autonome, ne
# savait lire que du GPG.
#
# L'echec etait particulierement mauvais : gpg disait « aucune donnee OpenPGP valable »
# puis le script concluait « phrase de passe erronee, ou archive abimee ». Il accusait
# une phrase de passe qu'on n'avait jamais posee, sur une archive parfaitement saine.
#
# ON RECONNAIT LA FORME, on ne la demande pas : `tarfile.is_tarfile` lit l'en-tete.
# Un drapeau a passer serait une chose de plus a savoir le jour ou l'on restaure —
# c'est-a-dire le jour ou l'on sait le moins.
with tempfile.TemporaryDirectory() as tmp:
clair = Path(tmp) / "cles.tar"
print(" La phrase de passe de l'archive va etre demandee.\n")
r = subprocess.run(["gpg", "--quiet", "--output", str(clair),
"--decrypt", str(arch)])
if r.returncode != 0:
raise SystemExit(
"\nECHEC du dechiffrement.\n"
" Phrase de passe erronee, ou archive abimee. gpg verifie l'integrite\n"
" (AES256 + MDC) : s'il refuse, le contenu n'est pas fiable.")
if tarfile.is_tarfile(arch):
print(" Archive EN CLAIR — la protection etait celle du support (LUKS).\n")
clair = arch
else:
clair = Path(tmp) / "cles.tar"
print(" Archive chiffree. La phrase de passe va etre demandee.\n")
r = subprocess.run(["gpg", "--quiet", "--output", str(clair),
"--decrypt", str(arch)])
if r.returncode != 0:
raise SystemExit(
"\nECHEC du dechiffrement.\n"
" Phrase de passe erronee, ou archive abimee. gpg verifie l'integrite\n"
" (AES256 + MDC) : s'il refuse, le contenu n'est pas fiable.")
with tarfile.open(clair) as tar:
noms = [n for n in tar.getnames() if "/" not in n and not n.startswith("..")]