Runbook del ciclo de lanzamiento
Flujo de lanzamiento completo, desde las puertas locales, pasando por el GitHub Release firmado, hasta la publicación en npm.
Este runbook lleva un lanzamiento vX.Y.Z de apothem desde un árbol de
trabajo limpio hasta superficies de distribución verificadas. El procedimiento
está escrito para el mantenedor que maneja gh, git y la shell de nivel de
lanzamiento; termina con una página de Release verificada, un CHANGELOG
archivado y una prueba de humo de las rutas de instalación que confirma que cada
superficie orientada al usuario responde al comando de instalación canónico.
El modelo de lanzamiento es aditivo. Cada lanzamiento agrega un commit en
main y una etiqueta vX.Y.Z anotada y firmada; no se hace force-push de nada y
no se elimina ninguna etiqueta, GitHub Release ni versión de npm anterior. Cada lanzamiento conserva su etiqueta, su GitHub Release y su versión de npm, y todos siguen publicados: las versiones de npm son
inmutables (un name@version publicado nunca puede reemplazarse), y las
instalaciones fijadas dependen de las etiquetas.
El push de la etiqueta inicia tres flujos de trabajo.
.github/workflows/release.yml compila, firma, atesta y publica el GitHub
Release con su conjunto completo de artefactos: sdist, wheel, SBOM de
CycloneDX, bundles cosign de Sigstore, procedencia SLSA-3 y los archivos
comprimidos del runtime por plataforma. publish-npm.yml publica
@ahmed-g-gad/apothem en npmjs.com mediante la publicación de confianza de npm, y
publish-vscode.yml empaqueta la extensión de VS Code y la publica en Visual Studio
Marketplace. La sección versionada del CHANGELOG llega en el commit de lanzamiento; el
operador ejecuta la prueba de humo de las rutas de instalación cuando ambos
flujos de trabajo terminan.
1. Requisitos previos
El mantenedor confirma lo siguiente antes de etiquetar:
-
Árbol de trabajo. Limpio (
git statusno muestra nada pendiente). Todo el trabajo de funcionalidades del lanzamiento está enmain. -
CI en verde. Para el último
main,gh run list --branch=main --limit=1 --json conclusion --jq '.[0].conclusion'devuelvesuccess. -
Herramientas.
gh(GitHub CLI) versión 2.40 o posterior, autenticado comoahmed-g-gad;git2.40 o posterior con la subclave de firma GPG cargada; el vínculo de publicador de confianza de npm para@ahmed-g-gad/apothemestá activo (verificado según el runbook de configuración de la cuenta de publicador). -
Anclas de versión alineadas. La cadena de versión declarada en
pyproject.tomlcoincide con la etiqueta planificada sin el prefijov(§2.1 la establece, junto con todas las demás anclas). Verifica:grep '^version' pyproject.tomlSalida esperada (para un lanzamiento
vX.Y.Z; los marcadores de posición representan la etiqueta del lanzamiento en curso):version = "X.Y.Z" -
Entradas del CHANGELOG preparadas. Los puntos del lanzamiento están bajo
## [Unreleased]en encabezados de Keep-a-Changelog; §2.1 los convierte en la sección de versión fechada en el commit que recibe la etiqueta.
2. Etiquetar y disparar
2.1 Redactar el commit de lanzamiento
La versión aparece en más de una docena de archivos, así que no los edites a mano. Un solo comando los actualiza todos:
git checkout main
git pull --ff-only origin main
python scripts/release/bump_version.py X.Y.Zbump_version.py actualiza todas las anclas de versión a la vez:
-
Cada manifiesto de empaquetado, extensión, plugin y marketplace, además del archivo de cita (versión y fecha de lanzamiento). La lista completa:
pyproject.toml package.json site/package.json site/package-lock.json (the project entries only) vscode-extension/package.json gemini-extension.json qwen-extension.json .claude-plugin/marketplace.json (top level and metadata) plugins/apothem/plugin.json plugins/apothem/.codex-plugin/plugin.json CITATION.cff -
CHANGELOG.md: las entradas de[Unreleased]se convierten en una sección## [X.Y.Z]fechada,[Unreleased]compara a partir devX.Y.Zy se agrega un enlace[X.Y.Z]. -
SECURITY.md: una nueva versión menor recibe una filaX.Y.xadmitida. Si las versiones menores anteriores siguen listadas es decisión tuya; el script imprime un recordatorio.
Después regenera los árboles derivados: el paquete del plugin de Claude Code,
los goldens de behavior-diff y las páginas de referencia y de changelog de la
documentación. Pasa --dry-run para listar primero los cambios, --date YYYY-MM-DD para fijar la fecha de lanzamiento (predeterminada: hoy en UTC) o
--no-regen para omitir la regeneración. El script rechaza una versión mal
formada o un retroceso de versión, y volver a ejecutarlo con la versión actual
solo realinea las anclas desalineadas.
Revisa el diff y luego haz commit:
git add -A
git commit -S -m "chore(release): cut vX.Y.Z"
git push origin mainEl indicador -S firma el commit con la clave GPG. El push dispara la matriz de
CI estándar (lint, test, build); espera a que esté en verde antes de etiquetar.
La comprobación de §2.4 también necesita que CodeQL y Conformity estén en verde
en el commit de lanzamiento. Ambos se ejecutan solo cuando cambian sus propias
rutas de archivos, y un commit de lanzamiento normalmente no cambia ninguna de
ellas, así que inícialos una vez que el commit de lanzamiento sea la punta de
main y luego confirma que cada ejecución corresponde a ese commit:
gh workflow run codeql.yml --ref main
gh workflow run conformity.yml --ref main
gh run list --workflow codeql.yml --commit "$(git rev-parse HEAD)" --limit 1
gh run list --workflow conformity.yml --commit "$(git rev-parse HEAD)" --limit 1Espera a que ambos estén en verde antes de etiquetar, y no hagas push de nada
más a main hasta que el lanzamiento esté publicado: un push posterior aleja
main del commit de lanzamiento, y la CI cancela una ejecución que todavía está
en curso en la misma rama.
2.2 Firmar y hacer push de la etiqueta
git tag -a -s vX.Y.Z -m "vX.Y.Z"
git push origin vX.Y.ZLa combinación -a -s produce una etiqueta anotada y firmada con GPG. El push
dispara .github/workflows/release.yml, que compila, firma, atesta y publica.
2.3 Confirmar que el flujo de trabajo de lanzamiento se completó
gh run watch $(gh run list --workflow=release.yml --limit=1 --json databaseId --jq '.[0].databaseId')El flujo de trabajo ejecuta la compilación (sdist + wheel, y luego un SBOM de
CycloneDX de esas distribuciones, escrito junto a ellas), la firma cosign sin
clave, la generación y verificación de la procedencia SLSA-3, la compilación de
los archivos comprimidos por plataforma (darwin / linux / windows), la firma de
esos archivos con un manifiesto SHA256SUMS agregado y la publicación final del
GitHub Release. El mantenedor revisa el registro del trabajo
publish GitHub Release en busca de las confirmaciones de subida de recursos.
El trabajo publish GitHub Release se ejecuta en el entorno release, que
requiere la aprobación del mantenedor, así que la ejecución espera ahí una vez
que pasan los trabajos anteriores. Apruébala en la página de la ejecución
(Review deployments), o desde la shell:
run_id=$(gh run list --workflow=release.yml --limit=1 --json databaseId --jq '.[0].databaseId')
env_id=$(gh api repos/ahmed-g-gad/apothem/environments/release --jq .id)
gh api -X POST "repos/ahmed-g-gad/apothem/actions/runs/${run_id}/pending_deployments" \
-F "environment_ids[]=${env_id}" -f state=approved -f comment="vX.Y.Z"El push de la etiqueta también inicia los flujos de trabajo de npm y de la extensión de VS Code. Sus trabajos de publicación esperan la misma aprobación hasta §2.4.
2.4 Confirmar la publicación en npm
El push de la etiqueta también ejecuta publish-npm.yml junto a release.yml. El flujo de trabajo de npm no espera al flujo de trabajo de lanzamiento; la aprobación del entorno release es la puerta. Cuando el flujo de trabajo de lanzamiento de §2.3 haya terminado, confirma que el lanzamiento está listo. La comprobación lee los lanzamientos, las ejecuciones de flujos de trabajo y el SBOM publicado, así que antes prepara dos entradas:
GH_TOKEN. El script se niega a ejecutarse sin él, aunqueghya tenga una sesión iniciada. Usa un token de acceso personal de grano fino limitado aahmed-g-gad/apothem, con Actions: Read (ejecuciones de flujos de trabajo) y Contents: Read (lanzamientos). La comprobación no escribe nada, así que no necesita ningún permiso de escritura. Un token obtenido congh auth tokentiene todos los alcances del inicio de sesión, así que usa preferentemente el token de grano fino.- El SBOM publicado. La comprobación lee
dist/release-assets/sbom.cdx.json, el archivo CycloneDX que adjunta el lanzamiento. Descarga la copia que publicó el lanzamiento en lugar de una compilación local.
read -rs GH_TOKEN && export GH_TOKEN
mkdir -p dist/release-assets
gh release download vX.Y.Z --repo ahmed-g-gad/apothem \
--pattern sbom.cdx.json --dir dist/release-assets --clobber
bash scripts/release/check-release-ready.sh vX.Y.ZLa comprobación falla cuando el lanzamiento es un borrador o una versión preliminar, cuando un flujo de trabajo requerido para el commit de la etiqueta no está en verde, cuando falta el SBOM, cuando describe otra versión o cuando omite un paquete vendorizado. El mensaje de fallo indica la causa.
Cuando la comprobación pase, aprueba la ejecución en espera Publish npm del
mismo modo que en §2.3 (su ID de ejecución se obtiene de
gh run list --workflow=publish-npm.yml). El flujo de trabajo publica
@ahmed-g-gad/[email protected] en npmjs.com mediante la publicación de confianza de
npm (OIDC); no se almacena ningún token de registro en el repositorio. Aprueba
también la ejecución en espera Publish VS Code Extension. Este flujo de trabajo
empaqueta apothem.vsix y lo publica en Visual Studio Marketplace como
ahmed-g-gad.apothem-vscode. El paso de publicación se ejecuta solo mientras la
variable del repositorio VSCODE_MARKETPLACE_READY sea true y haya una
credencial configurada: la variable VSCE_AUTH=oidc (Trusted Publishing del
Marketplace, sin secreto almacenado), las variables VSCE_AUTH=entra,
AZURE_CLIENT_ID y AZURE_TENANT_ID (un token de Microsoft Entra ID de corta
duración, sin secreto almacenado) o el secreto VSCE_PAT. Sin ninguna, la
ejecución empaqueta la extensión y omite la publicación. La credencial es un
interruptor, no un reintento: una publicación fallida en una ruta no recurre
por sí sola a otra. La configuración de cada ruta está en
Publicación en el Marketplace con Trusted Publishing
(preferida) y en
Publicación en el Marketplace con Microsoft Entra ID
más abajo.
Para volver a publicar después de una ejecución fallida, despacha el flujo de
trabajo para la misma etiqueta
(gh workflow run publish-npm.yml --field tag=vX.Y.Z). Omite la publicación
cuando la versión ya está en el registro, porque las versiones de npm son
inmutables.
Publicación en el Marketplace con Trusted Publishing
Trusted Publishing permite que el Marketplace acepte directamente el token OIDC
de GitHub de este repositorio: vsce publish --oidc intercambia el token del
trabajo de publicación por una credencial del Marketplace de corta duración. No
hay ningún secreto almacenado ni ningún recurso de Azure, así que esta es la
ruta preferida. La ruta de Entra que se describe más abajo y el secreto
VSCE_PAT siguen siendo alternativas que el operador selecciona.
-
Usa una versión de vsce que lo admita. En esta ruta, el trabajo de publicación comprueba la versión de vsce bloqueada en
tools/vsceantes de publicar, y se detiene con un error que indica la versión mínima cuando el bloqueo es más antiguo. Dependabot propone actualizaciones de vsce para ese archivo de bloqueo; fusiona la que alcance la versión mínima antes de cambiar de ruta. -
Crea la política. Inicia sesión como Owner del publicador, abre
https://marketplace.visualstudio.com/manage/publishers/ahmed-g-gady agrega una política en Trusted Publishing:- Nombre de la política: cualquier nombre, como
apothem-release - Propietario del repositorio:
Ahmed-G-Gad - Repositorio:
apothem - Flujo de trabajo:
publish-vscode.yml - Entorno:
release
Los nombres de los campos son los que enumera la guía de publicación de VS Code, en su sección sobre la publicación con GitHub Actions y Trusted Publishing (
https://code.visualstudio.com/api/working-with-extensions/publishing-extension). Sin confirmar: si todos los publicadores ven ya la pestaña Trusted Publishing. Si el tuyo no la ve, usa la ruta de Entra. - Nombre de la política: cualquier nombre, como
-
Cambia la ruta. Mantén
VSCODE_MARKETPLACE_READYcon el valortruey define el selector. Defínelo cuando no haya ninguna etiqueta en espera, porque el siguiente push de etiqueta publica por esta ruta.gh variable set VSCE_AUTH --body oidc -
Publica. El siguiente push de etiqueta, o un despacho para una etiqueta existente, publica mediante Trusted Publishing. Esta ruta no tiene ejecución de prueba: la primera publicación es la comprobación, y un despacho con
dry_runsolo advierte de que no se verificó nada. -
Recurre a la alternativa si falla. Elimina el selector y vuelve a despachar para la misma etiqueta; con el secreto
VSCE_PATdefinido, publica la ruta del token. Una publicación fallida no publicó nada, así que se puede volver a despachar la misma etiqueta.gh variable delete VSCE_AUTH
Publicación en el Marketplace con Microsoft Entra ID
La ruta de Entra sustituye el token de acceso personal almacenado por un token
de corta duración. publish-vscode.yml solicita a GitHub un token OIDC, la
acción Azure/login lo intercambia por un inicio de sesión de Entra mediante
una credencial federada, y vsce publish --azure-credential publica con el
token resultante. No existe ningún secreto de cliente. El secreto VSCE_PAT
sigue siendo una alternativa que el operador selecciona; el flujo de trabajo
nunca cambia a él por su cuenta.
La versión de vsce fijada en tools/vsce admite esta ruta. Necesita un tenant
de Entra, un registro de aplicación y la pertenencia al publicador, que Trusted
Publishing (descrito arriba) no necesita; úsala cuando Trusted Publishing no
esté disponible para el publicador.
-
Comprueba los requisitos previos. Busca la cuenta propietaria del publicador
ahmed-g-gad(la pestaña Members enhttps://marketplace.visualstudio.com/manage/publishers/ahmed-g-gad) y el tenant de Entra donde puedes registrar aplicaciones. Sin confirmar: si el tenant del propietario del publicador debe coincidir con el tenant de la aplicación, y si la organización de Azure DevOpsAhmed-G-Gaddebe estar conectada a Entra (dev.azure.com/Ahmed-G-Gad, Organization settings, Microsoft Entra). Ninguna fuente afirma ninguna de las dos cosas. Si el paso 5 o el 6 falla, comprueba esto primero. -
Registra la aplicación. En
https://entra.microsoft.com, abre App registrations y luego New registration. Llámalaapothem-vscode-publish, elige un solo tenant y deja vacío el URI de redirección. En Overview, copia el Application (client) ID y el Directory (tenant) ID. No crees ningún secreto de cliente ni concedas ningún permiso de API. El paso requiere derechos de propietario de la aplicación o un rol de Entra como Application Administrator. -
Agrega la credencial federada. En esa aplicación, abre Certificates & secrets, Federated credentials, Add credential, y elige el escenario "GitHub Actions deploying Azure resources". Introduce la organización
Ahmed-G-Gad, el repositorioapothem, el tipo de entidadEnvironment, el nombre de entornoreleasey el nombre de credencialapothem-release. Los campos generados deben decir:issuer: https://token.actions.githubusercontent.com subject: repo:Ahmed-G-Gad/apothem:environment:release audience: api://AzureADTokenExchangeLa coincidencia es exacta y distingue mayúsculas de minúsculas. Si un inicio de sesión posterior falla con AADSTS700213 o AADSTS7002138, compara la credencial con la línea
subject claimqueAzure/loginescribe en el registro del trabajo. AADSTS70021 justo después de la creación significa que la credencial todavía no se ha propagado; espera unos minutos y vuelve a intentarlo. -
Define las variables del repositorio. Mientras
VSCODE_MARKETPLACE_READYseatrue, la ruta de Entra se activa en cuanto las tres están definidas, así que defínelas cuando ninguna etiqueta de lanzamiento esté esperando aprobación. SinVSCODE_MARKETPLACE_READY=truenada inicia sesión y la ejecución omite la publicación.gh variable set AZURE_CLIENT_ID --body "<application-client-id>" gh variable set AZURE_TENANT_ID --body "<directory-tenant-id>" gh variable set VSCE_AUTH --body entraDeja
VSCODE_MARKETPLACE_READYyVSCE_PATcomo están. CuandoVSCE_AUTHesentraperoAZURE_CLIENT_IDoAZURE_TENANT_IDestá vacío, el flujo de trabajo registra una advertencia, esté o no definidoVSCE_PAT, y no usa la ruta de Entra. Después usa el secretoVSCE_PATsi está definido; sin secreto no publica nada y la ejecución termina igualmente en verde, así que busca la advertencia. -
Ejecuta la ejecución de prueba. Despacha el flujo de trabajo para una etiqueta de lanzamiento existente con
dry_runactivado. En la ruta de Entra inicia sesión, imprime el perfil de Azure DevOps y verifica el acceso al publicador sin publicar. La ruta del token no tiene ejecución de prueba: si el registro muestraMarketplace credential mode: pat, la ejecución termina en verde con una advertencia y no ha verificado nada. Aprueba la ejecución en espera del entornorelease.gh workflow run publish-vscode.yml --ref main -f tag=vX.Y.Z -f dry_run=trueResultado esperado:
Marketplace credential mode: entra, una líneasubject claimigual al subject del paso 3, y elidy eldisplayNamedel perfil impresos por el primer paso de la ejecución de prueba. Se espera que el paso de verificación falle con un 403 hasta el paso 6. Sin confirmar: que un inicio de sesión sin una suscripción de Azure produzca un token para el Marketplace a través de la CLI de Azure. Esta ejecución es la primera prueba de ello. Si falla aquí, registra en su lugar una identidad administrada asignada por el usuario en una suscripción, que es la ruta que documenta Microsoft. -
Agrega la aplicación al publicador. En la pestaña Members del paso 1, inicia sesión como Owner del publicador y agrega un miembro con el
iddel perfil del paso 5, con el rol Contributor. Sin confirmar: la etiqueta del campo del cuadro de diálogo, y si acepta el id antes de que la aplicación sea miembro de una organización de Azure DevOps. Por regla general, Azure DevOps agrega las identidades de aplicación por organización. Si el cuadro de diálogo rechaza el id, agrega la entidad de servicio a la organizaciónAhmed-G-Gad(Organization settings, Users, con el Object ID de la Enterprise application) y vuelve a intentarlo. También sin confirmar: si el perfil existe antes de la primera llamada de la identidad a Azure DevOps. -
Repite la ejecución de prueba. El paso de verificación ahora tiene éxito con "verification succeeded for the publisher"; sus mensajes siguen diciendo Personal Access Token, porque el token de Entra recorre el mismo camino. La comprobación demuestra la pertenencia al publicador (Creator, Owner, Contributor o Reader), no los derechos de publicación. Sin confirmar: que Contributor baste para publicar una actualización. La descripción del rol de Microsoft dice que sí, y ninguna fuente muestra una publicación con él, así que la primera publicación real es la prueba.
-
Publica un lanzamiento. Etiqueta como en §2.2 y aprueba la ejecución. Se ejecuta el paso
Publish to Visual Studio Marketplace (Entra ID), su encabezado de entorno lista soloAZURE_TENANT_ID, el paso de alternativa con token se omite y vsce imprimeDONE Published ahmed-g-gad.apothem-vscode. La galería del Marketplace lista la nueva versión al cabo de unos cuatro minutos. -
Decide qué hacer con el token. Conserva
VSCE_PAThasta la primera publicación correcta con Entra y luego elimina el secreto si no quieres ninguna alternativa. Una vez eliminado, una variable de Entra eliminada o vacía deja la ejecución en verde sin publicar: con una advertencia cuandoVSCE_AUTHsigue siendoentra, y solo con el aviso de omisión cuando no lo es. Lee las anotaciones de la ejecución después de cada etiqueta. Para conservar una alternativa más allá de la retirada de los tokens de acceso personal globales, crea un token con ámbito de organización paraAhmed-G-Gadcon el ámbito personalizado Marketplace Manage y la caducidad más corta que aceptes, y guárdalo comoVSCE_PAT. Sin confirmar: las etiquetas del portal de este paso proceden de memoria, no de una fuente primaria; Microsoft llama a los tokens con ámbito de organización una solución temporal y puede dejar de aceptarlos; y las páginas de Microsoft no coinciden en la fecha de retirada de los tokens globales. -
Recurre al token. Elimina el selector y vuelve a despachar; luego aprueba la ejecución. Una publicación fallida con Entra no publicó nada, así que se puede volver a despachar la misma etiqueta; comprueba antes la página del Marketplace, porque una versión que ya llegó no se puede publicar dos veces.
gh variable delete VSCE_AUTH gh workflow run publish-vscode.yml --ref main -f tag=vX.Y.Z
Cuando la publicación con Entra falle, lee el registro del paso:
- Un mensaje que empieza por "Can not acquire a Microsoft Entra ID access token"
significa que falló el inicio de sesión o la cadena de credenciales.
Comprueba primero el paso
Sign in to Microsoft Entra IDy la credencial federada. Si el inicio de sesión está en verde, quitaAZURE_TENANT_IDdelenvdel paso de vsce en el flujo de trabajo; el propio flujo de trabajo de lanzamiento de extensiones de GitHub no lo exporta. - "InvalidAccessException" o "not allowed" significa que la identidad del token
no es miembro del publicador. Compara el
iddel perfil de la ejecución de prueba con la pestaña Members. - Un 403 del paso de verificación de la ejecución de prueba significa que la aplicación todavía no tiene ningún rol.
A esta ruta se aplican tres límites:
id-token: writese concede a todo el trabajo de publicación, así que cualquier paso de ese trabajo puede solicitar un token OIDC, también en modo token. El subject del token está vinculado al entornorelease, que requiere la aprobación de un revisor.- El entorno
releaseno tiene ninguna política de ramas ni de etiquetas de despliegue, así que cualquier ref que apruebe un mantenedor puede obtener el token con el subject del entorno. Restringirlo a etiquetasv*.*.*requiere comprobar primero qué despachanrelease.ymlypublish-npm.yml. - Un cambio de nombre o una transferencia del repositorio cambia el formato del
subject de OIDC y rompe en silencio la credencial federada. Después de
cualquier cambio de nombre, vuelve a copiar el subject del registro de
Azure/loginen la credencial.
2.5 Actualizar el pin del digest de plantillas
Una vez que exista la etiqueta, define _LATEST_RELEASE y
_LATEST_RELEASE_DIGESTS en tests/unit/test_template_digests.py con el nuevo
lanzamiento y el digest SHA-256 de cada plantilla de texto plano tal como la
distribuyó ese lanzamiento
(git show vX.Y.Z:<template path> | sha256sum). Hazlo en el siguiente cambio a
main, y agrega el digest anterior a earlier_digests de la entrada
del manifiesto cuando la plantilla haya cambiado. El trabajo de CI
release-preflight hace checkout de cada etiqueta, así que falla con los nombres
de las etiquetas hasta que se actualiza el pin.
3. Superficies de distribución
Cada superficie tiene un comando de verificación que responde a «¿llegó el lanzamiento aquí?»:
| # | Superficie | Artefacto | Verificación |
|---|---|---|---|
| 1 | GitHub Release (distribuciones de Python) | apothem-X.Y.Z.tar.gz (sdist) + apothem-X.Y.Z-py3-none-any.whl | gh release view vX.Y.Z --json assets --jq '.assets[].name' incluye ambos nombres de archivo |
| 2 | GitHub Release (SBOM) | sbom.cdx.json + sbom.cdx.json.cosign.bundle | la lista de recursos incluye ambos; el metadata.component.purl del SBOM es pkg:pypi/[email protected] y sus componentes incluyen cada paquete de src/apothem/_vendor/vendor.txt |
| 3 | GitHub Release (firmas) | un <asset>.cosign.bundle por cada sdist, wheel, SBOM, extensión de VS Code, archivo comprimido por plataforma y SHA256SUMS (en los lanzamientos anteriores, los bundles de los archivos comprimidos y de SHA256SUMS se llaman <asset>.sig) | cosign verify-blob con la identidad exacta de §5.5 termina con código 0 |
| 4 | GitHub Release (procedencia) | provenance.intoto.jsonl | bash scripts/release/verify-provenance.sh <download-dir> termina con código 0 (§5.5) |
| 5 | GitHub Release (archivos comprimidos por plataforma) | apothem-vX.Y.Z-darwin.tar.gz, apothem-vX.Y.Z-linux.tar.gz, apothem-vX.Y.Z-windows.zip | la lista de recursos incluye cada archivo comprimido más SHA256SUMS. Los archivos comprimidos de darwin y linux son los mismos bytes con dos nombres (el runtime es independiente de la plataforma; --platform solo elige entre tar.gz y zip), por lo que sus líneas de SHA256SUMS muestran un mismo digest dos veces |
| 6 | GitHub Release (extensión de VS Code) | apothem.vsix + apothem.vsix.cosign.bundle | la lista de recursos incluye ambos; code --install-extension apothem.vsix la instala. Los lanzamientos anteriores a que el flujo de trabajo de lanzamiento empaquetara la extensión no incluyen ninguno de los dos |
| 7 | npmjs.com | @ahmed-g-gad/[email protected] | npm view @ahmed-g-gad/apothem version devuelve X.Y.Z; npx @ahmed-g-gad/[email protected] --version imprime Apothem, version X.Y.Z |
| 8 | Pages (instaladores de script) | install.sh / install.ps1 en el sitio de documentación | curl -fsSL https://apothem.ahmedgad.com/install.sh | head -n 1 devuelve el encabezado del script |
| 9 | Visual Studio Marketplace | ahmed-g-gad.apothem-vscode versión X.Y.Z | la página de la extensión en el Marketplace lista X.Y.Z; code --install-extension ahmed-g-gad.apothem-vscode la instala |
El GitHub Release es la superficie canónica de artefactos; el paquete de npm y los instaladores de script son las rutas de instalación que se apoyan sobre él. La publicación en npm se ejecuta junto al flujo de trabajo de lanzamiento, con el mismo push de la etiqueta.
4. Disciplina del CHANGELOG
CHANGELOG.md lleva una sección por lanzamiento según la convención
Keep-a-Changelog. La edición del CHANGELOG en el commit de lanzamiento:
- Confirma que la sección de versión usa el encabezado
## [X.Y.Z] - YYYY-MM-DD(con guion;bump_version.pylo escribe, yextract_release_notes.pyreconoce el prefijo## [X.Y.Z]). - Confirma que los encabezados estándar —Added, Changed, Deprecated, Removed, Fixed, Security— se usan donde corresponda. Los encabezados vacíos se eliminan del archivo renderizado.
- Recoge capacidades, no implementación. Solo lenguaje del dominio; sin referencias internas del plan; sin hashes de commit; sin identificadores de plan ni de fase.
Una sección del CHANGELOG que superó la revisión del mantenedor sirve como ancla de las notas de lanzamiento para el relato del anuncio.
5. Prueba de humo de las rutas de instalación
Cuando ambas etapas se completan, el mantenedor ejecuta la prueba de humo. La prueba de humo es la verificación canónica de que los comandos de instalación orientados al usuario responden.
5.1 Plugin de Claude Code
/plugin marketplace add ahmed-g-gad/apothem
/plugin install apothem@apothemEsperado: el plugin se instala y los comandos apothem están disponibles dentro
de Claude Code.
5.2 Node.js (npx)
npx @ahmed-g-gad/[email protected] --versionSalida esperada: Apothem, version X.Y.Z.
5.3 Instalador de script de un solo paso (POSIX)
El instalador escribe el lanzador apothem en ~/.local/bin, o en el directorio que indica APOTHEM_BIN_DIR cuando esa variable está definida. La comprobación siguiente necesita que ese directorio esté en PATH. Cuando no lo está, el instalador imprime la línea export PATH que hay que añadir. Mientras ese directorio no esté en PATH, el shell no encuentra apothem y la comprobación falla. Si el instalador no puede colocar el lanzador, imprime una advertencia y no imprime ninguna línea export PATH. En un equipo que todavía no tiene la clave de firma del mantenedor, la primera línea la importa; sin ella, el instalador se detiene.
curl -fsSL https://github.com/ahmed-g-gad.gpg | gpg --import
curl -fsSL https://apothem.ahmedgad.com/install.sh | sh
apothem --versionSalida esperada: Apothem, version X.Y.Z.
5.4 Instalador de script de un solo paso (Windows)
La primera línea importa la clave de firma del mantenedor a través del propio bash de Git, cuyo llavero de gpg es el que lee git verify-tag.
& "$env:ProgramFiles\Git\bin\bash.exe" -c 'curl -fsSL https://github.com/ahmed-g-gad.gpg | gpg --import'
irm https://apothem.ahmedgad.com/install.ps1 | iex
apothem --versionSalida esperada: Apothem, version X.Y.Z.
5.5 Verificación de artefactos (evidencia de la cadena de suministro)
Descarga todos los recursos en un directorio vacío y luego verifica. La
identidad del certificado es el flujo de trabajo de lanzamiento en esta etiqueta
exacta. Las comprobaciones de identidad distinguen entre mayúsculas y
minúsculas, y los certificados llevan el propietario tal como lo reporta GitHub,
Ahmed-G-Gad, por lo que un propietario en minúsculas falla.
mkdir release-vX.Y.Z && cd release-vX.Y.Z
gh release download vX.Y.Z --repo ahmed-g-gad/apothem
cosign verify-blob \
--bundle apothem-X.Y.Z-py3-none-any.whl.cosign.bundle \
--certificate-identity https://github.com/Ahmed-G-Gad/apothem/.github/workflows/release.yml@refs/tags/vX.Y.Z \
--certificate-oidc-issuer https://token.actions.githubusercontent.com \
apothem-X.Y.Z-py3-none-any.whl
slsa-verifier verify-artifact \
--provenance-path provenance.intoto.jsonl \
--source-uri github.com/Ahmed-G-Gad/apothem \
--source-tag vX.Y.Z \
apothem-X.Y.Z-py3-none-any.whl apothem-X.Y.Z.tar.gz
bash ../scripts/release/verify-provenance.sh .Esperado: Verified OK, PASSED: SLSA verification passed y
verify-provenance: chain OK (3 of 3 layers verified). El script comprueba
SHA256SUMS, cada bundle de firma y la procedencia en una sola ejecución; deriva
la etiqueta del nombre del wheel (--tag vX.Y.Z la reemplaza).
La prueba de humo produce una fila PASS / FAIL de una línea por superficie; registra las filas en el registro de lanzamientos del mantenedor.
6. Recuperación ante fallos
El flujo de trabajo de lanzamiento tiene modos de fallo documentados para el motor de lanzamiento y el publicador de npm:
| Fallo | Diagnóstico | Recuperación |
|---|---|---|
| Push de la etiqueta rechazado (fallo de firma) | git push origin vX.Y.Z devuelve error: failed to push some refs con un mensaje relacionado con GPG | Verifica que la subclave GPG esté cargada (gpg --list-secret-keys --keyid-format=long); vuelve a etiquetar localmente con -s después de corregir el llavero; vuelve a hacer push |
La compilación del lanzamiento se detiene en Check the plugin version changed with the plugin | El registro del trabajo de compilación nombra el plugin y la etiqueta anterior; no se compiló ni se publicó ningún recurso | El paquete del plugin cambió desde el lanzamiento anterior, pero su versión no. Elimina la etiqueta (git push --delete origin vX.Y.Z, git tag -d vX.Y.Z), ejecuta python scripts/release/bump_version.py X.Y.Z, haz commit y luego vuelve a firmar y hacer push de la etiqueta (§2.2). La misma comprobación se ejecuta en cada pull request como anotación de advertencia, por lo que normalmente esto aparece antes de etiquetar |
Un trabajo de release.yml falla en una sola etapa | gh run view <run-id> --log nombra el trabajo que falla (build, que también escribe el SBOM / sign / provenance / archive / publish) | Vuelve a ejecutar solo el trabajo fallido mediante gh run rerun <run-id> --failed; si el fallo se repite, corrige la entrada del trabajo en su origen antes de volver a etiquetar |
| La verificación de la procedencia SLSA falla | El trabajo verify SLSA provenance artifact termina con un código distinto de cero | Inspecciona el artefacto de procedencia en busca de un desajuste del digest del sujeto; recompila desde la misma etiqueta: la procedencia se vincula a los digests exactos de los artefactos, por lo que cualquier regeneración de artefactos requiere volver a ejecutar el flujo de trabajo completo |
| Publicación en npmjs.com rechazada | El trabajo de npm termina con un código distinto de cero durante npm publish; un 404 del registro durante PUT es un desajuste de autorización / publicador de confianza, no una prueba de que falte el código del paquete | Verifica que npm Trusted Publishing para @ahmed-g-gad/apothem nombre al propietario ahmed-g-gad, el repositorio apothem, el flujo de trabajo publish-npm.yml y la acción permitida npm publish; confirma que el trabajo se ejecuta con la versión de Node y la versión mínima de la CLI de npm para OIDC fijadas en el flujo de trabajo |
| Etiqueta visible, pero faltan recursos | gh release view vX.Y.Z devuelve un lanzamiento incompleto | Vuelve a ejecutar el trabajo de publicación del flujo de trabajo de lanzamiento; este edita el lanzamiento existente y vuelve a subir cada recurso. Elimina la etiqueta y vuelve a etiquetar solo cuando nada de la etiqueta llegó a los usuarios (sin recursos, sin versión de npm); en caso contrario, corrige hacia adelante con el siguiente lanzamiento de parche (runbook de recuperación de lanzamientos §2) |
Si un ciclo de recuperación no logra completar una superficie en una sola pasada de diagnóstico, la superficie se registra como fallo conocido en las notas de lanzamiento, con un enlace al issue abierto; a los usuarios de aguas abajo se les dirige a las superficies que funcionan mientras la defectuosa se corrige en un lanzamiento de parche.
7. Referencias cruzadas
- Configuración del publicador. El runbook de configuración de la cuenta de publicador establece el vínculo de publicador de confianza de npm y los requisitos previos del lado de GitHub que este runbook da por supuestos.
- Flujo de recuperación. El runbook de recuperación de lanzamientos sigue el mismo modelo aditivo: recupera una etiqueta o una etapa de publicador fallida, etapa por etapa, y revierte lanzando la corrección como una nueva versión de parche, nunca eliminando ni redirigiendo una etiqueta, un lanzamiento o una versión de npm publicados.
- Habilitación de Pages. El flujo de trabajo
publish-static-site.ymlvalida y despliega el sitio web del proyecto en el dominio personalizado; el runbook de habilitación de Pages (site/content/docs/runbooks/pages-enablement.mdx) es el procedimiento previo que estableció el dominio personalizado en primer lugar. - Política de versionado.
site/content/docs/governance/release-engineering-policy.mdxcontiene la política de SemVer + firma + obsolescencia que este runbook respeta.