Skip to content

Commit b0796a2

Browse files
committed
chore: update docs/delendai/proposals/in-progress/c00010-higiene-critica-ci-verde-branch-protection-real-cobertura-80-fixtures-reparadas-monkey-patches-eliminados.md, docs/delendai/proposals/ready/feats/f00016-projectsession-projectindex-application-api-un-scan-por-proyecto-snapshot-inmutable-bridge-host-agnostic.md, docs/delendai/proposals/ready/feats/f00017-tanit-desktop-angular-app-selector-nativo-de-carpetas-endpoints-explorer-export-center-history-diff-paridad-cli-secure-storage.md +3 more
1 parent 824bf18 commit b0796a2

6 files changed

Lines changed: 1368 additions & 0 deletions

docs/delendai/proposals/in-progress/c00010-higiene-critica-ci-verde-branch-protection-real-cobertura-80-fixtures-reparadas-monkey-patches-eliminados.md

Lines changed: 274 additions & 0 deletions
Large diffs are not rendered by default.

docs/delendai/proposals/ready/feats/f00016-projectsession-projectindex-application-api-un-scan-por-proyecto-snapshot-inmutable-bridge-host-agnostic.md

Lines changed: 375 additions & 0 deletions
Large diffs are not rendered by default.

docs/delendai/proposals/ready/feats/f00017-tanit-desktop-angular-app-selector-nativo-de-carpetas-endpoints-explorer-export-center-history-diff-paridad-cli-secure-storage.md

