ci(security): Forgejo Actions CI (gitleaks + php-lint + guarded phpstan/phpunit), SECURITY.md, PR auto-merge script
This commit is contained in:
parent
bf82ba25e6
commit
84ed730e8d
3 changed files with 195 additions and 0 deletions
81
.forgejo/workflows/ci.yml
Normal file
81
.forgejo/workflows/ci.yml
Normal file
|
|
@ -0,0 +1,81 @@
|
||||||
|
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
|
||||||
55
SECURITY.md
Normal file
55
SECURITY.md
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
# 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.
|
||||||
59
scripts/forgejo-pr-automerge.sh
Executable file
59
scripts/forgejo-pr-automerge.sh
Executable file
|
|
@ -0,0 +1,59 @@
|
||||||
|
#!/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