contexte : etape 3, l'instancier lit la fiche du site (P91)
Le site depose fiche-site.yml chez ses locataires (make fiches-site- deposer) ; l'instancier y lit temps, delegation DNS et routage. Sans le site, l'inventaire genere est identique au versionne, a l'octet pres. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
d6591cb271
commit
2beef04dc6
11 changed files with 218 additions and 8 deletions
|
|
@ -188,7 +188,7 @@ Si `ansible-lint` n’est pas disponible, le signaler clairement. Ne pas invente
|
|||
## Écrire, puis relire (D-68)
|
||||
|
||||
`--syntax-check` et `ansible-lint` prouvent que le dépôt est cohérent **avec lui-même**.
|
||||
C'est aussi ce que font les 90 preuves de `make prouver` : elles lisent le dépôt, sans le
|
||||
C'est aussi ce que font les 91 preuves de `make prouver` : elles lisent le dépôt, sans le
|
||||
moindre appel réseau. **Aucune ne demande au système déployé s'il ressemble à ce que le
|
||||
dépôt annonce.**
|
||||
|
||||
|
|
|
|||
38
CHANGELOG.md
38
CHANGELOG.md
|
|
@ -1,5 +1,43 @@
|
|||
# CHANGELOG — Set-OPS
|
||||
|
||||
## 2026-10-05 (90) — Étape 3, premier consommateur : l'inventaire d'un locataire se génère sans son site
|
||||
|
||||
**Le chemin** (`docs/conception-contextes.md` §6), étape 3 : les consommateurs lisent les
|
||||
fiches au lieu des fichiers de l'autre, à résultat identique. Premier consommateur :
|
||||
l'instancier.
|
||||
|
||||
**Le site dépose sa fiche** (décision du 2026-10-04) :
|
||||
- `site.deposer_fiche(locataire)` écrit `fiche-site.yml` dans le dépôt du locataire ; aucune
|
||||
date dedans, deux dépôts d'une même fiche sont identiques (vérifié) ;
|
||||
- `make fiches-site-deposer` (runbook « Tenir un site en état ») dépose chez chaque locataire
|
||||
dont le site est l'hébergeur actif ; le fichier se commite chez le locataire ;
|
||||
- déposée chez OPS-Chezlepro et OPS-Technolibre.
|
||||
|
||||
**L'instancier la lit** : la zone du site et ses résolveurs (avec sa règle propre, pas de
|
||||
délégation de sa propre zone), les serveurs de temps, le mode de routage, viennent de
|
||||
`fiche-site.yml`. Sans fiche, il lit encore le site monté, et le dit (transition).
|
||||
|
||||
**Le critère, mesuré en mémoire sans rien écrire**, pour les deux locataires :
|
||||
|
||||
| | inventaire généré |
|
||||
|---|---|
|
||||
| site monté, avec fiche | **identique** au versionné, à l'octet près |
|
||||
| **site absent, avec fiche** | **identique** à l'octet près |
|
||||
| site absent, sans fiche | différent (sans temps, sans SDN, sans délégation DNS) |
|
||||
|
||||
C'est la portabilité d'un locataire : son runner, qui n'a pas le dépôt de son site, génère
|
||||
désormais l'inventaire exact.
|
||||
|
||||
**Éprouvé** :
|
||||
- **P91**, « La fiche du site est déposée à jour, et l'inventaire se génère sans le site » :
|
||||
la fiche déposée est celle que le site calcule aujourd'hui, et l'instancier, lancé dans un
|
||||
processus sans le site, rend l'inventaire versionné. Aucun écart chez les deux locataires.
|
||||
- `test_contexte.py`, 97 contrôles : une fiche déposée altérée est vue périmée, et elle change
|
||||
l'inventaire généré (le test la remet en place).
|
||||
- `make verifier` conforme, **91/91**. Les trois documents comptent 91 preuves.
|
||||
|
||||
**À commiter** : `fiche-site.yml` chez les deux locataires.
|
||||
|
||||
## 2026-10-05 (89) — Étape 2 terminée : les sorties, et le contrat entier tient
|
||||
|
||||
**Le chemin** (`docs/conception-contextes.md` §6), étape 2, frontière, dernier temps : ce qui
|
||||
|
|
|
|||
8
Makefile
8
Makefile
|
|
@ -610,7 +610,7 @@ site: ansible-runtime ## Regenere playbooks/site.yml depuis les couches et le gr
|
|||
site-verifier: ## Verifie que playbooks/site.yml correspond aux couches declarees
|
||||
python3 scripts/orchestrer.py verifier
|
||||
|
||||
.PHONY: flux flux-verifier
|
||||
.PHONY: flux flux-verifier fiches-site-deposer
|
||||
cles-recenser: ## Montre ce qui n'existe QUE sur ce poste (sans rien ecrire)
|
||||
python3 scripts/exporter_cles.py --recenser
|
||||
|
||||
|
|
@ -870,6 +870,12 @@ site-intrants: ## Les intrants que le SITE monte expose a ses locataires (derive
|
|||
site-intrants-verifier: ## Le locataire monte suit-il encore son site ? (aucune ecriture)
|
||||
python3 scripts/site_intrants.py --verifier
|
||||
|
||||
fiches-site-deposer: ## Le site depose chez chacun de ses locataires la fiche qu'il lui destine (a commiter chez eux)
|
||||
@# LE SITE DEPOSE, LE LOCATAIRE LIT (2026-10-05). Le runner d'un locataire n'a pas le depot
|
||||
@# de son site : ce que le site lui attribue et lui offre lui parvient par ce fichier,
|
||||
@# `fiche-site.yml`, que l'instancier lit. P91 refuse une fiche perimee.
|
||||
python3 scripts/contexte.py --deposer-fiches
|
||||
|
||||
.PHONY: vpn-admin-plan vpn-admin-appliquer
|
||||
vpn-admin-plan: ## Acces WireGuard des admins : ce que la frontiere porte face au plan (aucune ecriture)
|
||||
python3 scripts/vpn_admin.py plan
|
||||
|
|
|
|||
|
|
@ -180,7 +180,8 @@ croisées produisent. La première mesure des flux a trouvé une information que
|
|||
jetait : les clients nommés d'un port aussi public, que Proxmox doit admettre nommément. Il
|
||||
les publie désormais (`sources_declarees`). La frontière, en trois temps : les identités
|
||||
(P87), les entrées publiques (P88), l'administration (P89) et les sorties (P90) sont faites.
|
||||
**L'étape 2 est terminée** (2026-10-05).
|
||||
**L'étape 2 est terminée** (2026-10-05). Étape 3 : l'instancier lit la fiche déposée par le site, et
|
||||
l'inventaire d'un locataire se génère sans son site, à l'octet près (P91).
|
||||
|
||||
Méthodes du contrat : `site.fiche_pour(locataire)`, `locataire.face_reseau()`. Une classe
|
||||
n'ouvre jamais les fichiers de l'autre ; une preuve vérifiera la règle.
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ make placement-plan # chaque VM est-elle là où le plan la met
|
|||
|
||||
## Le trou qu'il comble
|
||||
|
||||
`scripts/prouver.py` porte 90 preuves (dont une conditionnelle, sautée sans la clé de la voûte). Elles sont toutes **statiques** : elles lisent le
|
||||
`scripts/prouver.py` porte 91 preuves (dont une conditionnelle, sautée sans la clé de la voûte). Elles sont toutes **statiques** : elles lisent le
|
||||
dépôt. Zéro appel réseau, zéro SSH, zéro `ansible`. Elles établissent que le dépôt est
|
||||
cohérent **avec lui-même** — que les handlers existent, que les intrants ont un
|
||||
propriétaire, que rien n'est codé en dur.
|
||||
|
|
|
|||
|
|
@ -99,7 +99,7 @@ Nommer un point ouvert vaut mieux qu'une ligne rassurante sans mécanisme derri
|
|||
Aucune de ces responsabilités n'est laissée à la parole :
|
||||
|
||||
```
|
||||
make prouver le dépôt est-il cohérent avec lui-même (90 preuves, zéro réseau)
|
||||
make prouver le dépôt est-il cohérent avec lui-même (91 preuves, zéro réseau)
|
||||
make remise-verifier le second temps de la remise est-il fait, ou en retard ? (P80)
|
||||
make certificats-plan ce que le disque porte contre ce que la mémoire sert
|
||||
make expositions-plan chaque service publié répond-il, et depuis où
|
||||
|
|
|
|||
|
|
@ -209,6 +209,12 @@ runbooks:
|
|||
- cible: site-intrants
|
||||
nature: mesure
|
||||
pourquoi: "Ce que ce site expose a ses locataires, derive et non declare deux fois."
|
||||
- cible: fiches-site-deposer
|
||||
nature: ecriture
|
||||
pourquoi: >-
|
||||
Deposer chez chaque locataire la fiche que le site lui destine. Son runner n'a pas
|
||||
le depot du site : c'est par elle que son inventaire se genere sans lui. A commiter
|
||||
dans le depot de chaque locataire.
|
||||
- cible: site-verifier
|
||||
nature: mesure
|
||||
pourquoi: "Le playbook du site correspond-il encore aux couches declarees ?"
|
||||
|
|
|
|||
|
|
@ -47,6 +47,9 @@ DOSSIER_ECOSYSTEMES = RACINE.parent
|
|||
# Le contexte actif, nomme (decision du 2026-10-04) : une seule valeur, `site:<depot>` ou
|
||||
# `locataire:<depot>`. Absent, on retombe sur les liens d'avant, le temps de la bascule.
|
||||
NOM_FICHIER_CONTEXTE = "contexte"
|
||||
# La fiche que le site depose chez chacun de ses locataires (decision du 2026-10-04 : le site
|
||||
# DEPOSE, le runner du locataire n'a pas acces au depot du site).
|
||||
NOM_FICHIER_FICHE_SITE = "fiche-site.yml"
|
||||
NATURES = ("site", "locataire")
|
||||
|
||||
|
||||
|
|
@ -290,6 +293,20 @@ class Site(Ecosysteme):
|
|||
"serveurs_temps": temps, "routage_tenants": routage},
|
||||
}
|
||||
|
||||
def deposer_fiche(self, locataire: "Locataire") -> Path:
|
||||
"""Ecrit chez le locataire la fiche que ce site lui destine. Rend le chemin ecrit.
|
||||
|
||||
Aucune date dans le fichier : deux depots d'une meme fiche sont identiques, et un
|
||||
depot qui ne change rien ne fabrique pas de difference a commiter.
|
||||
"""
|
||||
chemin = locataire.depot / NOM_FICHIER_FICHE_SITE
|
||||
entete = (f"# GENERE par le site {self.nom} (scripts/contexte.py --deposer-fiches).\n"
|
||||
"# Ne pas editer : c'est ce que le site attribue et offre a ce locataire.\n"
|
||||
"# Voir docs/conception-contextes.md §2.4.\n")
|
||||
chemin.write_text(entete + yaml.safe_dump(self.fiche_pour(locataire), allow_unicode=True,
|
||||
sort_keys=False), encoding="utf-8")
|
||||
return chemin
|
||||
|
||||
def decrire(self) -> dict:
|
||||
d = super().decrire()
|
||||
d.update({"locataires": self.noms_locataires(),
|
||||
|
|
@ -351,6 +368,11 @@ class Locataire(Ecosysteme):
|
|||
return str(d["domaine_interne"]).strip()
|
||||
return ""
|
||||
|
||||
def fiche_du_site(self) -> dict | None:
|
||||
"""La fiche que son hebergeur a deposee chez lui, ou None s'il n'y en a pas."""
|
||||
d = _yaml(self.depot / NOM_FICHIER_FICHE_SITE)
|
||||
return d or None
|
||||
|
||||
def nom_hebergeur(self) -> str | None:
|
||||
h = ((self.filiation.get("depots") or {}).get("hebergeur") or {}).get("nom")
|
||||
return str(h) if h else None
|
||||
|
|
@ -998,6 +1020,44 @@ def verifier_frontiere(site: "Site", locataire: "Locataire", face: dict | None =
|
|||
return ecarts
|
||||
|
||||
|
||||
def verifier_fiche_deposee(site: "Site", locataire: "Locataire") -> list[str]:
|
||||
"""La fiche que le locataire porte est-elle celle que son site lui destine aujourd'hui ?"""
|
||||
deposee = locataire.fiche_du_site()
|
||||
if deposee is None:
|
||||
return [f"aucune `{NOM_FICHIER_FICHE_SITE}` chez le locataire : la deposer "
|
||||
f"(`python3 scripts/contexte.py --deposer-fiches`)"]
|
||||
attendue = site.fiche_pour(locataire)
|
||||
if deposee != attendue:
|
||||
cles = sorted(k for k in set(deposee) | set(attendue) if deposee.get(k) != attendue.get(k))
|
||||
return [f"`{NOM_FICHIER_FICHE_SITE}` perimee ({', '.join(cles)}) : la redeposer et la commiter"]
|
||||
return []
|
||||
|
||||
|
||||
def verifier_inventaire_sans_site(locataire: "Locataire") -> list[str]:
|
||||
"""L'inventaire du locataire se genere-t-il SANS son site, a l'octet pres ?
|
||||
|
||||
C'est la portabilite promise (§2.4) : generer sur le runner du locataire, qui n'a pas le
|
||||
depot du site, doit rendre l'inventaire versionne. On lance l'instancier dans un processus a
|
||||
part, `SETOPS_UNDERLAY` pointe sur rien — ses globales se fixent a l'import.
|
||||
"""
|
||||
import subprocess
|
||||
code = ("import sys, yaml; sys.path.insert(0, 'scripts'); import instancier\n"
|
||||
"t = yaml.safe_dump(instancier.generer(), default_flow_style=False, sort_keys=True, "
|
||||
"allow_unicode=True)\n"
|
||||
"r = instancier.INVENTAIRE.read_text(encoding='utf-8')\n"
|
||||
"r = r[r.index('all:'):] if 'all:' in r else r\n"
|
||||
"print('IDENTIQUE' if t == r else 'DIFFERENT')\n")
|
||||
env = dict(os.environ, SETOPS_INSTANCE=str(locataire.depot), SETOPS_UNDERLAY="/nulle/part")
|
||||
env.pop("SETOPS_INVENTAIRE", None)
|
||||
r = subprocess.run([sys.executable, "-c", code], capture_output=True, text=True, env=env, cwd=RACINE)
|
||||
verdict = (r.stdout or "").strip().splitlines()[-1:] or [""]
|
||||
if verdict[0] == "IDENTIQUE":
|
||||
return []
|
||||
if verdict[0] == "DIFFERENT":
|
||||
return ["sans le site, l'inventaire genere differe de l'inventaire versionne"]
|
||||
return [f"la generation sans le site a echoue : {(r.stderr or '').strip().splitlines()[-1:]}"]
|
||||
|
||||
|
||||
def couples_hebergeur() -> list[tuple["Site", "Locataire"]]:
|
||||
"""Chaque (site, locataire) dont ce site est l'hebergeur ACTIF — les seuls qui ont une fiche
|
||||
a verifier : un site de reprise ne depose rien tant que la bascule n'a pas eu lieu."""
|
||||
|
|
@ -1077,6 +1137,8 @@ def main(argv: list[str] | None = None) -> int:
|
|||
ap = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
||||
ap.add_argument("--json", action="store_true")
|
||||
ap.add_argument("--fiche", metavar="LOCATAIRE", help="la fiche que son hebergeur lui destine")
|
||||
ap.add_argument("--deposer-fiches", action="store_true",
|
||||
help="chaque site ecrit sa fiche chez ses locataires (hebergeur actif)")
|
||||
ap.add_argument("--verifier-fiches", action="store_true",
|
||||
help="chaque fiche dit-elle ce que le locataire porte ?")
|
||||
ap.add_argument("--face", metavar="LOCATAIRE", help="la face reseau qu'il publie pour son site")
|
||||
|
|
@ -1113,6 +1175,16 @@ def main(argv: list[str] | None = None) -> int:
|
|||
return 1
|
||||
print(yaml.safe_dump(site.fiche_pour(loc), allow_unicode=True, sort_keys=False), end="")
|
||||
return 0
|
||||
if args.deposer_fiches:
|
||||
couples = couples_hebergeur()
|
||||
if not couples:
|
||||
print("Aucun site frere : aucune fiche a deposer.")
|
||||
return 0
|
||||
for site, loc in couples:
|
||||
chemin = site.deposer_fiche(loc)
|
||||
print(f" {site.nom} -> {chemin}")
|
||||
print("Deposees. Les commiter dans le depot de chaque locataire.")
|
||||
return 0
|
||||
if args.verifier_fiches:
|
||||
couples = couples_hebergeur()
|
||||
if not couples:
|
||||
|
|
|
|||
|
|
@ -87,6 +87,28 @@ def _domaine_interne() -> str:
|
|||
|
||||
|
||||
|
||||
def _fiche_du_site() -> dict | None:
|
||||
"""La fiche que l'hebergeur a deposee chez CE locataire (`fiche-site.yml`), ou None.
|
||||
|
||||
ETAPE 3 DU CHEMIN (docs/conception-contextes.md §6). Trois valeurs de l'inventaire venaient
|
||||
d'une lecture DIRECTE du site, monte sur le poste : la zone a deleguer et ses resolveurs,
|
||||
les serveurs de temps, le mode de routage. Generer sur le runner du locataire, qui n'a pas
|
||||
le depot du site, les aurait perdues. La fiche les porte, et l'inventaire devient le meme
|
||||
ou qu'on le genere. Sans fiche (transition), on lit encore le site, et on le dit.
|
||||
"""
|
||||
try:
|
||||
import contexte
|
||||
return contexte.Locataire(INSTANCE.resolve()).fiche_du_site()
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
||||
FICHE_SITE = _fiche_du_site()
|
||||
if FICHE_SITE is None:
|
||||
print("note : pas de `fiche-site.yml` chez ce locataire — temps, delegation DNS et routage "
|
||||
"lus directement dans le site monte (transition).", file=sys.stderr)
|
||||
|
||||
|
||||
def _zones_deleguees() -> list:
|
||||
"""La zone de l'HEBERGEUR, et l'adresse a qui la demander. [] si aucune carte.
|
||||
|
||||
|
|
@ -116,6 +138,13 @@ def _zones_deleguees() -> list:
|
|||
ne delegue plus rien, donc ne peut plus nommer les services du site. C'est ce qu'on
|
||||
veut CONSTATER d'une emancipation, pas une panne a reparer.
|
||||
"""
|
||||
if FICHE_SITE is not None:
|
||||
gen = FICHE_SITE.get("generation") or {}
|
||||
zone = str(gen.get("zone_site") or "").strip()
|
||||
if not zone or zone == _domaine_interne():
|
||||
return []
|
||||
adresses = [str(a) for a in gen.get("resolveurs_site") or [] if a]
|
||||
return [{"nom": zone, "adresses": adresses}] if adresses else []
|
||||
try:
|
||||
import underlay as underlay_mod
|
||||
zone = str((underlay_mod.lire_plan_site("10-intrants.yml") or {})
|
||||
|
|
@ -240,8 +269,11 @@ def generer() -> dict:
|
|||
# La patte de la frontiere que les tenants traversent — calculee une fois.
|
||||
_temps_frontiere: list = []
|
||||
try:
|
||||
_carte = underlay_mod.charger()
|
||||
if _carte:
|
||||
_carte = None if FICHE_SITE is not None else underlay_mod.charger()
|
||||
if FICHE_SITE is not None:
|
||||
_temps_frontiere = [str(x) for x in (FICHE_SITE.get("generation") or {})
|
||||
.get("serveurs_temps") or []]
|
||||
elif _carte:
|
||||
# LE LIEN DE TRANSIT SE DECLARE, IL NE SE DEVINE PAS. `reseau_transit()`
|
||||
# le derive de `passerelle_sortie` — le champ qui dit « c'est par la qu'on
|
||||
# sort ». Le reconnaitre a son prefixe d'adresse aurait marche ici et menti
|
||||
|
|
@ -275,7 +307,9 @@ def generer() -> dict:
|
|||
#
|
||||
# L'ETIQUETTE DOIT ETRE VIDE en SDN : le VNet la porte deja. En poser une seconde
|
||||
# au niveau de la carte donnerait un double etiquetage.
|
||||
sdn = underlay_mod.routage_tenants(underlay_mod.charger()) == "sdn"
|
||||
sdn = (str((FICHE_SITE.get("generation") or {}).get("routage_tenants")) == "sdn"
|
||||
if FICHE_SITE is not None
|
||||
else underlay_mod.routage_tenants(underlay_mod.charger()) == "sdn")
|
||||
index_tenant = nomenclature.get("index")
|
||||
|
||||
# UNE MACHINE SANS FONCTION DECLAREE N'A PAS D'ADRESSE — ET LE DISAIT PAS (2026-08-24).
|
||||
|
|
|
|||
|
|
@ -4830,6 +4830,31 @@ def preuve_frontiere_sorties() -> tuple[bool, str]:
|
|||
f"face reseau publie.")
|
||||
|
||||
|
||||
def preuve_inventaire_portable() -> tuple[bool, str]:
|
||||
"""Chaque locataire porte-t-il la fiche a jour de son site, et son inventaire se genere-t-il
|
||||
SANS le site, a l'octet pres ?
|
||||
|
||||
POURQUOI (2026-10-05, `docs/conception-contextes.md` §6, etape 3). L'instancier lisait le site
|
||||
monte sur le poste pour trois valeurs (temps, delegation DNS, routage) ; genere ailleurs,
|
||||
l'inventaire les perdait. Il lit desormais la fiche que le site depose. Deux conditions : la
|
||||
fiche deposee est celle que le site calcule aujourd'hui ; et l'inventaire genere sans le site
|
||||
est l'inventaire versionne. C'est la portabilite d'un locataire, prouvee.
|
||||
"""
|
||||
sys.path.insert(0, str(RACINE / "scripts"))
|
||||
import contexte as _ctx
|
||||
couples = _ctx.couples_hebergeur()
|
||||
if not couples:
|
||||
return True, "Aucun site frere : aucune fiche deposee a confronter."
|
||||
ecarts = []
|
||||
for s, l in couples:
|
||||
ecarts += [f"{l.nom} : {e}" for e in _ctx.verifier_fiche_deposee(s, l)]
|
||||
ecarts += [f"{l.nom} : {e}" for e in _ctx.verifier_inventaire_sans_site(l)]
|
||||
if ecarts:
|
||||
return False, f"{len(ecarts)} ecart(s) : " + " | ".join(ecarts[:4])
|
||||
return True, (f"{len(couples)} locataire(s) : fiche du site deposee a jour, et inventaire genere "
|
||||
f"sans le site identique a l'octet pres.")
|
||||
|
||||
|
||||
PREUVES: list[dict] = [
|
||||
{"id": "P01", "titre": "Lint (ansible-lint)", "refs": ["AFF-006"],
|
||||
"cmds": [["ansible-lint", "-q"]]},
|
||||
|
|
@ -5030,6 +5055,8 @@ PREUVES: list[dict] = [
|
|||
"refs": [], "func": preuve_frontiere_administration},
|
||||
{"id": "P90", "titre": "Ce qui sort d'un locataire vers l'Internet, la frontiere le tient de lui",
|
||||
"refs": [], "func": preuve_frontiere_sorties},
|
||||
{"id": "P91", "titre": "La fiche du site est deposee a jour, et l'inventaire se genere sans le site",
|
||||
"refs": [], "func": preuve_inventaire_portable},
|
||||
]
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -425,6 +425,31 @@ def sorties() -> None:
|
|||
verifier(bool(C.verifier_sorties(site, loc, f)), f"une sortie alteree ({nom}) est vue a la frontiere")
|
||||
|
||||
|
||||
def fiche_deposee() -> None:
|
||||
"""La fiche deposee est a jour, l'inventaire se genere sans le site — et une fiche deposee
|
||||
alteree se voit."""
|
||||
couples = C.couples_hebergeur()
|
||||
if not couples:
|
||||
print("SAUTE aucun site frere : aucune fiche deposee a confronter")
|
||||
return
|
||||
for site, loc in couples:
|
||||
e = C.verifier_fiche_deposee(site, loc)
|
||||
verifier(not e, f"{loc.nom} porte la fiche que {site.nom} lui destine" + (f" ({e[0]})" if e else ""))
|
||||
e = C.verifier_inventaire_sans_site(loc)
|
||||
verifier(not e, f"{loc.nom} : l'inventaire se genere sans le site, a l'octet pres"
|
||||
+ (f" ({e[0]})" if e else ""))
|
||||
site, loc = couples[0]
|
||||
chemin = loc.depot / C.NOM_FICHIER_FICHE_SITE
|
||||
original = chemin.read_text(encoding="utf-8")
|
||||
try:
|
||||
chemin.write_text(original.replace("10.0.4.1", "192.0.2.1"), encoding="utf-8")
|
||||
verifier(bool(C.verifier_fiche_deposee(site, loc)), "une fiche deposee alteree est vue perimee")
|
||||
verifier(bool(C.verifier_inventaire_sans_site(loc)),
|
||||
"une fiche deposee alteree change l'inventaire genere : la preuve le voit")
|
||||
finally:
|
||||
chemin.write_text(original, encoding="utf-8")
|
||||
|
||||
|
||||
def main() -> int:
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
d = Path(tmp)
|
||||
|
|
@ -440,6 +465,7 @@ def main() -> int:
|
|||
entrees_publiques()
|
||||
administration()
|
||||
sorties()
|
||||
fiche_deposee()
|
||||
if ECHECS:
|
||||
print(f"\n{len(ECHECS)} echec(s).")
|
||||
return 1
|
||||
|
|
|
|||
Loading…
Reference in a new issue