Lo que se empaqueta deja de llevar tests, payloads y rutas que no resuelven - #40
Merged
Conversation
…uelven
Exportar la skill al estandar Agent Skills fallaba con codigo 3: la revision
de seguridad bloqueaba el empaquetado por dos hallazgos de severidad alta que
resultaron ser la propia defensa anti-inyeccion documentandose a si misma.
- SKILL.md:273 llevaba un display-name de ejemplo con la formulacion
literal de una inyeccion. Era un ejemplo entrecomillado y declarado como
tal, pero un detector lexico no puede ver eso: lo lee como instruccion.
- triage_helpers.py llevaba en un comentario el PoC completo de descarga y
ejecucion remota que motiva el escape de message-ids.
Los dos se reformulan conservando el sentido docente. El payload literal
sigue existiendo donde sirve de algo: en TestEscaparApplescript.MID_ATAQUE,
donde se EJECUTA contra el escape en vez de quedarse como texto.
Ademas, cuatro cambios que ya no dependian del bloqueo:
- Los 4 test_*.py salen de skills/email-triage/scripts/ a tests/. Eran
217 KB de los 384 KB del paquete y viajaban dentro de cada .zip sin
aportar nada al agente de destino. El gate de unicidad del arbol se
invierte (test_triage_helpers.py ahora DEBE estar fuera) y se le anade
la invariante que protege el adelgazamiento: ni un test_*.py dentro de
la skill. tests/__init__.py pone scripts/ en sys.path.
- La description del frontmatter se reescribe a mano: 962 -> 454 bytes,
con los disparadores delante. Cabe entera en el presupuesto mas estrecho
(490 B, instalacion por carpeta), asi que el conversor ya no recorta ni
reordena nada y el .zip y la carpeta salen identicos.
- base_estado() resuelve el directorio de estado una sola vez:
$EMAIL_TRIAGE_HOME, si no ~, si no un temporal. La tilde no es fiable en
todas partes: donde $HOME vale "/", ~/.email-triage escribia en la raiz.
base_estado_es_efimera() permite avisar cuando el estado no persiste, que
es lo que evita dar por escrito un registro que nunca se escribio.
- references/paso-1c-hilos.md usaba ${CLAUDE_PLUGIN_ROOT}, que solo existe
dentro de un plugin de Claude Code; pasa a <ruta-del-skill>, la
convencion que ya usaba el resto del arbol.
Resultado medido con el conversor: codigo 3 -> 2 (se escriben artefactos),
Claude Code de "compatible con adaptacion" a "compatible" sin adaptaciones,
y la dimension de comportamiento de la revision de seguridad de alto a bajo.
309 tests en verde en 3.12 y 3.13.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
…g publicado El gate sincronia-con-release tenia razon: v3.12.0 ya estaba tagueada y este PR cambia ficheros distribuibles, asi que quien instalara por tag no recibiria nada de esto y el marketplace anunciaria 3.12.0 para un codigo que ya no es ese. Minor y no patch porque hay capacidad nueva de usuario: EMAIL_TRIAGE_HOME y base_estado_es_efimera() no existian. bump-version.sh cubre los 9 sitios; la entrada de changelog del README va a mano, que es justo lo que el otro gate comprueba. 309 tests en verde en 3.12 y 3.13. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
PyYAML>=6.0 dejaba que la version instalada hoy no fuera la que se probo, y config.yaml lo parsea justo esa libreria. Se fija a ==6.0.3, la misma con la que corre la suite. El pin no vale de nada si el CI instala por su cuenta: 'pip install pyyaml' pasa a 'pip install -r requirements.txt', asi lo que se prueba es lo que se declara. Sin hashes a proposito, y escrito en el fichero: en cuanto una linea lleva hash, pip exige --require-hashes para todas y falla si el wheel de la plataforma del usuario no esta listado. Para un unico dependency opcional con un 'pip install' documentado en el propio fichero, eso es una trampa, no una mejora. Retira SEC-DEP-SIN-FIJAR-002: la dimension de cadena de suministro de la revision de seguridad baja de moderado a bajo. 309 tests en verde en 3.12 y 3.13. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Por qué
Exportar
email-triageal estándar abierto Agent Skills fallaba con código 3:la revisión de seguridad del conversor bloqueaba el empaquetado y no se escribía
ningún artefacto.
Los dos hallazgos que bloqueaban resultaron ser falsos positivos con una causa
común: la defensa anti-inyección de la skill documentándose a sí misma. Un
detector léxico no distingue entre describir un ataque y ejecutarlo.
SKILL.md:273triage_helpers.pyLos dos se reformulan conservando el sentido docente. El payload literal sigue
existiendo donde sirve de algo: en
TestEscaparApplescript.MID_ATAQUE, donde seejecuta contra el escape en vez de quedarse como texto en un comentario que además
viajaba dentro del paquete.
Qué más entra
test_*.pysalen de la skill (skills/email-triage/scripts/→tests/).Eran 217 KB de los 384 KB del paquete y viajaban dentro de cada
.zipsin aportarnada al agente de destino. El gate de unicidad del árbol se invierte y se le añade
la invariante que protege el cambio: ni un
test_*.pydentro de la skill.descriptionreescrita a mano: 962 → 454 bytes, disparadores delante. Cabeentera en el presupuesto más estrecho (490 B, instalación por carpeta), así que el
conversor ya no recorta ni reordena — y el
.zipy la carpeta salen idénticos.base_estado()resuelve el directorio de estado una vez:$EMAIL_TRIAGE_HOME,si no
~, si no un temporal. Donde$HOMEvale/,~/.email-triageescribía enla raíz.
base_estado_es_efimera()permite avisar cuando el estado no persiste.references/paso-1c-hilos.mdusaba${CLAUDE_PLUGIN_ROOT}, que sólo existedentro de un plugin de Claude Code; pasa a
<ruta-del-skill>, la convención que yausaba el resto del árbol.
Resultado medido
.zipEl único hallazgo que queda dentro de lo que se empaqueta es
adapter_mailapp.py:162—subprocess.run(["osascript", "-"], input=script), queya es una lista de argumentos explícita sin
shell=True, o sea justo lo que pide lamitigación. Los otros 8 están en
tests/con ámbito «paquete»: no viajan.309 tests en verde en Python 3.12 y 3.13. Los gates de CI (coherencia de
versiones, changelog, conformidad con Agent Plugins 1.0.0, unicidad del árbol) se
replicaron localmente y pasan. El fuzz se validó con N reducido (400) para
comprobar el cableado del import; la pasada completa de 20.000 la hace CI.
Bump a v3.13.0
El gate
sincronia-con-releasefalló en el primer push, y tenía razón:v3.12.0ya estaba tagueada y este PR cambia ficheros distribuibles, así que quien instalara
por tag no habría recibido nada de esto. Minor y no patch porque hay capacidad
nueva de usuario:
EMAIL_TRIAGE_HOMEybase_estado_es_efimera()no existían.bump-version.shcubre los 9 sitios; la entrada de changelog va a mano.Lo que este PR NO arregla
cambio de este PR iba a moverlos: dependen de AppleScript, de ejecutar Python o de
no cortar a los 90 s. Es una limitación real de la skill, no del empaquetado.
por los tres 🟠
SEC-EXEC-REMOTO-001detests/, que son los payloads de ataquecontra los que se verifica
applescript_quote. Se podría bajar a 0 troceando esosliterales para que el detector no los case, y deliberadamente no se hace:
ofuscar un payload para esquivar un escáner es el patrón que vuelve inútiles a los
escáneres, y contradice el «mecanismo, no confianza» del resto del repo. 2 es el
estado correcto aquí.
🤖 Generated with Claude Code