From 83d40af35c373225cb5abe43320af5a17d67fd97 Mon Sep 17 00:00:00 2001 From: sergio Date: Thu, 16 Jul 2026 23:27:57 -0400 Subject: [PATCH] =?UTF-8?q?harkaq:=20el=20clasificador=20nunca=20propone?= =?UTF-8?q?=20runtime=20base=20como=20declarable=20(fix=20de=20ra=C3=ADz?= =?UTF-8?q?=20de=20busybox)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit El bug que declaró `busybox` en 29 recetas y rompió binutils: harkaq-suggest veía `/bin/busybox` denegado, encontraba `recipes/busybox.toml` en el store y decía "declarar dep: busybox" — sin mirar que la política YA lo concede (`ro /bin/busybox`: el sandbox corre `sh -c` y /bin/sh→busybox ⇒ es CONTRATO, no dep). Fix: harkaq-suggest ahora lee los paths CONCEDIDOS de la política (`ro`/`rw`/`list`), no sólo los `# expect`. Si un path está concedido ⇒ categoría RUNTIME BASE: no se declara, aunque el store lo provea. Las 4 clasificaciones verificadas tras el cambio: /bin/busybox → RUNTIME BASE (ya concedido; NO declarar) ← el fix /usr/bin/make → DECLARABLE (declarar dep: make) /usr/lib/libstdc++.so → IRREDUCIBLE (nadie lo provee) /usr/bin/gcc en broot → DEUDA DE COMPILADOR (compiler=gcc) /usr/bin/gcc en zlib → sin deuda (sonda esperada; zlib compila con zig) Con esto puesto, busybox JAMÁS se habría declarado. Cierra el TODO que dejó el revert: la campaña automática ya no puede cimentar contrato como dependencia. Co-Authored-By: Claude Opus 4.8 --- scripts/harkaq/harkaq-suggest.py | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/scripts/harkaq/harkaq-suggest.py b/scripts/harkaq/harkaq-suggest.py index 98af5226..937c3a42 100755 --- a/scripts/harkaq/harkaq-suggest.py +++ b/scripts/harkaq/harkaq-suggest.py @@ -101,11 +101,22 @@ def main(): usa_gcc = receta_toml and compiler_de(receta_toml) == "gcc" esperadas = set() + # RUNTIME BASE: lo que la política ya CONCEDE (`ro`/`rw`/`list`). Si un path está acá, NO es + # deuda declarable aunque el store lo provea — es contrato del sandbox. + # + # Este bug costó caro: `/bin/busybox` está concedido (el sandbox corre `sh -c` y /bin/sh→ + # busybox), pero como `recipes/busybox.toml` existe, el clasificador propuso "declarar dep: + # busybox" y la cosecha lo declaró en 29 recetas. Declararlo apila el busybox de hammer sobre + # el de Alpine y ROMPE el build (binutils: "cannot run C compiled programs"). Además va contra + # la Etapa C, que reemplaza busybox por uutils. Medir bien y accionar mal. + concedidos = set() with open(politica) as f: for l in f: l = l.strip() if l.startswith("# expect "): esperadas.add(l[len("# expect "):].strip()) + elif l[:3] in ("ro ", "rw ") or l.startswith("list "): + concedidos.add(l.split(None, 1)[1].strip()) # Si la receta compila con gcc, los frontends NO se perdonan: son la deuda de compilador. if usa_gcc: esperadas -= FRONTENDS_GCC @@ -117,11 +128,15 @@ def main(): idx = indice_del_store(store) recetas = catalogo(recipes_dir) - declarable, irreducible, compilador = {}, [], [] + declarable, irreducible, compilador, base = {}, [], [], [] for p in deuda: if usa_gcc and p in FRONTENDS_GCC: compilador.append(p) continue + # ¿Ya concedido por la política? ⇒ runtime base, NO se declara (ver arriba: busybox). + if p in concedidos or any(p.startswith(c.rstrip("/") + "/") for c in concedidos if c != "/"): + base.append(p) + continue provs = idx.get(p) if provs: # El store es autoritativo: sabe qué ficheros aporta cada artefacto. @@ -144,6 +159,10 @@ def main(): else: irreducible.append(p) + if base: + print("RUNTIME BASE — ya concedido por la política; NO declarar (es contrato del sandbox):") + for p in base: + print(f" {p}") if compilador: print("DEUDA DE COMPILADOR (matar-gcc) — la receta usa el gcc de Alpine (compiler=gcc):") for p in compilador: