cles : le terrain etait inoccupable — la cle du tenant nait avec ses machines
Le deploiement lance depuis ops-01 s est arrete au premier geste, sur les quinze
machines a la fois : Permission denied (publickey). Les VM neuves n acceptaient que
la cle de l exploitant. Celle du runner EST declaree au plan, mais c est le SOCLE
qui la depose — et le socle doit etre applique par quelqu un qui peut deja entrer.
Boucle fermee : le tenant recevait un terrain qu il ne pouvait pas occuper.
DEUX CLES, DEUX PORTEES :
la cle du SITE -> sur le SEUL runner du tenant l insemination
la cle du TENANT -> sur TOUTES ses machines il va les configurer
POSER UNE CLE AU CLONAGE N EST PAS ENTRER CHEZ LE TENANT. C est un parametre de
creation, au meme titre que l adresse ou le disque : le site ecrit les conditions
de NAISSANCE, il n ouvre aucune session. Le site n obtient aucun acces sur ces
machines ; seul le runner du tenant en obtient un.
Forme tranchee par l exploitant : le site renseigne le seul runner, qui se charge
de toute sa flotte. Le plancher /etc/hosts suit le meme chemin — ops-01 a le sien
depuis son insemination et resout ses quinze voisines par leur nom.
LA REVOCATION EST HONOREE A LA NAISSANCE : une entree a etat absent n est pas
reposee. Sans cette lecture, une cle retiree de la flotte serait ressuscitee sur
chaque VM creee ensuite — panne lente, silencieuse, invisible au plan.
P55 garde les deux moities : la cle du site ne nait que sur un porteur de
serveur_ops_tenant, et aucune machine ne reste sans celle de son tenant. Une
frontiere tenue a une seule couche n est pas tenue. Deux controles negatifs.
make verifier : vert. make prouver : CONFORME, 55 OK, 0 echec, 0 saute.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019f91zs9SDdwSzL2CVei6on
This commit is contained in:
parent
f2f6cccd3e
commit
bb63865a37
5 changed files with 207 additions and 21 deletions
49
CHANGELOG.md
49
CHANGELOG.md
|
|
@ -1,5 +1,54 @@
|
||||||
# CHANGELOG — Set-OPS
|
# CHANGELOG — Set-OPS
|
||||||
|
|
||||||
|
## 2026-08-30 — Le terrain etait inoccupable : la cle du tenant nait avec ses machines
|
||||||
|
|
||||||
|
**55 preuves.** Le deploiement lance depuis `ops-01` s'est arrete au premier geste, sur les
|
||||||
|
quinze machines a la fois :
|
||||||
|
|
||||||
|
```
|
||||||
|
ops-01 -> toutes : Permission denied (publickey)
|
||||||
|
```
|
||||||
|
|
||||||
|
Les VM neuves n'acceptaient qu'une cle : celle de l'exploitant, posee par cloud-init. La
|
||||||
|
cle du runner **est** declaree au plan (`ssh_baseline_cles_admin`) — mais c'est le SOCLE
|
||||||
|
qui la depose, et le socle doit etre applique par quelqu'un qui peut deja entrer. *Boucle
|
||||||
|
fermee : le tenant recevait un terrain qu'il ne pouvait pas occuper.*
|
||||||
|
|
||||||
|
### Deux cles, deux portees, et la difference est toute l'architecture
|
||||||
|
|
||||||
|
```
|
||||||
|
la cle du SITE -> sur le SEUL runner du tenant l'insemination
|
||||||
|
la cle du TENANT -> sur TOUTES ses machines il va les configurer
|
||||||
|
```
|
||||||
|
|
||||||
|
**Poser une cle au clonage n'est pas entrer chez le tenant.** C'est un parametre de
|
||||||
|
creation, au meme titre que l'adresse ou le disque : le site ecrit les conditions de
|
||||||
|
NAISSANCE, il n'ouvre aucune session. La distinction n'est pas rhetorique — le site
|
||||||
|
n'obtient aucun acces sur ces machines, seul le runner du tenant en obtient un.
|
||||||
|
|
||||||
|
*C'est la forme que l'exploitant a tranchee : le site renseigne le seul runner, qui se
|
||||||
|
charge ensuite de toute sa flotte. Le plancher `/etc/hosts` suit le meme chemin — `ops-01`
|
||||||
|
a le sien depuis son insemination, il resout ses quinze voisines par leur nom (verifie :
|
||||||
|
`obs-01.chezlepro.internal:22` ouvert), et c'est lui qui posera le leur en appliquant le
|
||||||
|
socle. Le SITE n'a jamais a toucher une machine de tenant.*
|
||||||
|
|
||||||
|
### La revocation est honoree a la naissance
|
||||||
|
|
||||||
|
Une entree passee a `etat: absent` n'est pas reposee sur les VM neuves. Sans cette lecture,
|
||||||
|
une cle retiree de toute la flotte serait **ressuscitee sur chaque machine creee ensuite** —
|
||||||
|
une panne lente, silencieuse, et invisible au plan.
|
||||||
|
|
||||||
|
### P55 — le pouvoir se lit dans les cles, pas dans les intentions
|
||||||
|
|
||||||
|
Une VM recoit ses cles a la naissance, et personne ne relit un `authorized_keys` pose il y
|
||||||
|
a six mois. Si celle du site partait sur toute une flotte, l'hebergeur y gagnerait un acces
|
||||||
|
que rien ne declare. P55 verifie les deux moities : la cle du site ne nait que sur un
|
||||||
|
porteur de `serveur_ops_tenant`, et aucune machine ne reste sans celle de son tenant.
|
||||||
|
*C'est le pendant exact du flux d'insemination — une frontiere tenue a une seule couche
|
||||||
|
n'est pas tenue.* Deux controles negatifs verifies.
|
||||||
|
|
||||||
|
make verifier : vert. make prouver : CONFORME, 55 OK, 0 echec, 0 saute.
|
||||||
|
|
||||||
## 2026-08-30 — Le demarrage declarait en panne ce qui fonctionnait
|
## 2026-08-30 — Le demarrage declarait en panne ce qui fonctionnait
|
||||||
|
|
||||||
**54 preuves.** Quinze VM de Chezlepro creees trois a la fois. L'une d'elles a depasse le
|
**54 preuves.** Quinze VM de Chezlepro creees trois a la fois. L'une d'elles a depasse le
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
> [`docs/audit/affirmations.md`](affirmations.md).
|
> [`docs/audit/affirmations.md`](affirmations.md).
|
||||||
|
|
||||||
- **Instance** : `instance` — inventaire `instance/inventories/principal/hosts.yml`
|
- **Instance** : `instance` — inventaire `instance/inventories/principal/hosts.yml`
|
||||||
- **Verdict** : ✅ CONFORME (54 OK · 0 echec · 0 saute)
|
- **Verdict** : ✅ CONFORME (55 OK · 0 echec · 0 saute)
|
||||||
|
|
||||||
## Preuves
|
## Preuves
|
||||||
|
|
||||||
|
|
@ -46,7 +46,7 @@
|
||||||
| P31 | Documentation : tout ce que le depot FAIT est nomme | — | ✅ OK | 53 scripts expliques et atteignables, 106 cibles make documentees, 62 roles avec README. |
|
| P31 | Documentation : tout ce que le depot FAIT est nomme | — | ✅ OK | 53 scripts expliques et atteignables, 106 cibles make documentees, 62 roles avec README. |
|
||||||
| P32 | Intrants exiges par les roles : tous fournis | — | ✅ OK | CONFORME : 41 exigence(s) de role, toutes satisfaites (130 cle(s) declaree(s) par l'instance). |
|
| P32 | Intrants exiges par les roles : tous fournis | — | ✅ OK | CONFORME : 41 exigence(s) de role, toutes satisfaites (130 cle(s) declaree(s) par l'instance). |
|
||||||
| P33 | Aucune collision de port entre roles co-localises | — | ✅ OK | CONFORME : 33 revendication(s) de port, aucune collision entre roles co-localises (38 groupes). |
|
| P33 | Aucune collision de port entre roles co-localises | — | ✅ OK | CONFORME : 33 revendication(s) de port, aucune collision entre roles co-localises (38 groupes). |
|
||||||
| P34 | Chaque document declare son lecteur | — | ✅ OK | 42 document(s) declarent leur lecteur (26 genere(s) exempte(s)). |
|
| P34 | Chaque document declare son lecteur | — | ✅ OK | 42 document(s) declarent leur lecteur (27 genere(s) exempte(s)). |
|
||||||
| P35 | Toute application exigeant une base en a une au plan | — | ✅ OK | 5 application(s) exigeant une base l'ont toutes (4 entree(s) au registre). |
|
| P35 | Toute application exigeant une base en a une au plan | — | ✅ OK | 5 application(s) exigeant une base l'ont toutes (4 entree(s) au registre). |
|
||||||
| P36 | Tout detenteur d'etat porte une sauvegarde | — | ✅ OK | 9 hote(s) detiennent de l'etat, tous porteurs de `client_backup` (9 groupe(s) au catalogue). |
|
| P36 | Tout detenteur d'etat porte une sauvegarde | — | ✅ OK | 9 hote(s) detiennent de l'etat, tous porteurs de `client_backup` (9 groupe(s) au catalogue). |
|
||||||
| P37 | Le placement du tenant existe chez son hebergeur | — | ✅ OK | placement confronte a l'hebergeur monte (SITE-Chezlepro) : noeud, stockage, pont — tous offerts. |
|
| P37 | Le placement du tenant existe chez son hebergeur | — | ✅ OK | placement confronte a l'hebergeur monte (SITE-Chezlepro) : noeud, stockage, pont — tous offerts. |
|
||||||
|
|
@ -67,6 +67,7 @@
|
||||||
| P52 | Materialiser n'exige pas d'entrer dans le tenant | — | ✅ OK | `creer-vm` confirme par l'agent invite (API des hyperviseurs, deja utilisee pour creer), sans exiger d'entrer dans le tenant. |
|
| P52 | Materialiser n'exige pas d'entrer dans le tenant | — | ✅ OK | `creer-vm` confirme par l'agent invite (API des hyperviseurs, deja utilisee pour creer), sans exiger d'entrer dans le tenant. |
|
||||||
| P53 | L'interne refuse a voix haute, la bordure se tait | — | ✅ OK | L'interne parle, la bordure se tait — 15 ruleset(s) nftables refusent a voix haute ; pare-feu est-ouest en REJECT, source unique ; frontiere muette (actions : b |
|
| P53 | L'interne refuse a voix haute, la bordure se tait | — | ✅ OK | L'interne parle, la bordure se tait — 15 ruleset(s) nftables refusent a voix haute ; pare-feu est-ouest en REJECT, source unique ; frontiere muette (actions : b |
|
||||||
| P54 | L'insemination ne reclame aucun secret du tenant | — | ✅ OK | 2 couche(s) d'insemination (serveur_debian, serveur_ops), 10 role(s) applique(s), aucun secret de tenant reclame. |
|
| P54 | L'insemination ne reclame aucun secret du tenant | — | ✅ OK | 2 couche(s) d'insemination (serveur_debian, serveur_ops), 10 role(s) applique(s), aucun secret de tenant reclame. |
|
||||||
|
| P55 | La cle du SITE ne nait que sur le runner d'un tenant | — | ✅ OK | 15 hote(s) : la cle du SITE ne nait que sur 1 runner(s) de tenant, celle du tenant sur 15. |
|
||||||
|
|
||||||
## Couverture des affirmations ✅ du registre
|
## Couverture des affirmations ✅ du registre
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ README de rôles). Cette page comble ces deux trous.
|
||||||
| rôles | 62 | `roles/*/` |
|
| rôles | 62 | `roles/*/` |
|
||||||
| README de rôles | 62 | `roles/*/README.md` — l'écart avec la ligne au-dessus est la dette |
|
| README de rôles | 62 | `roles/*/README.md` — l'écart avec la ligne au-dessus est la dette |
|
||||||
| documents | 38 | `docs/*.md` |
|
| documents | 38 | `docs/*.md` |
|
||||||
| pièces d'audit | 29 | `docs/audit/*` |
|
| pièces d'audit | 30 | `docs/audit/*` |
|
||||||
| unités de wiki | 27 | `wiki/*.md` |
|
| unités de wiki | 27 | `wiki/*.md` |
|
||||||
| décisions en vigueur | 78 | lignes `\| **D-nn** \|` de `decisions-architecture.md` |
|
| décisions en vigueur | 78 | lignes `\| **D-nn** \|` de `decisions-architecture.md` |
|
||||||
| décisions renversées | 3 | lignes `\| **D-nn** —` du même document |
|
| décisions renversées | 3 | lignes `\| **D-nn** —` du même document |
|
||||||
|
|
|
||||||
|
|
@ -271,7 +271,7 @@ def parametres_proxmox_hote(data: dict, host: str,
|
||||||
# La cle vient du PLAN DU SITE, pas du disque local : on materialise depuis le runner
|
# La cle vient du PLAN DU SITE, pas du disque local : on materialise depuis le runner
|
||||||
# comme depuis le poste de l'exploitant, et un `lookup` local rendrait deux valeurs
|
# comme depuis le poste de l'exploitant, et un `lookup` local rendrait deux valeurs
|
||||||
# differentes selon qui agit — la VM nee du poste n'accepterait pas le runner.
|
# differentes selon qui agit — la VM nee du poste n'accepterait pas le runner.
|
||||||
lignes.append(f"SETOPS_CLES_AMORCAGE='{_cle_amorcage(data, host)}'")
|
lignes.append(f"SETOPS_CLES_AMORCAGE='{_cle_amorcage(data, host, inventaire)}'")
|
||||||
|
|
||||||
return lignes
|
return lignes
|
||||||
|
|
||||||
|
|
@ -279,27 +279,93 @@ def parametres_proxmox_hote(data: dict, host: str,
|
||||||
GROUPE_RUNNER_TENANT = "serveur_ops_tenant"
|
GROUPE_RUNNER_TENANT = "serveur_ops_tenant"
|
||||||
|
|
||||||
|
|
||||||
def _cle_amorcage(data: dict, host: str) -> str:
|
def _cle_amorcage(data: dict, host: str, inventaire: Path | None = None) -> str:
|
||||||
"""La cle publique du runner du SITE, si cet hote est le runner de son tenant.
|
"""Les cles publiques a poser sur cet hote A SA NAISSANCE. Une par ligne.
|
||||||
|
|
||||||
Rend '' partout ailleurs — et aussi quand le depot de l'hebergeur n'est pas monte
|
DEUX CLES, DEUX PORTEES, ET LA DIFFERENCE EST TOUTE L'ARCHITECTURE :
|
||||||
ou ne declare pas de runner : un ecosysteme se materialise alors comme avant, avec
|
|
||||||
la seule cle de l'exploitant. Degrader, jamais deviner.
|
la cle du SITE -> sur le SEUL runner du tenant. C'est l'insemination : le site
|
||||||
|
amorce une machine, et une seule, puis s'arrete.
|
||||||
|
la cle du TENANT -> sur TOUTES les machines de ce tenant. C'est son runner qui
|
||||||
|
les configurera, et il ne peut pas le faire sans y entrer.
|
||||||
|
|
||||||
|
POSER UNE CLE AU CLONAGE N'EST PAS ENTRER CHEZ LE TENANT. C'est un parametre de
|
||||||
|
creation, au meme titre que l'adresse ou le disque : le site ecrit les conditions de
|
||||||
|
NAISSANCE de la machine, il n'ouvre aucune session dedans. La distinction n'est pas
|
||||||
|
rhetorique — le site n'obtient aucun acces sur ces machines, seul le runner du tenant
|
||||||
|
en obtient un.
|
||||||
|
|
||||||
|
SANS ELLE, LE TERRAIN EST INOCCUPABLE (mesure du 2026-08-30). Quinze VM creees, et le
|
||||||
|
runner du tenant se voyait refuser l'entree sur les quinze :
|
||||||
|
|
||||||
|
ops-01 -> toutes : Permission denied (publickey)
|
||||||
|
|
||||||
|
Sa cle EST declaree au plan (`ssh_baseline_cles_admin`), mais c'est le SOCLE qui la
|
||||||
|
depose — et le socle doit etre applique par quelqu'un qui peut deja entrer. Boucle
|
||||||
|
fermee : le tenant recevait un terrain qu'il ne pouvait pas occuper.
|
||||||
|
|
||||||
|
Rend '' pour ce qui n'est pas trouve, jamais une valeur devinee : un ecosysteme dont
|
||||||
|
le plan ne declare rien se materialise comme avant, avec la seule cle de l'exploitant.
|
||||||
|
"""
|
||||||
|
cles: list[str] = []
|
||||||
|
|
||||||
|
# 1. LA CLE DU SITE — le runner du tenant, et lui seul.
|
||||||
|
if GROUPE_RUNNER_TENANT in groupes_hote(data, host):
|
||||||
|
try:
|
||||||
|
import underlay as underlay_mod
|
||||||
|
c = str((underlay_mod.lire_plan_site("10-intrants.yml") or {})
|
||||||
|
.get("runner_cle_publique") or "").strip()
|
||||||
|
if c:
|
||||||
|
cles.append(c)
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# 2. LA CLE DU TENANT — toutes ses machines, y compris son runner (il se joint
|
||||||
|
# lui-meme comme les autres, et l'exclure creerait un cas particulier de plus).
|
||||||
|
#
|
||||||
|
# ELLE VIENT DU PLAN DU TENANT, pas d'un fichier lu sur une machine : materialiser
|
||||||
|
# depuis le poste et depuis le runner du site doit produire la meme VM.
|
||||||
|
for entree in _cles_admin_du_plan(inventaire):
|
||||||
|
if entree not in cles:
|
||||||
|
cles.append(entree)
|
||||||
|
|
||||||
|
for c in cles:
|
||||||
|
if "'" in c:
|
||||||
|
raise ValueError(
|
||||||
|
f"Une cle publique declaree contient une apostrophe ({host}) : "
|
||||||
|
"la valeur passe par une commande shell, elle ne peut pas en porter."
|
||||||
|
)
|
||||||
|
return "\n".join(cles)
|
||||||
|
|
||||||
|
|
||||||
|
def _cles_admin_du_plan(inventaire: Path | None) -> list[str]:
|
||||||
|
"""Les cles `ssh_baseline_cles_admin` de l'instance, celles a l'etat `present`.
|
||||||
|
|
||||||
|
ON HONORE L'ETAT. Une entree passee a `absent` est une REVOCATION : la reposer a la
|
||||||
|
naissance ressusciterait sur chaque VM neuve une cle qu'on vient de retirer de toute
|
||||||
|
la flotte — la panne serait lente, silencieuse, et parfaitement invisible au plan.
|
||||||
"""
|
"""
|
||||||
if GROUPE_RUNNER_TENANT not in groupes_hote(data, host):
|
|
||||||
return ""
|
|
||||||
try:
|
try:
|
||||||
import underlay as underlay_mod
|
depuis = Path(inventaire).parent if inventaire else None
|
||||||
cle = str((underlay_mod.lire_plan_site("10-intrants.yml") or {})
|
gv = (depuis or _instance_dir()) / "group_vars" / "all"
|
||||||
.get("runner_cle_publique") or "").strip()
|
for fichier in sorted(gv.glob("*.yml")):
|
||||||
|
if "vault" in fichier.name:
|
||||||
|
continue
|
||||||
|
data = yaml.safe_load(fichier.read_text(encoding="utf-8")) or {}
|
||||||
|
if isinstance(data, dict) and data.get("ssh_baseline_cles_admin"):
|
||||||
|
return [str(e.get("cle", "")).strip()
|
||||||
|
for e in data["ssh_baseline_cles_admin"]
|
||||||
|
if isinstance(e, dict)
|
||||||
|
and str(e.get("etat", "present")) == "present"
|
||||||
|
and str(e.get("cle", "")).strip()]
|
||||||
except Exception:
|
except Exception:
|
||||||
return ""
|
pass
|
||||||
if "'" in cle:
|
return []
|
||||||
raise ValueError(
|
|
||||||
f"`runner_cle_publique` du site contient une apostrophe ({host}) : "
|
|
||||||
"la valeur passe par une commande shell, elle ne peut pas en porter."
|
def _instance_dir() -> Path:
|
||||||
)
|
from inventory_rules import instance_courante
|
||||||
return cle
|
return Path(instance_courante())
|
||||||
|
|
||||||
|
|
||||||
def _rang_des_couches() -> dict[str, int]:
|
def _rang_des_couches() -> dict[str, int]:
|
||||||
|
|
|
||||||
|
|
@ -1396,6 +1396,74 @@ def preuve_carte_dit_vrai() -> tuple[bool, str]:
|
||||||
f"{len(_carte_chiffres_mesures())} chiffres correspondent a la mesure.")
|
f"{len(_carte_chiffres_mesures())} chiffres correspondent a la mesure.")
|
||||||
|
|
||||||
|
|
||||||
|
def preuve_cle_du_site_bornee_au_runner() -> tuple[bool, str]:
|
||||||
|
"""La cle du SITE ne nait que sur le runner d'un tenant. Celle du tenant, partout chez lui.
|
||||||
|
|
||||||
|
LE POUVOIR SE LIT DANS LES CLES, PAS DANS LES INTENTIONS. Une VM recoit ses cles a la
|
||||||
|
NAISSANCE, par cloud-init — et personne ne relit un `authorized_keys` pose il y a six
|
||||||
|
mois. Si la cle du site se mettait a partir sur toutes les machines d'un locataire,
|
||||||
|
l'hebergeur obtiendrait un acces SSH a sa flotte entiere, en silence, et rien dans le
|
||||||
|
plan ne le dirait.
|
||||||
|
|
||||||
|
C'est le pendant exact du flux d'insemination : celui-ci vise le groupe
|
||||||
|
`serveur_ops_tenant`, cette preuve verifie que la CLE suit le meme critere. Une
|
||||||
|
frontiere tenue a une seule couche n'est pas tenue.
|
||||||
|
|
||||||
|
L'AUTRE MOITIE COMPTE AUSSI : sans la cle du TENANT sur ses machines, son runner recoit
|
||||||
|
un terrain qu'il ne peut pas occuper — mesure du 2026-08-30, quinze VM et quinze
|
||||||
|
« Permission denied ».
|
||||||
|
"""
|
||||||
|
inv = RACINE / INV
|
||||||
|
if not inv.is_file():
|
||||||
|
return True, "Aucun inventaire monte : rien a verifier."
|
||||||
|
sys.path.insert(0, str(RACINE / "scripts"))
|
||||||
|
import inventory_host as ih
|
||||||
|
data = yaml.safe_load(inv.read_text(encoding="utf-8")) or {}
|
||||||
|
actifs = sorted(ih._hotes_du_groupe(data, "hotes_actifs")
|
||||||
|
if hasattr(ih, "_hotes_du_groupe")
|
||||||
|
else (data.get("all", {}).get("children", {})
|
||||||
|
.get("hotes_actifs", {}).get("hosts", {}) or {}))
|
||||||
|
if not actifs:
|
||||||
|
return True, "Aucun hote actif : rien a verifier."
|
||||||
|
|
||||||
|
cle_site = ""
|
||||||
|
try:
|
||||||
|
import underlay as underlay_mod
|
||||||
|
cle_site = str((underlay_mod.lire_plan_site("10-intrants.yml") or {})
|
||||||
|
.get("runner_cle_publique") or "").strip()
|
||||||
|
except Exception:
|
||||||
|
pass
|
||||||
|
|
||||||
|
runners = set(ih.groupes_hote(data, h) and h for h in actifs
|
||||||
|
if ih.GROUPE_RUNNER_TENANT in ih.groupes_hote(data, h))
|
||||||
|
fautes: list[str] = []
|
||||||
|
porteurs_site: list[str] = []
|
||||||
|
sans_cle_tenant: list[str] = []
|
||||||
|
for h in actifs:
|
||||||
|
recues = [c for c in ih._cle_amorcage(data, h, inv).split("\n") if c.strip()]
|
||||||
|
if cle_site and cle_site in recues:
|
||||||
|
porteurs_site.append(h)
|
||||||
|
if h not in runners:
|
||||||
|
fautes.append(f"{h} recoit la cle du SITE sans porter "
|
||||||
|
f"`{ih.GROUPE_RUNNER_TENANT}` — l'hebergeur y gagnerait "
|
||||||
|
f"un acces qu'aucun flux ne declare")
|
||||||
|
if not [c for c in recues if c != cle_site]:
|
||||||
|
sans_cle_tenant.append(h)
|
||||||
|
|
||||||
|
# Sans cle du tenant, le runner ne peut pas occuper le terrain qu'on lui prepare.
|
||||||
|
# On ne l'exige que si l'instance en declare une : un plan qui n'en nomme aucune
|
||||||
|
# se materialise comme avant, avec la seule cle de l'exploitant.
|
||||||
|
if ih._cles_admin_du_plan(inv) and sans_cle_tenant:
|
||||||
|
fautes.append(f"{len(sans_cle_tenant)} hote(s) ne recevraient AUCUNE cle de "
|
||||||
|
f"leur tenant : son runner ne pourrait pas les configurer "
|
||||||
|
f"({', '.join(sans_cle_tenant[:3])})")
|
||||||
|
if fautes:
|
||||||
|
return False, "Les cles de naissance debordent :\n - " + "\n - ".join(fautes)
|
||||||
|
return True, (f"{len(actifs)} hote(s) : la cle du SITE ne nait que sur "
|
||||||
|
f"{len(porteurs_site)} runner(s) de tenant, celle du tenant sur "
|
||||||
|
f"{len(actifs) - len(sans_cle_tenant)}.")
|
||||||
|
|
||||||
|
|
||||||
def preuve_insemination_sans_secret() -> tuple[bool, str]:
|
def preuve_insemination_sans_secret() -> tuple[bool, str]:
|
||||||
"""Ce que le SITE pose chez un tenant ne demande AUCUN secret de ce tenant.
|
"""Ce que le SITE pose chez un tenant ne demande AUCUN secret de ce tenant.
|
||||||
|
|
||||||
|
|
@ -2145,6 +2213,8 @@ PREUVES: list[dict] = [
|
||||||
"refs": [], "func": preuve_interne_parle_bordure_se_tait},
|
"refs": [], "func": preuve_interne_parle_bordure_se_tait},
|
||||||
{"id": "P54", "titre": "L'insemination ne reclame aucun secret du tenant",
|
{"id": "P54", "titre": "L'insemination ne reclame aucun secret du tenant",
|
||||||
"refs": [], "func": preuve_insemination_sans_secret},
|
"refs": [], "func": preuve_insemination_sans_secret},
|
||||||
|
{"id": "P55", "titre": "La cle du SITE ne nait que sur le runner d'un tenant",
|
||||||
|
"refs": [], "func": preuve_cle_du_site_bornee_au_runner},
|
||||||
{"id": "P43", "titre": "Frontiere : le devis voit les machines du site", "refs": [],
|
{"id": "P43", "titre": "Frontiere : le devis voit les machines du site", "refs": [],
|
||||||
"func": preuve_devis_frontiere_du_site},
|
"func": preuve_devis_frontiere_du_site},
|
||||||
{"id": "P33", "titre": "Aucune collision de port entre roles co-localises", "refs": [],
|
{"id": "P33", "titre": "Aucune collision de port entre roles co-localises", "refs": [],
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue