arch-system/docs/deploy-safety.md

8.4 KiB

Déploiement par étapes : contrat de sécurité V1

Ce document décrit scripts/deploy.sh. Il ne valide pas une réinstallation et n'autorise pas son exécution réelle sur ArchASP tant que les décisions pertinentes de reconstruction (notamment réseau et signature) restent ouvertes. Le script ne restaure ni /etc/fstab, ni Limine, ni les clés Secure Boot, ni les données ou dotfiles.

Options et résultat

--packages, --configs, --tools, --services sélectionnent explicitement des étapes ; --all sélectionne les quatre dans cet ordre. Plusieurs sélections peuvent être combinées. Sans sélection, le code est 2. -h/--help affiche l'aide. --dry-run s'ajoute à une sélection et affiche sources, destinations et actions sans confirmation, sudo, gestionnaire de paquets, sauvegarde ni temporaire de déploiement. Il peut lire les fichiers du dépôt et interroger sans privilèges la présence des unités systemd lorsque leur installation n'est pas demandée.

Exemples de plan uniquement :

./scripts/deploy.sh --dry-run --configs
./scripts/deploy.sh --dry-run --all

Le code 0 en simulation signifie seulement « préconditions statiques connues satisfaites et plan affiché ». Les validations nftables/sudoers privilégiées, la présence future des unités apportées par les paquets et le résultat d'une installation ne sont pas vérifiés par ce code. Le code 1 signale une précondition ou une étape échouée ; le code 2, un usage invalide ; 130/143, une interruption gérable par INT/TERM. En application, 0 signifie que les commandes sélectionnées se sont terminées sans erreur signalée ou que l'utilisateur a répondu non à la confirmation ; dans ce dernier cas, « Déploiement annulé » est affiché et rien n'est appliqué. Un code 0 après application ne prouve pas le démarrage ni la conformité fonctionnelle.

Préconditions et ordre

Les fichiers de configuration, helpers et templates sélectionnés doivent exister, être lisibles, non vides et ne pas être des liens. Les listes de paquets et manifests doivent exister et être lisibles ; un fichier présent mais vide est une sélection volontairement vide. Les lignes vides et commentaires entiers sont ignorés ; chaque autre ligne doit contenir un seul nom valide, sans doublon ni option commençant par -. Une source manquante ou une ligne invalide arrête le lot avant toute application.

Le script doit être appelé depuis un compte non root lorsque des paquets étrangers ou --tools sont demandés. Il obtient le bénéficiaire avec id, pas avec USER ou SUDO_USER, et refuse une règle sudoers au nom de root. Il n'amorce pas yay : une liste étrangère non vide avec yay absent fait échouer le précontrôle avant l'installation native. Les noms du fichier « AUR » sont des entrées à soumettre à yay, pas une preuve qu'ils proviennent tous de l'AUR ; leur compatibilité et leur source doivent être examinées séparément.

Pour une application, le nom de machine est lu et validé dans /etc/hostname avant la confirmation et toute mutation. Un fichier absent, illisible, vide ou invalide arrête l'application avec code 1. La commande externe hostname n'est pas requise. Le contrôle privilégié des cibles utilise find et /usr/bin/bash, qui doivent être disponibles ; une absence de find est diagnostiquée au précontrôle.

Après confirmation, les validations privilégiées connues sont tentées avant la première mutation durable : sudo -v, nft -c -f pour --configs, puis rendu des deux règles sudoers et visudo -cf pour --tools. Si --packages est également demandé et fournit nft, sa disponibilité et la validation sont différées après les paquets, avant la première configuration. Les unités systemd sont vérifiées immédiatement si aucun paquet n'est demandé ; sinon elles sont vérifiées après les paquets, avant leur première utilisation. Un --all peut donc échouer après installation des paquets : il n'est pas garanti entièrement avant la première mutation.

