Audit pré-publication portfolio Astro + Cloudflare
Checklist complète avant de mettre en ligne un site Astro sur Cloudflare Pages : agent-readiness, sécurité HTTP, supply chain, exposition PII, SEO, a11y.
[TUTO-15] Audit pré-publication portfolio Astro + Cloudflare
Objectif
Passer une grille d’audit en 6 catégories avant de mettre un site public en ligne. L’ordre est délibéré : les audits bloquants (PII, sécurité, supply chain) passent avant les audits de confort (agent readiness, SEO, performance). Un seul point 🔴 non validé = ne pas mettre en ligne.
Prérequis
- Site Astro avec pnpm, déployé sur Cloudflare Pages via Cloudflare Tunnel
- Domaine DNS géré par Cloudflare
exiftoolinstallé (sudo apt install libimage-exiftool-perl)
Étape 1 — Exposition PII et données personnelles 🔴 Bloquant
Scanner le repo git en entier (historique compris) :
# Emails, tokens, clés dans l'historique git
git log --all --full-history -- . | xargs git show --stat 2>/dev/null | head -50
git log -p --all | grep -iE "(email|@gmail|@proton|token|secret|ghp_|sk-)" | head -20
# EXIF des images livrées
find public/ -name "*.jpg" -o -name "*.png" -o -name "*.webp" \
| xargs exiftool -Author -Creator -Comment -GPS 2>/dev/null | grep -v "^$"
# Emails en clair dans le HTML généré
grep -rn "@" dist/ --include="*.html" | grep -v "node_modules"
⚠️ Sécurité : un email en clair dans le HTML est scrappable par n’importe quel bot. C’est acceptable pour un portfolio de contact — c’est un risque spam conscient, pas une fuite. En revanche un token ou une clé API dans le HTML ou dans le git log = rotation immédiate avant toute mise en ligne.
Checklist ☑ :
-
git log -p→ aucun secret dans l’historique - EXIF images → aucune donnée GPS ou identifiant personnel
- Décision documentée sur les emails en clair (intentionnel ou encodé)
Étape 2 — Sécurité HTTP 🔴 Bloquant
Vérifier les headers de réponse (avec le site déjà déployé sur Cloudflare Pages) :
TARGET="https://ton-domaine.fr"
# Headers de sécurité
curl -sI "$TARGET" | grep -iE \
"(content-security|x-frame|x-content-type|strict-transport|permissions-policy|referrer)"
# Vérification avec securityheaders.com
curl -s "https://securityheaders.com/?q=${TARGET}&followRedirects=on" \
| grep -oE 'grade-[A-F+]' | head -1
Vérifier dans public/_headers (Cloudflare Pages) que ces directives sont présentes :
Content-Security-Policy— inclurescript-srcrestrictifX-Frame-Options: DENYX-Content-Type-Options: nosniffStrict-Transport-Security: max-age=31536000; includeSubDomainsPermissions-Policy: camera=(), microphone=(), geolocation=()
⚠️ Sécurité : si un script tiers est chargé (ex: Cloudflare Insights Beacon), son domaine doit apparaître dans
script-src. Un script externe hors CSP est silencieusement bloqué mais aucune alerte n’est générée — piège classique. Challenge : est-ce que les analytics Cloudflare sont vraiment nécessaires si le dashboard Tunnel donne déjà les métriques de trafic ?
Vérifier l’exposition de l’IP origin Hetzner :
# L'IP Hetzner ne doit JAMAIS apparaître dans les headers Cloudflare
curl -sI "$TARGET" | grep -iE "(server|via|x-powered|cf-ray)"
# Vérification DNS : seul Cloudflare doit être résolvable
dig +short ton-domaine.fr
# Attendu : IPs Cloudflare (104.x.x.x ou 172.x.x.x) — jamais l'IP Hetzner directe
⚠️ Sécurité : si vault.ton-domaine.fr et ton portfolio partagent le même VPS Hetzner, une fuite d’IP origin sur le portfolio expose aussi l’endpoint MCP du vault. Ces deux sous-domaines partagent la même surface d’attaque — auditer ensemble.
Checklist ☑ :
-
securityheaders.com→ grade A ou A+ - IP Hetzner absente des headers et DNS public
- Script tiers (Beacon CF) : décision intentionnelle documentée
Étape 3 — Supply chain et dépendances 🔴 Bloquant
# Audit des vulnérabilités (pnpm, pas npm audit)
pnpm audit --audit-level moderate
# Scripts tiers chargés depuis CDN externes dans le HTML généré
grep -rn 'src="https://' dist/ --include="*.html" | grep -v "cloudflare\|fonts.googleapis"
# Vérifier que les versions sont fixées (pas de ^ ou ~ sur les dépendances critiques)
cat package.json | jq '.dependencies, .devDependencies' | grep -E '"\^|"~'
⚠️ Sécurité : chaque dépendance avec
^peut être mise à jour automatiquement parpnpm installvers une version mineure qui peut introduire du code malveillant (supply chain attack). Pour un portfolio statique public, c’est un risque modéré mais documenté. Pinner les versions critiques.
Checklist ☑ :
-
pnpm audit→ 0 vulnérabilités high/critical - Scripts CDN tiers identifiés et justifiés
Étape 4 — Agent readiness 🟠
TARGET="https://ton-domaine.fr"
# robots.txt
curl -s "$TARGET/robots.txt"
# Attendu : User-agent: *, Sitemap: https://...
# sitemap.xml
curl -sI "$TARGET/sitemap.xml" | grep "HTTP/"
# Attendu : HTTP/2 200
# llms.txt
curl -sI "$TARGET/llms.txt" | grep "HTTP/"
# Attendu : HTTP/2 200 (à créer si absent)
# Vérification complète → lancer isitagentready.com après déploiement
Créer public/llms.txt si absent. Format minimal :
# [Prénom Nom] — Portfolio
> Portfolio professionnel d'architecte solutions.
## Sections
- /tutos/ : tutoriels techniques open source
- /about/ : profil et expérience
## Contact
- Email : [email]
- GitHub : [url]
⚠️ llms.txt n’est pas un standard officiel mais devient un signal fort pour les agents qui crawlent le web. Le négliger n’est pas bloquant mais c’est une occasion manquée si le portfolio cible une audience tech.
Checklist ☑ :
-
robots.txt: présent, Sitemap référencé -
sitemap.xml: présent et valide -
llms.txt: présent -
isitagentready.compassé après déploiement
Étape 5 — SEO 🟡
# Balises meta dans les pages HTML générées
grep -n "og:title\|og:description\|og:image\|twitter:card" dist/index.html
# Alt text sur les images
grep -n '<img' dist/index.html | grep -v 'alt="'
# Attendu : 0 résultat (toutes les images ont un alt)
# Canonical URLs
grep "canonical" dist/index.html
Checklist ☑ :
- Open Graph : title, description, image présents
-
<img>sansalt: 0 occurrence - Canonical URL défini
Étape 6 — Performance 🟡
Après déploiement uniquement :
# PageSpeed Insights API (ou manuellement sur web.dev/measure)
curl "https://www.googleapis.com/pagespeedonline/v5/runPagespeed?url=https://ton-domaine.fr&strategy=mobile" \
| jq '.lighthouseResult.categories | {perf: .performance.score, a11y: .accessibility.score}'
Checklist ☑ :
- Score performance mobile > 90
- Score a11y > 90
Étape 7 — Ordre d’exécution recommandé
| Ordre | Étape | Bloquant ? |
|---|---|---|
| 1 | PII et historique git | 🔴 Oui |
| 2 | Sécurité HTTP + IP origin | 🔴 Oui |
| 3 | Supply chain pnpm | 🔴 Oui |
| 4 | Agent readiness | 🟠 Avant live |
| 5 | SEO | 🟡 Post-live OK |
| 6 | Performance | 🟡 Post-live OK |
Un seul point 🔴 non validé = ne pas mettre en ligne.
Dépannage
| Problème | Vérification |
|---|---|
pnpm audit retourne des erreurs réseau | Vérifier le proxy ou utiliser pnpm audit --no-optional |
securityheaders.com ne charge pas les headers | Tester avec curl -sI directement |
dig retourne l’IP Hetzner | Le proxy Cloudflare n’est pas activé (orange cloud dans DNS) |
exiftool non disponible | sudo apt install libimage-exiftool-perl |
Références
- Cloudflare agent readiness : https://blog.cloudflare.com/agent-readiness/
- isitagentready.com
- securityheaders.com
- web.dev/measure
- 00-meta/securite-checklist — procédure de sécurité inline