Keyboard shortcuts

Press ← or → to navigate between chapters

Press ? to show this help

Press Esc to hide this help

CI y Acciones

Cada workflow vive en .github/workflows/. Las secciones a continuación los agrupan por desencadenador: automáticos en eventos de git, o workflows invocados por mantenedores/de asesoramiento mediante workflow_dispatch y programaciones.

Flujos de trabajo automáticos

Puerta de calidad (ci.yml)

Se activa en cada PR dirigido a master y en pushes confiables a master. Job compuesto con múltiples ramas de matriz:

  • fmt: cargo fmt --all -- --check

  • history-guard: obtiene el historial completo y compara el commit en pruebas con origin/master; las solicitudes de extracción usan el github.event.pull_request.head.sha explícito, mientras que los pushes de confianza y las ejecuciones de merge-queue usan github.sha. El guard y su prueba con fixture rechazan un git merge-base vacío, evitando que una segunda raíz injertada colapse git blame después de la fusión

  • lint: cargo clippy --workspace --exclude zeroclaw-desktop --all-targets --features ci-all -- -D warnings, después cargo doc --no-deps --workspace --exclude zeroclaw-desktop (las advertencias de rustdoc son errores fatales mediante .cargo/config.toml build.rustdocflags; desktop se excluye para ajustarse a xtask build_api / docs-deploy y evitar GTK/glib-sys en el ejecutor de lint), y la comprobación de higiene de comentarios

  • build: matriz incondicional para x86_64-unknown-linux-gnu y aarch64-apple-darwin; un job separado windows-build comprueba x86_64-pc-windows-msvc cuando la propiedad de paquetes selecciona cualquiera de sus comandos

  • check: dos pasadas con advertencias como errores sobre el workspace (excluyendo zeroclaw-desktop): sin funcionalidades predeterminadas; y funcionalidades predeterminadas con --all-targets, que es la única pasada que compila los targets de prueba sobre la superficie de funcionalidades predeterminadas. La superficie con todas las funcionalidades es compilada y verificada por tipos en lint, cuyo paso de clippy ejecuta --features ci-all --all-targets sobre el mismo workspace; una pasada separada de cargo check con todas las funcionalidades duplicaría esa compilación sin aportar cobertura.

  • check-32bit: i686-unknown-linux-gnu sin características predeterminadas

  • check-plugin-backends: seleccionado por scripts/ci/plugin_backend_change_filter.sh. Compila zeroclaw-plugins con cada backend de ejecución y ejecuta las pruebas de componentes, de admisión en tiempo de ejecución y de plugins de la CLI raíz bajo plugins-wasm-cranelift. Un paso separado, smoke de artefactos de plugin, compila el binario zeroclaw con la misma feature y ejecuta scripts/ci/plugin_artifact_smoke.sh contra él, con los paquetes generados por scripts/ci/build_plugin_smoke_packages.sh. El smoke acepta cualquier binario zeroclaw, usa un directorio de configuración desechable y el proveedor local scriptado de scripts/ci/plugin_smoke_provider.py, y ejecuta los comandos propios del operador: plugin install, config set y un turno de agente que ejecuta la herramienta. Comprueba que un plugin instalado permanece sin usarse hasta que el operador habilita el sistema de plugins, activa el descubrimiento y aprueba la herramienta; que los valores configurados para un paquete que no los solicita no se entregan; que una carga útil con digest incorrecto, una carga útil que no es un componente y un componente para otro mundo WIT son rechazados; y que el modo de firma estricto rechaza un paquete sin firma, no confiable o editado, mientras ejecuta uno confiable. El último paso del paso ejecuta el smoke con la expectativa opuesta y exige el código de salida reservado para una comprobación fallida.

    El turno de agente también depende de crates que el filtro de rutas no selecciona, como zeroclaw-providers, zeroclaw-tools, zeroclaw-memory y zeroclaw-api, por lo que una rotura en ellos aparece primero en las ejecuciones de la cola de merge y de master, donde el job siempre se ejecuta.

  • bench: verifica la compilación de los benchmarks; se ejecuta en los push a master, en las ejecuciones de la cola de fusión y en el despacho manual únicamente. Los PR omiten esta comprobación (la puerta de calidad trata el omitido como no fatal), por lo que el deterioro de los benchmarks se sigue detectando antes de una publicación sin gastar la compilación en cada PR.

  • test: el gate independiente de protocolo de firmware para hosts desde scripts/ci/firmware_protocol_gate.sh y cargo nextest run --locked --workspace --exclude zeroclaw-desktop en Linux, incluyendo las guardas de arquitectura de aislamiento de escritura de configuración y de cobertura de Fluent (sin cadenas visibles para el usuario sin localizar). Un paso informativo final reproduce los escenarios de fotogramas dorados de la gateway (crates/zeroclaw-gateway/tests/golden_frames.rs: chat por WebSocket, webhook JSON y SSE, /api/events y ACP) contra sus fixtures grabados con --run-ignored only. Reutiliza la compilación del job, escribe cualquier divergencia en el resumen del paso con una advertencia y nunca hace fallar el job; seguirá siendo informativo hasta que la gateway se conecte con el núcleo por RPC.

  • test-tool-features: las pruebas de los adaptadores SaaS, de CLI de programación y externos de adhesión voluntaria, que Cargo default ya no compila: cargo nextest run sobre las pruebas de biblioteca de la raíz, config, tools, runtime, channels y gateway, más las pruebas de integración de plantillas de informe de la raíz, con --features tools-compat. lint compila el mismo código bajo ci-all, pero no ejecuta ninguna prueba

  • memory-postgres-test: cargo nextest run --locked -p zeroclaw-memory --features memory-postgres, seguido de las pruebas de aceptación seriales ignoradas del crate contra un servicio efímero de PostgreSQL 17

  • parallel-runtime-test: pruebas repetidas de runtime/canal en el mismo proceso desde scripts/ci/parallel_runtime_test_gate.sh, ejecutadas en paralelo con el trabajo de pruebas principal para las rutas de PR relevantes y de forma incondicional en los pushes a master y las ejecuciones de la cola de fusión

  • seguridad: cargo deny check

  • nix-eval: evalúa las aserciones del módulo de NixOS (verificación del flake nixos-module-eval)

  • docs-style: lint de Markdown, comprobación de prosa con raya larga y verificación de enlaces en líneas modificadas mediante scripts/ci/docs_quality_gate.sh y scripts/ci/docs_links_gate.sh

Los jobs de Linux del gate requerido se ejecutan en Blacksmith, excepto la comprobación de Landlock que depende del kernel: la flota intensiva en compilación en blacksmith-8vcpu-ubuntu-2404 y el conjunto de tareas de mantenimiento (fmt, los detectores de cambios, los guardas del repositorio, los gates de documentación y política, las comprobaciones de Nix, la prueba de humo del contenedor, security, web-permission-tests y el propio agregador gate) en blacksmith-4vcpu-ubuntu-2404. La única excepción deliberada en Linux es test-landlock, que permanece en ubuntu-latest alojado por GitHub porque la comprobación del LSM Landlock depende del kernel alojado. La recuperación de propietario de tareas en Windows usa blacksmith-8vcpu-windows-2025; macOS y los demás jobs de Windows mantienen sus runners alojados por GitHub. Esta división existe porque la asignación de runners alojados de GitHub se detuvo en toda la organización el 2026-09-14, mientras Blacksmith seguía dando servicio: con los jobs de mantenimiento trasladados, una caída de los runners alojados solo afecta a las comprobaciones específicas de plataforma en lugar de a todo el gate requerido. Todos los jobs declaran sus etiquetas de runner y las entradas del proveedor de caché directamente; tests/architecture/ci_runner_labels.rs verifica los inventarios de Linux (flota de compilación, flota de mantenimiento y la lista de permitidos de Linux alojado), así como el contrato del runner de Windows solo para recuperación y del escritor de caché. Los jobs de trabajo no esperan a fmt; la contrapartida deliberada es más trabajo de runners en los PR que fallan el formateo. CI Required Gate sigue necesitando fmt directamente y agrega los resultados requeridos, por lo que los errores de formateo siguen bloqueando la fusión. El workflow de Windows asesor, controlado por etiquetas por separado, permanece fuera de ese gate. Su selector de Linux también se ejecuta en la clase de 4 vCPU de Blacksmith. La protección de ramas fija el job compuesto del gate. La ejecución de push a master mantiene la misma señal de calidad mientras prepara cachés de Rust de confianza para las ejecuciones de PR posteriores.

Las pull requests y las entradas de la cola de fusión que cambian [workspace.package] version a una versión estable X.Y.Z también ejecutan crates-preflight, que invoca pub-crates.yml con stage: preflight, sin secreto y con la etiqueta de runner de la flota de compilación. crates-preflight-changes decide esto mediante scripts/ci/crates_preflight_trigger.sh; cualquier otro cambio omite ambos jobs, y un job omitido no hace fallar el gate. Como el job es una llamada a un workflow reutilizable sin runs-on, tests/architecture/ci_runner_labels.rs lo inventaría por separado y exige que pase la etiqueta de la flota.

