Cómo auditamos, para repetirlo por tu cuenta
Cada cierto tiempo el proyecto se audita: calidad, contratos entre capas, pruebas, integridad de los datos y seguridad. Esta página explica el método, para que puedas repetirlo en tu copia, con la herramienta que prefieras: una persona, o cualquier asistente de programación, no solo el que usamos nosotros.
Se publican el método y los hallazgos ya cerrados; los abiertos, cuando se cierran. Así nadie lee un fallo antes de que esté arreglado, y los identificadores que cita el código (SEG-…) llevan a algún sitio. El procedimiento, además, sirve a quien quiera revisar su propia copia o un cambio que prepara.
La idea
Sección titulada «La idea»Una auditoría mezcla trabajo mecánico y trabajo de juicio, y conviene no mezclarlos:
- Lo mecánico lo hacen scripts, sin modelo ni juicio. Sacan una copia fija del código, pasan escáneres y calculan hechos comprobables («¿coinciden estas dos listas?»). Cuestan casi nada y siempre dan lo mismo.
- Lo que pide juicio lo hace quien audita (una persona o un modelo), sobre un paquete de código ya preparado: las preguntas, las decisiones que aplican y solo el código que importa. Nadie explora el repositorio entero.
- Todo lo que se afirma se verifica contra el código antes de entrar en un informe.
Por qué así: explorar un repositorio entero es lo más caro y lo menos fiable. Con un paquete cerrado, el trabajo es reproducible, cuesta poco y se puede repartir.
Qué necesitas
Sección titulada «Qué necesitas»- Una copia del repositorio con Git.
- Docker. Todas las herramientas se ejecutan en contenedores con versión fijada: no se instala nada en tu máquina.
python3en tu máquina (solo biblioteca estándar) para preparar los paquetes.- Alguien (o algo) que haga las revisiones: una persona, o el modelo que quieras.
Los scripts y las reglas están en .claude/skills/audit/: bin/ con los scripts, topics/ con los temas, y review-rules.md y triage-rules.md con las reglas de las revisiones. La carpeta se llama así porque el maintainer la lanza con una orden de Claude Code (/audit), pero nada del método depende de eso: es texto, scripts y Docker.
Parte 1: la parte mecánica
Sección titulada «Parte 1: la parte mecánica»El script bin/prepare.sh hace, en unos 20 segundos:
- Saca con
git archiveuna copia fija del último commit demain, para auditar siempre algo concreto. Si le das el commit de la auditoría anterior, también calcula qué ha cambiado desde entonces. - Lanza los escáneres, todos en Docker con versión fijada:
| Herramienta | Versión | Qué hace | Qué sale de la máquina |
|---|---|---|---|
| osv-scanner | v2.6.0 | Dependencias con fallos conocidos (Rust, npm, Composer) y licencias | Nombres y versiones de las dependencias, a osv.dev y deps.dev |
| gitleaks | v8.30.1 | Secretos en el historial de Git | Nada |
| semgrep | 1.177.0 | Análisis estático de PHP, TypeScript, Rust, Docker, nginx y GitHub Actions | Nada; solo descarga las reglas |
| knip | 6.39.0 | Exportaciones, archivos y dependencias sin usar en la app | Nada; solo descarga knip |
| python | 3.13.15 | Ejecuta facts.py |
Nada |
- Ejecuta
bin/facts.py, que escribe hechos comprobables en una carpeta, con un resumen (SUMMARY.md) que marca lo que merece atención:- que el esquema de las migraciones,
schema.rs, el JSON Schema y el espejo en PHP coincidan; - que cada comando de Tauri que llama la interfaz exista, y con los mismos argumentos;
- cada lista cerrada (formatos, tipos, roles, estados, géneros) y cada familia de códigos de error, comparadas entre Rust, TypeScript y las traducciones, según
bin/contracts.json; - los campos de cada
structde Rust frente a lainterfacede TypeScript del mismo nombre; - las traducciones en inglés frente a las españolas, y los casos de conformidad frente a quien los ejecuta;
- el inventario de pruebas y la superficie de ataque (CSP, permisos, Android, Docker, variables de entorno);
- los candidatos a problema:
unwrap, SQL construido a mano, errores que se pierden, efectos de React…
- que el esquema de las migraciones,
Cómo se lee
Sección titulada «Cómo se lee»- Se abre solo
SUMMARY.md, y de ahí solo las secciones que marca (un aviso, un número distinto de cero). - Una diferencia mecánica entre dos listas no se descarta como «error del script» sin comparar a mano las dos fuentes reales.
- Los hechos se convierten en hallazgos directamente: una lista a la que le falta un valor en TypeScript es un problema de contratos de gravedad media; un campo que la interfaz lee y Rust ya no manda es de gravedad alta.
- Los candidatos a problema no son hallazgos todavía: pasan por el triaje de la parte 2.
Parte 2: la parte de juicio
Sección titulada «Parte 2: la parte de juicio»Triaje: ¿esto es un problema de verdad?
Sección titulada «Triaje: ¿esto es un problema de verdad?»Los candidatos mecánicos son muchos y casi todos son falsos positivos (un unwrap sobre una constante, por ejemplo). El triaje decide cuáles son reales. Cada paquete de triaje lleva hasta 40 candidatos, cada uno con su trozo de código (la función entera si es corta), y las reglas de su categoría. Por ejemplo:
- Un
unwrapsobre datos que vienen de otro dispositivo, del servidor o de la red es un problema serio (un par defectuoso podría hacer caer la app); sobre un archivo local o una entrada del usuario, uno menor; sobre una constante, no es nada. - SQL construido con
format!: es un problema si se interpola un valor; no lo es si solo se interpolan nombres de tabla o de columna que vienen de constantes. - Una escritura en una tabla del catálogo fuera de donde debe estar (
ops.rsysync.rs) es siempre grave, porque se salta la regla de que toda escritura es una operación.
Quien hace el triaje puede leer solo su paquete. Responde con una tabla: qué candidatos son hallazgos y por qué, cuáles no, y cuáles «no concluyentes» (los que el trozo no basta para decidir).
Revisión por temas
Sección titulada «Revisión por temas»Cada tema es una pregunta amplia con su propio paquete. Los temas, por orden de riesgo:
| # | Tema | Qué revisa |
|---|---|---|
| 1 | sync-convergence |
Que los dispositivos converjan: reloj, borrados, lotes, versiones distintas de la app |
| 2 | library-access |
Quién puede acabar con los datos de una biblioteca |
| 3 | permissions-on-receipt |
Que quien recibe compruebe los permisos y la retirada de acceso |
| 4 | lan-pairing |
Identidad, emparejamiento por QR y transporte en la red local |
| 5 | ipc-surface |
Comandos de Tauri, permisos, CSP, claves y Android |
| 6 | data-files |
SQLite, copias de seguridad, restaurar con sincronización, CSV |
| 7 | migrations |
Migraciones que pueden perder datos o dejar la base a medias |
| 8 | signatures |
Firmas en Rust y PHP: los mismos bytes, diferencias entre analizadores de JSON |
| 9–10 | flows-sharing, flows-catalog |
Costuras entre funciones: roles sin conexión, peticiones, mover libros, marcas |
| 11 | webview-rendering |
Datos no fiables mostrados en la interfaz |
| 12 | server |
El servidor Symfony: seguridad y convenciones |
| 13 | metadata-covers |
Servicios de datos y portadas, sin conexión o con respuestas hostiles |
| 14–15 | spec-coverage, tests-quality |
Que cada regla tenga casos, y si las pruebas detectarían un fallo |
| 16–20 | ux-* |
Pantallas sin salida, errores, estados vacíos, textos |
| 21–22 | quality-rust, quality-ts |
Calidad |
| 23 | docs-vs-code |
Decisiones y hojas de ruta frente al código |
| 24 | supply-chain |
Dependencias, secretos, licencias, integración continua |
Se revisa un tema entero por pasada, rotando, y el tema vuelve antes si su código ha cambiado. El modelo de amenazas (threat-model) se escribe una vez y se revisa solo cuando cambian decisiones de seguridad.
Cada tema es un archivo de topics/ con una cabecera (qué código incluir, qué documentos de contexto, qué decisiones aplican, el tamaño máximo) y una lista de preguntas concretas. El script bin/packet.py convierte ese archivo en un paquete: las instrucciones, las preguntas, las decisiones, los hechos y solo el código de las funciones implicadas, con números de línea. Por ejemplo, las preguntas de sync-convergence piden razonar con líneas de tiempo concretas: «los dispositivos A, B y C, las operaciones que hace cada uno, el orden en que llegan y el estado final de cada uno. Una línea de tiempo que acaba en estados distintos, o un cambio perdido sin avisar, es un hallazgo».
Las reglas de quien revisa
Sección titulada «Las reglas de quien revisa»Se resumen en review-rules.md. Las más importantes:
- Trabajar con el paquete. Contestar a cada pregunta desde el código que trae, sin explorar el repositorio. Como mucho ocho comprobaciones extra, solo para confirmar o descartar una hipótesis concreta, y siempre de solo lectura.
- Las decisiones aceptadas son la intención del proyecto. Lo que una decisión elige no es un hallazgo, salvo que el código la contradiga o haya un riesgo que la decisión no menciona.
- Sin cita, no hay hallazgo. Cada hallazgo cita el código exacto con su ruta y sus líneas. «Falta X» exige prueba: decir qué código se comprobó.
- Una causa, un hallazgo, y como mucho doce por tema.
- Un escenario concreto: quién hace qué, en qué estado, y cuál es el resultado equivocado.
Gravedad y confianza
Sección titulada «Gravedad y confianza»| Gravedad | Cuándo |
|---|---|
| Crítica | En uso normal o para un atacante realista: pérdida o corrupción de datos que no se puede deshacer, dispositivos que ya no convergen, alguien lee o escribe lo que su rol no permite, o un secreto real expuesto |
| Alta | Se rompe una funcionalidad o una garantía en un caso realista, o hay un fallo de seguridad con una condición plausible: misma red, móvil robado, un miembro de mala fe, una app modificada |
| Media | Casos raros, defensas que faltan, reglas importantes sin pruebas, deuda que dará fallos pronto |
| Baja | Claridad, nombres, limpieza |
Ante la duda entre dos niveles, el más bajo, diciendo qué lo subiría. La confianza puede ser confirmada (se trazó el camino en el código), probable (un paso depende de algo en ejecución) o posible (una sospecha, que nunca es crítica ni alta).
Verificación
Sección titulada «Verificación»Una auditoría llena de falsos positivos es peor que ninguna. Por eso:
- Ningún hallazgo entra si su cita no está en el código auditado.
- Los críticos y altos se comprueban a mano: se busca la cita y se leen unas líneas alrededor. Se confirma el escenario o se baja o descarta con el motivo. Si depende de algo en ejecución, queda como «probable» con pasos concretos para comprobarlo en pantalla.
- Se buscan duplicados entre revisiones y contra los hallazgos ya registrados.
- Lo que una decisión aceptada elige pasa a «aceptado» con su número; lo que necesita una decisión nueva va a una lista «Para decidir». La auditoría nunca escribe en el registro de decisiones.
- Lo descartado se anota con su motivo, para que no vuelva a salir.
Qué se registra
Sección titulada «Qué se registra»Cada hallazgo tiene un identificador fijo que no se reutiliza, con un prefijo según su familia: seguridad, integridad de datos, costuras entre funciones, contratos entre capas, pruebas o calidad. Los estados son abierto, resuelto, aceptado (con la decisión) y descartado. Cada pasada escribe un informe con lo nuevo, lo resuelto, lo que sigue abierto, lo que hay que decidir, escenarios de prueba manual y lo pendiente. La auditoría no arregla nada: quien mantiene el proyecto decide qué se arregla y cuándo.
Repetirlo por tu cuenta
Sección titulada «Repetirlo por tu cuenta»- Prepara. Desde la raíz del repositorio, ejecuta
.claude/skills/audit/bin/prepare.sh <repo> <carpeta-de-trabajo> [commit-anterior]. Tarda unos veinte segundos. - Lee los hechos. Abre solo
facts/SUMMARY.mdy las secciones que marca. Convierte en hallazgos los hechos mecánicos, comprobando a mano las dos fuentes. - Elige el trabajo. Un tema de la tabla (el siguiente por riesgo, o el que toca tu cambio) y, si quieres, un grupo de candidatos para el triaje.
- Construye el paquete.
python3 .claude/skills/audit/bin/packet.py review <carpeta> <tema>(otriage <carpeta> "<categorías>"). Imprime la ruta y el tamaño. Con--incrementalsolo incluye lo que cambió desde la auditoría anterior. - Dáselo a quien revise. El paquete es un único archivo de texto con todo lo que hace falta: puedes leerlo tú, o dárselo a cualquier asistente con la instrucción de seguirlo tal cual y contestar en el formato que pide. No necesita acceso al repositorio.
- Verifica. Sigue las reglas de verificación de arriba para cada respuesta antes de aceptarla.
- Escribe y limpia. Anota lo encontrado donde prefieras, y borra la carpeta de trabajo (es una copia del código).
Un consejo: audita poco y a menudo. Dos temas bien revisados por pasada valen más que veinte a medias, y por eso el método tiene un presupuesto: como mucho dos revisiones por temas por pasada y tres paquetes de triaje.
Lo que todavía no cubre
Sección titulada «Lo que todavía no cubre»- Lo que se ve en pantalla (textos tapados, contraste en modo oscuro, botones fuera de la zona segura): hace falta una revisión visual con capturas, que aún no está construida.
- Si las pruebas detectarían un fallo (pruebas de mutación, que cambian el código a propósito para ver si alguna prueba se queja): se hicieron a mano una vez, no forman parte del método ni de la integración continua.
- Pruebas en ejecución: el método lee código y escáneres; no lanza ataques contra un servidor en marcha ni fuzzing. Lo que depende de algo en ejecución queda como «probable» y con pasos para probarlo a mano.
- Una auditoría externa. Esto es una revisión sistemática hecha por quien mantiene el proyecto y por modelos, no una auditoría independiente ni una prueba de penetración. Un modelo puede equivocarse: por eso todo se verifica contra el código.
© 2026 Kosmotheka
Kosmotheka es software libre: la aplicación y el servidor, bajo la AGPL-3.0-or-later; la especificación de operaciones, bajo la MIT. El nombre y el logotipo no entran en la licencia.
kosmotheka.com · Política de marca · Política de privacidad · info@kosmotheka.com