Compare commits
No commits in common. "84ed730e8d20865132ccd30a9a61a0418aaf69cc" and "fae5c237226161bfb72039c9022cded1efccb4ee" have entirely different histories.
84ed730e8d
...
fae5c23722
8 changed files with 1 additions and 460 deletions
44
.env.example
44
.env.example
|
|
@ -66,50 +66,6 @@ CORS_ALLOWED_ORIGIN=https://kiosk.example.com
|
||||||
# argon2id recommande depuis PHP 7.3 pour les nouveaux projets.
|
# argon2id recommande depuis PHP 7.3 pour les nouveaux projets.
|
||||||
PASSWORD_ALGO=argon2id
|
PASSWORD_ALGO=argon2id
|
||||||
|
|
||||||
# Parametres de cout argon2id (password_hash options).
|
|
||||||
# Defauts alignes sur les recommandations OWASP Password Storage Cheat Sheet
|
|
||||||
# (memoire >= 19 MiB, >= 2 iterations). 65536 KiB = 64 MiB, marge confortable.
|
|
||||||
# Ces valeurs servent aussi au hash du PIN equipier (pin_hash, actions sensibles).
|
|
||||||
ARGON2_MEMORY_COST=65536 # KiB (64 MiB)
|
|
||||||
ARGON2_TIME_COST=4 # nombre d'iterations
|
|
||||||
ARGON2_THREADS=1 # parallelisme (1 = portable, deterministe)
|
|
||||||
|
|
||||||
# ===================================================================
|
|
||||||
# Anti brute-force - throttling de connexion (security-by-design)
|
|
||||||
# ===================================================================
|
|
||||||
# Deux gardes complementaires (cf. docs/merise/mld.md 4.21 + PROJECT_CONTEXT 19) :
|
|
||||||
# 1. par compte : colonnes user.failed_login_attempts / user.lockout_until
|
|
||||||
# 2. par IP source : table login_throttle (entite 21)
|
|
||||||
# Backoff degressif (pas de lock definitif) : evite le DoS sur compte legitime.
|
|
||||||
|
|
||||||
# Compteur par compte : nombre d'echecs avant declenchement du backoff.
|
|
||||||
ACCOUNT_LOCKOUT_THRESHOLD=5
|
|
||||||
# Duree de base du backoff (secondes). Croit de facon degressive a chaque
|
|
||||||
# palier d'echecs supplementaires (ex : 60 -> 300 -> 900).
|
|
||||||
ACCOUNT_LOCKOUT_BASE_SECONDS=60
|
|
||||||
ACCOUNT_LOCKOUT_MAX_SECONDS=900 # plafond du backoff (15 min)
|
|
||||||
|
|
||||||
# Gate par IP : fenetre glissante et plafond de tentatives sur cette fenetre.
|
|
||||||
IP_THROTTLE_WINDOW_SECONDS=900 # 15 min
|
|
||||||
IP_THROTTLE_MAX_ATTEMPTS=20 # par IP sur la fenetre
|
|
||||||
|
|
||||||
# PIN equipier pour actions sensibles (annulation, override). Longueur minimale.
|
|
||||||
STAFF_PIN_MIN_LENGTH=4
|
|
||||||
|
|
||||||
# Expiration du token de reinitialisation de mot de passe (secondes).
|
|
||||||
PASSWORD_RESET_TTL=3600 # 1h
|
|
||||||
|
|
||||||
# ===================================================================
|
|
||||||
# Retention des donnees (RGPD - minimisation et limitation de conservation)
|
|
||||||
# ===================================================================
|
|
||||||
# Purges executees par le service cron (docker/cron/crontab).
|
|
||||||
# Justification documentee : interet legitime / obligations probatoires.
|
|
||||||
|
|
||||||
AUDIT_LOG_RETENTION_DAYS=365 # journal d'audit ~12 mois
|
|
||||||
THROTTLE_PURGE_AFTER_HOURS=24 # login_throttle : lignes sans lockout actif > 24h
|
|
||||||
ORDER_RETENTION_DAYS=1095 # commandes (historique/stats) ~3 ans
|
|
||||||
# Purge des sessions expirees : deja geree par le cron */15 (voir crontab).
|
|
||||||
|
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
# Upload images produits
|
# Upload images produits
|
||||||
# ===================================================================
|
# ===================================================================
|
||||||
|
|
|
||||||
|
|
@ -1,81 +0,0 @@
|
||||||
name: CI
|
|
||||||
# CI Wakdo - Forgejo Actions (runner stark-wakdo, label `docker`).
|
|
||||||
# Strategie solo dev : PR obligatoire + auto-merge sur CI verte (voir SECURITY.md).
|
|
||||||
#
|
|
||||||
# Etat des jobs selon la phase projet :
|
|
||||||
# - secret-scan : fonctionnel des maintenant (gitleaks scanne tout le depot)
|
|
||||||
# - php-lint : fonctionnel sur les fichiers PHP presents (stubs P1, code P2+)
|
|
||||||
# - static-tests: PHPStan + PHPUnit GARDES - s'activent quand P2 ajoute
|
|
||||||
# composer.json / phpstan.neon / tests + phpunit.xml
|
|
||||||
|
|
||||||
on:
|
|
||||||
pull_request:
|
|
||||||
branches: [dev, main]
|
|
||||||
push:
|
|
||||||
branches: [dev, main]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
secret-scan:
|
|
||||||
runs-on: docker
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
fetch-depth: 0
|
|
||||||
- name: Install tools
|
|
||||||
run: |
|
|
||||||
apt-get update -qq
|
|
||||||
apt-get install -y -qq curl ca-certificates tar >/dev/null
|
|
||||||
- name: Install gitleaks
|
|
||||||
run: |
|
|
||||||
VER=8.21.2
|
|
||||||
curl -sSL "https://github.com/gitleaks/gitleaks/releases/download/v${VER}/gitleaks_${VER}_linux_x64.tar.gz" -o /tmp/gl.tgz
|
|
||||||
tar -xzf /tmp/gl.tgz -C /usr/local/bin gitleaks
|
|
||||||
gitleaks version
|
|
||||||
- name: Scan for secrets
|
|
||||||
run: gitleaks detect --config .gitleaks.toml --redact --no-banner --verbose
|
|
||||||
|
|
||||||
php-lint:
|
|
||||||
runs-on: docker
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: Install PHP CLI
|
|
||||||
run: |
|
|
||||||
apt-get update -qq
|
|
||||||
apt-get install -y -qq php-cli >/dev/null
|
|
||||||
php --version
|
|
||||||
- name: Lint all PHP files
|
|
||||||
run: |
|
|
||||||
set -eu
|
|
||||||
files=$(find . -path ./node_modules -prune -o -name '*.php' -print)
|
|
||||||
if [ -z "$files" ]; then echo "No PHP files yet - skip"; exit 0; fi
|
|
||||||
echo "$files" | while IFS= read -r f; do
|
|
||||||
[ -z "$f" ] && continue
|
|
||||||
php -l "$f"
|
|
||||||
done
|
|
||||||
|
|
||||||
static-tests:
|
|
||||||
runs-on: docker
|
|
||||||
steps:
|
|
||||||
- uses: actions/checkout@v4
|
|
||||||
- name: PHPStan (guarded)
|
|
||||||
run: |
|
|
||||||
if [ -f composer.json ] && [ -f phpstan.neon ]; then
|
|
||||||
echo "phpstan config detected - running"
|
|
||||||
apt-get update -qq && apt-get install -y -qq php-cli unzip git >/dev/null
|
|
||||||
curl -sS https://getcomposer.org/installer | php -- --install-dir=/usr/local/bin --filename=composer
|
|
||||||
composer install --no-interaction --no-progress
|
|
||||||
vendor/bin/phpstan analyse --no-progress
|
|
||||||
else
|
|
||||||
echo "PHPStan skipped: no composer.json/phpstan.neon yet (activates in P2)"
|
|
||||||
fi
|
|
||||||
- name: PHPUnit (guarded)
|
|
||||||
run: |
|
|
||||||
if [ -d tests ] && [ -f phpunit.xml ]; then
|
|
||||||
echo "phpunit config detected - running"
|
|
||||||
apt-get update -qq && apt-get install -y -qq php-cli >/dev/null
|
|
||||||
if [ -f vendor/bin/phpunit ]; then vendor/bin/phpunit; \
|
|
||||||
elif [ -f phpunit.phar ]; then php phpunit.phar; \
|
|
||||||
else echo "phpunit binary missing despite config" && exit 1; fi
|
|
||||||
else
|
|
||||||
echo "PHPUnit skipped: no tests/ + phpunit.xml yet (activates in P2)"
|
|
||||||
fi
|
|
||||||
|
|
@ -1,31 +0,0 @@
|
||||||
# Wakdo - configuration gitleaks (secret-scan)
|
|
||||||
#
|
|
||||||
# Utilise par :
|
|
||||||
# - le hook pre-commit local (defense en profondeur)
|
|
||||||
# - le job CI Forgejo Actions (.forgejo/workflows/, lot D) sur chaque PR -> dev
|
|
||||||
#
|
|
||||||
# Principe : etendre le jeu de regles par defaut de gitleaks, puis ne tolerer
|
|
||||||
# QUE les faux positifs explicitement justifies ci-dessous (placeholders de doc).
|
|
||||||
|
|
||||||
[extend]
|
|
||||||
useDefault = true
|
|
||||||
|
|
||||||
[allowlist]
|
|
||||||
description = "Faux positifs documentes - placeholders de configuration, jamais des secrets reels"
|
|
||||||
|
|
||||||
# Fichiers de template / doc : ne contiennent que des placeholders RFC 2606 / change_me.
|
|
||||||
paths = [
|
|
||||||
'''\.env\.example$''',
|
|
||||||
'''\.gitleaks\.toml$''',
|
|
||||||
'''docs/.*\.md$''',
|
|
||||||
]
|
|
||||||
|
|
||||||
# Valeurs placeholder explicites tolerees ou qu'elles apparaissent.
|
|
||||||
regexes = [
|
|
||||||
'''change_me_strong_password''',
|
|
||||||
'''change_me_root_password''',
|
|
||||||
'''example\.com''',
|
|
||||||
]
|
|
||||||
|
|
||||||
# Note : le vrai .env est gitignore et ne doit jamais etre commite. Ce scan est
|
|
||||||
# une defense en profondeur, pas un substitut a l'hygiene .gitignore.
|
|
||||||
55
SECURITY.md
55
SECURITY.md
|
|
@ -1,55 +0,0 @@
|
||||||
# Politique de securite - Wakdo
|
|
||||||
|
|
||||||
Wakdo est un projet de fin de formation (RNCP 37805) construit en
|
|
||||||
**security-by-design** : la menace est modelisee avant le code. Ce document
|
|
||||||
resume la posture, le signalement de vulnerabilites et les garde-fous CI.
|
|
||||||
|
|
||||||
## Modele de menace
|
|
||||||
|
|
||||||
Le modele STRIDE complet, le registre des risques et la classification des
|
|
||||||
donnees (4 niveaux) vivent dans `docs/PROJECT_CONTEXT.md` section 19, et le flux
|
|
||||||
d'authentification durci dans `docs/uml/security-sequence.md`.
|
|
||||||
|
|
||||||
## Mesures en place (resume)
|
|
||||||
|
|
||||||
| Domaine | Mesure |
|
|
||||||
|---|---|
|
|
||||||
| Mots de passe | `password_hash` argon2id (cout configurable, defauts OWASP) |
|
|
||||||
| Actions sensibles | PIN equipier hashe argon2id (`pin_hash`) |
|
|
||||||
| Brute-force | double throttle : compteur par compte (`user`) + par IP (`login_throttle`), backoff degressif |
|
|
||||||
| Sessions | cookies `HttpOnly` + `Secure` + `SameSite=Strict`, regeneration d'ID a la connexion (anti-fixation), idle 4h / absolu 10h |
|
|
||||||
| Injection | PDO prepared statements exclusivement |
|
|
||||||
| Upload | validation MIME + taille, stockage hors webroot |
|
|
||||||
| En-tetes / PHP | `expose_php=Off`, `allow_url_fopen/include=Off`, `cgi.fix_pathinfo=0`, fonctions d'execution systeme desactivees |
|
|
||||||
| RGPD | retention limitee (audit ~12 mois, throttle 24h, commandes ~3 ans), droit consultation/modif/suppression |
|
|
||||||
| Secrets | `.env` gitignore, tenu hors de `.git/config` (credential helper lisant `.env`), secret-scan gitleaks en CI |
|
|
||||||
|
|
||||||
Les seuils operationnels (couts argon2, lockout, throttle, retention) sont
|
|
||||||
documentes dans `.env.example`.
|
|
||||||
|
|
||||||
## Garde-fous CI (Forgejo Actions)
|
|
||||||
|
|
||||||
Chaque PR vers `dev` ou `main` declenche `.forgejo/workflows/ci.yml` :
|
|
||||||
|
|
||||||
- **secret-scan** (gitleaks) : empeche un secret d'entrer dans l'historique
|
|
||||||
- **php-lint** : `php -l` sur tous les fichiers PHP
|
|
||||||
- **static-tests** : PHPStan + PHPUnit (s'activent quand le code PHP arrive en P2)
|
|
||||||
|
|
||||||
La strategie de merge est **PR + auto-merge sur CI verte** (travail solo) : la
|
|
||||||
PR est obligatoire (trace de gouvernance), le merge se declenche automatiquement
|
|
||||||
une fois les checks au vert. Voir `scripts/forgejo-pr-automerge.sh` et
|
|
||||||
`scripts/forgejo-branch-protection.sh`.
|
|
||||||
|
|
||||||
## Signaler une vulnerabilite
|
|
||||||
|
|
||||||
Projet pedagogique non destine a la production publique. Pour signaler un
|
|
||||||
probleme de securite : ouvrir une issue sur le depot Forgejo
|
|
||||||
(`https://git.acadenice.com/AcadeNice/corentin_wakdo`) ou contacter l'auteur.
|
|
||||||
Merci de ne pas divulguer publiquement un detail exploitable avant correction.
|
|
||||||
|
|
||||||
## Perimetre
|
|
||||||
|
|
||||||
Couvert : authentification, autorisation (RBAC), gestion de session, validation
|
|
||||||
d'entree, integrite des donnees de commande, hygiene des secrets.
|
|
||||||
Hors perimetre : paiement reel (remplace par numero de commande), durcissement
|
|
||||||
OS de l'hote, securite physique de la borne.
|
|
||||||
|
|
@ -41,31 +41,8 @@ session.cookie_secure = 1
|
||||||
; Persistance inter-container non necessaire : chaque session est liee a une
|
; Persistance inter-container non necessaire : chaque session est liee a une
|
||||||
; instance unique du service wakdo-app (pas de scale horizontal pour ce projet).
|
; instance unique du service wakdo-app (pas de scale horizontal pour ce projet).
|
||||||
|
|
||||||
; session.gc_maxlifetime : filet de securite cote serveur (l'idle reel est
|
; --- Expose_php = Off : ne pas leak la version PHP dans l'entete HTTP ---
|
||||||
; pilote par l'appli via SESSION_LIFETIME_IDLE). 4h.
|
|
||||||
session.gc_maxlifetime = 14400
|
|
||||||
; IDs de session longs et a forte entropie (anti-prediction/fixation).
|
|
||||||
session.sid_length = 48
|
|
||||||
session.sid_bits_per_character = 6
|
|
||||||
; Pas de cache navigateur sur les pages avec session (anti-fuite via cache).
|
|
||||||
session.cache_limiter = nocache
|
|
||||||
|
|
||||||
; --- Durcissement general (security-by-design, cf. PROJECT_CONTEXT 19) ---
|
|
||||||
; Expose_php = Off : ne pas leak la version PHP dans l'entete HTTP.
|
|
||||||
expose_php = Off
|
expose_php = Off
|
||||||
; Anti RFI/SSRF : interdire l'ouverture d'URL distantes et leur inclusion.
|
|
||||||
allow_url_fopen = Off
|
|
||||||
allow_url_include = Off
|
|
||||||
; FPM : ne pas deviner le script a partir du PATH_INFO (anti exploitation
|
|
||||||
; d'upload mal route vers l'interpreteur). Le routage passe par le front controller.
|
|
||||||
cgi.fix_pathinfo = 0
|
|
||||||
; Interdire le chargement dynamique d'extensions au runtime.
|
|
||||||
enable_dl = Off
|
|
||||||
; Ne pas inclure les arguments dans les stack traces (anti-fuite de secrets).
|
|
||||||
zend.exception_ignore_args = On
|
|
||||||
; Desactiver les fonctions d'execution systeme : l'appli n'en a aucun usage
|
|
||||||
; legitime (anti-RCE en cas d'injection). Les scripts d'ops vivent cote cron/host.
|
|
||||||
disable_functions = exec,passthru,shell_exec,system,proc_open,popen
|
|
||||||
|
|
||||||
; --- OPcache (perf + stabilite) ---
|
; --- OPcache (perf + stabilite) ---
|
||||||
[opcache]
|
[opcache]
|
||||||
|
|
|
||||||
|
|
@ -1,102 +0,0 @@
|
||||||
# Forgejo Actions - runner (act_runner)
|
|
||||||
|
|
||||||
Prerequis d'infrastructure pour la CI/CD Wakdo. Les workflows vivent dans
|
|
||||||
`.forgejo/workflows/` (lot D) ; ils ne s'executent que si un `act_runner` est
|
|
||||||
enregistre et en ligne sur le serveur.
|
|
||||||
|
|
||||||
## Pourquoi un runner separe de la stack app
|
|
||||||
|
|
||||||
La stack `docker-compose.yml` de Wakdo = runtime applicatif (web, app, db, cron).
|
|
||||||
Le runner CI est du **tooling** : il se rattache au depot Forgejo, pas a l'app.
|
|
||||||
On le fait tourner comme service dedie sur l'hote stark (meme lecon que
|
|
||||||
"gh dans Docker = mauvaise idee", cf. journal session 6). Cela evite que la CI
|
|
||||||
puisse impacter le runtime, et garde un cycle de vie independant.
|
|
||||||
|
|
||||||
## 1. Obtenir le token de registration (action manuelle, niveau admin)
|
|
||||||
|
|
||||||
Le token vient de l'instance Forgejo, pas du repo. Dans l'UI Forgejo :
|
|
||||||
|
|
||||||
- niveau **repo** : `Settings > Actions > Runners > Create new runner`
|
|
||||||
- ou niveau **org/instance** : `Site Administration > Actions > Runners`
|
|
||||||
|
|
||||||
Recuperer le `REGISTRATION_TOKEN` affiche. Il est a usage unique pour
|
|
||||||
l'enregistrement (pas a versionner).
|
|
||||||
|
|
||||||
## 2. Enregistrer le runner (sur stark)
|
|
||||||
|
|
||||||
Setup reel en place (image `simplyforma/forgejo-runner` deja presente sur
|
|
||||||
l'hote, data dir sous `$HOME` car `/srv` non inscriptible par `corentin`).
|
|
||||||
Le conteneur tourne sous l'uid de l'hote (`--user`) pour pouvoir ecrire
|
|
||||||
`.runner` dans le volume monte.
|
|
||||||
|
|
||||||
```bash
|
|
||||||
DATA=/home/corentin/forgejo-runner-wakdo
|
|
||||||
mkdir -p "$DATA"
|
|
||||||
|
|
||||||
docker run --rm \
|
|
||||||
--user "$(id -u):$(id -g)" \
|
|
||||||
-v "$DATA":/data --workdir /data \
|
|
||||||
--entrypoint forgejo-runner \
|
|
||||||
simplyforma/forgejo-runner:12.10.2 \
|
|
||||||
register --no-interactive \
|
|
||||||
--instance https://git.acadenice.com \
|
|
||||||
--token "<REGISTRATION_TOKEN>" \
|
|
||||||
--name stark-wakdo \
|
|
||||||
--labels 'docker:docker://node:20-bookworm,php-ci:docker://php:8.3-cli'
|
|
||||||
```
|
|
||||||
|
|
||||||
L'enregistrement ecrit `$DATA/.runner` (contient le secret du runner - ne pas
|
|
||||||
versionner, ne pas sortir de l'hote). Runner enregistre le 2026-06-15
|
|
||||||
(uuid `e4a3dbef-...`, labels `docker` + `php-ci`).
|
|
||||||
|
|
||||||
## 3. Lancer le runner en service
|
|
||||||
|
|
||||||
```bash
|
|
||||||
DATA=/home/corentin/forgejo-runner-wakdo
|
|
||||||
DOCKER_GID=$(stat -c '%g' /var/run/docker.sock)
|
|
||||||
|
|
||||||
docker run -d --restart=always \
|
|
||||||
--name forgejo-runner-wakdo \
|
|
||||||
--user "$(id -u):$(id -g)" \
|
|
||||||
--group-add "$DOCKER_GID" \
|
|
||||||
-e HOME=/data \
|
|
||||||
-v "$DATA":/data --workdir /data \
|
|
||||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
|
||||||
--entrypoint forgejo-runner \
|
|
||||||
simplyforma/forgejo-runner:12.10.2 \
|
|
||||||
daemon
|
|
||||||
```
|
|
||||||
|
|
||||||
Notes :
|
|
||||||
- `--group-add $DOCKER_GID` : acces au socket Docker pour executer les jobs
|
|
||||||
dans des conteneurs (sans tourner en root).
|
|
||||||
- `-e HOME=/data` : evite l'erreur `mkdir /.cache: permission denied` (le cache
|
|
||||||
server interne ecrit sous `$HOME`).
|
|
||||||
- Verifier `docker logs forgejo-runner-wakdo` : `declared successfully` +
|
|
||||||
`[poller] launched`, et `Settings > Actions > Runners` doit montrer `stark-wakdo` **Idle**.
|
|
||||||
- Prerequis cote depot : **Actions activees** (`Settings > Actions` du depot).
|
|
||||||
|
|
||||||
## 4. Labels et usage en workflow
|
|
||||||
|
|
||||||
Les jobs ciblent un label via `runs-on`. Pour la CI PHP de Wakdo :
|
|
||||||
|
|
||||||
```yaml
|
|
||||||
jobs:
|
|
||||||
ci:
|
|
||||||
runs-on: docker # image par defaut node:20-bookworm
|
|
||||||
# les etapes installent/php via le conteneur ou une action setup-php
|
|
||||||
```
|
|
||||||
|
|
||||||
## Securite du runner
|
|
||||||
|
|
||||||
- Le `.runner` (secret) reste sur l'hote, hors du repo.
|
|
||||||
- Le socket Docker monte donne un acces privilegie : le runner ne doit executer
|
|
||||||
que des workflows du depot Wakdo (runner dedie au repo, pas partage).
|
|
||||||
- Roter le secret = re-enregistrer avec un nouveau token et supprimer l'ancien
|
|
||||||
runner dans l'UI.
|
|
||||||
|
|
||||||
## Lien avec les autres lots
|
|
||||||
|
|
||||||
- **Lot C** : ce document + prerequis infra.
|
|
||||||
- **Lot D** : `.forgejo/workflows/ci.yml` (PHPUnit + PHPStan + secret-scan gitleaks)
|
|
||||||
et auto-merge des PR sur CI verte (strategie solo dev validee).
|
|
||||||
|
|
@ -1,64 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
#
|
|
||||||
# Wakdo - applique (idempotent) les regles de protection de branche sur Forgejo.
|
|
||||||
#
|
|
||||||
# Pourquoi un script versionne : la regle de gouvernance devient reproductible
|
|
||||||
# et auditable (Cr 7.b), pas un clic dans une UI. Roter le token = editer .env.
|
|
||||||
#
|
|
||||||
# Regle posee :
|
|
||||||
# - main et dev : push direct interdit (PR obligatoire), force-push bloque
|
|
||||||
# - required_approvals = 0 (travail solo : on ne peut pas approuver sa propre PR)
|
|
||||||
# - status check : OPTIONNEL via REQUIRE_CI=1, contextes dans CI_CONTEXTS
|
|
||||||
# (a activer en lot D, une fois les jobs .forgejo/workflows/ nommes ;
|
|
||||||
# activer avant que le workflow n'existe bloquerait tout merge)
|
|
||||||
#
|
|
||||||
# Usage :
|
|
||||||
# scripts/forgejo-branch-protection.sh # baseline (PR requise)
|
|
||||||
# REQUIRE_CI=1 CI_CONTEXTS='ci' scripts/forgejo-branch-protection.sh # + CI verte requise
|
|
||||||
#
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
REPO_API="https://git.acadenice.com/api/v1/repos/AcadeNice/corentin_wakdo"
|
|
||||||
ENV_FILE="$(cd "$(dirname "$0")/.." && pwd)/.env"
|
|
||||||
|
|
||||||
TOKEN="$(grep -E '^FORGEJO_TOKEN=' "$ENV_FILE" | cut -d= -f2-)"
|
|
||||||
if [ -z "${TOKEN:-}" ]; then
|
|
||||||
echo "ERREUR : FORGEJO_TOKEN absent de $ENV_FILE" >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
REQUIRE_CI="${REQUIRE_CI:-0}"
|
|
||||||
CI_CONTEXTS="${CI_CONTEXTS:-ci}"
|
|
||||||
|
|
||||||
# Construit le tableau JSON des contextes de status check si REQUIRE_CI=1.
|
|
||||||
status_check_json="false"
|
|
||||||
contexts_json="[]"
|
|
||||||
if [ "$REQUIRE_CI" = "1" ]; then
|
|
||||||
status_check_json="true"
|
|
||||||
contexts_json="$(printf '%s' "$CI_CONTEXTS" | awk -F, '{printf "["; for(i=1;i<=NF;i++){printf "%s\"%s\"", (i>1?",":""), $i}; printf "]"}')"
|
|
||||||
fi
|
|
||||||
|
|
||||||
for branch in main dev; do
|
|
||||||
payload=$(cat <<JSON
|
|
||||||
{
|
|
||||||
"branch_name": "$branch",
|
|
||||||
"enable_push": false,
|
|
||||||
"enable_force_push": false,
|
|
||||||
"required_approvals": 0,
|
|
||||||
"enable_status_check": $status_check_json,
|
|
||||||
"status_check_contexts": $contexts_json
|
|
||||||
}
|
|
||||||
JSON
|
|
||||||
)
|
|
||||||
# PATCH si la protection existe, sinon POST pour la creer.
|
|
||||||
if curl -sf -o /dev/null -H "Authorization: token $TOKEN" "$REPO_API/branch_protections/$branch"; then
|
|
||||||
method=PATCH; url="$REPO_API/branch_protections/$branch"
|
|
||||||
else
|
|
||||||
method=POST; url="$REPO_API/branch_protections"
|
|
||||||
fi
|
|
||||||
echo "[$branch] $method (status_check=$status_check_json contexts=$contexts_json)"
|
|
||||||
curl -s -X "$method" -H "Authorization: token $TOKEN" -H "Content-Type: application/json" \
|
|
||||||
-d "$payload" "$url" >/dev/null
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "OK - protections appliquees sur main et dev."
|
|
||||||
|
|
@ -1,59 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
#
|
|
||||||
# Wakdo - ouvre une PR Forgejo et planifie son auto-merge quand la CI passe.
|
|
||||||
#
|
|
||||||
# Strategie solo dev : la PR reste obligatoire (trace de gouvernance, Cr 4.f)
|
|
||||||
# mais le merge se declenche tout seul des que les checks requis sont verts.
|
|
||||||
# Prerequis : status checks requis sur la branche de base
|
|
||||||
# (voir scripts/forgejo-branch-protection.sh avec REQUIRE_CI=1).
|
|
||||||
#
|
|
||||||
# Usage :
|
|
||||||
# scripts/forgejo-pr-automerge.sh [HEAD] [BASE] ["Titre"]
|
|
||||||
# Defauts : HEAD = branche courante, BASE = dev, titre = dernier sujet de commit.
|
|
||||||
#
|
|
||||||
set -euo pipefail
|
|
||||||
|
|
||||||
REPO_API="https://git.acadenice.com/api/v1/repos/AcadeNice/corentin_wakdo"
|
|
||||||
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
||||||
ENV_FILE="$ROOT/.env"
|
|
||||||
|
|
||||||
TOKEN="$(grep -E '^FORGEJO_TOKEN=' "$ENV_FILE" | cut -d= -f2-)"
|
|
||||||
[ -n "${TOKEN:-}" ] || { echo "ERREUR : FORGEJO_TOKEN absent de $ENV_FILE" >&2; exit 1; }
|
|
||||||
|
|
||||||
HEAD="${1:-$(git -C "$ROOT" rev-parse --abbrev-ref HEAD)}"
|
|
||||||
BASE="${2:-dev}"
|
|
||||||
TITLE="${3:-$(git -C "$ROOT" log -1 --pretty=%s "$HEAD")}"
|
|
||||||
|
|
||||||
if [ "$BASE" = "main" ] && [ "$HEAD" != "dev" ]; then
|
|
||||||
echo "Garde-fou : seules les PR depuis 'dev' visent 'main'. Abandon." >&2
|
|
||||||
exit 1
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "PR : $HEAD -> $BASE"
|
|
||||||
echo "Titre : $TITLE"
|
|
||||||
|
|
||||||
# 1. Creer la PR (ou recuperer l'index si elle existe deja).
|
|
||||||
create_resp=$(curl -s -X POST -H "Authorization: token $TOKEN" -H "Content-Type: application/json" \
|
|
||||||
-d "$(printf '{"head":"%s","base":"%s","title":"%s"}' "$HEAD" "$BASE" "$TITLE")" \
|
|
||||||
"$REPO_API/pulls")
|
|
||||||
index=$(printf '%s' "$create_resp" | python3 -c "import sys,json;d=json.load(sys.stdin);print(d.get('number',''))" 2>/dev/null || true)
|
|
||||||
|
|
||||||
if [ -z "$index" ]; then
|
|
||||||
# PR deja existante : la retrouver par branche head.
|
|
||||||
index=$(curl -s -H "Authorization: token $TOKEN" "$REPO_API/pulls?state=open&limit=50" \
|
|
||||||
| python3 -c "import sys,json;hs='$HEAD';d=json.load(sys.stdin);print(next((p['number'] for p in d if p['head']['ref']==hs),''))" 2>/dev/null || true)
|
|
||||||
fi
|
|
||||||
[ -n "$index" ] || { echo "Impossible de creer/trouver la PR. Reponse : $create_resp" >&2; exit 1; }
|
|
||||||
echo "PR #$index"
|
|
||||||
|
|
||||||
# 2. Planifier l'auto-merge (squash) quand les checks requis sont verts.
|
|
||||||
merge_resp=$(curl -s -o /dev/null -w "%{http_code}" -X POST \
|
|
||||||
-H "Authorization: token $TOKEN" -H "Content-Type: application/json" \
|
|
||||||
-d '{"Do":"squash","merge_when_checks_succeed":true,"delete_branch_after_merge":false}' \
|
|
||||||
"$REPO_API/pulls/$index/merge")
|
|
||||||
|
|
||||||
case "$merge_resp" in
|
|
||||||
200|201|202) echo "Auto-merge planifie sur PR #$index (squash a la CI verte)." ;;
|
|
||||||
405) echo "PR #$index : merge differe - checks pas encore verts, auto-merge en attente." ;;
|
|
||||||
*) echo "Reponse merge HTTP $merge_resp sur PR #$index (verifier l'etat des checks / protections)." ;;
|
|
||||||
esac
|
|
||||||
Loading…
Add table
Reference in a new issue