Los inventarios de runners abarcan tanto ci.yml como windows-tests.yml, con identidades de trabajo calificadas por workflow para que los trabajos con el mismo nombre no puedan ocultarse entre sí. La matriz build de Linux/macOS no espera a ningún detector. Los trabajos separados de compilación, servicio y recuperación de Windows esperan al detector windows-required-changes de Blacksmith. Ese detector lee la propiedad de los paquetes con cargo metadata --locked --offline --no-deps, sin resolución de registro ni descargas. El detector path-changes, que no es de Rust, sigue siendo independiente de este grafo de paquetes.

En pushes a master únicamente, los trabajos intensivos en compilación (y los detectores que habilitan los trabajos de clippy en Windows y de runtime paralelo) esperan primero cinco minutos en master-debounce. Los pushes a master llegan en ráfagas, y cancel-in-progress a nivel de ejecución solo cancela un push reemplazado después de que su flota de compilación ya se ha iniciado. Con la espera, un push reemplazado dentro de esa ventana se cancela mientras el trabajo barato sigue en suspenso. El trabajo se omite en las ejecuciones de pull request y de cola de fusión, y un trabajo omitido se resuelve sin usar un runner, por lo que su latencia no cambia. Como GitHub propaga un ancestro omitido a través de un success() implícito, cada trabajo posterior a master-debounce incluye una condición explícita !cancelled() más una comprobación del resultado de cada dependencia, y tests/architecture/ci_runner_labels.rs falla si alguno no la cumple. CI Required Gate necesita master-debounce, así que un fallo en el debounce no puede dejar trabajos de compilación omitidos detrás de una puerta en verde. El precio es de cinco minutos adicionales antes de que una ejecución de master empiece a compilar, lo que también retrasa en el mismo tiempo la carga de las cachés de Rust de master.

Fresh required CI suele ser la evidencia compartida para las superficies de Cargo que realmente ejecuta. Una nueva ejecución local del mismo comando de Cargo en el mismo head, destino y conjunto de características es confianza duplicada, no una prueba más sólida. Antes de pedir Cargo o Clippy adicionales, compara la superficie modificada con los archivos de flujo de trabajo actuales y las comprobaciones reales en el PR. La validación adicional corresponde donde la puerta de entrada requerida no demuestra lo que está bajo revisión:

  • una plataforma recibió comprobaciones de compilación, pero no pruebas;
  • una plataforma, crate o ruta está fuera del trabajo de lint requerido;
  • un cambio de escritorio no activó el flujo de trabajo de escritorio;
  • un objetivo de release está fuera de la matriz de PR y solo está cubierto por los flujos de trabajo release/manual;
  • CI obsoleta, cancelada, omitida o no disponible no es evidencia reciente.

Cuando una definición o importación está condicionada por una feature, compara su predicado cfg con cada consumidor. Valida tanto la configuración habilitada como cada configuración deshabilitada pertinente: una comprobación con la feature habilitada demuestra que el consumidor sigue funcionando, mientras que la comprobación de todo el workspace con no-default-features detecta discrepancias que producen advertencias, como definiciones privadas o importaciones sin usar. Esa comprobación ejecuta cargo check sin --all-targets, por lo que nunca compila los destinos de prueba: un auxiliar condicionado por un test simple cuyos únicos llamadores están detrás de una feature se detecta, en cambio, en la etapa de default-features/all-targets. Las combinaciones de features específicas siguen siendo necesarias cuando ninguna de las dos configuraciones de CI requeridas ejercita el predicado modificado.

El job de memoria de PostgreSQL ejecuta todas las pruebas no ignoradas de zeroclaw-memory con memory-postgres habilitado y, a continuación, ejecuta en serie las pruebas ignoradas del crate con ZEROCLAW_TEST_POSTGRES_URL apuntando a su servicio desechable. Para reproducir localmente la mitad que depende de la base de datos, proporcione una base de datos PostgreSQL aislada y ejecute ZEROCLAW_TEST_POSTGRES_URL=postgres://<user>:<password>@127.0.0.1:5432/<database> cargo test --locked -p zeroclaw-memory --features memory-postgres -- --ignored --test-threads=1. Cada prueba de aceptación posee un esquema con nombre único y elimina únicamente ese esquema.

La compilación requerida de Windows sigue siendo automática sin etiqueta, pero solo verifica el código que los comandos pueden compilar. En los PR, scripts/ci/windows_test_scope.py --required-jobs reutiliza la clasificación de la raíz del paquete y el cierre de dependencias inversas. El comando raíz se ejecuta cuando el cierre afectado contiene zeroclaw; el comando voice-wake se ejecuta cuando contiene zeroclaw-channels. Las aristas de ruta internas incluyen de forma conservadora las dependencias opcionales, específicas de destino, de compilación y de desarrollo. Una edición aislada solo de ZeroCode no ejecuta estos comandos no relacionados. Los manifiestos del workspace, los lockfiles, las toolchains, la configuración de Cargo, los controles de workflow/action, las rutas desconocidas y la evidencia ausente o malformada seleccionan todos los trabajos requeridos de Windows. Los push a master y las compilaciones de la cola de fusión siempre ejecutan todos ellos. La compilación de Linux/macOS sigue siendo incondicional.

La prueba de humo del servicio compila windows_service_smoke_fixture, que gestiona su daemon sintético y el despacho de argumentos. Los cambios en la CLI raíz de src/main.rs no seleccionan automáticamente esta prueba. El código fuente del servicio, la conexión de módulos de runtime, el fixture y el script de humo, las dependencias de configuración y spawn, y los controles de manifiesto y compilación pertinentes mantienen su cobertura. El trabajo de recuperación del propietario de la tarea conserva los disparadores directos del plano de control y de la conexión de módulos de runtime. Los manifiestos de paquetes y los scripts de compilación seleccionan estos trabajos nativos cuando su cierre de dependencias inversas alcanza runtime; los manifiestos de gateway o de aplicaciones independientes no relacionados no lo hacen. El punto de entrada de shell de recuperación delega en el mismo selector de paquetes en lugar de mantener un segundo registro de propiedad.

Las pruebas de recuperación se ejecutan en su propio job windows-task-owner-recovery en blacksmith-8vcpu-windows-2025, en paralelo con la compilación, porque su arnés de pruebas unitarias en tiempo de ejecución no puede reutilizar la salida de cargo check. Un job no seleccionado se omite antes de asignar un runner de Windows. CI Required Gate consume directamente el detector y cada job de Windows obligatorio, rechaza las salidas de selección que falten y exige que todo job seleccionado termine con éxito. Un job seleccionado que se omite, falla o se cancela no puede contar como omisión intencionada.

Recovery llama directamente a la acción fijada Swatinem/rust-cache con shared-key: windows-recovery-blacksmith, en lugar de asumir que la caché del runner de compilación de GitHub tiene un hash de entorno de Rust compatible. Solo las ejecuciones push exitosas en refs/heads/master guardan esta caché de dependencias dedicada; las ejecuciones de PR y de la cola de fusión solo la restauran. Un fallo de caché compila con normalidad y no omite ninguna de las dos pruebas. La limpieza predeterminada de artefactos del espacio de trabajo sigue habilitada, por lo que el harness de runtime sigue compilándose. Esto añade un espacio de nombres de caché que consume almacenamiento del repositorio; la compilación y las pruebas de humo del servicio mantienen sus runners y cachés existentes.

Pruebas de ventanas de asesoramiento con control por etiquetas (windows-tests.yml)

Usa ci:windows cuando ejecutar las pruebas en Windows pueda cubrir una brecha importante que la compilación no detecta. Los casos típicos incluyen cambios en el ciclo de vida de procesos o servicios, ejecución de PowerShell, manejo de sistema de archivos y rutas, codificación, dependencias nativas y cambios en la selección o ejecución de CI para Windows. No es una etiqueta predeterminada para cada PR de Rust, ni para cambios que solo afectan la documentación, ni para fallos de pruebas de Linux no relacionados.

Añade la etiqueta cuando el candidato sea lo bastante estable como para obtener evidencia útil en Windows. Mantenla durante las iteraciones centradas en Windows, cuando cada actualización necesite otra ejecución; retírala después de completar una validación puntual si los envíos posteriores no necesitan esa cobertura. La compilación obligatoria en Windows sigue siendo automática sin la etiqueta. Las pruebas nocturnas de plataforma son una red de seguridad posterior a la fusión, no un sustituto de la ejecución previa a la fusión cuando un cambio necesita pruebas específicas de Windows.

