From e409d169549bfbb55a6d03c117ac38ea76665d56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Arnulfo=20R=2E=20H=2E?= Date: Sun, 27 Sep 2026 09:45:59 -0500 Subject: [PATCH] fix: fijar Supabase JS y verificar recursos CDN con SRI --- .github/workflows/site-validation.yml | 3 +-- 2026/about.html | 2 +- 2026/agenda.html | 2 +- 2026/codigo_conducta.html | 2 +- 2026/convence-a-tu-jefe.html | 2 +- 2026/faq.html | 2 +- 2026/index.html | 2 +- 2026/patrocinadores.html | 2 +- 2026/ponentes.html | 4 +-- 2026/privacidad.html | 2 +- 2026/registro.html | 4 +-- 2026/sedes.html | 2 +- 2026/voluntariado/index.html | 4 +-- README.md | 28 +++++++++++++++++++ tests/cdn-integrity.cjs | 39 +++++++++++++++++++++++++++ 15 files changed, 83 insertions(+), 17 deletions(-) create mode 100644 tests/cdn-integrity.cjs diff --git a/.github/workflows/site-validation.yml b/.github/workflows/site-validation.yml index d446a4f..9d4535c 100644 --- a/.github/workflows/site-validation.yml +++ b/.github/workflows/site-validation.yml @@ -38,7 +38,6 @@ jobs: node --check tests/consent-coc.cjs - name: Check consent persistence and Code of Conduct version run: | - node --test tests/consent-coc.cjs - node --test tests/voluntariado-page.cjs + node --test tests/*.cjs - name: Check whitespace errors run: git diff --check HEAD^ HEAD diff --git a/2026/about.html b/2026/about.html index ee5fe5e..9827dc6 100644 --- a/2026/about.html +++ b/2026/about.html @@ -22,7 +22,7 @@ - + diff --git a/2026/agenda.html b/2026/agenda.html index e6fcb31..66c27c1 100644 --- a/2026/agenda.html +++ b/2026/agenda.html @@ -22,7 +22,7 @@ - + diff --git a/2026/codigo_conducta.html b/2026/codigo_conducta.html index 6efad43..9c609af 100644 --- a/2026/codigo_conducta.html +++ b/2026/codigo_conducta.html @@ -22,7 +22,7 @@ - + diff --git a/2026/convence-a-tu-jefe.html b/2026/convence-a-tu-jefe.html index 5416a11..28e680b 100644 --- a/2026/convence-a-tu-jefe.html +++ b/2026/convence-a-tu-jefe.html @@ -22,7 +22,7 @@ - + diff --git a/2026/faq.html b/2026/faq.html index 4f51ee9..694e217 100644 --- a/2026/faq.html +++ b/2026/faq.html @@ -22,7 +22,7 @@ - + diff --git a/2026/index.html b/2026/index.html index 3632054..6d718f4 100644 --- a/2026/index.html +++ b/2026/index.html @@ -22,7 +22,7 @@ - + diff --git a/2026/patrocinadores.html b/2026/patrocinadores.html index 2041f32..5a158df 100644 --- a/2026/patrocinadores.html +++ b/2026/patrocinadores.html @@ -22,7 +22,7 @@ - + diff --git a/2026/ponentes.html b/2026/ponentes.html index 2f077cd..373f768 100644 --- a/2026/ponentes.html +++ b/2026/ponentes.html @@ -22,7 +22,7 @@ - + @@ -332,7 +332,7 @@

¿Por qué presentar en PyCon?

- + diff --git a/2026/privacidad.html b/2026/privacidad.html index 636b435..1f2e649 100644 --- a/2026/privacidad.html +++ b/2026/privacidad.html @@ -22,7 +22,7 @@ - + diff --git a/2026/registro.html b/2026/registro.html index 297c5aa..908a321 100644 --- a/2026/registro.html +++ b/2026/registro.html @@ -22,7 +22,7 @@ - + @@ -338,7 +338,7 @@

PyCon Panamá 2026

- + diff --git a/2026/sedes.html b/2026/sedes.html index dafa233..874b17f 100644 --- a/2026/sedes.html +++ b/2026/sedes.html @@ -22,7 +22,7 @@ - + diff --git a/2026/voluntariado/index.html b/2026/voluntariado/index.html index 3d2dc05..8a68193 100644 --- a/2026/voluntariado/index.html +++ b/2026/voluntariado/index.html @@ -22,7 +22,7 @@ - + @@ -221,7 +221,7 @@

Construyamos PyCon juntos

- + diff --git a/README.md b/README.md index 82aa4d5..b98b93b 100644 --- a/README.md +++ b/README.md @@ -14,6 +14,7 @@ Este repositorio contiene el sitio público de [PyCon Panamá](https://pycon.pa/ - [Estructura y alcance](#estructura-y-alcance) - [Cambiar el sitio](#cambiar-el-sitio) - [Validar antes de proponer cambios](#validar-antes-de-proponer-cambios) +- [Actualizar recursos CDN e integridad](#actualizar-recursos-cdn-e-integridad) - [Despliegue](#despliegue) - [Contribuir](#contribuir) - [Documentación y contacto](#documentación-y-contacto) @@ -107,6 +108,33 @@ git diff --check git diff -- 2026/ netlify.toml sitemap.xml robots.txt ``` +## Actualizar recursos CDN e integridad + +Última actualización: 27 de septiembre de 2026. + +La edición 2026 fija Supabase JS en `2.117.2` (`dist/umd/supabase.js`) y Font Awesome en `6.4.0` (`css/all.min.css`). Sus etiquetas llevan `integrity="sha384-…"` y `crossorigin="anonymous"`. La versión de Supabase corresponde a la que resolvía `@2` al realizar este cambio; el archivo UMD coincide con el distribuido en npm. + +Para actualizar cualquiera de estos recursos: + +1. Revisa las notas de la versión y elige una versión exacta; no uses `@2`, `latest` ni rangos. +2. Descarga la URL exacta en un archivo temporal fuera del repositorio y calcula SHA-384 sobre sus bytes. Por ejemplo, para la versión actual de Supabase: + + ```bash + cdn_file=$(mktemp) + curl --fail --location --silent --show-error --compressed \ + 'https://cdn.jsdelivr.net/npm/@supabase/supabase-js@2.117.2/dist/umd/supabase.js' \ + --output "$cdn_file" && + openssl dgst -sha384 -binary "$cdn_file" | openssl base64 -A + rm -f "$cdn_file" + ``` + +3. Anteponer `sha384-` al resultado da el valor de `integrity`. Para Font Awesome usa su URL exacta de cdnjs y el mismo procedimiento. Verifica el archivo contra la distribución oficial y comprueba que el CDN devuelve `Access-Control-Allow-Origin: *`. +4. Actualiza URL e integridad juntas en las tres páginas con Supabase (`registro.html`, `ponentes.html`, `voluntariado/index.html`) o en las doce páginas de 2026 con Font Awesome. Conserva `crossorigin="anonymous"`. No cambies las ediciones archivadas. +5. Ejecuta `node --test tests/*.cjs`, `python3 scripts/validate_site.py` y `git diff --check`. La prueba de CDN detecta versiones flotantes, atributos ausentes e inconsistencias entre páginas; verifica también el hash descargando los recursos, ya que esa prueba local no consulta la red. +6. Revisa el preview de Netlify: SDK e iconos deben cargar sin errores de SRI/CORS. Antes de probar envíos, confirma que el preview utiliza una base de pruebas aislada. Comprueba los flujos abiertos con datos sintéticos y conserva cerrado el formulario de ponencias mientras la convocatoria siga cerrada; su ruta de integración puede probarse con respuestas simuladas. + +Si el navegador rechaza un recurso, compara los bytes y la versión con el hash esperado; no retires `integrity` para sortear el fallo. SRI verifica el JS y la hoja CSS enlazados, no los archivos de fuentes que esa hoja descarga. Consulta [Subresource Integrity en MDN](https://developer.mozilla.org/en-US/docs/Web/Security/Defenses/Subresource_Integrity). + ## Despliegue Netlify publica la raíz del repositorio (`publish = "."`) según [`netlify.toml`](netlify.toml). La configuración redirige `/` a `/2026/` y define cabeceras de seguridad para el sitio. diff --git a/tests/cdn-integrity.cjs b/tests/cdn-integrity.cjs new file mode 100644 index 0000000..8fc3136 --- /dev/null +++ b/tests/cdn-integrity.cjs @@ -0,0 +1,39 @@ +const test = require('node:test'); +const assert = require('node:assert/strict'); +const fs = require('node:fs'); +const path = require('node:path'); + +function htmlFiles(directory) { + return fs.readdirSync(directory, { withFileTypes: true }).flatMap(entry => { + const file = path.join(directory, entry.name); + return entry.isDirectory() ? htmlFiles(file) : file.endsWith('.html') ? [file] : []; + }); +} + +test('los recursos CDN usan versiones exactas, SRI y CORS coherentes', () => { + const hashes = new Map(); + const sdkPages = []; + for (const file of htmlFiles('2026')) { + const html = fs.readFileSync(file, 'utf8'); + let fontAwesome = 0; + for (const [tag] of html.matchAll(/<(?:script|link)\b[^>]*>/g)) { + const attrs = Object.fromEntries([...tag.matchAll(/([\w-]+)="([^"]*)"/g)].map(m => [m[1], m[2]])); + const url = attrs.src || attrs.href || ''; + if (!url.includes('cdn.jsdelivr.net/npm/@supabase/') && !url.includes('cdnjs.cloudflare.com/ajax/libs/font-awesome/')) continue; + assert.equal(attrs.crossorigin, 'anonymous', file); + assert.match(attrs.integrity || '', /^sha384-[A-Za-z0-9+/]{64}$/, file); + if (url.includes('@supabase/')) { + assert.match(url, /^https:\/\/cdn\.jsdelivr\.net\/npm\/@supabase\/supabase-js@\d+\.\d+\.\d+\/dist\/umd\/supabase(?:\.min)?\.js$/, file); + sdkPages.push(file); + } else { + assert.match(url, /^https:\/\/cdnjs\.cloudflare\.com\/ajax\/libs\/font-awesome\/\d+\.\d+\.\d+\/css\/all\.min\.css$/, file); + fontAwesome++; + } + if (hashes.has(url)) assert.equal(attrs.integrity, hashes.get(url), file); + hashes.set(url, attrs.integrity); + } + assert.equal(fontAwesome, 1, file); + } + assert.deepEqual(sdkPages.sort(), ['2026/ponentes.html', '2026/registro.html', '2026/voluntariado/index.html']); + assert.equal(hashes.size, 2, 'Todas las páginas deben usar la misma versión de cada recurso'); +});