[DTP-Worker] Sprint 1 · CI/CD Gitea Actions (gate qualité 4Big · DevOps)

Débloque le dernier livrable DevOps Sprint 1 authorable en-repo (GAP §7).

- .gitea/workflows/ci.yml : pipeline Gitea Actions (Gitea ONLY, jamais GitHub)
  4 jobs : constraints-guard · validate-json · check-docs · gate agrégat.
- ci/guard_constraints.sh : enforce contraintes NON-NÉGOCIABLES CLAUDE.md
  (GitHub/GitLab/Bitbucket #2 · EspoCRM/HubSpot #3 · Stripe #10 ·
  /var/www/html/static · git clean · remote non-Gitea).
  Heuristique zéro faux positif (ignore lignes de prohibition) + escape ci-allow.
- ci/validate_json.sh : parse strict schémas Faisabilité↔Publiciste.
- ci/check_docs.sh : liens Markdown internes [HARD] + auto-score 4Big [SOFT].
- ci/README.md : doc pipeline + procédure enregistrement act_runner (VPS/DevOps).
- GAP_ANALYSIS §7 : critère CI/CD Gitea Actions -> done (runner VPS restant).

Validé localement : 3 scripts verts (exit 0) sans faux positif ;
test négatif (hubspot+github.com) -> guard exit 1 correct.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Claude Code DTP Worker
2026-07-30 00:30:40 +00:00
parent 0b2c97916a
commit 1cfb8191f4
7 changed files with 385 additions and 1 deletions
+52
View File
@@ -0,0 +1,52 @@
# ============================================================================
# CI · OTO Enterprise OS DTP · Gitea Actions
# ----------------------------------------------------------------------------
# Gate qualité DevOps (roadmap Sprint 1 · GAP_ANALYSIS §7).
# Plateforme : Gitea Actions UNIQUEMENT (CLAUDE.md #2 · JAMAIS GitHub).
# Runner : act_runner enregistré sur le VPS avec le label « ubuntu-latest ».
# Voir ci/README.md pour l'enregistrement du runner.
# Aucune dépendance réseau/marketplace externe hors actions/checkout.
# ============================================================================
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
workflow_dispatch:
jobs:
constraints-guard:
name: Contraintes NON-NÉGOCIABLES (CLAUDE.md)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Guard des contraintes
run: bash ci/guard_constraints.sh
validate-json:
name: Validation JSON (schémas Faisabilité)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Valider les JSON
run: bash ci/validate_json.sh
check-docs:
name: Qualité documentaire (liens + 4Big)
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Contrôle docs
run: bash ci/check_docs.sh
gate:
name: Gate qualité (agrégat)
runs-on: ubuntu-latest
needs: [constraints-guard, validate-json, check-docs]
steps:
- name: Résultat
run: echo "✅ Gate qualité 4Big franchi — tous les checks verts."
+1 -1
View File
@@ -199,7 +199,7 @@ Chaque item confirmé lève le marqueur **⚠ à confirmer VPS** correspondant.
| Critère | Responsable | Statut |
|---|---|---|
| Repo Gitea mandat live + fichiers poussés | DevOps | ⚠ à confirmer VPS |
| CI/CD Gitea Actions configuré | DevOps | ☐ à faire |
| CI/CD Gitea Actions configuré | DevOps | `.gitea/workflows/ci.yml` + `ci/` (guard contraintes · JSON · docs) — ⚠ enregistrement runner VPS restant |
| **Gap analysis complète** | Tous / ce doc | ✅ **présent document** |
| Template faisabilité canonique v1.0 | Faisabilité | ✅ `faisabilite/TEMPLATE_FAISABILITE_CANONIQUE_v1.0.md` (+ schémas) |
| Baseline Playwright (`/crm` `/waf-home` `/qa` `/choisir-mon-unite`) | QA | ☐ à faire |
@@ -0,0 +1,44 @@
# Daily Report · 2026-07-30 · Claude Code DTP Worker
**Session** : `20260730_002624`
## Tâche exécutée
**Sprint 1 · Livrable DevOps « CI/CD Gitea Actions »**
(roadmap `04_roadmap/ROADMAP_8_WEEKS_OR_LESS.md` §Sprint 1 · GAP_ANALYSIS_SPRINT1 §7 = `☐ à faire`).
## Contexte / analyse
- Relu `CLAUDE.md`, `ROADMAP_8_WEEKS_OR_LESS.md`, `GAP_ANALYSIS_SPRINT1.md`, daily report 2026-07-29, AGENT.md DevOps + QA.
- **Sprint 1 non terminé.** Critères de sortie restants (§7) authorables **dans ce repo sans toucher au VPS** :
1. **CI/CD Gitea Actions** (DevOps · marqué *PRIORITÉ S1* · gate qualité qui conditionne tous les sprints).
2. Baseline Playwright (QA) — dépend des endpoints VPS pour s'exécuter réellement.
- Priorité évidente : **CI/CD Gitea Actions** — 100 % authorable en-repo, débloque le gate qualité 4Big, déjà signalé comme prochaine tâche par la session précédente.
## Réalisé
- Créé `.gitea/workflows/ci.yml` : pipeline Gitea Actions (push/PR `main` + `workflow_dispatch`), 4 jobs → `constraints-guard`, `validate-json`, `check-docs`, `gate` agrégat. Zéro dépendance marketplace hors `actions/checkout`. **Gitea Actions uniquement** (contrainte #2, jamais GitHub).
- Créé `ci/guard_constraints.sh` : enforce les contraintes NON-NÉGOCIABLES de CLAUDE.md — GitHub/GitLab/Bitbucket (#2), EspoCRM/HubSpot (#3), Stripe (#10), écriture `/var/www/html/static/`, `git clean`, remote git non-Gitea. **Heuristique zéro faux positif** : ignore les lignes portant un marqueur de prohibition (`jamais`/`❌`/`only`/`interdit`…) + escape hatch `ci-allow`.
- Créé `ci/validate_json.sh` : parse strict de tous les `*.json` suivis (contrat Faisabilité↔Publiciste).
- Créé `ci/check_docs.sh` : liens Markdown internes cassés [HARD] + présence auto-score 4Big [SOFT].
- Créé `ci/README.md` : doc pipeline + exécution locale + **procédure d'enregistrement du runner Gitea** (act_runner, à exécuter côté VPS par DevOps).
- Mis à jour `GAP_ANALYSIS_SPRINT1.md` §7 : critère « CI/CD Gitea Actions » → ✅ (runner VPS restant à confirmer).
## Vérifications effectuées (dans le repo, sans toucher au VPS)
- Les 3 scripts passent au **vert (exit 0)** sur l'état actuel du repo — aucun faux positif sur le texte de politique de CLAUDE.md/AGENT.md.
- **Test négatif** : fichier de violation temporaire (`hubspot` + `github.com`) → guard retourne **exit 1** et pointe les 2 violations, en ignorant correctement les lignes de prohibition. Fichier de test retiré (repo propre).
- `git remote -v` = Gitea (`gitea.otov7.com`) → conforme #2.
## Non fait (hors périmètre worker · touche au VPS)
- Enregistrement de l'`act_runner` Gitea (label `ubuntu-latest`) → DevOps sur VPS (procédure dans `ci/README.md` §4).
- Activation de Gitea Actions au niveau instance + repo → DevOps.
- Baseline Playwright QA (`/crm`, `/waf-home`, `/qa`, `/choisir-mon-unite`) → nécessite endpoints VPS.
## Note de convention
Rapport écrit dans `05_deliverables_mvp/daily_reports/` (chemin canonique fixé roadmap l.92 + session précédente) plutôt que `05_activity_log/`, pour éviter un doublon (workflow #5).
## Prochaine tâche suggérée
- QA S1 : fichiers Playwright baseline (`tests/e2e/`) — authorables en-repo, exécution différée VPS.
- Ou Faisabilité S2/S3 : scaffold doc du générateur 4 volets automatique consommant le template v1.0.
- Ou Publiciste S2 : scaffold doc `otoia/capabilities/publiciste.py` (seul module net-neuf, chemin critique).
---
**Auto-score 4Big du livrable CI/CD : 96/100.** Réserve 4 : runner Gitea à enregistrer sur VPS (DevOps) avant exécution serveur ; scripts validés localement.
+95
View File
@@ -0,0 +1,95 @@
# 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`). Quatre jobs :
| 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) |
| `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.
## 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
```
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 4 jobs 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.
+60
View File
@@ -0,0 +1,60 @@
#!/usr/bin/env bash
# ============================================================================
# check_docs.sh · OTO Enterprise OS DTP
# ----------------------------------------------------------------------------
# Contrôle qualité documentaire (gate 4Big, roadmap Sprint 1) :
# [HARD] Liens Markdown relatifs internes → la cible doit exister.
# [SOFT] Livrables 05_deliverables_mvp/*.md → auto-score 4Big attendu.
# Dépendances : bash, git, grep, sed. Aucun réseau requis.
# ============================================================================
set -uo pipefail
cd "$(git rev-parse --show-toplevel)"
FAIL=0
report() { printf ' \033[31m✗\033[0m %s\n' "$1"; FAIL=1; }
warn() { printf ' \033[33m⚠\033[0m %s\n' "$1"; }
ok() { printf ' \033[32m✓\033[0m %s\n' "$1"; }
echo "== 1. Liens Markdown relatifs internes (cible existe ?) =="
broken=0
while read -r md; do
dir="$(dirname "$md")"
# Extrait les cibles [texte](cible) ; ignore http(s), mailto, ancres pures,
# gabarits {{...}} et liens wiki [[...]].
grep -oE '\]\([^)]+\)' "$md" 2>/dev/null \
| sed -E 's/^\]\(//; s/\)$//' \
| while read -r link; do
link="${link%% *}" # retire un éventuel "titre"
link="${link%%#*}" # retire l'ancre
[[ -z "$link" ]] && continue
case "$link" in
http://*|https://*|mailto:*|tel:*|\#*|\{\{*|data:*) continue ;;
esac
target="$dir/$link"
if [[ ! -e "$target" ]]; then
printf ' \033[31m✗\033[0m %s → lien cassé : %s\n' "$md" "$link"
echo "BROKEN" >> /tmp/brokenlinks
fi
done
done < <(git ls-files '*.md')
if [[ -s /tmp/brokenlinks ]]; then FAIL=1; rm -f /tmp/brokenlinks; else ok "Aucun lien interne cassé"; fi
echo "== 2. Auto-score 4Big sur les livrables (SOFT · CLAUDE.md #5 · ≥95/100) =="
while read -r md; do
case "$md" in
05_deliverables_mvp/daily_reports/*) continue ;; # rapports : hors gate score
esac
if grep -qiE 'score|/100' "$md"; then
ok "$md — mention de score présente"
else
warn "$md — pas de mention d'auto-score 4Big (recommandé ≥95/100)"
fi
done < <(git ls-files '05_deliverables_mvp/*.md')
echo
if [[ "$FAIL" -eq 0 ]]; then
echo -e "\033[32m✅ Documentation conforme (liens internes OK).\033[0m"
else
echo -e "\033[31m❌ Lien(s) interne(s) cassé(s) — corriger avant merge.\033[0m"
fi
exit "$FAIL"
+94
View File
@@ -0,0 +1,94 @@
#!/usr/bin/env bash
# ============================================================================
# guard_constraints.sh · OTO Enterprise OS DTP
# ----------------------------------------------------------------------------
# Enforce les contraintes NON-NÉGOCIABLES de CLAUDE.md dans la CI.
# Objectif : empêcher qu'un commit introduise un outil/plateforme interdit
# ou une pratique proscrite. Gate qualité DevOps (roadmap Sprint 1).
#
# Principe de robustesse (zéro faux positif sur le texte de politique) :
# - On détecte l'USAGE d'un terme interdit, PAS sa simple mention.
# - Une ligne qui contient un MARQUEUR DE PROHIBITION (jamais, ❌, only,
# pas de, interdit, SEUL...) est un rappel de la règle → on l'ignore.
# - Escape hatch explicite : une ligne contenant « ci-allow » est ignorée.
#
# Sortie : exit 0 si conforme, exit 1 sinon (liste des violations).
# Dépendances : bash, git, grep. Aucun réseau requis.
# ============================================================================
set -uo pipefail
cd "$(git rev-parse --show-toplevel)"
# Marqueur de prohibition : si présent sur la ligne, c'est un rappel de règle.
PROHIBITION='jamais|JAMAIS|Jamais|❌|SEUL|Seul|only|Only|ONLY|pas de|pas d|\(pas |NON-|non-|[Ii]nterdit|INTERDIT|forbidden|proscrit|éliminer'
# ci-allow : échappatoire manuel documenté.
ALLOW='ci-allow'
FAIL=0
report() { printf ' \033[31m✗\033[0m %s\n' "$1"; FAIL=1; }
ok() { printf ' \033[32m✓\033[0m %s\n' "$1"; }
# Fichiers suivis (exclut ce script lui-même : il liste les termes interdits).
tracked_files() {
git ls-files -- . \
':(exclude)ci/guard_constraints.sh' \
':(exclude).gitea/workflows/*.yml'
}
# scan_forbidden <label> <regex-terme>
# Flag toute occurrence NON préfixée d'un marqueur de prohibition / ci-allow.
scan_forbidden() {
local label="$1" term="$2" hits
hits="$(tracked_files | while read -r f; do
grep -inE "$term" "$f" 2>/dev/null \
| grep -ivE "$PROHIBITION" \
| grep -ivE "$ALLOW" \
| sed "s#^#${f}:#"
done)"
if [[ -n "$hits" ]]; then
report "Interdit détecté — $label :"
echo "$hits" | sed 's/^/ /'
else
ok "Aucun usage interdit — $label"
fi
}
echo "== 1. Plateformes git interdites (CLAUDE.md #2 · Gitea SEULEMENT) =="
scan_forbidden "GitHub" 'github\.com|git@github|github\.io'
scan_forbidden "GitLab" 'gitlab\.com|gitlab\.io'
scan_forbidden "Bitbucket" 'bitbucket\.org'
echo "== 2. CRM interdits (CLAUDE.md #3 · CRM = ERPNext natif) =="
scan_forbidden "EspoCRM" 'espocrm'
scan_forbidden "HubSpot" 'hubspot'
echo "== 3. Paiement interdit (CLAUDE.md #10 · Cardnet, pas Stripe) =="
scan_forbidden "Stripe" 'stripe'
echo "== 4. Écriture directe /var/www/html/static (Interdit absolu) =="
scan_forbidden "chemin /var/www/html/static en écriture" '/var/www/html/static/'
echo "== 5. Commande git clean (Interdit absolu) =="
scan_forbidden "git clean" 'git[[:space:]]+clean'
echo "== 6. Remote git = Gitea uniquement =="
if git remote -v >/dev/null 2>&1 && [[ -n "$(git remote)" ]]; then
bad_remote="$(git remote -v | grep -iE 'github\.com|gitlab\.com|bitbucket\.org' || true)"
if [[ -n "$bad_remote" ]]; then
report "Remote git interdit configuré :"; echo "$bad_remote" | sed 's/^/ /'
else
ok "Remotes git conformes (Gitea / interne uniquement)"
fi
else
ok "Aucun remote git configuré (CI checkout) — rien à vérifier"
fi
echo
if [[ "$FAIL" -eq 0 ]]; then
echo -e "\033[32m✅ Contraintes NON-NÉGOCIABLES respectées.\033[0m"
else
echo -e "\033[31m❌ Violation(s) de contrainte détectée(s). Voir ci-dessus.\033[0m"
echo " (Faux positif légitime ? Ajouter « ci-allow » sur la ligne concernée.)"
fi
exit "$FAIL"
+39
View File
@@ -0,0 +1,39 @@
#!/usr/bin/env bash
# ============================================================================
# validate_json.sh · OTO Enterprise OS DTP
# ----------------------------------------------------------------------------
# Valide que tous les fichiers .json suivis sont bien formés (parse strict).
# Les schémas JSON (version.schema.json, projets_master.schema.json) sont le
# contrat de données Faisabilité ↔ Publiciste : un JSON cassé bloque le
# pipeline en aval → on l'attrape ici.
# Dépendances : bash, git, python3. Aucun réseau requis.
# ============================================================================
set -uo pipefail
cd "$(git rev-parse --show-toplevel)"
FAIL=0
mapfile -t files < <(git ls-files '*.json')
if [[ "${#files[@]}" -eq 0 ]]; then
echo "Aucun fichier .json suivi — rien à valider."
exit 0
fi
for f in "${files[@]}"; do
if python3 -c "import json,sys; json.load(open(sys.argv[1]))" "$f" 2>/tmp/jsonerr; then
printf ' \033[32m✓\033[0m %s\n' "$f"
# Si un $schema est déclaré, contrôle que 'draft' est reconnu (info seule).
else
printf ' \033[31m✗\033[0m %s\n' "$f"
sed 's/^/ /' /tmp/jsonerr
FAIL=1
fi
done
echo
if [[ "$FAIL" -eq 0 ]]; then
echo -e "\033[32m✅ Tous les JSON sont bien formés.\033[0m"
else
echo -e "\033[31m❌ JSON invalide détecté.\033[0m"
fi
exit "$FAIL"