Añade la etiqueta ci:windows a un PR dirigido a master para activar las pruebas de Windows de carácter informativo. Al añadir la etiqueta se inicia el flujo de trabajo para la revisión actual del PR. Los envíos (pushes) y los eventos de reapertura lo vuelven a ejecutar mientras la etiqueta siga presente. Las adiciones de otras etiquetas no vuelven a ejecutar las pruebas ni cancelan una ejecución de Windows activa. Quitar la etiqueta detiene las ejecuciones automáticas futuras, pero no cancela una ejecución que ya está en curso. La etiqueta es un interruptor de costo de cómputo, no una aprobación de seguridad; siguen aplicándose los requisitos normales de aprobación de flujos de trabajo de forks en GitHub.

El flujo de trabajo usa el evento pull_request ordinario de solo lectura, no pull_request_target, y prueba el SHA de fusión congelado del evento. No tiene disparador de ejecución manual. Mantenerlo separado de ci.yml permite que la adición de etiquetas inicie solo el flujo de trabajo consultivo, sin reiniciar el CI obligatorio. El control obligatorio no depende de estos trabajos.

Lea el resumen del selector y la propia conclusión y los registros del trabajo de Windows antes de dar por bueno un resultado. El trabajo de Windows usa continue-on-error, por lo que un resultado verde del flujo de trabajo por sí solo no demuestra que sus pruebas hayan pasado. Registre la revisión probada, el alcance seleccionado y cualquier fase de ejecución fallida. Distinga los fallos de las pruebas de los fallos de selección o del flujo de trabajo utilizando los registros.

El selector de Linux comprueba el formato, compara el SHA base del PR con la revisión de fusión extraída y genera los metadatos del workspace de Cargo. Escribe mode base, packages en JSON, un reason conciso y needs_plugin_host en las salidas del trabajo y en el resumen del paso. La etiqueta opta por el selector existente, no por un conjunto completo incondicional. Las pruebas nocturnas de cada plataforma siguen siendo el respaldo automático posterior a la fusión.

skip significa que ningún cambio en una ruta afecta a la compilación o a las pruebas de Rust cubiertas por la suite actual del workspace. scoped asigna las rutas de código fuente, pruebas, benchmarks, ejemplos y manifiestos locales de paquete de Rust a las raíces de paquete a partir de los metadatos de Cargo, cierra ese conjunto sobre los dependientes inversos del workspace, asigna los src/ y tests/ de la raíz al paquete raíz, elimina los nombres de paquete duplicados y excluye zeroclaw-desktop igual que la suite actual del workspace. full se selecciona para los manifiestos del workspace o la resolución de dependencias, .cargo, la toolchain de Rust, la infraestructura de CI o de pruebas, el selector o el workflow, las rutas desconocidas, los metadatos ambiguos y otros cambios que no pueden asignarse de forma segura. Cada cambio en Cargo.lock selecciona full, porque la resolución de dependencias a nivel de workspace puede afectar a paquetes más allá de los manifiestos cambiados directamente. Los cambios directos en los paquetes raíz, gateway o provider, así como los cambios en las rutas de plugin, runtime, configuración de plugins, WIT, activación de plugins en la raíz, filtro de backend de plugins, dependencias, selector, contrato del selector, ci.yml o windows-tests.yml, establecen needs_plugin_host=true. Los archivos que controlan estos casos hacen que las revisiones de workflow ejerciten la ruta de plugin-host que les corresponde. La entrada de rutas modificadas malformada o no disponible selecciona el full base y true. Los metadatos de Cargo ausentes o malformados también seleccionan el full base con needs_plugin_host=true, porque no se puede establecer de forma segura el cierre de dependencias.

Para scoped, el trabajo de Windows pasa argumentos -p explícitos a cargo nextest; para full, ejecuta cargo nextest run --locked --no-fail-fast --workspace --exclude zeroclaw-desktop. Cuando needs_plugin_host=true, instala wasm32-wasip2 y añade los destinos de componentes de zeroclaw-plugins con las funciones habilitadas (channel_plugin_e2e, tool_plugin_timeout_e2e, reference_plugin, reference_plugin_e2e y tool_plugin_e2e), las pruebas de la biblioteca de plugins, las regresiones de admisión y de configuración en vivo del runtime, las pruebas de la biblioteca de la puerta de enlace, las pruebas de plugins de la CLI raíz (el cliente del registro de plugins, los módulos plugins::, incluidas las pruebas de shell de Windows del ceremonial de egreso, las pruebas del ceremonial de egreso de la CLI y las pruebas de plugin update en el binario raíz), las pruebas de componentes plugin_update_cli y plugin_info_cli, que ejecutan el binario real, y los destinos raíz plugin_channel_runtime_e2e y channel_egress_e2e. Cada invocación añadida se ejecuta aunque falle una anterior, y el resumen conserva el estado de cada fase y el inventario de fallos. El trabajo informa duraciones separadas para la línea base, el plugin-host y el total. Las selecciones scoped y full ordinarias no pagan el costo de compilación del plugin-host. Este flujo de PR restaura entradas de caché platform-test compatibles, pero nunca las guarda. Hace checkout del SHA de fusión del PR congelado y no persiste las credenciales de checkout. Un trabajo de Windows omitido es intencional y se muestra junto al resultado del selector.

Pruebas de plataforma programadas (platform-tests.yml)

Ejecuta cargo nextest run --locked --workspace --exclude zeroclaw-desktop --no-fail-fast en macos-15 y windows-latest después de una comprobación de formato en Linux de bajo costo. Esta ejecución nocturna de todo el workspace es la red de seguridad cubierta por la cobertura de Windows seleccionada mediante etiquetas, y registra los fallos con --no-fail-fast. La matriz se ejecuta para:

  • solicitudes de incorporación de cambios que modifican el propio platform-tests.yml;
  • ejecuciones manuales; y
  • el horario nocturno de las 03:17 UTC.

Los trabajos usan continue-on-error y no alimentan CI Required Gate. Son evidencia de portabilidad, no requisitos para fusionar. Los PR de código habituales no lanzan esta matriz completa automáticamente; los mantenedores pueden dispararla manualmente contra una rama cuando una prueba completa de plataformas sea útil. El flujo de trabajo no se ejecuta para eventos push o merge_group habituales. Las ejecuciones nocturnas y las lanzadas manualmente en master pueden escribir cachés de confianza; las ejecuciones de pull request no pueden. --no-fail-fast mantiene visible cada fallo de plataforma en una única ejecución.

Escaneo diario de avisos (daily-audit.yml)

Ejecuta cargo deny check advisories diariamente a las 09:00 UTC contra el árbol de dependencias. Abre un issue cuando hay hallazgos. No se requiere ninguna acción a menos que se reporte una vulnerabilidad.

Auditoría diaria de npm (daily-npm-audit.yml)

Ejecuta npm audit --audit-level=high diariamente a las 09:23 UTC contra web/package-lock.json. Abre un único issue deduplicado de security + dependencies cuando avisos de npm de alta severidad afecten al lockfile web comprometido.

Escaneo semanal de imágenes con Trivy (trivy-scheduled.yml)

Analiza las imágenes GHCR de dist y default-features publicadas cada sábado y sube los hallazgos de gravedad ALTA/CRÍTICA a la pestaña Security como SARIF. El análisis es de informe prioritario (exit-code: 0 para hallazgos), pero una imagen esperada ausente hace fallar el trabajo antes de la configuración de Trivy, indicando la etiqueta ausente y el flujo de trabajo publicador propietario en el error.

Canary semanal del bucket de Scoop (scoop-bucket-canary.yml)

Prueba el flujo de publicación de Scoop con la versión estable actual cada lunes. Resuelve la etiqueta vX.Y.Z más reciente e invoca pub-scoop.yml con dry_run: true y credential_canary: true, de modo que pone a prueba el SCOOP_BUCKET_TOKEN real contra el bucket real sin escribir nada.

credential_canary es la parte de ese contrato que falla de forma segura: la ausencia de SCOOP_BUCKET_REPO o SCOOP_BUCKET_TOKEN hace que la ejecución falle, y las credenciales configuradas deben llegar a la comprobación de autorización de git push --dry-run. Una ejecución manual genérica de pub-scoop.yml que solo incluya dry_run: true sigue siendo permisiva para la generación del manifiesto y puede omitir esa comprobación cuando las credenciales no están disponibles; no uses el modo genérico como evidencia de verificación de credenciales.

Esto existe porque SCOOP_BUCKET_TOKEN está vinculado a una cuenta: caduca y pierde silenciosamente los permisos de escritura cuando cambia el permiso de colaborador de la identidad propietaria en el bucket. Ambas cosas han ocurrido. Antes del canario, lo único que ponía a prueba la credencial era el trabajo de scoop posterior a la publicación, por lo que un token inutilizado se descubría después de que la versión ya se había generado y anunciado, y el bucket tenía que actualizarse manualmente.

El canario detecta el deterioro de las credenciales. Deliberadamente, no es lo que mantiene el bucket en estado correcto y no está conectado a Release Stable: una credencial inservible del gestor de paquetes nunca debe bloquear ni retrasar una publicación.

Cómo se mantiene correcto el bucket de Scoop

