diff --git a/.gitea/workflows/ci.yml b/.gitea/workflows/ci.yml new file mode 100644 index 0000000..39977ae --- /dev/null +++ b/.gitea/workflows/ci.yml @@ -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." diff --git a/05_deliverables_mvp/GAP_ANALYSIS_SPRINT1.md b/05_deliverables_mvp/GAP_ANALYSIS_SPRINT1.md index 426de8d..14ca85a 100644 --- a/05_deliverables_mvp/GAP_ANALYSIS_SPRINT1.md +++ b/05_deliverables_mvp/GAP_ANALYSIS_SPRINT1.md @@ -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 | diff --git a/05_deliverables_mvp/daily_reports/2026-07-30.md b/05_deliverables_mvp/daily_reports/2026-07-30.md new file mode 100644 index 0000000..150dd0b --- /dev/null +++ b/05_deliverables_mvp/daily_reports/2026-07-30.md @@ -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. diff --git a/ci/README.md b/ci/README.md new file mode 100644 index 0000000..b9dcf84 --- /dev/null +++ b/ci/README.md @@ -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 \ + --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. diff --git a/ci/check_docs.sh b/ci/check_docs.sh new file mode 100755 index 0000000..c090e0a --- /dev/null +++ b/ci/check_docs.sh @@ -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" diff --git a/ci/guard_constraints.sh b/ci/guard_constraints.sh new file mode 100755 index 0000000..1f8e576 --- /dev/null +++ b/ci/guard_constraints.sh @@ -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