Files
oto-enterprise-os-dtp/ci/README.md
T
Claude Code DTP Worker a30ff937f0 [DTP-Worker] Sprint 8 · buffer L75 · Reproductibilité checkout propre : hand-off out/ des 4 générateurs RBAC était .gitignore-é (gate rouge en CI, vert local seulement) + durcissement check_artifacts (build produit ⇒ DOIT être suivi par git)
Défaut réel (même classe que le bug regression_run.json corrigé plus tôt) :
les 4 générateurs RBAC (fixtures_gen/userperm_gen/roleprofile_gen/apply_plan)
.gitignore-aient leur out/, alors qu'ils sont audités en archétype `generator`
(critère HANDOFF). En checkout PROPRE (git archive HEAD = ce que voit le runner
Gitea) leur out/ est absent → qa/audit_4big (dont le build relit le out/ de
CHAQUE module) les note 80<95 ⇒ INV7 ⇒ build refusé ⇒ check-artifacts ET
check-regression ROUGES. Ça ne passait qu'en local via les out/ non suivis
laissés par des build manuels.

Fix : committer le out/ des 4 générateurs (build byte-déterministe prouvé ;
apply_plan lit ses frères en process, pas via out/) → alignement sur les 15
autres générateurs ; audit 100/100 en checkout propre.

Durcissement : check_artifacts.sh exige désormais `git ls-files --error-unmatch`
sur chaque fichier produit → un out/ ignoré/non commité devient une erreur
LOCALE honnête au lieu d'une surprise en CI. Bite-proof : git rm --cached d'un
artefact (laissé sur disque) ⇒ exit 1 ; re-add ⇒ exit 0.

Régénéré : quality_report.json (dérive DOC = taille des 4 README édités).
Vérifs : 6 gates verts sur git archive propre ; 534/21 inchangé ; suites OK.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-31 01:42:14 +00:00

8.2 KiB
Raw Blame History

CI/CD · OTO Enterprise OS DTP · Gitea Actions

Livrable Sprint 1 (roadmap 04_roadmap/ROADMAP_8_WEEKS_OR_LESS.md §Sprint 1 · DevOps) « CI/CD Gitea Actions » — gate qualité qui conditionne tous les sprints suivants.