Hoy, el publicador de versiones es el único escritor automatizado:

  1. pub-scoop.yml hace push al publicar. Los usuarios de Scoop ven la nueva versión inmediatamente cuando se completa correctamente. Necesita el SCOOP_BUCKET_TOKEN entre repositorios, que es la parte frágil.
  2. Los mantenedores recuperan los envíos fallidos. Rota o repara el token, envía Scoop Bucket Canary para verificarlo mediante la ruta credential_canary con cierre ante fallos, vuelve a ejecutar el publicador con dry_run: false y confirma que el manifiesto del bucket contiene la versión de lanzamiento.

Se propone un Excavator del lado del bucket en scoop-zeroclaw#1. Una vez que se fusione ese flujo de trabajo, el repositorio del bucket conceda a Actions permisos de lectura/escritura para los flujos de trabajo y una prueba de humo del mantenedor demuestre que realiza un commit con una actualización, puede convertirse en una capa de recuperación independiente de las credenciales. Hasta que se cumplan las tres condiciones, no se debe asumir que un publicador que haya fallado se recuperará automáticamente.

Los bloques checkver y autoupdate ya son fundamentales para la ruta prevista de Excavator. La ruta actual de publicación también usa scripts/release/scoop_metadata.sh para obtener la plantilla de URL de lanzamiento a partir de autoupdate, por lo que ambas rutas comparten un único contrato de manifiesto. No elimines esos bloques ni los quites manualmente de dist/scoop/zeroclaw.json.

Etiquetador de rutas de PR (pr-path-labeler.yml)

Aplica automáticamente etiquetas de ruta y alcance según los archivos modificados. Se ejecuta al abrir el PR, al reabrirlo y con cada actualización enviada a la rama del PR. Dado que sync-labels: true está habilitado, las etiquetas definidas en .github/labeler.yml se recalculan a partir del conjunto actual de archivos del PR.

Este flujo de trabajo no aplica etiquetas risk:*, size:*, type:*, de nivel de colaborador, de estado, de resolución, de stale ni de asignación. Si a un PR le falta una etiqueta de ruta o de ámbito, verifica si las rutas de .github/labeler.yml cubren los cambios.

Dependabot tiene una configuración de etiquetas separada en .github/dependabot.yml para sus propios PRs. Los PRs de actualización de Cargo comienzan con dependencies; los PRs de actualización de GitHub Actions y Docker comienzan con ci y dependencies.

Etiquetador de tamaño de PR (pr-size-labeler.yml)

Aplica exactamente una etiqueta canónica size:* a partir de los metadatos de archivos del PR. Se ejecuta al abrir o reabrir el PR y en cada actualización enviada a la rama del PR. El clasificador cuenta las adiciones más las eliminaciones, excluyendo los archivos de tipo documentación y Cargo.lock, y luego aplica la tabla de umbrales de Labels.

Este flujo de trabajo se ejecuta en pull_request_target para poder escribir etiquetas en los PR de forks, pero obtiene el script de clasificación de la revisión de confianza del flujo de trabajo o de la rama predeterminada. No hace checkout, no compila, no importa, no ejecuta con source ni ejecuta código del pull request. No aplica risk:*, type:*, los niveles de contribuidor, los campos de estado, de resolución, de stale ni de pickup, ni los campos de ProjectV2.

Informe de riesgo de PR (pr-risk-labeler.yml)

Se ejecuta al actualizarse los PR y al cambiar las etiquetas risk/security mediante pull_request_target, además de con un despacho manual para un solo PR. Obtiene el clasificador y la política compatible con JSON desde la revisión confiable del flujo de trabajo, lee los metadatos del PR, los archivos modificados, las etiquetas y el texto fuente de la API solo cuando la prueba exclusiva de tests #9530 lo necesita, y escribe un resumen legible para las personas en el resumen del paso, junto con la evidencia en JSON. Nunca hace checkout, compila, importa ni hace source de código de la solicitud de cambios, ni lo ejecuta.

La fase 2 es solo de informes: el flujo de trabajo tiene los permisos contents: read y pull-requests: read, no añade, elimina ni reemplaza etiquetas, no crea estados de commit, no aplica recuentos de aprobaciones y no requiere un conjunto de reglas del repositorio. risk:manual se informa como una congelación estricta para mutaciones futuras, mientras que domain:security se informa de forma independiente del resultado propuesto risk:*.

El clasificador asigna por defecto un nivel superior cuando la evidencia es incierta. La documentación, los fixtures y los metadatos mecánicos conocidos pueden ser risk:low; los cambios ordinarios de comportamiento son risk:medium; las rutas configuradas de confianza, credenciales, compatibilidad, gobernanza, autoridad de publicación, seguridad o mínimo de toolchain son risk:high. La política versionada también incluye reglas deterministas de escalado por línea modificada para la ampliación de permisos de workflows, el acceso a secretos, OIDC, la publicación de artefactos, el comportamiento de releases, pull_request_target elevado, las instalaciones de toolchain o las bases de contenedores, los cambios en el mínimo de releases y los contratos WIT probables. Si cambia uno de esos archivos sensibles al contenido pero el parche no está disponible o está mal formado, el informe permanece en nivel alto en lugar de suponer medio. La excepción #9530 solo puede recomendar risk:medium cuando un parche completo de Rust y el código fuente base/head correspondiente demuestren que todo cambio de Rust de alto riesgo permanece dentro de código #[cfg(test)] existente; la evidencia faltante, truncada, mal formada, mixta, de compilación condicional, de renombrado, de adición o de eliminación permanece en nivel alto.

Planificador del panel del proyecto (project-dashboard-plan.yml)

Se ejecuta manualmente para un solo número de issue. Lee el estado y las etiquetas del issue, y luego escribe un resumen de paso solo de informe proponiendo el valor existente de Project Status que mejor se ajusta al issue.

Este flujo de trabajo no se ejecuta automáticamente con eventos de incidencias, no escribe campos de ProjectV2, no edita incidencias, no añade etiquetas, no publica comentarios ni recalcula las etiquetas risk:* o type:* de los PR. La mutación en vivo de ProjectV2 o la planificación automática de eventos de incidencias requiere una asignación de campos, una política de disparadores y una credencial con alcance de proyecto aprobadas por separado.

Validar el título del PR (pr-title.yml)

Se ejecuta en cada apertura/edición/sincronización de PR. Ejecuta las pruebas unitarias del validador (scripts/check-pr-title.test.sh) y verifica el título del PR contra Conventional Commits (scripts/check-pr-title.sh).

Desplegar documentación de mdBook en Pages (docs-deploy.yml)

Se activa al hacer push de tags (y workflow_dispatch); compila y publica la documentación versionada en la rama gh-pages. Consulte Release Runbook → Versioned documentation deployment para conocer las reglas de versión mínima y de arranque inicial.

Verificación de PR de Imagen Docker (docker-image-pr.yml)

Se ejecuta solo cuando cambian archivos de imagen de Docker, Compose o contexto de Docker de la versión. Valida la configuración combinada de Compose predeterminada más Alpine y, para cambios que van más allá de ediciones solo de Compose, compila las imágenes de prueba de humo predeterminada y Debian precompiladas, además de los Dockerfile de origen, sin publicarlas. Cuando el único cambio en la ruta de Docker es release-stable-manual.yml, compila solo las imágenes de prueba de humo precompiladas: el job de Docker del flujo de trabajo de release empaqueta binarios precompilados mediante scripts/ci/prepare_docker_context.sh, que esas imágenes ejercitan, y nunca usa los Dockerfile de origen. Un diff que también modifique cualquier entrada de imagen de origen (un Dockerfile, el Containerfile, archivos de Compose, .dockerignore, la plantilla de configuración, los scripts de contexto de Docker o este flujo de trabajo) sigue compilando la matriz completa de origen. Las imágenes de origen predeterminada y Alpine se compilan para linux/amd64 y linux/arm64; la imagen de origen Debian se compila para linux/amd64. Los carriles separados de Alpine y Debian para linux/amd64 activan plugins-wasm-runtime-only, de modo que sus contextos de construcción prueban de forma continua que el contrato WIT del repositorio está disponible para las compilaciones de origen con plugins habilitados.

La imagen de origen con todas las funcionalidades definida en Containerfile se compila para linux/amd64 cuando cambian ese archivo o el flujo de trabajo de Docker. Usa un ámbito de caché aislado y no se carga ni se publica. El carril Alpine amd64 ejecuta ambos binarios, inicia la imagen compilada mediante la configuración combinada de Compose y comprueba el estado de salud de la puerta de enlace y las superficies del panel. El carril Alpine arm64 solo ofrece cobertura de compilación y de ensamblado de la imagen. Se compila de forma cruzada en blacksmith-8vcpu-ubuntu-2404, la clase de runner pesada de Rust de 32 GB que ya existe, porque su enlazado de release agotó la memoria en ubuntu-latest. Los demás trabajos de Docker siguen en ubuntu-latest; la optimización de release, las opciones de compilación y el tamaño de la matriz no cambian. Los cambios que afectan solo a Compose usan una matriz Alpine amd64 reducida, de modo que siguen ejercitando el contrato de ejecución sin recompilar imágenes no relacionadas. Todos los trabajos tienen permisos de solo lectura sobre el repositorio y ningún permiso de escritura en el registro.

