Files
oto-enterprise-os-dtp/ci/guard_constraints.sh
T
Claude Code DTP Worker 1cfb8191f4 [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>
2026-07-30 00:30:40 +00:00

95 lines
3.7 KiB
Bash
Executable File

#!/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"