Plateforme : Gitea Actions UNIQUEMENT (CLAUDE.md contrainte #2 · JAMAIS GitHub).


1. Ce que fait le pipeline

Workflow : .gitea/workflows/ci.yml. Déclenché sur push / pull_request vers main et manuellement (workflow_dispatch). Jobs statiques (+ une suite unittest par module) :

Job Script Rôle Blocant
constraints-guard ci/guard_constraints.sh Enforce les contraintes NON-NÉGOCIABLES de CLAUDE.md oui
validate-json ci/validate_json.sh Parse strict de tous les *.json (schémas Faisabilité↔Publiciste) oui
check-docs ci/check_docs.sh Liens Markdown internes + présence auto-score 4Big oui (liens)
check-artifacts ci/check_artifacts.sh Reproductibilité : chaque out/*.json versionné == build frais oui
check-regression ci/check_regression.sh Fraîcheur : qa/regression/out/regression_run.json (run) == run frais + verdict PASS oui
check-ci-integrity ci/check_ci_integrity.sh Intégrité du câblage : gate.needs == tous les jobs non-manuels · chaque ci/*.sh câblé au gate oui
gate Agrégat vert = gate qualité 4Big franchi oui

Aucune dépendance réseau/marketplace hors actions/checkout. Tout tourne avec bash + git + python3 (déjà présents sur un runner standard).

2. Détail des contrôles

guard_constraints.sh — contraintes NON-NÉGOCIABLES

Détecte l'usage (pas la simple mention) de :

  • Plateformes git interdites : github.com, gitlab.com, bitbucket.org (#2).
  • CRM interdits : EspoCRM, HubSpot (#3).
  • Paiement interdit : Stripe (#10 · Cardnet only).
  • Écriture directe dans /var/www/html/static/ (Interdit absolu).
  • Commande git clean (Interdit absolu).
  • Remote git pointant ailleurs que Gitea/interne.

Zéro faux positif : une ligne contenant un marqueur de prohibition (jamais, , only, pas de, interdit…) est un rappel de règle → ignorée. Escape hatch documenté : ajouter ci-allow sur une ligne pour l'exclure.

validate_json.sh

Parse chaque *.json suivi (dont version.schema.json et projets_master.schema.json, contrat de données Faisabilité → Publiciste). Un JSON cassé casse le pipeline aval → attrapé ici.

check_docs.sh

  • [HARD] liens Markdown relatifs internes : la cible doit exister.
  • [SOFT] livrables 05_deliverables_mvp/*.md : mention d'auto-score 4Big attendue (≥95/100, CLAUDE.md #5). Avertissement seul, non blocant.

check_artifacts.sh

Régénère chaque artefact 05_deliverables_mvp/**/out/ versionné depuis son générateur (build -o <tmp>) et exige que tout fichier produit soit (a) suivi par git — jamais un artefact seulement sur disque (out/ .gitignore-é ou non-git add), qui serait absent en CI propre et rendrait le gate « vert en local » par artefact fantôme (même classe que le bug regression_run.json) — et (b) en égalité byte-for-byte avec le fichier commité. Découverte automatique (zéro liste à la main · #6) : tout module avec un out/ et un générateur build entre dans le gate.

Cible la dérive silencieuse : un module auto-résout des valeurs depuis les artefacts d'autres modules (ex. demo/scenarios lit qa/audit_4big/coverage/ci_modules_count) ; quand la source grandit, l'artefact consommateur devient périmé s'il n'est pas régénéré — dérive qu'aucune suite tests/ (qui teste des fonctions, pas le fichier commité) n'attrape. Correctif : build -o out puis commit. Les artefacts d'exécution non produits par build (p.ex. qa/regression/out/regression_run.json, issu de run) sont hors de ce gate — ils sont couverts par check-regression ci-dessous.

check_regression.sh

Rejoue la matrice de régression complète (qa/regression/regression_gen.py run, ~5 s, stdlib pur) vers un tmp et exige que le regression_run.json frais soit byte-identique au commité, puis que son verdict soit PASS. Complément direct de check_artifacts : celui-ci ne rejoue que build (→ regression_plan.json) et laisse hors périmètre l'artefact d'exécution regression_run.json — pourtant c'est lui qui porte les compteurs cités partout dans la doc et les logs (« 21 suites · 534 tests · PASS »). Sans ce gate, ce chiffre pouvait se périmer en silence (module + job CI ajoutés sans régénérer la matrice → « 21 suites » faux ; c'est la dérive « demo 18→21 » corrigée à la main), ou une matrice rouge être commitée verte. regression_run.json ne contient aucun horodatage/hôte → le run est déterministe et l'égalité exacte licite. Correctif : regression_gen.py run -o out puis commit.

check_ci_integrity.sh

Prouve, en lisant .gitea/workflows/ci.yml, que le câblage du workflow tient — car le job gate est le seul verrou de merge : un check absent de son needs: ne bloque rien, même rouge. Deux invariants :

  • INV-Agate.needs == { tous les jobs définis } { gate } { jobs manuels } (un job manuel = gardé par if: … workflow_dispatch …, ex. e2e-baseline, légitimement hors du gate push/PR car il exige un serveur live). Détecte un job oublié du gate (MISSING → ne bloque pas), une référence fantôme (DANGLING → typo / job renommé-supprimé) et un job manuel glissé dans needs (gate en attente perpétuelle sur push).
  • INV-B — chaque script ci/*.sh du dépôt est lancé par exactement un job (run: bash ci/<script>), lui-même dans gate.needs. Un nouveau gate statique non câblé (script mort) ou décâblé casse le check.

Ferme le trou laissé par les couvertures existantes (audit_4big/registry, qa/regression/discovery) qui ne prouvent l'appartenance au gate que des jobs de module (ceux portant un working-directory:) — les gates statiques sans working-directory n'étaient gardés par personne. Même classe d'anti-dérive que INV4 (disque→CI), appliquée au câblage CI. stdlib pur (bash/awk/git), zéro réseau.

3. Exécution locale (avant push)

bash ci/guard_constraints.sh   # contraintes CLAUDE.md
bash ci/validate_json.sh       # schémas JSON
bash ci/check_docs.sh          # liens + score
bash ci/check_artifacts.sh     # reproductibilité out/ (build)
bash ci/check_regression.sh    # fraîcheur matrice régression (run)
bash ci/check_ci_integrity.sh  # intégrité du câblage CI (gate ⊇ tous jobs)

Chaque script retourne 0 si conforme, 1 sinon. Reproduit exactement ce que fait la CI (mêmes scripts, aucune logique cachée côté YAML).

4. Enregistrement du runner Gitea (ops · à faire sur le VPS)

⚠ Étape hors périmètre de ce worker (touche au VPS). À réaliser par l'agent DevOps. Documenté ici pour traçabilité.

Le workflow cible un runner avec le label ubuntu-latest. Sur le VPS Gitea (:3015), enregistrer un act_runner :

# Sur le VPS, récupérer le token runner :
#   Gitea → Site Administration → Actions → Runners → Create new Runner
act_runner register \
  --instance http://153.75.250.214:3015 \
  --token <RUNNER_TOKEN> \
  --labels ubuntu-latest:docker://node:20-bookworm \
  --name oto-dtp-runner
act_runner daemon    # ou service systemd dédié

Vérifier ensuite : Gitea → repo michel/oto-enterprise-os-dtpSettings → Actions doit être activé, et le runner doit apparaître « Idle ».

5. Checklist de vérification (DevOps, sur VPS)

  • [ ] Gitea Actions activé au niveau instance ET repo.
  • [ ] act_runner enregistré, label ubuntu-latest, statut Idle.
  • [ ] Push de test → les 6 gates statiques apparaissent et passent au vert.
  • [ ] PR de test avec violation volontaire → constraints-guard bloque (rouge).

Auto-score 4Big du livrable : 96/100. Réserve 4 : l'enregistrement du runner (§4) est hors périmètre repo et reste à confirmer sur le VPS par DevOps ; tant que le runner n'est pas Idle, la CI ne s'exécute pas côté serveur bien que les scripts soient validés localement.