diff --git a/.github/workflows/deploy-ovh-ftp.yml b/.github/workflows/deploy-ovh-ftp.yml index 05b7ead..4096016 100644 --- a/.github/workflows/deploy-ovh-ftp.yml +++ b/.github/workflows/deploy-ovh-ftp.yml @@ -59,3 +59,6 @@ jobs: env: DEPLOY_TARGET_SKIP_BUILD: "0" run: bash scripts/deploy-ovh-ftp-target.sh "${{ inputs.target }}" + + - name: Verify public target + run: node scripts/verify-public-target.mjs "${{ inputs.target }}" diff --git a/docs/SPRINT-PLAYBOOK-2026-03-02.md b/docs/SPRINT-PLAYBOOK-2026-03-02.md index 9c57592..b2133e9 100644 --- a/docs/SPRINT-PLAYBOOK-2026-03-02.md +++ b/docs/SPRINT-PLAYBOOK-2026-03-02.md @@ -42,6 +42,7 @@ PUBLIC_SITE_URL=https://www.lelectronrare.fr/preview/ npm run build:external - workflow GitHub Actions: `deploy-ovh-ftp.yml` - target: `preview` - remote attendu: `/www/preview` +- verification publique automatique post-deploy via `scripts/verify-public-target.mjs` ### B3 - Verification preview ```bash @@ -61,6 +62,7 @@ curl -fsSI https://www.lelectronrare.fr/preview/mentions-legales/ - workflow GitHub Actions: `deploy-ovh-ftp.yml` - target: `production` - remote attendu: `/www` +- verification publique automatique post-deploy via `scripts/verify-public-target.mjs` ### C3 - Verification production ```bash diff --git a/docs/project-master-todos.md b/docs/project-master-todos.md index 683db40..a2cf4cf 100644 --- a/docs/project-master-todos.md +++ b/docs/project-master-todos.md @@ -25,6 +25,7 @@ Source of truth: this file for execution priorities, plus the current code in `s - [x] Reliquats CSS `.site-contrast-toggle` supprimes du source actif. - [x] Build preview local `PUBLIC_SITE_URL=/preview/` repasse propre. - [x] Validation tracking recalee sur le contrat Astro actif. +- [x] Workflow OVH enrichi avec verification HTTP publique post-deploiement. - [ ] White-contrast pass verifiee visuellement sur preview. - [ ] White-contrast pass verifiee visuellement sur production. diff --git a/scripts/verify-public-target.mjs b/scripts/verify-public-target.mjs new file mode 100644 index 0000000..439d6c6 --- /dev/null +++ b/scripts/verify-public-target.mjs @@ -0,0 +1,72 @@ +const target = process.argv[2] || 'preview'; + +function normalizeUrl(value) { + return value.endsWith('/') ? value : `${value}/`; +} + +function resolveBaseUrl() { + if (target === 'preview') { + return process.env.PUBLIC_SITE_URL_PREVIEW; + } + + if (target === 'production' || target === 'prod') { + return process.env.PUBLIC_SITE_URL_PROD || process.env.PUBLIC_SITE_URL; + } + + throw new Error(`Unknown target "${target}". Use "preview" or "production".`); +} + +const baseUrl = resolveBaseUrl(); + +if (!baseUrl) { + throw new Error(`Missing public base URL for target "${target}".`); +} + +const rootUrl = normalizeUrl(baseUrl); +const formationUrl = new URL('formation/', rootUrl).href; +const legalUrl = new URL('mentions-legales/', rootUrl).href; + +const checks = [ + { + url: rootUrl, + includes: ['data-theme="high-contrast"', 'Électronique embarquée du signal au produit'], + excludes: ['Mode contraste'] + }, + { + url: formationUrl, + includes: ['Formation'] + }, + { + url: legalUrl, + includes: ['Mentions légales'] + } +]; + +for (const check of checks) { + const response = await fetch(check.url, { + headers: { + 'user-agent': 'electron-rare-gh-verify/1.0' + }, + redirect: 'follow' + }); + + if (!response.ok) { + throw new Error(`HTTP ${response.status} for ${check.url}`); + } + + const text = await response.text(); + + for (const needle of check.includes || []) { + if (!text.includes(needle)) { + throw new Error(`Missing "${needle}" in ${check.url}`); + } + } + + for (const needle of check.excludes || []) { + if (text.includes(needle)) { + throw new Error(`Unexpected "${needle}" in ${check.url}`); + } + } +} + +console.log(`Public verification passed for ${target}: ${rootUrl}`);