Publicación de Docker (docker-publish.yml)

Compila, firma y escanea la matriz generada de cuatro variantes de dev/ci/docker-tags.toml: minimal, default-features, dist y all-features. Una etiqueta v* creada por una persona inicia este flujo de trabajo directamente. Una versión estable iniciada con workflow_dispatch crea su etiqueta con GITHUB_TOKEN, lo que no emite otro evento de push de etiqueta, por lo que release-stable-manual.yml llama a Docker Publish de forma síncrona en la etiqueta de versión inmutable después de que la versión canónica y los trabajos de Docker se completen correctamente.

Esta matriz complementa, sin reemplazar, las imágenes preconstruidas latest, versionadas y debian de la versión estable. Ambas rutas utilizan distintas entradas de compilación y publican etiquetas diferentes.

Lanzamiento de Discord (discord-release.yml)

Se ejecuta después de una versión estable exitosa. Publica las notas de la versión en el Discord de la comunidad.

Lanzamiento de Tweet (tweet-release.yml)

Se ejecuta después de una versión estable exitosa. Publica un tweet de anuncio.

Comprobación semanal de la vigencia de AUR (aur-freshness-check.yml)

Compara la versión de AUR publicada de zeroclawlabs con la versión estable actual de GitHub cada lunes y falla si la versión de AUR está desactualizada.

Publicar en el AUR sigue un modelo de lanzar y olvidar: si pub-aur.yml falla, nadie vuelve a comprobarlo, por lo que el paquete queda desactualizado silenciosamente. Eso es exactamente lo que ocurrió después de v0.8.4. Una ventana de mantenimiento de aur.archlinux.org coincidió con el lanzamiento, el único intento de clonación, sin reintentos, falló con The AUR is down due to maintenance, y el paquete quedó tres semanas desactualizado sin ninguna señal. El publicador ahora permite como máximo una publicación activa que no sea una ejecución en seco y reintenta para superar una breve interrupción; GitHub puede reemplazar una publicación real anterior en cola dentro del mismo grupo de concurrencia, mientras que las ejecuciones en seco usan un grupo independiente. Cada intento vuelve a clonar el estado canónico del paquete y se niega a sustituir una tupla epoch:pkgver-pkgrel más reciente por una más antigua. Un presupuesto de reintentos aún no puede cubrir todos los fallos, por lo que esta comprobación es la última línea de defensa que convierte una omisión silenciosa o una ejecución reemplazada en un caso visible.

Si no se puede acceder a la RPC de AUR, la comprobación emite una advertencia y pasa en lugar de fallar. Una interrupción de AUR es un problema de disponibilidad del servicio ascendente, no de obsolescencia de paquetes, y la próxima ejecución programada vuelve a comprobarlo. La obsolescencia es persistente, por lo que un retraso en la detección es aceptable; una alerta semanal por la ventana de mantenimiento de otra persona, no.

Los documentos se construyen y publican como parte del pipeline de lanzamiento en lugar de en cada push a master. La traducción es un flujo de trabajo solo local para PRs de caché de traducción dedicados, nuevos idiomas y pasadas de traducción de lanzamiento. Los PRs de documentación en inglés de rutina pueden diferir el ruido generado de .po a gran escala. Consulta Docs & Translations para la guía de contribuidores y el Release Runbook para el procedimiento de lanzamiento.

Flujos de trabajo manuales y de asesoramiento

Escaneo mensual de obsoletos (monthly-outdated.yml)

Escaneo mensual programado el día 1 de cada mes a las 09:00 UTC. Ejecuta cargo outdated --workspace en todos los miembros del espacio de trabajo. Abre un issue con la etiqueta dependencies- cuando se encuentran dependencias obsoletas. Permisos: contents: read + issues: write. Una protección contra duplicados evita que se acumulen si el issue anterior sigue abierto.

La vista previa del issue puede estar truncada, pero el artefacto monthly-outdated-report vinculado conserva la salida completa del escaneo durante 30 días.

Primer paso de triaje para un issue nuevo: comprueba si las crates desactualizadas reportadas tienen cambios de versión incompatibles con semver y si la API de la crate consumidora cambió. Si el cambio es trivial (patch/minor), crea una PR corta solo de dependencias. Si la actualización está bloqueada por rupturas de semver, cierra el issue con una nota y el nombre de la crate que bloquea.

Compilación multiplataforma (cross-platform-build-manual.yml)

Activación manual para compilar binarios de lanzamiento en toda la matriz de destinos: Linux x86_64/aarch64 GNU y MUSL más armv7 y arm hard-float, macOS Intel/ARM, Windows x86_64, y aarch64-linux-android (compilado con el NDK). Úsalo para verificar que una rama compila sin errores en destinos no Linux antes de crear la etiqueta.

Cada ejecución también ejecuta de forma independiente una pequeña matriz de pruebas de humo de las herramientas de lanzamiento. Establece release_tools_only cuando solo se necesite esta evidencia; los trabajos web y de compilación de lanzamiento se omiten entonces. En Linux x86_64 alojado por GitHub de confianza, la prueba de humo instala el archivo comprimido de cross con la versión fijada, confirma tanto cross como cross-util y registra cross --version. En Windows x86_64 alojado por GitHub de confianza, utiliza la misma versión de Rust y la misma estructura de rutas de Bash a Cargo que el flujo de trabajo de lanzamiento estable, y después registra tanto cargo-tauri.exe --version como cargo tauri --version. Cada variante registra el commit exacto probado y la arquitectura del ejecutor en el resumen público del trabajo. La prueba de humo utiliza permisos de solo lectura del repositorio y no tiene ningún trabajo de publicación, entorno, secreto ni carga de artefactos.

Las variantes de compilación de MUSL también instalan cross mediante scripts/ci/install_release_tool.sh, que descarga el artefacto exacto de la versión upstream fijada y verifica su SHA-256 antes de instalarlo. El trabajo obligatorio de Repository Structure prueba la asignación compatible entre ejecutor y artefacto, así como el contrato del flujo de trabajo de smoke, sin realizar llamadas de red.

El valor predeterminado qualification_profile: normal conserva la matriz completa, la ruta de humo dist-broad para binarios sin procesar, la ruta estándar de archivos dist, las políticas de caché normales, y el ciclo de vida de memoria ARM64 existente y el límite de 180 minutos de macOS. Sus cinco trabajos mantienen CARGO_INCREMENTAL=0 a nivel de trabajo. La prueba de humo de la herramienta de publicación valida las entradas de despacho antes de instalar herramientas; los trabajos de producto normales conservan su programación independiente.

Seleccione qualification_profile: stable-gnu-ubuntu22 con distribution: dist y release_tools_only: false para una calificación finita y sin publicación. Las combinaciones vacías, desconocidas, malformadas, de distribución amplia o solo de herramientas se rechazan. Cuatro filas de compilación GNU se ejecutan en Ubuntu22: x86_64, aarch64, armv7 y arm. Todas llaman a la misma acción local build-release-payloads que usa Stable, con sus enlaces existentes de linker y ARMv6, Rust1.98, perfil de release bloqueado (locked), características canónicas explícitas, trabajos ordinarios de Cargo, tres payloads por fila, un límite de 90 minutos y un tope inclusivo de 83.886.080 bytes para el binario principal. Solo el calificador habilita la salida de features de la acción; su manifiesto consume esa única resolución. Stable deja desactivado el interruptor de evidencia.

Los productores separados de web y de fixtures usan los puntos de entrada existentes y la configuración de toolchain Stable. Estos tres roles de compilación llaman directamente a la acción Swatinem fijada, con las claves compartidas originales web, plugin-smoke-packages y build. El prefijo de fixtures y cada prefijo de destino de Ubuntu22 coinciden con Stable, y la restauración predeterminada de destinos sigue habilitada. Cada caché de calificador usa save-if: false, incluso en master. Estos roles omiten la declaración de CARGO_INCREMENTAL a nivel de workflow o de job, igual que Stable. La acción de caché fijada exporta CARGO_INCREMENTAL=0 antes de construir su configuración de caché y conserva ese valor en los pasos posteriores. Los recibos del productor requieren y registran la cadena efectiva "0", y las comprobaciones de completitud verifican ese mismo valor. El valor exportado por la acción se mantiene. La política normal de caché web no cambia. Los logs de la acción deben mostrar la clave primaria real, las claves de restauración, el acierto y el origen de la caché antes de que se pueda aceptar la paridad de caché. Estas entradas no garantizan ni una caché caliente ni una duración posterior de la compilación Stable.

