From 6574d5c29094b375e6f8e85ff96881671539d89b Mon Sep 17 00:00:00 2001 From: Juank de Gorvet Date: Sun, 25 Oct 2026 03:01:47 -0400 Subject: [PATCH 1/5] Comprueba Redis real, MySQL PHP 8.4 y routing Nginx CGI en CI --- .github/workflows/tests.yml | 57 +++++++++ .../verificacion-infraestructura-20261025.md | 13 ++ tests/RedisSessionIntegrationTest.php | 112 ++++++++++++++++++ 3 files changed, 182 insertions(+) create mode 100644 maintenance/verificacion-infraestructura-20261025.md create mode 100644 tests/RedisSessionIntegrationTest.php diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1a38d46..61444bc 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -87,6 +87,63 @@ jobs: GFRAME_TEST_NGINX: /usr/sbin/nginx GFRAME_TEST_PHP_FPM: /usr/sbin/php-fpm8.3 + infrastructure-84: + name: MySQL, HTTP y Redis reales con PHP 8.4 + runs-on: ubuntu-24.04 + services: + mysql: + image: mysql:8.0 + env: + MYSQL_ROOT_PASSWORD: gframe_test + ports: + - 3306:3306 + options: >- + --health-cmd="mysqladmin ping -h 127.0.0.1 -pgframe_test" + --health-interval=10s --health-timeout=5s --health-retries=10 + redis: + image: redis:7-alpine + ports: + - 6379:6379 + options: >- + --health-cmd="redis-cli ping" + --health-interval=5s --health-timeout=3s --health-retries=10 + env: + GFRAME_TEST_MYSQL: '1' + GFRAME_TEST_MYSQL_DSN: mysql:host=127.0.0.1;port=3306 + GFRAME_TEST_MYSQL_USER: root + GFRAME_TEST_MYSQL_PASSWORD: gframe_test + GFRAME_TEST_REDIS: '1' + steps: + - uses: actions/checkout@v4 + - uses: shivammathur/setup-php@v2 + with: + php-version: '8.4' + extensions: mbstring, openssl, pdo_mysql, pdo_sqlite, redis + coverage: none + - uses: ramsey/composer-install@v3 + with: + dependency-versions: locked + - run: php packages/phpunit/phpunit/phpunit --filter 'MySqlMigrationIntegration|DatabasePreflight|InstallerTest|InstallerHttp|InstallerWizardHttp|RedisSessionIntegration' --fail-on-skipped + + nginx-cgi: + name: Routing real con Nginx y PHP-CGI + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - uses: shivammathur/setup-php@v2 + with: + php-version: '8.3' + extensions: mbstring, openssl, pdo_sqlite + coverage: none + - uses: ramsey/composer-install@v3 + with: + dependency-versions: locked + - run: sudo apt-get update && sudo apt-get install -y nginx php8.3-cgi php8.3-sqlite3 php8.3-mbstring php8.3-xml + - run: php packages/phpunit/phpunit/phpunit --filter 'ServerRoutingTest::testRealNginxRoutesRequestsAndServerErrorsToTheInstalledFramework' --fail-on-skipped + env: + GFRAME_TEST_NGINX: /usr/sbin/nginx + GFRAME_TEST_PHP_CGI: /usr/bin/php-cgi8.3 + javascript: name: JavaScript (sin navegador) runs-on: ubuntu-latest diff --git a/maintenance/verificacion-infraestructura-20261025.md b/maintenance/verificacion-infraestructura-20261025.md new file mode 100644 index 0000000..442e290 --- /dev/null +++ b/maintenance/verificacion-infraestructura-20261025.md @@ -0,0 +1,13 @@ +# Verificación de infraestructura pendiente + +Base: main `d477d760a3b2a3661b0c120dd258fed42a30a230`. Continuación de V-02 del [seguimiento histórico](cierre-auditorias-20261025.md). Solo pruebas y CI; no se modifica el core ni se instalan servicios en proyectos del usuario. + +Convenciones seleccionadas: orchestrator, framework-maintenance y auth-access, con los contratos de sesiones y revocación. El resultado requiere ejecuciones reales; un test omitido impide aprobar el job dedicado. + +## Comprobaciones preparadas + +- PHP 8.4 contra MySQL 8: migraciones, preflight, instalación y recorridos HTTP de fixtures temporales. +- phpredis contra Redis 7: lectura/escritura, revocación desde otra instancia, escritura tardía que no restaura sesiones, bloqueo/desbloqueo, versiones de autorización global/usuario/tenant y expiración real. La cuenta se consulta en SQLite temporal; los Lua y TTL se ejecutan en Redis real. Limpieza limitada al prefijo aleatorio de cada prueba, sin vaciar bases Redis. +- Routing Nginx/PHP-CGI: ejecutar el test existente con recursos públicos, rutas virtuales, archivos internos protegidos, errores y canales. + +Los resultados de CI se registrarán después de la ejecución. No se presenta esta preparación como V-02 resuelta. SMTP, personalización del pie, hosting real y cobertura visual universal conservan sus límites. diff --git a/tests/RedisSessionIntegrationTest.php b/tests/RedisSessionIntegrationTest.php new file mode 100644 index 0000000..a86e180 --- /dev/null +++ b/tests/RedisSessionIntegrationTest.php @@ -0,0 +1,112 @@ +prefix = 'gframe-test:' . bin2hex(random_bytes(12)) . ':'; + $this->redis = new \Redis(); + self::assertTrue($this->redis->connect(getenv('GFRAME_TEST_REDIS_HOST') ?: '127.0.0.1', (int)(getenv('GFRAME_TEST_REDIS_PORT') ?: 6379), 2)); + define('DB_DEFAULT_CONNECTION', 'redis-test'); + define('DB_CONNECTIONS', ['redis-test' => ['driver' => 'sqlite', 'path' => ':memory:']]); + $database = \DatabaseManager::connection(); + self::assertInstanceOf(\PDO::class, $database); + $database->exec("CREATE TABLE users(user_id INTEGER PRIMARY KEY,status TEXT); INSERT INTO users VALUES(7,'verify'),(8,'verify'),(9,'suspended')"); + SessionRuntime::clearAuthorizationStale(); + } + + protected function tearDown(): void + { + if (isset($this->redis) && $this->redis->isConnected()) { + $keys = $this->redis->keys($this->prefix . '*'); + if ($keys !== []) $this->redis->del($keys); + $this->redis->close(); + } + \DatabaseManager::disconnect(); + SessionRuntime::clearAuthorizationStale(); + } + + public function testRevocationAcrossHandlersDoesNotResurrectSessions(): void + { + $writer = new RedisSessionHandler($this->redis, $this->prefix, 60); + foreach (['desktop', 'mobile'] as $id) { + $writer->register(7, $id); + self::assertTrue($writer->write($id, $id . '-payload')); + } + $writer->register(8, 'other'); + $writer->write('other', 'other-payload'); + $stale = new RedisSessionHandler($this->redis, $this->prefix, 60); + self::assertSame('desktop-payload', $stale->read('desktop')); + $revoker = new RedisSessionHandler($this->redis, $this->prefix, 60); + self::assertSame(2, $revoker->revokeUser(7)); + self::assertTrue($stale->write('desktop', 'late-payload')); + self::assertTrue($stale->updateTimestamp('desktop', 'late-payload')); + self::assertFalse($writer->validateId('desktop')); + self::assertFalse($writer->validateId('mobile')); + self::assertSame('', $writer->read('desktop')); + self::assertSame('other-payload', $writer->read('other')); + $writer->register(7, 'new-login'); + $writer->write('new-login', 'new-payload'); + self::assertSame('new-payload', $writer->read('new-login')); + } + + public function testBlockingAndAuthorizationVersionsUseRealRedisState(): void + { + $handler = new RedisSessionHandler($this->redis, $this->prefix, 60); + $handler->register(7, 'authorized', ['role_id' => 3, 'role_version' => 1, 'authorization_version' => 1]); + $handler->write('authorized', 'payload'); + $handler->publishRoleVersion(3, 2); + self::assertSame('payload', $handler->read('authorized')); + self::assertTrue(SessionRuntime::authorizationStale()); + SessionRuntime::clearAuthorizationStale(); + $handler->updateAuthorization(7, 'authorized', 3, 2, 1); + $handler->publishUserAuthorizationVersion(7, 2); + $handler->read('authorized'); + self::assertTrue(SessionRuntime::authorizationStale()); + SessionRuntime::clearAuthorizationStale(); + $handler->updateAuthorization(7, 'authorized', 3, 2, 2); + $handler->updateTenantAuthorization(7, 'authorized', 4, 1); + $handler->publishRoleVersion(4, 2); + $handler->read('authorized'); + self::assertTrue(SessionRuntime::authorizationStale()); + self::assertSame(1, $handler->revokeUser(7, true)); + try { + $handler->register(7, 'blocked'); + self::fail('Una cuenta bloqueada no debe registrar una sesión.'); + } catch (\RuntimeException $exception) { + self::assertSame('La cuenta no admite nuevas sesiones.', $exception->getMessage()); + } + $handler->allowUser(7); + $handler->register(7, 'allowed'); + self::assertTrue($handler->validateId('allowed')); + $this->expectException(\RuntimeException::class); + $handler->register(9, 'suspended'); + } + + public function testStoredSessionExpiresInRedis(): void + { + $handler = new RedisSessionHandler($this->redis, $this->prefix, 2); + $handler->register(7, 'short'); + $handler->write('short', 'expires'); + self::assertSame('expires', $handler->read('short')); + $deadline = microtime(true) + 5; + while ($handler->validateId('short') && microtime(true) < $deadline) usleep(50000); + self::assertFalse($handler->validateId('short')); + self::assertSame('', $handler->read('short')); + self::assertTrue($handler->write('short', 'late')); + self::assertFalse($handler->validateId('short')); + } +} From 68971073b7d508f58d39776061e9a06fe20a7975 Mon Sep 17 00:00:00 2001 From: Juank de Gorvet Date: Sun, 25 Oct 2026 03:06:37 -0400 Subject: [PATCH 2/5] =?UTF-8?q?Actualiza=20la=20comprobaci=C3=B3n=20Nginx?= =?UTF-8?q?=20al=20contrato=20CSRF=20vigente?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../verificacion-infraestructura-20261025.md | 8 ++++++++ tests/ServerRoutingTest.php | 15 +++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/maintenance/verificacion-infraestructura-20261025.md b/maintenance/verificacion-infraestructura-20261025.md index 442e290..42a5a9e 100644 --- a/maintenance/verificacion-infraestructura-20261025.md +++ b/maintenance/verificacion-infraestructura-20261025.md @@ -11,3 +11,11 @@ Convenciones seleccionadas: orchestrator, framework-maintenance y auth-access, c - Routing Nginx/PHP-CGI: ejecutar el test existente con recursos públicos, rutas virtuales, archivos internos protegidos, errores y canales. Los resultados de CI se registrarán después de la ejecución. No se presenta esta preparación como V-02 resuelta. SMTP, personalización del pie, hosting real y cobertura visual universal conservan sus límites. + +## Primera ejecución + +[CI 40171290826](https://github.com/gorvet/gframe-framework/actions/runs/40171290826), commit `6574d5c`: MySQL/HTTP y Redis reales, PHP 8.4.27, 36 pruebas/764 aserciones, sin omisiones ni fallos; job 121102466808. Redis 7.4.11 y MySQL 8.0.46 reales en contenedores temporales. + +Nginx/PHP-CGI llegó a 79 aserciones y falló porque el test antiguo esperaba `recovery_requested` enviando un POST sin CSRF; el framework devolvió correctamente `fail_csrf`. Job 121102466609. El resto de la matriz pasó. Se conserva este fallo como evidencia de una expectativa obsoleta del fixture, no se cambia la protección del framework. + +La corrección de la prueba conserva el caso negativo y añade GET del formulario, cookie de sesión y token/timestamp reales antes del POST válido. Requiere una nueva ejecución de Nginx/PHP-CGI para cerrar ese escenario. diff --git a/tests/ServerRoutingTest.php b/tests/ServerRoutingTest.php index fd09b07..011dbba 100644 --- a/tests/ServerRoutingTest.php +++ b/tests/ServerRoutingTest.php @@ -110,6 +110,21 @@ public function testRealNginxRoutesRequestsAndServerErrorsToTheInstalledFramewor self::assertStringNotContainsString('request($base . '/ajax/lostpassword', 'POST', 'recovery_email=unknown%40example.test&middle_name='); self::assertSame(200, $status); + self::assertSame('fail_csrf', json_decode($body, true)['code'] ?? null); + [$status, $form, $headers] = $this->request($base . '/login/lostpassword'); + self::assertSame(200, $status); + self::assertSame(1, preg_match('/name="csrfToken" value="([^"]+)"/', $form, $token)); + self::assertSame(1, preg_match('/name="csrfTimestamp" value="([^"]+)"/', $form, $timestamp)); + $cookies = []; + foreach ($headers as $header) { + if (preg_match('/^Set-Cookie:\s*([^;]+)/i', $header, $cookie)) $cookies[] = $cookie[1]; + } + self::assertNotEmpty($cookies); + [$status, $body] = $this->request($base . '/ajax/lostpassword', 'POST', http_build_query([ + 'recovery_email' => 'unknown@example.test', 'middle_name' => '', + 'csrfToken' => $token[1], 'csrfTimestamp' => $timestamp[1], + ]), ['Cookie: ' . implode('; ', $cookies)]); + self::assertSame(200, $status); self::assertSame('recovery_requested', json_decode($body, true)['code'] ?? null); } finally { foreach (array_reverse($processes) as $process) { proc_terminate($process); proc_close($process); } From 8c1e3037e317fd2f3af13be9b3fd858a809f9509 Mon Sep 17 00:00:00 2001 From: Juank de Gorvet Date: Sun, 25 Oct 2026 03:13:28 -0400 Subject: [PATCH 3/5] Mide el intervalo en el navegador y verifica recorridos con Chromium --- .github/workflows/tests.yml | 28 +++++++++++++++++++ .../verificacion-infraestructura-20261025.md | 14 ++++++++++ tests/js/content-autosave.browser.test.cjs | 12 +++++++- 3 files changed, 53 insertions(+), 1 deletion(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 61444bc..1910ba0 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -155,6 +155,34 @@ jobs: package-manager-cache: false - run: node --test --test-reporter=tap tests/js/*.test.cjs + browser: + name: Recorridos reales con Chromium + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v4 + - uses: shivammathur/setup-php@v2 + with: + php-version: '8.3' + extensions: mbstring, openssl, pdo_sqlite, gd + coverage: none + - uses: ramsey/composer-install@v3 + with: + dependency-versions: locked + - uses: actions/setup-node@v7 + with: + node-version: '24' + package-manager-cache: false + - name: Instalar navegador de pruebas en el directorio temporal + run: | + npm install --prefix "$RUNNER_TEMP/gframe-browser" --no-package-lock --no-audit --no-fund playwright@1.62.1 + "$RUNNER_TEMP/gframe-browser/node_modules/.bin/playwright" install --with-deps chromium + echo "NODE_PATH=$RUNNER_TEMP/gframe-browser/node_modules" >> "$GITHUB_ENV" + - name: Ejecutar todos los recorridos de navegador + run: | + export GFRAME_TEST_PHP="$(command -v php)" + export GFRAME_TEST_BROWSER="$(node -p 'require("playwright").chromium.executablePath()')" + node --test --test-concurrency=1 --test-reporter=tap tests/js/*.test.cjs + skills-metadata: name: Metadata YAML de skills runs-on: ubuntu-latest diff --git a/maintenance/verificacion-infraestructura-20261025.md b/maintenance/verificacion-infraestructura-20261025.md index 42a5a9e..fe2a2ac 100644 --- a/maintenance/verificacion-infraestructura-20261025.md +++ b/maintenance/verificacion-infraestructura-20261025.md @@ -19,3 +19,17 @@ Los resultados de CI se registrarán después de la ejecución. No se presenta e Nginx/PHP-CGI llegó a 79 aserciones y falló porque el test antiguo esperaba `recovery_requested` enviando un POST sin CSRF; el framework devolvió correctamente `fail_csrf`. Job 121102466609. El resto de la matriz pasó. Se conserva este fallo como evidencia de una expectativa obsoleta del fixture, no se cambia la protección del framework. La corrección de la prueba conserva el caso negativo y añade GET del formulario, cookie de sesión y token/timestamp reales antes del POST válido. Requiere una nueva ejecución de Nginx/PHP-CGI para cerrar ese escenario. + +## Segunda ejecución de infraestructura + +[CI 40171556708](https://github.com/gorvet/gframe-framework/actions/runs/40171556708), commit `6897107`: doce jobs aprobados. Nginx/PHP-CGI: 1 prueba/85 aserciones, sin omisiones; job 121103266424. MySQL/HTTP y Redis con PHP 8.4.27: 36 pruebas/764 aserciones, sin omisiones; job 121103266379. Los tres escenarios concretos de V-02 quedan acreditados, sin extender el resultado a producción. + +## Recorridos de navegador + +Suite local completa con Chrome, Playwright 1.62.1 y PHP 8.3.35, base d477d76: 99 casos, 95 aprobados, cuatro fallidos, sin omisiones. Instalador, gestión y selector fallan al navegar a loopback con `ERR_NETWORK_ACCESS_DENIED`; no se presentan como fallos demostrados del producto. El autoguardado falla al comparar timestamps tomados cuando Node recibe los eventos de red, en lugar del instante de envío en el navegador. La repetición aislada vuelve a fallar. + +Sonda independiente en memoria, sin editar el runtime: envíos separados por 5005,6 ms en `performance.now()` y 5005 ms en Date.now() del navegador; recepción de esos mismos eventos en Node separada por 4933 ms. La sonda completa termina aprobada, 1 caso. La llegada del evento al arnés no es el reloj del planificador; la demora de cada evento varía. + +El test conserva el umbral de 4800 ms y observa el envío real de XMLHttpRequest mediante el reloj monótono del navegador. No modifica temporizadores ni tráfico del producto. La nueva ejecución con demora deliberada del arnés debe confirmar que no se confunde esa demora con el intervalo del editor. + +Se añade un job Chromium que ejecuta la suite completa en Linux, donde no se hereda el bloqueo local. Dependencias solo en el directorio temporal del runner; sin package.json ni cambios del core. La cobertura de todos los paquetes visuales opcionales sigue siendo más amplia que estos recorridos y no se da por completada automáticamente. diff --git a/tests/js/content-autosave.browser.test.cjs b/tests/js/content-autosave.browser.test.cjs index 898b362..d513337 100644 --- a/tests/js/content-autosave.browser.test.cjs +++ b/tests/js/content-autosave.browser.test.cjs @@ -20,6 +20,15 @@ test('Autoguardado privado real: recuperación, petición en vuelo, conflictos y const {chromium} = require('playwright'); const browser = await chromium.launch({headless: true, executablePath: process.env.GFRAME_TEST_BROWSER}); const context = await browser.newContext({viewport: {width: 1440, height: 1000}}); + await context.addInitScript(() => { + window.__autosaveRequestTimes = []; + const send = XMLHttpRequest.prototype.send; + XMLHttpRequest.prototype.send = function(body) { + const action = new URLSearchParams(body || '').get('action'); + if (action) window.__autosaveRequestTimes.push({action, time: performance.now()}); + return send.apply(this, arguments); + }; + }); const requests = [], errors = []; let hold, heldStarted, release, failSaves = 0, active = 0, maximum = 0; context.on('page', page => { page.on('pageerror', e => errors.push(e.message)); page.on('dialog', dialog => dialog.accept()); page.setDefaultTimeout(12000); }); await context.route('**/*', async route => { @@ -55,7 +64,8 @@ test('Autoguardado privado real: recuperación, petición en vuelo, conflictos y let state = await inspect(); assert.equal(state.article.content, old.article.content); assert.equal(state.draft.data.content, '