--tools et --services peuvent arrêter les quatre unités VMware/Samba du manifest à la demande avec disable --now. --services active les services et timers listés. Une unité requise absente est une erreur ; une unité à la demande déjà désactivée et inactive est laissée telle quelle. Les autres erreurs de désactivation ou d'activation ne sont pas masquées. --configs effectue daemon-reload et lance TLP si sa commande est disponible. Ces actions peuvent interrompre un service déjà utilisé : choisir les étapes et le moment en conséquence.

Cibles, sauvegardes et reprise

Les cibles existantes sont copiées avant remplacement dans un répertoire root privé créé paresseusement par mktemp -d sous /root/arch-system-restore.*. Chaque invocation obtient un nom atomiquement unique, y compris dans la même seconde. Les fichiers remplacés sont sous existing/ avec leur chemin d'origine et conservent leurs métadonnées par cp -a. Une cible initialement absente reçoit seulement un marqueur vide sous absent/ : ce n'est pas une fausse copie de sauvegarde. Les helpers et les deux règles sudoers suivent la même politique que les configurations. Le chemin de sauvegarde est affiché en cas d'échec et à la fin.

Le script refuse une cible ou un parent qui est un lien symbolique, même cassé, ou une cible existante non régulière. Il réexamine les cibles avant sauvegarde et avant installation. Le contrôle privilégié renvoie, uniquement après succès de l'inspection, un état strict : EXISTING, ABSENT, LINK ou INVALID. Une erreur de sudo ou de l'inspection, une réponse vide ou inconnue, ou un état plausible accompagné d'un code d'échec arrêtent le lot ; aucun marqueur d'absence ni remplacement de la cible concernée n'est alors autorisé. Une erreur au second contrôle conserve la sauvegarde déjà faite. Cela limite les écritures inattendues mais ne garantit pas l'absence de toute course avec un autre processus privilégié. Les fichiers sudoers rendus sont gardés dans un répertoire temporaire privé et supprimés sur sortie normale, erreur, INT ou TERM. Les sauvegardes root ne sont jamais supprimées par ce nettoyage. Un SIGKILL ou une coupure de courant ne déclenche pas de trap.

Une erreur arrête les étapes suivantes et affiche la phase, les phases achevées, les actions déjà appliquées et le répertoire de sauvegarde disponible. Sur INT ou TERM, le bilan affiche le signal, la phase, les étapes achevées, les actions confirmées, l'action en cours dont les effets sont à vérifier, et le chemin des sauvegardes lorsqu'il existe. Une commande interrompue peut avoir déjà eu des effets, même si elle n'est pas dans la liste des actions confirmées. Il n'y a aucun rollback automatique global : pacman/yay, services et fichiers n'ont pas une annulation commune. Pour reprendre, comparer l'état réel aux cibles et aux copies ou marqueurs, restaurer manuellement ce qui doit l'être, puis relancer uniquement une étape comprise. Les installations de paquets peuvent être relancées avec --needed, mais cela n'annule pas une transaction partielle ; les copies et activations systemd sont répétables seulement après vérification de l'état et des effets de service.

Tests autorisés

Commande unique du harnais :

tests/deploy/test.sh

Le harnais exige bwrap déjà installé et vérifie les exécutables réels qu'il place dans son PATH fermé ; un outil manquant échoue avant la création d'un lien cassé. Il crée un dépôt synthétique et exécute une copie de deploy.sh dans un espace sans réseau, avec / en lecture seule, /etc et /usr/local/sbin remplacés par des fixtures privées. La doublure sudo reconnaît strictement le fragment de contrôle prévu et simule son résultat sans jamais exécuter librement un argument bash -c ; toute autre sous-commande inconnue est refusée. Paquets, yay, nftables et systemd sont simulés. Les scénarios nominaux rejettent tout stderr ; les scénarios d'erreur contrôlent les diagnostics admis. Aucun essai réel du script du dépôt sur ArchASP n'est effectué. bash -n complète les tests ; ShellCheck n'est utilisé que s'il est déjà présent. Les réponses simulées prouvent uniquement les branches exercées : ni déploiement, ni pare-feu, ni signature, ni démarrage, ni restauration ne sont validés.