Los dos consumidores nativos ejecutan x86 GNU en Ubuntu22 y ARM64 GNU en Ubuntu24-arm, con límites de 30 minutos. Cada uno verifica y extrae su archivo de la misma ejecución, ejecuta la suite completa, detallada y con proveedor scripted en un plazo de cinco minutos, e invoca de forma incondicional el smoke test del plugin consciente de archivos. No existe ningún respaldo sin procesar. El trabajo de completitud seleccionado se ejecuta incluso tras un fallo en una etapa anterior y rechaza cada rol que falte, se omita, falle o sea cancelado. Comprueba cuatro archivos con el verificador sin cambios, doce hashes de entrada y su ELF guardado, las observaciones de compilador/sysroot y de recursos, y dos portadores de evidencia nativa. Los hashes del commit de origen, del árbol, de la ejecución, del intento, del perfil, de web y de los fixtures vinculan los recibos a un único despacho.

Antes de aceptar esta ruta, conserve los recibos reales de caché, interprete las doce observaciones de ABI e inspeccione las trece pruebas de proveedor nombradas y los dieciocho controles de archivo de cada carrier nativo. Un trabajo exitoso o un inventario de carriers, por sí solo, no sustituye esos resultados ni la revisión de los mantenedores. La evidencia faltante o no interpretable mantiene en suspenso la aceptación; no autoriza ningún cambio automático de presupuesto, recursos, funcionalidades ni política de ABI. La ejecución en Ubuntu24 ARM64 no es prueba de ejecución en tiempo de ejecución de Ubuntu22 ARM64. ARM32, la ejecución de companion, Darwin, MUSL, Android, Windows, la matriz completa de Stable y la preparación para la publicación requieren su propia evidencia. Un cambio en el código fuente, por sí solo, no demuestra ninguno de estos resultados de ejecución.

Clippy multiplataforma (cross-platform-clippy.yml)

Cobertura de lint de advisory programada manual y semanalmente en objetivos macOS aarch64 y Windows x86_64. Replica el comando de lint de PR requerido con --target establecido para cada plataforma, pero intencionalmente no se ejecuta en PRs y no forma parte de CI Required Gate.

Clippy requerido de Linux, Clippy multiplataforma informativo y Clippy de Windows específico llaman a scripts/ci/run_clippy.sh. Ese ejecutor se encarga de los formatos de comando admitidos, la propagación del estado de salida de Cargo y los diagnósticos compartidos de duración, caché, recuento de compilaciones y recuento de descargas. Los archivos de flujo de trabajo siguen encargándose de los desencadenadores, ejecutores, cadenas de herramientas, cachés, tiempos de espera y la inclusión en las comprobaciones obligatorias.

Lanzamiento Estable (release-stable-manual.yml)

Activación manual del pipeline de lanzamiento completo. Compila todos los objetivos, crea el GitHub Release, publica las imágenes Docker precompiladas latest, versionadas y debian en GHCR, ejecuta la matriz de variantes Docker generada en la etiqueta de lanzamiento, activa el redespliegue del sitio web e invoca los sub-workflows de distribución (Scoop, AUR, Discord, tweet). Homebrew Core detecta las nuevas versiones a través de su propio servicio autobump. Dos puertas de entorno requieren aprobación de un mantenedor durante la ejecución: github-releases (el job publish) y docker.

Los recursos descargables usan atestaciones Build Level 2 alojadas en GitHub. Los paquetes sin conexión y el material de raíz de confianza se incluyen en un archivo de verificación, y ambos formatos de SBOM se validan mediante sumas de comprobación y se atestiguan antes de crear la versión. Cosign sigue limitado a la firma de imágenes de GHCR.

Todo archivo de 64 bits, excepto el de Android experimental, incluye el host de plugins WASM, y una publicación iniciada por dispatch lo verifica antes de la GitHub Release y de sus propios envíos de imágenes: plugin-smoke-packages compila una vez los paquetes de plugin de prueba en Linux, y plugin-smoke descarga cada archivo en un runner de su propia plataforma y ejecuta scripts/ci/plugin_artifact_smoke.sh contra el binario empaquetado (el mismo script que ejecuta la etapa de humo check-plugin-backends en los pull requests). publish y docker esperan a que terminen todas las etapas. Una prueba de xtask mantiene la lista de etapas igual a la política de plugins por destino del registro, de modo que un destino no puede incluir el host sin una etapa ni perder su etapa mientras sigue incluyéndolo. Las etapas de compilación fallan con cualquier binario que supere el límite de 80 MiB definido en el paso de comprobación de tamaño. El workflow manual Cross-Platform Build ensaya las mismas etapas con los binarios que compila, de modo que un cambio de distribución se mide y se verifica desde un único dispatch antes de ejecutar una publicación. Una publicación iniciada por un push de etiqueta también activa Docker Publish mediante su propio disparador de etiqueta v*, y esa ejecución no espera a la prueba de humo.

Consulte el Runbook de versiones para conocer el procedimiento completo.

Las herramientas de compilación utilizadas únicamente en las versiones de lanzamiento no se compilan desde el código fuente en cada ejecución. El flujo de trabajo instala los binarios de lanzamiento fijados de upstream de cross y Tauri CLI mediante scripts/ci/install_release_tool.sh; ese script verifica un SHA-256 mantenido por el repositorio para cada archivo comprimido específico del ejecutor antes de colocar el binario en el directorio bin de Cargo. Para actualizar cualquiera de las herramientas, es necesario actualizar conjuntamente su versión, nombre del recurso y suma de comprobación, y luego ejecutar scripts/ci/install_release_tool.test.sh.

Editores de paquetes

Cada uno se activa en workflow_dispatch con una entrada de versión. También se invocan desde el flujo de trabajo de lanzamiento después de una publicación exitosa.

Flujo de trabajoQué hace
pub-aur.ymlActualiza el PKGBUILD del Repositorio de Usuarios de Arch y lo envía al AUR
pub-crates.ymlEmpaqueta y verifica la versión coordinada del espacio de trabajo y, a continuación, la publica en crates.io en orden de dependencias, tras la barrera del entorno crates-io
pub-scoop.ymlActualiza el manifiesto de Scoop para Windows

El servicio oficial de autobump de Homebrew Core descubre versiones estables de GitHub y abre actualizaciones de fórmulas de forma independiente. No restaures un publicador de Homebrew propiedad del proyecto ni un token de fork; eso duplica la automatización autorizada de Homebrew.

Secrets requeridos

SecretoUtilizado por
AUR_SSH_KEYpub-aur.yml
CARGO_REGISTRY_TOKENSecreto del repositorio que se pasa explícitamente a pub-crates.yml y al que solo hace referencia su trabajo de publicación protegido; v0.8.5 necesita publish-new para zerorelay, zeroclaw-relay-proto y zeroclaw-tls, mientras que las actualizaciones coordinadas posteriores necesitan publish-update
DISCORD_WEBHOOK_URLdiscord-release.yml
TWITTER_ACCESS_TOKEN, TWITTER_ACCESS_TOKEN_SECRET, TWITTER_CONSUMER_API_KEY, TWITTER_CONSUMER_API_SECRET_KEYtweet-release.yml
SCOOP_BUCKET_TOKENpub-scoop.yml, release-stable-manual.yml, scoop-bucket-canary.yml; PAT con permisos específicos limitado a zeroclaw-labs/scoop-zeroclaw con acceso de lectura/escritura a Contents
WEBSITE_REPO_PATrelease-stable-manual.yml (activa el redespliegue del repositorio del sitio web)
GITHUB_TOKEN (automático)Todos los flujos de trabajo que envían commits, abren PRs o publican imágenes en GHCR

Las imágenes de Docker se publican en GHCR mediante el GITHUB_TOKEN automático; no hay ningún token de registro independiente. Guarda CARGO_REGISTRY_TOKEN como secreto del repositorio y asigna únicamente ese secreto con nombre al publicador reutilizable. El flujo de trabajo invocado solo lo referencia en el paso de publicación irreversible, cuyo trabajo requiere aprobación mediante el entorno crates-io; la comprobación previa sin token ni lo referencia ni lo exporta. La comprobación previa empaqueta el mismo commit inmutable de la versión antes de que un aprobador pueda iniciar el trabajo de publicación.

Release Stable llama al publicador dos veces mediante su entrada stage. El job crates-preflight ejecuta stage: preflight junto a las compilaciones de los binarios, sin ningún secreto. Una ejecución disparada manualmente todavía no tiene tag, por lo que verifica directamente el commit de la ejecución. El job publish de GitHub Release lo necesita, de modo que un fallo en crates detiene el release antes de que nada sea público. Después del GitHub Release, el job crates ejecuta stage: publish con el token. Esa etapa exige que el nuevo tag resuelva al mismo commit, omite la re-verificación y sube el paquete del panel cuyo digest registró la etapa preflight. Una ejecución manual de pub-crates.yml sigue ejecutando ambas mitades en una sola llamada.

Ambos trabajos ejecutan los scripts de publicación desde un segundo checkout disperso (sparse) de scripts/release/ en .release-tooling, excluido del árbol empaquetado, y pasan el árbol a través de PUBLISH_SOURCE_ROOT. En una ejecución de publicación, ese checkout es el commit de la publicación. Un despacho manual desde master para una etiqueta existente usa los scripts de master contra el árbol etiquetado, de modo que una corrección del publicador puede llegar a una publicación sin mover su etiqueta. resolve_crates_release.sh rechaza cualquier otro commit de herramientas.