Privado inicial

'); assert.equal(await page.evaluate(() => AdminRichTextEditor.hasUnsavedChanges()), true, 'Autoguardar no equivale a publicar.'); assert.ok(requests.every(req => req.data.csrfToken === 'fixture-token')); - assert.ok(requests.find(req => req.action === 'save').time - requests[0].time >= 4800, 'Respeta el intervalo mínimo entre peticiones.'); + const attempts = await page.evaluate(() => window.__autosaveRequestTimes); + assert.ok(attempts.find(req => req.action === 'save').time - attempts[0].time >= 4800, 'Respeta el intervalo mínimo entre peticiones en el reloj del navegador.'); await page.reload(); await ready(page); await page.locator('[data-autosave-recovery]').waitFor({state:'visible'}); assert.equal(await get(page), '

Publicado

'); From 5e4970c230728df5bb1fe82a0c0d5b18c2b8fe76 Mon Sep 17 00:00:00 2001 From: Juank de Gorvet Date: Sun, 25 Oct 2026 03:16:05 -0400 Subject: [PATCH 4/5] Registra infraestructura acreditada y exige navegador sin omisiones --- .github/workflows/tests.yml | 4 +++- maintenance/cierre-auditorias-20261025.md | 4 ++-- maintenance/verificacion-infraestructura-20261025.md | 2 ++ 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 1910ba0..a9af13d 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -181,7 +181,9 @@ jobs: run: | export GFRAME_TEST_PHP="$(command -v php)" export GFRAME_TEST_BROWSER="$(node -p 'require("playwright").chromium.executablePath()')" - node --test --test-concurrency=1 --test-reporter=tap tests/js/*.test.cjs + set -o pipefail + node --test --test-concurrency=1 --test-reporter=tap tests/js/*.test.cjs | tee "$RUNNER_TEMP/gframe-browser.tap" + grep -Fx '# skipped 0' "$RUNNER_TEMP/gframe-browser.tap" skills-metadata: name: Metadata YAML de skills diff --git a/maintenance/cierre-auditorias-20261025.md b/maintenance/cierre-auditorias-20261025.md index a1007f3..a3c9a40 100644 --- a/maintenance/cierre-auditorias-20261025.md +++ b/maintenance/cierre-auditorias-20261025.md @@ -49,12 +49,12 @@ Los nueve deltas se marcan `auditada` porque la última pasada de su etapa los i | [BridgeFrame](bridgeframe-pending.md) | El usuario confirmó la adaptación v2 el 6 de octubre | Retirado del backlog de GFrame; no acredita integración externa en vivo | | [Skills y contratos](inventario-skills-contratos.md), [distribución](distribucion-skills.md) | Lotes 31–33, instalación/carga en Codex y resolución K-01–K-04/M-01 documentadas | No quedan esos cambios pospuestos de código; Claude fue excluido expresamente de esa validación | -## Verificaciones que no se marcan como realizadas +## Estado de verificaciones complementarias Estos puntos son límites concretos de evidencia, no nuevas funcionalidades ni razones para reabrir una etapa cuyo alcance aprobado ya se auditó: - **V-01 — cobertura visual restante:** prueba visual de cada biblioteca opcional y de todas las vistas/recursos de todos los módulos en una instalación limpia. Selector/editor y recorridos concretos sí tienen auditorías y pruebas. No equivalen a esa cobertura universal. Fuente: [auditoría de módulos](auditoria-modulos.md). -- **V-02 — infraestructura restante:** routing general con Nginx/PHP-CGI, integración MySQL/HTTP específicamente en PHP 8.4 y sesiones Redis con servicio real. Nginx/PHP-FPM para cron y la matriz PHP sin esas integraciones sí están acreditados. Fuente: [preparación histórica](preparacion-0.9.0.md) y [CI/lint](cobertura-checks-20261006.md). +- **V-02 — cerrada en continuación:** routing general con Nginx/PHP-CGI (1 prueba/85 aserciones), MySQL/HTTP con PHP 8.4 y Redis real (36/764), sin omisiones, en CI 40171556708. [Evidencia y límites](verificacion-infraestructura-20261025.md). La primera prueba Nginx tenía una expectativa CSRF obsoleta; el test corregido comprueba rechazo sin token y solicitud válida con sesión/token, sin cambiar el core. El resultado no certifica producción. - **V-03 — correo externo:** diagnóstico de recepción del registro inicial y compatibilidad en clientes remotos. Pruebas de render, cola y transporte falso no prueban aceptación SMTP ni recepción. No se envió correo ni se accedió a proveedores en este cierre. Fuente: [plantillas](auditorias/plantillas-correo/AUDIT.md). - **V-04 — personalización del pie del correo:** el año y la homogeneidad están implementados; el contenido personalizado de créditos del pie web no se reutiliza automáticamente en las plantillas de correo. Se conserva como decisión/integración pendiente; no se cambia el motor por marcar una lista. Fuente: [plantillas](auditorias/plantillas-correo/AUDIT.md). - **V-05 — hosting y consumidores:** cabeceras y bloqueos efectivos del servidor de producción, despliegue de cada aplicación y pruebas con proveedores reales. Las comprobaciones de fixtures no certifican esos entornos. Fuente: [seguridad inicial](auditorias/alineacion-4.3.0/SEGURIDAD-INICIAL.md). diff --git a/maintenance/verificacion-infraestructura-20261025.md b/maintenance/verificacion-infraestructura-20261025.md index fe2a2ac..4065263 100644 --- a/maintenance/verificacion-infraestructura-20261025.md +++ b/maintenance/verificacion-infraestructura-20261025.md @@ -32,4 +32,6 @@ Sonda independiente en memoria, sin editar el runtime: envíos separados por 500 El test conserva el umbral de 4800 ms y observa el envío real de XMLHttpRequest mediante el reloj monótono del navegador. No modifica temporizadores ni tráfico del producto. La nueva ejecución con demora deliberada del arnés debe confirmar que no se confunde esa demora con el intervalo del editor. +Sonda con 500 ms de demora deliberada antes de registrar el primer evento en Node: el navegador separa sus envíos 4999,2 ms, mientras el arnés registra 4410 ms. El criterio corregido mantiene el umbral y mide la propiedad exigida; el anterior rechazaría un intervalo correcto por la demora introducida en la observación. Recorrido completo con la demora inyectada: 1 caso aprobado, sin omisiones, 56,7 segundos. Log local `~/.gframe-agents/autosave-demora-controlada.log`. + Se añade un job Chromium que ejecuta la suite completa en Linux, donde no se hereda el bloqueo local. Dependencias solo en el directorio temporal del runner; sin package.json ni cambios del core. La cobertura de todos los paquetes visuales opcionales sigue siendo más amplia que estos recorridos y no se da por completada automáticamente. From 08eb45824bb290a893aa52ba5718bf581bcd951e Mon Sep 17 00:00:00 2001 From: Juank de Gorvet Date: Sun, 25 Oct 2026 03:20:29 -0400 Subject: [PATCH 5/5] Registra los 99 recorridos de Chromium y el cierre de infraestructura --- maintenance/cierre-auditorias-20261025.md | 2 +- maintenance/verificacion-infraestructura-20261025.md | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/maintenance/cierre-auditorias-20261025.md b/maintenance/cierre-auditorias-20261025.md index a3c9a40..8de32a6 100644 --- a/maintenance/cierre-auditorias-20261025.md +++ b/maintenance/cierre-auditorias-20261025.md @@ -53,7 +53,7 @@ Los nueve deltas se marcan `auditada` porque la última pasada de su etapa los i Estos puntos son límites concretos de evidencia, no nuevas funcionalidades ni razones para reabrir una etapa cuyo alcance aprobado ya se auditó: -- **V-01 — cobertura visual restante:** prueba visual de cada biblioteca opcional y de todas las vistas/recursos de todos los módulos en una instalación limpia. Selector/editor y recorridos concretos sí tienen auditorías y pruebas. No equivalen a esa cobertura universal. Fuente: [auditoría de módulos](auditoria-modulos.md). +- **V-01 — parcial:** los 99 casos de la suite con Chromium pasan sin fallos ni omisiones en CI 40171975482, incluidos instalador, selector, gestión y autoguardado. [Evidencia de la continuación](verificacion-infraestructura-20261025.md). Permanece sin acreditar la prueba visual de cada biblioteca opcional y de todas las vistas/recursos de todos los módulos en una instalación limpia; esos recorridos no equivalen a una cobertura universal. Fuente: [auditoría de módulos](auditoria-modulos.md). - **V-02 — cerrada en continuación:** routing general con Nginx/PHP-CGI (1 prueba/85 aserciones), MySQL/HTTP con PHP 8.4 y Redis real (36/764), sin omisiones, en CI 40171556708. [Evidencia y límites](verificacion-infraestructura-20261025.md). La primera prueba Nginx tenía una expectativa CSRF obsoleta; el test corregido comprueba rechazo sin token y solicitud válida con sesión/token, sin cambiar el core. El resultado no certifica producción. - **V-03 — correo externo:** diagnóstico de recepción del registro inicial y compatibilidad en clientes remotos. Pruebas de render, cola y transporte falso no prueban aceptación SMTP ni recepción. No se envió correo ni se accedió a proveedores en este cierre. Fuente: [plantillas](auditorias/plantillas-correo/AUDIT.md). - **V-04 — personalización del pie del correo:** el año y la homogeneidad están implementados; el contenido personalizado de créditos del pie web no se reutiliza automáticamente en las plantillas de correo. Se conserva como decisión/integración pendiente; no se cambia el motor por marcar una lista. Fuente: [plantillas](auditorias/plantillas-correo/AUDIT.md). diff --git a/maintenance/verificacion-infraestructura-20261025.md b/maintenance/verificacion-infraestructura-20261025.md index 4065263..6bc4670 100644 --- a/maintenance/verificacion-infraestructura-20261025.md +++ b/maintenance/verificacion-infraestructura-20261025.md @@ -35,3 +35,9 @@ El test conserva el umbral de 4800 ms y observa el envío real de XMLHttpRequest Sonda con 500 ms de demora deliberada antes de registrar el primer evento en Node: el navegador separa sus envíos 4999,2 ms, mientras el arnés registra 4410 ms. El criterio corregido mantiene el umbral y mide la propiedad exigida; el anterior rechazaría un intervalo correcto por la demora introducida en la observación. Recorrido completo con la demora inyectada: 1 caso aprobado, sin omisiones, 56,7 segundos. Log local `~/.gframe-agents/autosave-demora-controlada.log`. Se añade un job Chromium que ejecuta la suite completa en Linux, donde no se hereda el bloqueo local. Dependencias solo en el directorio temporal del runner; sin package.json ni cambios del core. La cobertura de todos los paquetes visuales opcionales sigue siendo más amplia que estos recorridos y no se da por completada automáticamente. + +## Cierre de los recorridos existentes + +[CI 40171975482](https://github.com/gorvet/gframe-framework/actions/runs/40171975482), commit `8c1e303`, job Chromium 121104534537: **99 casos aprobados, cero fallos, cero omisiones**, 219 segundos. Incluye instalador, gestión y selector que el entorno local impedía abrir, además del autoguardado con la medición corregida. La condición posterior del job exige explícitamente `# skipped 0`, conservando el fallo del proceso mediante pipefail. + +V-02 está cerrada para sus tres escenarios identificados. V-01 tiene ahora todos los recorridos existentes de navegador ejecutados, pero la cobertura visual universal de cada biblioteca/vista sigue sin acreditarse. V-03, V-04 y V-05 conservan su alcance: no hubo acceso a SMTP externo, cambios de pie personalizados ni despliegue o certificación del hosting.