Files
mafabriqueadeco/.woodpecker.yml
syoul 88b7205dbb
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Restaure docker restart apres cache clear pour eviter le 500 sur HTTPS
Le cache PHP incohérent apres UPDATE en DB sans redemarrage causait
un 500 Internal Server Error sur les requetes HTTPS.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-03-20 17:01:39 +01:00

229 lines
10 KiB
YAML

when:
- branch: main
event: push
steps:
# Etape 1 : Validation syntaxique du docker-compose.yml
# Les vars CI (CI_REPO_OWNER, CI_COMMIT_BRANCH) sont injectees automatiquement par Woodpecker
- name: validate
image: docker:27-cli
volumes:
- /var/run/docker.sock:/var/run/docker.sock
environment:
DB_PASSWORD: placeholder
DB_ROOT_PASSWORD: placeholder
PRESTASHOP_ADMIN_EMAIL: placeholder
PRESTASHOP_ADMIN_PASSWORD: placeholder
PS_DOMAIN: placeholder
PS_ADMIN_FOLDER: placeholder
commands:
- |
export COMPOSE_PROJECT_NAME=$(printf '%s-%s-%s' "$CI_REPO_OWNER" "$CI_REPO_NAME" "$CI_COMMIT_BRANCH" | tr 'A-Z/' 'a-z-')
docker compose config --quiet
- echo "docker-compose.yml valide"
# Etape 2 : Verifications de securite
- name: security-check
image: alpine:3.20
commands:
- |
if [ -f .env ]; then
echo "ERREUR: .env ne doit pas etre commite dans le depot !"
exit 1
fi
- 'grep -q "^\.env$" .gitignore || (echo "ERREUR: .env manquant dans .gitignore" && exit 1)'
- echo "Verifications de securite OK"
# Etape 2b : Generation SBOM (Syft) — inventaire des composants des images Docker
# NOTE: volumes: et from_secret incompatibles dans le meme step — pas de secrets ici
- name: sbom-generate
image: alpine:3.20
volumes:
- /var/run/docker.sock:/var/run/docker.sock
commands:
- apk add --no-cache curl
- curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin latest
- mkdir -p .reports
- syft prestashop/prestashop:9.0.3-3.0-classic-8.3-apache -o cyclonedx-json --file .reports/sbom-prestashop.cyclonedx.json
- syft mariadb:10.11 -o cyclonedx-json --file .reports/sbom-mariadb.cyclonedx.json
- echo "SBOM generes $(ls .reports/sbom-*.json | wc -l) fichiers"
# Etape 2c : Scan CVE (Trivy) depuis les SBOM Syft
# Cache /opt/trivy-cache evite ~200Mo de telechargement des DB CVE a chaque build
# Prerequis sur sonic : mkdir -p /opt/trivy-cache
- name: sbom-scan
image: aquasec/trivy:latest
volumes:
- /home/syoul/trivy-cache:/root/.cache/trivy
commands:
- trivy sbom --format json --output .reports/trivy-prestashop.json .reports/sbom-prestashop.cyclonedx.json
- trivy sbom --format json --output .reports/trivy-mariadb.json .reports/sbom-mariadb.cyclonedx.json
- echo "Scan CVE termine"
# Etape 2d : Publication SBOM vers Dependency-Track
# NOTE: from_secret et volumes: incompatibles — pas de volumes ici
- name: sbom-publish
image: alpine/curl:latest
environment:
DTRACK_TOKEN:
from_secret: dependency_track_token
DTRACK_DOMAIN:
from_secret: dtrack_domain
commands:
- |
VERSION=$(date +%Y-%m-%d)-$(echo "$CI_COMMIT_SHA" | cut -c1-8)
HTTP=$(curl -s -o /tmp/dtrack-response.txt -w "%{http_code}" -X POST "https://$DTRACK_DOMAIN/api/v1/bom" \
-H "X-Api-Key: $DTRACK_TOKEN" \
-F "autoCreate=true" \
-F "projectName=mafabriqueadeco-app" \
-F "projectVersion=$VERSION" \
-F "bom=@.reports/sbom-prestashop.cyclonedx.json")
echo "HTTP $HTTP : $(cat /tmp/dtrack-response.txt)"
[ "$HTTP" -ge 200 ] && [ "$HTTP" -lt 300 ] || exit 1
- |
VERSION=$(date +%Y-%m-%d)-$(echo "$CI_COMMIT_SHA" | cut -c1-8)
HTTP=$(curl -s -o /tmp/dtrack-response.txt -w "%{http_code}" -X POST "https://$DTRACK_DOMAIN/api/v1/bom" \
-H "X-Api-Key: $DTRACK_TOKEN" \
-F "autoCreate=true" \
-F "projectName=mafabriqueadeco-db" \
-F "projectVersion=$VERSION" \
-F "bom=@.reports/sbom-mariadb.cyclonedx.json")
echo "HTTP $HTTP : $(cat /tmp/dtrack-response.txt)"
[ "$HTTP" -ge 200 ] && [ "$HTTP" -lt 300 ] || exit 1
# Etape 3a : Ecriture du .env depuis les secrets
# NOTE: ne pas utiliser ${VAR} dans commands (bug Woodpecker next), utiliser env | grep
# NOTE: from_secret et volumes: incompatibles dans le meme step (bug Woodpecker next)
- name: write-env
image: alpine:3.20
environment:
PS_DOMAIN:
from_secret: ps_domain
PS_ADMIN_FOLDER:
from_secret: ps_admin_folder
PRESTASHOP_ADMIN_EMAIL:
from_secret: prestashop_admin_email
PRESTASHOP_ADMIN_PASSWORD:
from_secret: prestashop_admin_password
DB_ROOT_PASSWORD:
from_secret: db_root_password
DB_PASSWORD:
from_secret: db_password
commands:
- env | grep -E "^(PS_DOMAIN|PS_ADMIN_FOLDER|PRESTASHOP_ADMIN_EMAIL|PRESTASHOP_ADMIN_PASSWORD|DB_ROOT_PASSWORD|DB_PASSWORD)=" > .env.deploy
# COMPOSE_PROJECT_NAME : convention user-project-branch, genere depuis les vars CI
- OWNER=$(echo "$CI_REPO_OWNER" | tr 'A-Z' 'a-z') && REPO=$(echo "$CI_REPO_NAME" | tr 'A-Z' 'a-z') && BRANCH=$(echo "$CI_COMMIT_BRANCH" | tr 'A-Z/' 'a-z-') && echo "COMPOSE_PROJECT_NAME=$OWNER-$REPO-$BRANCH" >> .env.deploy
- echo "Fichier .env.deploy cree ($(wc -c < .env.deploy) octets)"
# Etape 3b : Deploiement sur sonic via Docker socket
# Modele pipeline sonic : deploy Docker Compose + cert TLS (acme.sh)
# Registrator enregistre automatiquement le container dans Consul via les labels SERVICE_*
# et publie les routes dans Fabio sans intervention manuelle
- name: deploy
image: docker:27-cli
volumes:
- /var/run/docker.sock:/var/run/docker.sock
- /opt/mafabriqueadeco:/opt/mafabriqueadeco
commands:
- cp .env.deploy /opt/mafabriqueadeco/.env
- chmod 600 /opt/mafabriqueadeco/.env
- cp docker-compose.yml /opt/mafabriqueadeco/docker-compose.yml
- cd /opt/mafabriqueadeco && docker compose pull
- cd /opt/mafabriqueadeco && docker compose up -d --remove-orphans
- cd /opt/mafabriqueadeco && docker compose ps
- |
DOMAIN=$(grep '^PS_DOMAIN=' /opt/mafabriqueadeco/.env | cut -d= -f2)
# --- Certificat TLS (acme.sh via sonic-acme-1) ---
# acme.sh est idempotent : skip si cert valide, renouvelle si proche expiration
# Exit 0 = emis/renouvele, exit 2 = skip (domaine inchange), autres = erreur
# --home /etc/acme.sh = volume persistant sonic_acme (sinon /root/.acme.sh non persiste)
# || ACME_EXIT=$? capture le code sans declencher set -e (contrairement a ; ACME_EXIT=$?)
ACME_EXIT=0
docker exec sonic-acme-1 /app/acme.sh \
--home /etc/acme.sh \
--issue -d "$DOMAIN" \
--webroot /usr/share/nginx/html \
--server letsencrypt \
--accountemail support+acme@asycn.io || ACME_EXIT=$?
if [ "$ACME_EXIT" -ne 0 ] && [ "$ACME_EXIT" -ne 2 ]; then
echo "ERREUR: acme.sh a echoue (exit $ACME_EXIT)"
exit 1
fi
docker exec sonic-acme-1 cp /etc/acme.sh/$DOMAIN/fullchain.cer /host/certs/$DOMAIN-cert.pem
docker exec sonic-acme-1 cp /etc/acme.sh/$DOMAIN/$DOMAIN.key /host/certs/$DOMAIN-key.pem
echo "Cert TLS: /host/certs/$DOMAIN-cert.pem OK (acme exit $ACME_EXIT)"
# Etape 4 : Configuration post-deploiement (SSL, cache)
# Attend la fin de l'installation PrestaShop (ps_configuration initialisee),
# puis active SSL dans la DB (PrestaShop genere des URLs https:// grace a X-Forwarded-Proto:https de Fabio)
- name: configure
image: docker:27-cli
volumes:
- /var/run/docker.sock:/var/run/docker.sock
commands:
- |
PROJECT=$(grep '^COMPOSE_PROJECT_NAME=' .env.deploy | cut -d= -f2)
DB_PASS=$(grep '^DB_PASSWORD=' .env.deploy | cut -d= -f2)
echo "Attente fin installation PrestaShop (ps_configuration)..."
MAX=60
i=0
until [ $i -ge $MAX ]; do
READY=$(docker exec "$PROJECT-db" mysql -uprestashop -p"$DB_PASS" -se \
"SELECT COUNT(*) FROM prestashop.ps_configuration WHERE name='PS_SSL_ENABLED';" 2>/dev/null || echo 0)
if [ "$READY" -gt "0" ] 2>/dev/null; then
echo "Base prete, activation SSL..."
docker exec "$PROJECT-db" mysql -uprestashop -p"$DB_PASS" prestashop -e \
"UPDATE ps_configuration SET value='1' WHERE name='PS_SSL_ENABLED';"
docker exec "$PROJECT-db" mysql -uprestashop -p"$DB_PASS" prestashop -e \
"UPDATE ps_configuration SET value='0' WHERE name='PS_SSL_ENABLED_EVERYWHERE';"
docker exec "$PROJECT-app" rm -rf /var/www/html/install/ 2>/dev/null || true
docker exec "$PROJECT-app" rm -rf /var/www/html/var/cache/prod/ 2>/dev/null || true
docker restart "$PROJECT-app"
echo "PS_SSL_ENABLED=1, PS_SSL_ENABLED_EVERYWHERE=0, install supprime, cache efface, app redemarree"
break
fi
i=$((i+1))
echo "Tentative $i/$MAX - installation en cours..."
sleep 10
done
[ $i -ge $MAX ] && echo "AVERTISSEMENT: timeout configure SSL" || true
# Etape 5 : Healthcheck post-deploiement
- name: healthcheck
image: alpine:3.20
commands:
- apk add --no-cache --quiet curl
- |
SITE=$(grep '^PS_DOMAIN=' .env.deploy | cut -d= -f2)
if [ -z "$SITE" ]; then
echo "ERREUR: PS_DOMAIN non defini dans .env.deploy"
exit 1
fi
TARGET="http://$SITE"
echo "Healthcheck sur $TARGET (max 10 minutes)..."
MAX=60
i=0
until [ $i -ge $MAX ]; do
CODE=$(curl -sSo /dev/null -w "%{http_code}" "$TARGET" 2>/dev/null)
echo "Tentative $((i+1))/$MAX - HTTP $CODE"
if [ "$CODE" = "200" ] || [ "$CODE" = "301" ] || [ "$CODE" = "302" ]; then
echo "PrestaShop repond correctement sur $TARGET"
exit 0
fi
i=$((i+1))
sleep 10
done
echo "ERREUR: PrestaShop ne repond pas apres 10 minutes"
exit 1
# Notification en cas d'echec
- name: notify-failure
image: alpine:3.20
commands:
- 'echo "ECHEC pipeline #$CI_BUILD_NUMBER sur commit $CI_COMMIT_SHA"'
- 'echo "Branche: $CI_COMMIT_BRANCH"'
when:
- status: failure