0eaf5bde39
L'artefact le plus cité du dépôt (qa/regression/out/regression_run.json · 21 suites · 534 tests · PASS) n'avait aucun garde-fou CI : check_artifacts ne rejoue que 'build' et exclut les artefacts d'exécution 'run'. Nouveau 5e gate statique rejoue 'regression_gen.py run' (~5s, déterministe) et exige byte-identité + verdict PASS. Rend impossible la re-commission d'une matrice périmée (dérive type demo 18->21) ou rouge commitée verte. parse_ci inchangé (gate sans working-directory) → 0 dérive des counts dérivés (check_artifacts exit 0). Preuve de morsure OK (534->999 => exit 1). 5 gates verts. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
129 lines
6.4 KiB
Markdown
129 lines
6.4 KiB
Markdown
# 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 |
|
||
| `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 une **é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.
|
||
|
||
## 3. Exécution locale (avant push)
|
||
|
||
```bash
|
||
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)
|
||
```
|
||
|
||
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` :
|
||
|
||
```bash
|
||
# 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-dtp` → **Settings →
|
||
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 5 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.
|