El crate raíz distribuye el panel generado en web/dist. La fase preflight lo compila una sola vez, registra un digest de cada ruta de archivo y de su contenido, verifica los paquetes con ese árbol y lo sube como el artefacto crates-io-web-dist. El trabajo de publicación no vuelve a compilar el panel. Restaura ese artefacto, y publish-crates.sh se niega a conectarse a crates.io a menos que el árbol restaurado coincida con el digest registrado. El artefacto se conserva durante 30 días para que una aprobación tardía o una nueva ejecución del trabajo de publicación fallido aún lo encuentre.

La mayoría de los crates del conjunto de versiones coordinadas ya existen y cumplen los requisitos para la publicación de confianza en crates.io. La versión v0.8.5 además crea zerorelay, zeroclaw-relay-proto y zeroclaw-tls, por lo que su token de arranque debe incluir publish-new. El token de entorno sigue siendo la vía de arranque hasta que cada crate tenga una entrada de publicador de confianza para este flujo de trabajo. Una vez configuradas esas entradas, migra el trabajo para que GitHub intercambie la identidad OIDC por un token de corta duración en lugar de conservar CARGO_REGISTRY_TOKEN.

Actualmente, la organización deshabilita las claves de despliegue en el bucket de Scoop, y el GITHUB_TOKEN automático no puede escribir en otro repositorio. Mantén SCOOP_BUCKET_TOKEN limitado estrictamente al bucket; no reutilices el token de CLI amplio de un responsable. El publicador comprueba el acceso de escritura con git push --dry-run y luego usa el mismo transporte de Git para la actualización real.

Rotación de SCOOP_BUCKET_TOKEN

Como las claves de implementación no están disponibles, esta credencial es un token de acceso personal y, por tanto, tiene dos modos de fallo independientes, que ya han causado problemas en un lanzamiento:

  1. El token caduca. Los PAT de granularidad fina tienen una duración máxima, por lo que esto se repite con una periodicidad fija, independientemente de que cambie o no cualquier otra cosa.
  2. La identidad propietaria pierde el permiso de escritura en el bucket. El token puede seguir siendo válido mientras la cuenta asociada a él solo sea un colaborador con read. Esto produce remote: Permission to zeroclaw-labs/scoop-zeroclaw.git denied to <account> y HTTP 403, no un error de autenticación, por lo que parece un problema de código cuando en realidad es un problema de permisos.

Haz que la cuenta ZeroClaw-Bot sea la propietaria del token, nunca una cuenta personal, para que el proceso de publicación no dependa de las credenciales de un único mantenedor. Para rotarlo:

  1. Como ZeroClaw-Bot, crea un PAT de granularidad fina con Propietario del recurso zeroclaw-labs, Acceso al repositorio limitado al único repositorio zeroclaw-labs/scoop-zeroclaw, y Permisos del repositorio → Contenidos: lectura y escritura. Nada más.
  2. Confirma que la organización aprobó el token. Los PAT de permisos detallados para el propietario de recursos de una organización permanecen pendientes hasta que se aprueban, y un token pendiente se autentica, pero no puede hacer push.
  3. Confirma que ZeroClaw-Bot aún tenga write en el bucket: gh api repos/zeroclaw-labs/scoop-zeroclaw/collaborators/ZeroClaw-Bot/permission --jq '.role_name'. El paso 1 no concede acceso al repositorio; solo delimita lo que puede usar el token. Un token no puede superar los permisos que ya tiene su propietario.
  4. Establece el secreto: gh secret set SCOOP_BUCKET_TOKEN --repo zeroclaw-labs/zeroclaw.
  5. Compruébalo sin tocar el bucket ejecutando Scoop Bucket Canary. Una ejecución correcta demuestra que el nuevo token puede hacer push.

Registra la fecha de caducidad en algún lugar persistente cuando hagas la rotación. El canario detectará un token caducado en el plazo de una semana de todos modos, pero solo después de que ya haya dejado de funcionar.

Propiedad de paquetes de AUR

El paquete propiedad del proyecto es actualmente zeroclawlabs, mantenido por zeroclaw-bot. El paquete con nombre canónico zeroclaw es un paquete de terceros y no puede reclamarse rotando AUR_SSH_KEY. Si ese mantenedor sigue inactivo, sigue el proceso de solicitud de paquetes huérfanos de AUR antes de cambiar pkgname o el destino de clonación del flujo de trabajo. Tras la transferencia de propiedad, coordina el renombrado o la fusión del paquete en un único cambio revisado.

Comportamiento de la caché de compilación

La mayoría de los trabajos intensivos en Rust de ci.yml usan caché a través del composite local ./.github/actions/rust-cache, que recibe use-blacksmith: 'true' de los trabajos de compilación de Blacksmith, igual que la etiqueta de runner que esos trabajos indican directamente. Ambos valores son constantes registradas en ci.yml, no una variable de Actions. vars no es legible en ejecuciones de pull_request originadas en forks, así que el antiguo interruptor CI_USE_BLACKSMITH enviaba en silencio todos los PR de forks (el 90 % de los PR de este repositorio) a runners alojados en GitHub con una caché fría, porque master había dejado de sembrar la caché de GitHub Actions al migrar a Blacksmith. Con las constantes, esos trabajos de PR de forks usan useblacksmith/rust-cache (disco persistente NVMe de Blacksmith, sticky disk) en runners de Blacksmith, igual que los trabajos correspondientes de master. Cambiar la etiqueta y las entradas del proveedor en los trabajos de compilación de Linux, que tests/architecture/ci_runner_labels.rs mantiene sincronizados, devuelve esa flota a ubuntu-latest + Swatinem/rust-cache en un único commit revisado. Ambas referencias de acciones viven en el composite independientemente de la selección, así que ambas deben permanecer en la lista de permitidos. La recuperación del task-owner de Windows es la excepción que usa Swatinem/rust-cache directamente en Blacksmith, con su propia caché de dependencias sembrada desde master. Las patas de compilación de macOS y Windows siguen usando Swatinem/rust-cache contra la caché de GitHub Actions, y los trabajos fmt, nix-eval y docs-style (ninguno compila el workspace) no usan caché de Rust. codeql.yml fija la misma etiqueta de Blacksmith para su análisis de Rust, así que ningún workflow lee ya la variable CI_USE_BLACKSMITH; puede eliminarse de la configuración del repositorio. Estos comportamientos conviene tenerlos en cuenta al investigar fallos intermitentes (flakes) relacionados con la caché:

  • Las combinaciones de Matrix necesitan claves de caché distintas. Una clave de caché se deriva del id del job (o de shared-key), del sistema operativo y la arquitectura del runner, de la toolchain, de las variables de entorno CARGO*/RUST* y del lockfile. Por tanto, las combinaciones de Matrix que solo difieren en feature flags o en argumentos de cargo resuelven a la misma clave: la combinación que guarda primero se apropia de ella, y todas las demás restauran un conjunto de dependencias que no coincide. Antes de las claves por combinación, la combinación del plugin backend de cranelift recompilaba unas 620 crates de dependencias (aproximadamente cuatro minutos) en cada ejecución, incluida master, porque compartía clave con las combinaciones de pulley y de solo runtime. Por eso, check y check-plugin-backends asignan a cada combinación un campo de matriz cache-key sin comas, que se pasa como shared-key; las combinaciones cuyos conjuntos de dependencias coinciden de verdad pueden compartir clave. Un nuevo job de matriz de Rust debe hacer lo mismo.
  • Las escrituras en caché son solo para master. save-if está condicionado a github.ref == 'refs/heads/master', por lo que las ejecuciones de PR leen la caché inicializada desde master pero nunca la actualizan. Las ramas de PR no pueden contaminar la caché compartida con artefactos específicos de la rama. El disparador push en master es lo que proporciona al flujo de trabajo una ejecución confiable con escritura en caché después de los merges.
  • La job Recuperación guarda la caché solo si tiene éxito. Su cache-on-failure: 'false' evita que las ejecuciones de recuperación fallidas llenen su caché. Los demás trabajos de compilación con caché compuesta mantienen cache-on-failure: true, así que una ejecución parcial de master todavía puede llenar la caché de su próximo intento y dejarla lista desde el principio.
  • La caché de compilación de Windows está habilitada. La etapa de compilación de Windows ejecuta la misma acción de caché de Rust fijada que Linux y macOS. Si el comportamiento de la caché de Windows falla de forma intermitente o presenta regresiones, revierta el cambio del flujo de trabajo y documente la evidencia de fallo de restauración/guardado en el issue de la caché.
  • La compilación incremental está desactivada. CARGO_INCREMENTAL: 0 a nivel del flujo de trabajo. Las compilaciones incrementales aumentan el tamaño de la caché y generan artefactos no reproducibles en condiciones parciales de obsolescencia.
  • cargo-deny y cargo-nextest se instalan desde cero en cada ejecución. El job security ejecuta cargo install cargo-deny --locked; el job test de Linux y ambas variantes programadas de platform-tests.yml descargan el binario de cargo-nextest adecuado desde get.nexte.st. El job de Windows para PRs de advisory descarga en su lugar el archivo de la versión fijada de nextest y verifica un SHA-256 codificado en el workflow antes de extraerlo, porque se ejecuta sobre un conjunto mucho mayor de PRs no confiables. Ninguna de las dos herramientas se almacena en caché, así que cada instalación añade un coste fijo a su job. Cambiar cualquiera de las dos a taiki-e/install-action permitiría almacenarlas en caché, pero esa acción no está actualmente en la lista de permitidas.

