Deploy
Produccion tiene dos dominios publicos:
ui.le-mn.comsirve este sitio Starlight de docs.showcase.ui.le-mn.comsirve el showcase interactivo como Worker SPA.
CI valida pull requests con typecheck, tests, build, metadata de release y
changeset status. Los pushes a main ejecutan el release workflow:
- Valida sin mutar Cloudflare que el API token de cuenta con scope limitado este activo para la cuenta configurada, pueda leer la zona requerida e inspeccionar los Workers y mapeos de custom domains objetivo.
- Hace fetch de
mainprotegido. Un rerun antiguo solo puede retomar el commit unico de release con su trailerRelease-Origin; en otro caso se detiene sin crear un sibling ni intentar un push non-fast-forward. - Si quedan changesets, crea y pushea un unico commit fast-forward. Version, SHA completo, timestamp del commit y release ID son entradas inmutables para todos los retries.
- Empaqueta el paquete exacto y calcula su integridad
sha512. Publica solo si la version no existe; si existe, exige identidad e integridad inmutable igual. - Despliega docs con la identidad inmutable del release.
- Sube codigo, assets, identidad y
PRODUCTION_STATUS_TOKENcomo una version inactiva del Worker etiquetada por release. Su metadata guarda baseline, identidad anterior y rol del token de rollback. - Crea una lease sin trafico nuevo (
baseline=100%,candidate=0%), hace smoke de la candidata con version override, vuelve a comprobar la lease y activa exactamente esa candidata al 100%. - Hace smoke del deployment activo. Un fallo normal restaura y verifica el baseline; una interrupcion deja un estado durable recuperable por release ID.
CI consulta la lista autenticada de GitHub Packages antes de publicar y la
metadata npm despues. Solo una consulta exitosa que omita la version exacta
permite publicarla. Una version presente nunca se republica: su dist.integrity
debe coincidir con el sha512 local o el release falla cerrado.
El job Release And Deploy es el unico que puede resolver credenciales de
produccion. Usa el GitHub Environment production, que exige al reviewer
angelllemn y solo permite deployments desde la rama main.
Los unicos nombres de secrets propios del Environment production son:
PRODUCTION_CLOUDFLARE_API_TOKENcon un API token propiedad de la cuentaPRODUCTION_STATUS_TOKEN
GitHub Actions aporta GITHUB_TOKEN; no es un secret configurado en el
Environment. Los nombres PRODUCTION_* hacen que un secret ausente falle cerrado
en lugar de resolver silenciosamente una credencial del repositorio.
Crea el token de Cloudflare con exactamente estos recursos y permisos:
- Recurso Account: incluye solo
Lemn DEV; permisoWorkers Scripts: Edit. - Recurso Zone: incluye solo
le-mn.com; permisoZone: Read.
El token se usa como CLOUDFLARE_API_TOKEN. El preflight rechaza un token
ausente, deshabilitado o expirado, y tambien el modo legacy key/email. Workers Scripts: Edit (llamado Workers Scripts Write por el API) cubre uploads,
versiones, deployments, secrets y custom domains de Workers para este release;
Zone: Read solo se usa para comprobar el scope de la zona sin mutaciones. No
agregues permisos de usuario, account settings, KV, R2, Workers Routes ni scopes
mas amplios de cuenta o zona.
Rotacion Y Rollback Del Status Token
Sección titulada «Rotacion Y Rollback Del Status Token»El showcase no tiene consumidores inbound de status. Se confirmo el 2026-07-14
buscando en 79 repositorios/worktrees locales, 14 repositorios GitHub,
LaunchAgents y procesos activos, y las dos bases D1 de Monitor. STATUS_TOKEN es
obligatorio en produccion; no existe deployment de staging.
Rota el valor del GitHub Environment sin exponerlo al historial del shell, filesystem, logs ni argumentos del comando:
openssl rand -hex 32 | gh secret set PRODUCTION_STATUS_TOKEN --env production --repo lemn-ltd/uiEl workflow aprobado de main ejecuta este orden exacto:
- Lee
wrangler deployments list --jsony versiones etiquetadas por release. Un retry retoma su candidata; un release nuevo exige un baseline unico al 100%. - Hace smoke de
/_status,/_status.jsony/health/deepsin token (401) y con elSTATUS_TOKENretenido en el repositorio (200). Si produccion ya fue rotada, reintenta conPRODUCTION_STATUS_TOKEN. - Crea el documento JSON de secretos de Wrangler como fichero regular dentro
de un directorio temporal aleatorio con modo
0700. El fichero se crea de forma exclusiva con modo0600y solo su ruta se pasa awrangler versions upload --secrets-file. El cleanup siempre se intenta enfinally; un fallo solo de cleanup detiene el rollout, y un fallo simultaneo de upload y cleanup reporta ambos con el fallo de upload primero. El token nunca aparece en argumentos ni logs. La candidata inactiva incluye codigo, assets, identidad, token y metadata de recovery sin cambiar trafico. - Despliega baseline al 100% y candidata al 0% con una lease del release. Hace
smoke publico/protegido de la candidata mediante
Cloudflare-Workers-Version-Overrides, manteniendo trafico normal en baseline. - Relee deployments, exige el mismo deployment ID y reparto de trafico, activa la candidata al 100% y repite mappings y smoke sin override.
- Escribe el summary solo despues de que todo pase.
El concurrency group usa cancel-in-progress: false; los releases conformes se
serializan y respetan la lease durable. La API de Cloudflare no ofrece update
condicional atomico para deployments, por lo que ningun operador externo debe
desplegar este Worker mientras exista la lease. Cualquier cambio de deployment
ID, trafico o mensaje detiene el run sin sobrescribir el deployment concurrente.
Los fallos normales despues de la lease ejecutan wrangler rollback <captured-version-id> --yes y verifican el baseline con el rol de token y la
identidad guardados. Los fallos de rollback no ocultan el error original.
SIGTERM/SIGINT terminan el child activo y un retry retoma candidata, lease o
candidata activa. SIGKILL no puede ejecutar el cleanup; los datos temporales
permanecen privados y limitados al runner hasta que este termina. El token nuevo
no recibe trafico antes del smoke y todos los limites quedan visibles en
Cloudflare.
Conserva los cuatro repository secrets legacy hasta que el deploy aprobado sea
estable: CLOUDFLARE_API_KEY, CLOUDFLARE_API_TOKEN, CLOUDFLARE_EMAIL y
STATUS_TOKEN. Estable significa que el SHA objetivo de main completo
Release And Deploy sin rollback, pasaron los smokes de mappings, publicos y las
tres rutas protegidas autenticadas/no autenticadas, y el operador reviso el
summary final.
Solo entonces elimina los repository secrets en este orden, verificando nombre y timestamp despues de cada operacion y sin leer valores:
gh secret delete CLOUDFLARE_API_TOKEN --repo lemn-ltd/uigh secret delete CLOUDFLARE_API_KEY --repo lemn-ltd/uigh secret delete CLOUDFLARE_EMAIL --repo lemn-ltd/uigh secret delete STATUS_TOKEN --repo lemn-ltd/uiSTATUS_TOKEN va ultimo porque es la credencial de rollback de la primera
rotacion. No elimines ni renombres los dos secrets PRODUCTION_* del
Environment.
Los dos wrangler.jsonc son la fuente de verdad de cuenta y Worker. No derives
CLOUDFLARE_API_TOKEN desde una Global API Key ni configures
CLOUDFLARE_API_KEY/CLOUDFLARE_EMAIL; el release guard acepta solo el API
token de cuenta con scope limitado.
Este runbook aplica PAT-SEC-SECRETS-001, PAT-SEC-RISK-001,
PAT-SEC-LOGGING-001, PAT-OPS-LEAST-PRIVILEGE-001,
PAT-CLOUDFLARE-WRANGLER-CONFIG-001 y PAT-TEST-EVIDENCE-001.