Lines changed: 218 additions & 0 deletions
Large diffs are not rendered by default.
Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
---
2+
id: i00003
3+
title: "Release industrial — desktop CI por plataforma, signing + notarization, secure updater firmado, SBOM CycloneDX, checksums firmados"
4+
kind: infra
5+
status: ready
6+
type: proposal
7+
track: api-source-tanit
8+
date: 2026-09-08
9+
dependencies: [a00019#phase-5-multi-language-precision]
10+
---
11+
12+
# i00003 — Release industrial — desktop CI por plataforma, signing + notarization, secure updater firmado, SBOM CycloneDX, checksums firmados
13+
14+
## Goal
15+
16+
Consolidar la fase 6 de [a00019](../../in-progress/a00019-auditoria-2026-09-07-consolidacion-post-158-propuestas-y-plan-de-productizacion-tanit.md) como una pipeline de release industrial para Tanit. El resultado exige: desktop CI verde y reproducible en Linux, macOS y Windows; signing endurecido y notarization de macOS; Authenticode con trusted timestamp en Windows; checksums y firmas verificables en Linux; updater firmado con clave pública versionada; un SBOM CycloneDX y provenance attestation adjuntos a cada release; y un `SECURITY.md` con threat model, proceso privado de reporte y política de versiones soportadas.
17+
18+
El signing continúa siendo opt-in para desarrollo mediante `delendai.config.json#release.sign` con default `false`; una release production exige `release.sign=true` y no puede publicar artefactos sin verificar todas las firmas disponibles. Ninguna clave, certificado, password, token de notarization o firma privada se persiste en el repositorio.
19+
20+
## Why
21+
22+
El workflow actual `validate.yml` no contiene un job Rust/Tauri específico. Los cambios en `packages/desktop/` pueden llegar a `develop` sin demostrar que el shell Tauri compila, que el sidecar arranca o que scan/export funcionan. Los releases existentes tampoco ofrecen una cadena verificable: macOS no pasa por codesign + notarytool + staple, Windows no tiene Authenticode ni trusted timestamp, Linux no publica checksums firmados, y falta un updater que rechace artefactos sin confianza. Sin SBOM, provenance y threat model no es posible operar el producto con equipos de seguridad ni responder con evidencia a un incidente de supply chain.
23+
24+
## Why this design
25+
26+
- **Capas verificables, no un flag único**. CI demuestra que cada plataforma compila y arranca; signing demuestra identidad e integridad; el updater repite la verificación antes de instalar; SBOM y threat model hacen auditables los componentes y supuestos de seguridad.
27+
- **Fallo cerrado en release**. Un job de publicación solo continúa cuando build, firma, verificación, SBOM y attestation están presentes. La ausencia de credenciales de signing falla antes de publicar; no se compensa con un artefacto unsigned.
28+
- **Compatibilidad development-first**. `release.sign=false` mantiene el flujo local actual; `release.sign=true` habilita los proveedores de credenciales definidos por plataforma sin obligar a cada desarrollador a configurar certificados.
29+
- **Un único release contract**. La matriz usa pares explícitos `OS × architecture × bundle`, con SHA-256, versión semver, signer y provenance asociados al mismo tag. El manifest no puede describir instaladores sin identidad.
30+
- **Seguridad documentada y operable**. `SECURITY.md` describe límites de confianza, activos protegidos, mitigaciones, reporte, soporte y recuperación para que un auditor pueda reproducir la cadena de confianza.
31+
32+
## Non-goals
33+
34+
- Migrar Tauri ni sustituir el sidecar `apisrc`: la release valida y empaqueta el shell Tauri existente y el CLI autocontenido.
35+
- Añadir canales alpha/beta/stable, staged rollout, downgrade o distribución corporativa; el primer contrato es stable semver.
36+
- Añadir Windows ARM64 o Linux ARM64; la matriz inicial es Linux x64, Windows x64, macOS x64 y macOS arm64. Nuevos targets entran por extensión del mismo manifest.
37+
- Publicar Flatpak, Snap, App Store ni Microsoft Store; esta propuesta cubre instaladores nativos y sus pruebas de trust.
38+
- Implementar disclosure management ni un programa de recompensas; `SECURITY.md` define el canal y el equipo conserva el triaging.
39+
40+
## Architecture
41+
42+
La propuesta se divide en cuatro controles independientes pero encadenados por sus artefactos:
43+
44+
1. **Desktop CI por plataforma (S1)**. `.github/workflows/desktop-ci.yml` construye la misma revisión en hosted runners nativos, corre quality gates Rust y Bun, empaqueta sin publicar y ejecuta un smoke real: sidecar handshake → scan → export → exit code 0. `ci-summary` exige el check `desktop-ci` y la branch protection lo incorpora a `develop`.
45+
2. **Signing y verificación (S2)**. Un contrato de configuración selecciona credenciales por `os`/`arch` y construye un manifest efímero de artefactos. macOS usa hardened runtime + timestamp + notarization + staple; Windows usa Authenticode SHA-256 + trusted timestamp; Linux genera `SHA256SUMS` y detached signatures GPG. Un job `verify-signatures` pasa antes de que `gh release` publique.
46+
3. **Updater firmado (S3)**. El updater Tauri consume un manifest versionado desde un endpoint HTTPS, verifica firma y hash del instalador antes de descargarlo o instalarlo y aborta con un error visible si la prueba criptográfica falla. El instalador actualizado contiene el sidecar de la misma versión.
47+
4. **Supply-chain transparency (S4)**. Tras verificar los artefactos finales, se genera un CycloneDX JSON 1.6 desde el grafo real, se valida su schema, se attesta la provenance de los assets y se publican SBOM, attestation y checksums firmados junto a la release. `SECURITY.md` documenta la cadena de confianza, supported versions, disclosure y límites de cada control.
48+
49+
### Dependency on `a00019#phase-5-multi-language-precision`
50+
51+
La dependencia del frontmatter es deliberada: la release se apoya en la precisión multi-lenguaje y en el snapshot/Application API que preceden a la fase 6. La comprobación no vuelve a implementar `ModuleResolver` ni la detección de frameworks; verifica que el artefacto Desktop contiene el contrato vigente y que el smoke usa un fixture representativo. Mientras `a00019#phase-5-multi-language-precision` no esté cerrada, esta propuesta queda `ready` pero no se puede declarar `done`.
52+
53+
### Artifact contract
54+
55+
Cada instalador publicado se describe por versión semver, nombre, plataforma, arquitectura, formato, SHA-256, firma, signer/key id, referencia de SBOM y referencia de provenance. El manifest se genera en un workspace limpio a partir de los archivos finales; no se aceptan rutas, nombres o hashes hardcodeados. La verificación final vuelve a calcular los hashes desde el staging de release y falla si encuentra drift.
56+
57+
## Slices
58+
59+
- global_gate: e2e
60+
61+
### S1-desktop-ci-platforms — S1 — Desktop CI por plataforma: quality gates y smoke real en Linux/macOS/Windows
62+
63+
- **Status**: pending
64+
- **Files**: `.github/workflows/desktop-ci.yml`, `packages/desktop/rust-toolchain.toml`, `scripts/gates/desktop-quality.script.ts`, `scripts/gates/desktop-smoke.script.ts`, `scripts/gates/ci-summary.script.ts`, `tests/desktop/launch-and-scan.test.ts`, `tests/desktop/export-and-exit.test.ts`, `tests/desktop/fixtures/scan-fixture/package.json`, `tests/desktop/fixtures/scan-fixture/src/main.ts`, `docs/CI.md`, `delendai.config.json`
65+
- **DependsOn**: []
66+
- **Gate**: e2e
67+
- acceptanceCriteria:
68+
- El workflow `desktop-ci` usa hosted runners nativos `ubuntu-latest`, `macos-latest` y `windows-latest`, fija Bun 1.4.2+, Node 20+ y el MSRV Rust 1.80+ en `rust-toolchain.toml`, y mantiene `fail-fast: false` para que un fallo no oculte los targets restantes.
69+
- En cada OS se ejecutan, como mínimo, `cargo fmt --check`, `cargo clippy --all-targets --all-features -- -D warnings`, `cargo test --all-targets --all-features`, el quality gate Bun, un build Tauri sin publicar y el smoke del sidecar.
70+
- El smoke compila el sidecar para el target nativo, arranca Tanit, espera un handshake/URL real, abre un fixture de scan representativo, ejecuta scan, ejecuta export Postman, valida el JSON de salida y termina con exit code 0.
71+
- `desktop-ci` aparece en `ci-summary` y en los required checks de `develop`; un cambio en `packages/desktop/` no puede mergearse con ese check fallido o skipped.
72+
- `desktop-quality.script.ts` es invocable localmente y en CI, devuelve diagnósticos accionables y no modifica el fixture; el workflow parsea con `actionlint` o equivalente antes de la ejecución.
73+
- `docs/CI.md` documenta triggers, matriz, secrets mínimos, troubleshooting y el procedimiento para añadir un nuevo `os × arch × bundle`.
74+
- DoD: un commit/tag de prueba obtiene los tres jobs nativos verdes, el gate local pasa en Linux y el fixture demuestra el flujo completo sin depender de red externa.
75+
- review-state: in_review
76+
- review-implementer: finch
77+
### S2-signing-notarization — S2 — Signing, notarization y verificación reproducible por plataforma
78+
- **Status**: pending
79+
- **Files**: `.github/workflows/release-desktop.yml`, `scripts/release/prepare-artifacts.mjs`, `scripts/release/sign-macos.sh`, `scripts/release/notarize-macos.sh`, `scripts/release/sign-windows.ps1`, `scripts/release/sign-linux.sh`, `scripts/release/verify-signature.sh`, `packages/contracts/interfaces/release/signing.interface.ts`, `packages/contracts/constants/release/signing.constant.ts`, `packages/desktop/tauri.conf.json`, `docs/RELEASE.md`, `tests/release/signing.spec.ts`
80+
- **DependsOn**: [S1-desktop-ci-platforms]
81+
- **Gate**: e2e
82+
- acceptanceCriteria:
83+
- "`delendai.config.json#release.sign` tiene default `false`; `release.sign=true` habilita signing y hace que la pipeline production assertion falle si falta cualquier credencial o target requerido."
84+
- "macOS genera `.app` y `.dmg` por x64/arm64, aplica `codesign` hardened runtime, entitlements mínimos, secure timestamp y Developer ID; `notarytool` espera la aceptación, se staplan ambos artefactos y el runner ejecuta una comprobación de Gatekeeper antes de publicar."
85+
- "Windows firma `.msi` y NSIS `.exe` x64 con Authenticode SHA-256, certificado EV/Azure Trusted Signing y trusted timestamp RFC 3161; el verifier confirma signer, digest y timestamp desde el artefacto real."
86+
- "Linux produce `.deb`/`.AppImage` x64, un `SHA256SUMS` generado con `sha256sum` y firmas detached GPG por artefacto/checksum; la verificación usa el keyring publicado y no depende de firmas no verificadas."
87+
- "El manifest efímero incluye semver, `os`, `arch`, bundle, ruta relativa, SHA-256, firma, signer/key id y referencias de SBOM/provenance; `verify-signature.sh` vuelve a calcular todo desde el manifest y los assets."
88+
- "El release job adjunta solo artefactos verificados: `.app`/`.dmg` notarizados macOS, `.msi`/`.exe` Authenticode Windows y `.deb`/`.AppImage` con `SHA256SUMS` y `.sig` Linux. La publicación de cualquier target no firmado falla cerrada."
89+
- "`docs/RELEASE.md` enumera secrets por proveedor, responsabilidades de rotación, troubleshooting, comandos de verificación y la política explícita de que una release es reproducible en identidad, no bit a bit."
90+
- "DoD: un dry-run sin publicar produce todos los artefactos esperados, cada verificador pasa para su OS y la matriz de credenciales faltantes se prueba sin exponer valores."
91+
92+
### S3-secure-updater — S3 — Updater firmado con manifest versionado y verificación antes de instalar
93+
94+
- **Status**: pending
95+
- **Files**: `packages/desktop/Cargo.toml`, `packages/desktop/src/main.rs`, `packages/desktop/src/updater.rs`, `packages/desktop/capabilities/updater.json`, `packages/desktop/keys/tanit-updater-public-key-v1.pem`, `scripts/release/build-update-manifest.mjs`, `scripts/release/verify-update.sh`, `tests/desktop/updater-contract.rs`, `docs/UPDATER.md`
96+
- **DependsOn**: [S2-signing-notarization]
97+
- **Gate**: e2e
98+
- acceptanceCriteria:
99+
- Tauri updater queda inicializado desde un contrato explícito de endpoint, public key versionada, versión actual, timeout y política de reintento; la clave privada nunca entra en la app, el repositorio ni los build logs.
100+
- El manifest HTTPS incluye versión semver, target `os/arch/bundle`, URL, SHA-256, firma, public-key id, versión mínima soportada y provenance; el cliente verifica firma, hash, versión y plataforma antes de descargar o instalar.
101+
- Una firma inválida, hash alterado, target incompatible, manifest ausente o respuesta no válida aborta con un mensaje visible y un evento de seguridad; no existe fallback a unsigned ni descarga HTTP.
102+
- El instalador candidato incluye un sidecar `apisrc` compatible y la misma versión semver; un smoke posterior al update comprueba handshake, scan y export antes de cerrar la operación.
103+
- Se prueba al menos actualización válida, versión anterior, target incorrecto, firma corrupta, hash corrupto, endpoint no disponible y rollback; las pruebas no requieren una cuenta real ni una red externa.
104+
- `docs/UPDATER.md` explica la rotación de claves, la compatibilidad de manifests, la verificación independiente y el procedimiento de rollback para usuarios y auditores.
105+
- DoD: el manifest staging se firma y verifica con fixtures locales, la versión anterior se rechaza de forma determinista y el instalador actualizado supera el smoke Desktop.
106+
107+
### S4-sbom-security — S4 — SBOM CycloneDX, provenance attestation y threat model en cada release
108+
109+
- **Status**: pending
110+
- **Files**: `.github/workflows/release-desktop.yml`, `scripts/release/build-sbom.mjs`, `scripts/release/verify-sbom.mjs`, `tests/release/sbom.spec.ts`, `docs/SBOM.md`, `SECURITY.md`
111+
- **DependsOn**: [S2-signing-notarization, S3-secure-updater]
112+
- **Gate**: e2e
113+
- acceptanceCriteria:
114+
- Cada release genera, a partir de los artefactos finales verificados por S2/S3, un SBOM CycloneDX JSON 1.6 válido con `bomFormat`, `specVersion`, `serialNumber`, version, components, dependencias, hashes y supplier cuando esté disponible.
115+
- El SBOM cubre Tanit Desktop, el sidecar `apisrc` y el grafo de dependencias Rust/Bun/nativas realmente empaquetado; excluye secretos, certificados privados, credenciales y archivos temporales. El manifest de S3 y el SBOM se validan mutuamente por versión y hash.
116+
- El workflow ejecuta `actions/attest-build-provenance` o equivalente SLSA-compatible sobre los assets firmados y publica la attestation/provenance junto a la release; una attestation ausente o no verificable impide publicar.
117+
- `verify-sbom.mjs` valida schema, componentes requeridos, hashes, firma, signer/key id y provenance; sus fixtures cubren SBOM válido, dependencia faltante, hash alterado y provenance no relacionada.
118+
- `SECURITY.md` incluye threat model con activos, adversaries, trust boundaries, controles por capa (CI, release credentials, signing, updater, endpoint, sidecar y usuario), riesgos aceptados, proceso privado de reporte, GPG/contacto de seguridad, supported versions y ventana de respuesta high/critical.
119+
- `docs/SBOM.md` explica consumidores, CycloneDX 1.6, consultas comunes, correlación con manifest/checksums, retención y pasos de revalidación para auditores.
120+
- DoD: un dry-run staging adjunta SBOM, provenance y attestation verificables, y la release real no se puede crear sin esos assets; `bun run lint:proposals:gen-index` y `bun run typecheck` permanecen verdes.
121+
122+
## acceptance
123+
124+
- `desktop-ci` está verde en hosted runners Linux, macOS y Windows y sus smoke tests ejecutan scan/export reales.
125+
- `desktop-ci` forma parte de los required checks y bloquea cambios Desktop no validados.
126+
- macOS publica `.app`/`.dmg` firmados, notarizados y stapled; Windows publica `.msi`/`.exe` Authenticode con timestamp; Linux publica `.deb`/`.AppImage`, `SHA256SUMS` y firmas verificables.
127+
- `release.sign=false` mantiene releases development unsigned y `release.sign=true` convierte la publicación en un flujo fail-closed con credenciales solo en GitHub Secrets.
128+
- El updater verifica firma, hash, target y versión antes de instalar; no instala un artefacto sin confianza y el sidecar permanece compatible.
129+
- Cada release incluye SBOM CycloneDX 1.6, provenance attestation y documentación de auditoría.
130+
- `SECURITY.md` documenta threat model, disclosure privado, supported versions y proceso de respuesta.
131+
- `bun run lint:proposals:gen-index` y `bun run typecheck` están verdes; la proposal permanece en estado de revisión hasta que un verificador independiente apruebe el diseño.
132+
133+
## Risks
134+
135+
- **Credenciales externas ausentes**. El pipeline puede construir artefactos unsigned, pero un job production con `release.sign=true` debe fallar antes de publicar si Apple, Windows o GPG no están configurados. Es un resultado correcto, no un motivo para relajar la trust chain.
136+
- **Rotación de claves**. La pérdida o exposición de una signing key requiere revocación, nueva public key versionada, re-firma de los manifests y una ventana de soporte documentada; no se puede sobrescribir silenciosamente la clave activa.
137+
- **Drift entre artefactos**. El manifest, hashes, SBOM, provenance y assets deben derivarse del mismo staging directory. Cualquier cambio posterior a la verificación obliga a regenerar toda la cadena y repetir la attestation.
138+
- **Entornos hosted**. macOS y Windows solo se construyen en sus runners nativos; la validación local Linux no pretende cross-compilar instaladores firmados. La matriz y el dry-run deben documentar esta limitación.
139+
- **Disponibilidad del updater**. Un endpoint caído no puede forzar una descarga sin firma. El cliente conserva la versión instalada, muestra el fallo y permite reintentar o descargar la release verificada manualmente.
140+
- **Cobertura SBOM incompleta**. Si una dependencia bundled no aparece, el verificador falla la release; el riesgo de publicar un SBOM incompleto es mayor que el coste de regenerarlo.
141+
- **Cambios de APIs de terceros**. `notarytool`, Authenticode, `actions/attest` y Tauri updater pueden cambiar; se fijan versiones/pines y se prueba el flujo en una release de staging antes de actualizar la toolchain.
142+
143+
## Definition of done
144+
145+
- Todos los criterios de S1–S4 están implementados, probados y aprobados por un verificador distinto de quien implementó esta consolidación.
146+
- La release industrial pasa los gates de S1–S4 y el slice queda en `in_review` hasta la peer review; no se cierra desde esta tarea.
147+
- La propuesta enlaza correctamente con `a00019#phase-5-multi-language-precision` y su frontmatter declara `kind: infra` y la dependencia de fase 5.
148+
- Solo se edita este documento de diseño en esta slice; la implementación de CI, scripts, workflows, manifests, claves, SBOM, attestation y documentación corresponde a los slices de ejecución posteriores.

0 commit comments

Comments
 (0)