Cuando el semáforo se pone en rojo

SíntomaLo primero que debes verificar
Release Stable muere en startup_failure con cero trabajos tras cambiar una referencia uses:Comprueba el resumen de la ejecución y la política de Actions del repositorio. Si GitHub informa de un rechazo de acciones seleccionadas, compara la referencia modificada con la lista de permitidos, añade solo el patrón rechazado, espera a que se propaguen los cambios de configuración y, después, inicia una ejecución nueva. De lo contrario, investiga la definición del flujo de trabajo u otra política del repositorio; startup_failure por sí solo no identifica la causa
Puerta de CI requerida rojoComience con fmt, luego lint, luego test y, por último, build
La validación de la versión fallóLa versión de Cargo.toml no coincide con la entrada del flujo de trabajo, o la etiqueta ya existe
La etapa de compilación de lanzamiento fallóEl registro de trabajo del objetivo específico. Android es experimental y se ejecuta con continue-on-error.
El tiempo de espera de la puerta de entorno se agotóVolver a ejecutar solo el trabajo que ha caducado desde la página de ejecución del flujo de trabajo
El editor de distribución fallóVuelve a ejecutar el subflujo correspondiente manualmente con dry_run: true primero

Acciones permitidas

El repositorio ejecuta Actions en modo selected; solo las acciones incluidas en esta lista de permitidos pueden ejecutarse. La lista de permitidos debe mantenerse restringida; las nuevas acciones de terceros requieren la aprobación explícita de un mantenedor antes de ser agregadas.

Todas las referencias de terceros están fijadas a un SHA de commit completo con un comentario de versión al final; la columna de versión a continuación registra ese comentario.

AcciónUsado enPropósito
actions/checkout (v6.0.2)La mayoría de los flujos de trabajoRepositorio de checkout
actions/cache (v4.2.3, v5.0.5)docker-image-pr.yml, tweet-release.ymlCaché genérica de dependencias y base de datos de Trivy
actions/setup-node (v7.0.0)ci-sbom.yml, ci.yml, cross-platform-build-manual.yml, daily-npm-audit.yml, pub-crates.yml, release-stable-manual.ymlCadena de herramientas de Node para la generación de SBOM de npm, pruebas/auditoría web y compilaciones web/de escritorio
actions/upload-artifact (v7.0.1)release-stable-manual.yml, cross-platform-build-manual.yml, docker-publish.yml, trivy-scheduled.ymlSubir artefactos de compilación y artefactos de transferencia SARIF de Trivy
actions/download-artifact (v8.0.1)release-stable-manual.yml, cross-platform-build-manual.yml, docker-publish.ymlDescargar artefactos de compilación y artefactos de entrega SARIF de Trivy
actions/attest (v4.2.2)release-stable-manual.ymlGenerar procedencia de nivel 2 de compilación alojada en GitHub para activos de lanzamiento
actions/labeler (v6.1.0)pr-path-labeler.ymlAplicar etiquetas de ruta/alcance desde .github/labeler.yml
dtolnay/rust-toolchain (stable, v1)ci.yml, platform-tests.yml, pub-crates.yml, release-stable-manual.yml, cross-platform-build-manual.yml, cross-platform-clippy.yml, daily-audit.yml, docs-deploy.yml, codeql.ymlInstalar la cadena de herramientas de Rust
Swatinem/rust-cache (v2.9.2)ci.yml (ruta compuesta alojada en GitHub y recuperación directa de Blacksmith Windows), platform-tests.yml, pub-crates.yml, release-stable-manual.yml, cross-platform-build-manual.yml, cross-platform-clippy.yml, docs-deploy.ymlCaché de compilación y dependencias de Cargo en los runners alojados en GitHub y recuperación de Windows en Blacksmith
useblacksmith/rust-cache (v3.0.1)ci.yml (ruta de Blacksmith de ./.github/actions/rust-cache)Caché de compilación y dependencias de Cargo en el sticky disk de Blacksmith; se selecciona mediante la entrada use-blacksmith: 'true' que cada trabajo de compilación de Blacksmith pasa al composite (una constante incluida en el repositorio)
docker/setup-buildx-action (v3.11.1, v4.0.0)release-stable-manual.yml, docker-publish.ymlConfiguración de Docker Buildx
docker/login-action (v3.4.0, v4.1.0)release-stable-manual.yml, docker-publish.yml, trivy-scheduled.ymlAutenticación de GHCR
docker/build-push-action (v6.18.0, v7.1.0)release-stable-manual.yml, docker-publish.ymlConstrucción y envío de imágenes multiplataforma
sigstore/cosign-installer (v3.8.1)release-stable-manual.yml, docker-publish.ymlInstalar cosign para la firma sin clave de imágenes de contenedor de GHCR
anchore/sbom-action (v0.24.0)release-stable-manual.ymlGenera SBOM de SPDX y CycloneDX para cada release
aquasecurity/trivy-action (v0.36.0)docker-image-pr.yml, docker-publish.yml, trivy-scheduled.ymlAnálisis de vulnerabilidades de contenedores solo para informes
github/codeql-action/upload-sarif (v3.36.2)docker-publish.yml, trivy-scheduled.yml, ci-code-analysis.ymlCarga los informes SARIF de Trivy y Semgrep en la pestaña Seguridad
github/codeql-action/init (v4.37.8)codeql.ymlInicializar el análisis de CodeQL (Rust y JS/TS)
github/codeql-action/analyze (v4.37.8)codeql.ymlSubir CodeQL SARIF a la pestaña de Seguridad

El GitHub Release en sí se crea con gh release create dentro del job publish, no con una action de release.

Patrones de lista blanca equivalentes (mantenidos estrechos a propósito):

actions/*
dtolnay/rust-toolchain@*
Swatinem/rust-cache@*
useblacksmith/rust-cache@*
docker/*
sigstore/cosign-installer@*
anchore/sbom-action@*
aquasecurity/trivy-action@*
github/codeql-action/upload-sarif@*
github/codeql-action/init@*
github/codeql-action/analyze@*

Exportar la política efectiva actual:

sh

gh api repos/zeroclaw-labs/zeroclaw/actions/permissions
gh api repos/zeroclaw-labs/zeroclaw/actions/permissions/selected-actions

Cualquier PR que agregue o modifique el origen de una acción uses: debe incluir una nota de impacto de la lista de permitidos en su cuerpo. Evita excepciones amplias con comodines; amplía la lista de permitidos únicamente para acciones faltantes verificadas.

Reglas de mantenimiento

  • Mantén el CI Required Gate determinista y pequeño. Agregar trabajos al gate requiere un argumento de calidad claro.
  • Todas las referencias de acciones de terceros deben estar fijadas a un SHA de commit completo (según la política de lista de permitidos anterior).
  • Mantén ci.yml, dev/ci.sh y .githooks/pre-push alineados. Las comprobaciones compartidas deben residir en scripts/ci/; cada punto de entrada invoca la función auxiliar en lugar de copiar sus comandos. Para la comprobación independiente del protocolo de firmware, el punto de entrada local documentado es ./dev/ci.sh firmware-protocol.
  • Mantén alineados scripts/ci/prepare_docker_context.sh, docker-image-pr.yml y el job de Docker en release-stable-manual.yml para que la validación de PRs ejercite la misma forma de contexto que publica el flujo de trabajo de release.
  • Ejecuta python3 scripts/ci/release_attestation_contract_test.py después de cambiar la atestación de lanzamiento, el checksum, el SBOM o la secuencia del archivo de verificación.
  • El trabajo de control docs-style ejecuta bash scripts/ci/docs_quality_gate.sh (lint de Markdown + comprobación de prosa con raya em) y bash scripts/ci/docs_links_gate.sh (control de enlaces en líneas cambiadas). Ejecuta ambos scripts localmente antes de enviar cambios en la documentación.

Reversión de emergencia

Si la lista de permitidos bloquea una acción crítica durante un incidente:

  1. Establece temporalmente la política de Actions de nuevo en all.
  2. Restaurar la lista blanca selected después de identificar la entrada faltante.
  3. Registra el incidente y el delta final de la lista de permitidos.

Esta es la única ruta justificada hacia el modo all, y nunca debería prolongarse más allá del incidente.