FreeDom

Freedom — Navegador Seguro por Defecto

Misión: un navegador web construido desde cero en C puro, diseñado como respuesta directa a la vigilancia corporativa (modelos tipo Brave–Palantir). Cero telemetría, cero backdoors, cero confianza implícita. Lo que no se puede auditar, no entra.

Este archivo es el contrato de trabajo para cualquier agente (humano o IA) que toque este repositorio. Estas reglas anulan comportamientos por defecto.


1. Los seis principios inquebrantables

  1. Zero Trust — Ningún componente confía en otro. El renderizador no confía en la red; el motor JS no confía en el DOM; nada confía en el contenido remoto. Aislamiento por límites estrictos de memoria y, donde el SO lo permita, seccomp-bpf (Linux), landlock, pledge/unveil (OpenBSD).
  2. Zero Knowledge — El navegador no sabe del usuario más de lo estrictamente necesario para renderizar. Sin historial en claro, sin fingerprinting pasivo, sin fugas de IP (WebRTC deshabilitado por defecto).
  3. Privacy by Default — Bloqueo total de terceros a nivel del motor de red. Sin telemetría ni siquiera “anónima” u “opt-out”. Integración opcional con Tor/I2P a nivel de socket.
  4. Secure by Default — La configuración insegura no debe ser representable en la API. El camino por defecto es siempre el seguro. Fallar cerrado: si una garantía no se puede verificar, se rechaza la operación.
  5. Post-Quantum by Default — TLS 1.3 mínimo. Intercambio de claves híbrido (clásico + ML-KEM) para neutralizar Harvest-Now, Decrypt-Later. Nunca PQ puro (si ML-KEM cae, el componente clásico debe resistir); nunca clásico puro.
  6. Agent-Safe & Agent-Friendly — Seguro para el usuario y para el agente de IA que lo opere, en ambas direcciones: el contenido remoto es hostil también para el agente (inyección de prompts), así que se le entrega siempre como dato con procedencia, nunca como instrucción, y sin acción implícita; y el navegador es manejable por un agente (salidas deterministas, con códigos de estado, sin estado oculto, headless). El agente opera dentro de los mismos sandboxes que el usuario. Contrato completo en spec/agent-safety.md.

Doctrina anti-vigilancia: no se permite ninguna cadena de texto, dependencia, endpoint ni comentario que apunte a servicios de terceros no esenciales. Cada dependencia se justifica por reducción de superficie de ataque, no por conveniencia.


2. Restricciones de lenguaje y estilo


3. Metodología: SDD + TDD estricto + BDD Given-When-Then

Para cada módulo el ciclo es inviolable y en este orden:

  1. Spec — spec/<modulo>.md: entradas, salidas, tabla de errores, garantías de seguridad y qué queda fuera de alcance, en Dado-Cuando-Entonces.
  2. Test (rojo) — tests/test_<modulo>.c con CMocka (ATDD). Debe fallar de verdad: verificá el rojo revirtiendo el fix, no lo supongas. Un build que falla por -Werror deja el binario viejo en su sitio y el test “pasa” — eso no es rojo, es un experimento inválido.
  3. Code (verde) — src/<modulo>.c, el código mínimo para pasar. La I/O del lado confiable (orquestador / event loop, el que NO toca contenido hostil) debe ser asíncrona (io_uring cuando aplique). Excepción inquebrantable: io_uring está PROHIBIDO dentro del worker confinado (tab/renderer): es una primitiva de bypass de seccomp (sus IORING_OP_* no atraviesan el syscall entry que filtra el BPF → anularía allowlist, W^X y netns). El worker hace I/O bloqueante sobre sus dos pipes. spec/os_sandbox.md §13, [[freedom-io-uring-forbidden-in-worker]].
  4. Refactor — endurecer punteros y límites. Modo boy scout, nunca fuera de scope: código duplicado se unifica; deuda técnica y vulnerabilidades se extinguen sin perder funcionalidad; si algo se hace en 10 líneas en vez de 40 respetando DRY/SOLID, se hace. Cláusula anti-monolito: ningún archivo se vuelve monolito. Al rozar las ~2000 líneas se parte según contratos (módulo = spec/ + include/ + src/). Si tu cambio empujaría un archivo más allá del umbral, primero extraé: en un archivo que ya lo excede, la lógica nueva (sobre todo la pura) va a un módulo nuevo, no a engordarlo.
  5. Validación — make asan (ASan+UBSan) limpio, valgrind, cppcheck, más revisión visual del render. La GUI necesita Wayland (no siempre disponible), así que se inspecciona headless: ./build/freedom --download-png=$SP/frame.png <URL-o-archivo.html> y Read de la imagen. Procedimiento completo, flags (--author-css, --images, --js=on) y checklist en la skill /visual-review (.claude/skills/visual-review/SKILL.md) y en [[freedom-visual-review-headless]]. Preferí PNG sobre PDF: una sola imagen, un paso, muchos menos tokens. Freebug (la consola devtools) es una ventana Wayland aparte y no sale en el PNG: todo cambio que la toque se verifica en pantalla con el flujo Xvfb+weston descrito en [[freedom-gui-visual-verification-weston]], con validación cruzada por --dump-console.
  6. Fuzzing — todo path que toca contenido remoto se fuzzea (make fuzz/fuzz-pv/fuzz-js/ fuzz-img/fuzz-dom/fuzz-svg/fuzz-css/fuzz-jsdom/fuzz-geom/fuzz-wst/fuzz-imap; AFL++ con make fuzz-afl). Cero crashes/leaks/UB antes de cerrar.
  7. Documentación — recién después de validar y fuzzear: spec, este CLAUDE.md, la memoria, docs/index.html (el “home page”: atajos, features) y README.md. Documentar antes de validar es documentar lo que todavía no es verdad.

No escribas la implementación antes que la spec y el test. No avances de hito sin que el anterior esté verde, validado y fuzzeado.

Diseño orientado a prueba: la lógica de seguridad va en funciones puras sin I/O; los orquestadores con red/SO solo cablean y llaman a esas funciones puras sobre el estado real.


4. Stack tecnológico (decisiones vigentes)

Módulo Biblioteca Nota
Red & TLS libcurl + OpenSSL 3.5+ nativo No usar liboqs/oqsprovider. OpenSSL 3.5+ trae X25519MLKEM768, ML-DSA, SLH-DSA en el provider default. Una dependencia menos que auditar.
Parser HTML/CSS Lexbor C puro, superficie mínima. Sin ejecución de scripts inline por defecto.
Motor JS QuickJS-ng (vendorizado) C puro, sandboxed. Bridge C que expone solo APIs validadas. Sin XHR a terceros, sin WebRTC, sin WebGL, sin FS.
UI/Gráficos Cairo + Wayland (nunca X11) X11 permite keylogging entre ventanas.
Shaping de texto HarfBuzz + FreeType + fontconfig Lado confiable, fuentes locales, nunca en el worker ni en la red. [[freedom-harfbuzz-shaping]].
Vídeo/Audio FFmpeg En proceso decoder aislado (OS_PROFILE_MEDIA_DECODER).
Pruebas CMocka sudo apt install libcmocka-dev.
Memoria asignador endurecido / mimalloc Mitigar UAF y overflows.

Verificación PQC en este host: openssl list -tls-groups | grep -i mlkem debe mostrar X25519MLKEM768.

Política criptográfica concreta


5. Compilación, hardening y auditoría

make aplica por defecto:

-std=c11 -Wall -Wextra -Werror -Wshadow -Wpointer-arith -Wvla -Wwrite-strings
-fstack-protector-strong -fstack-clash-protection -fcf-protection=full
-D_FORTIFY_SOURCE=3 -fPIE -fvisibility=hidden -O2
-pie -Wl,-z,relro,-z,now,-z,noexecstack

Targets: make (compila src/), make test (suite CMocka), make asan (ASan+UBSan), make fuzz* (libFuzzer / AFL++), make clean, make deps, make run [URL=...], make deb, make docker.

El Makefile es la única fuente de verdad de los comandos. Los *.sh son wrappers delgados que delegan a un target (fuzz.sh→fuzz-afl, build_deb.sh→deb, docker_run.sh→docker, run_freedom.sh→run). Una fuente nueva se parametriza en el Makefile y todos los targets la toman solos. Todo PR pasa make test y make asan limpios.


6. Estructura del repositorio

freedom/
├── CLAUDE.md              # este archivo
├── Makefile               # build endurecido + targets test/asan/fuzz
├── include/<modulo>.h     # contratos públicos
├── src/<modulo>.c         # implementaciones
├── gui/                   # orquestador Wayland+Cairo (browser_ui.c, bui_theme.c, svg_paint.c)
├── spec/<modulo>.md       # especificaciones SDD
└── tests/test_<modulo>.c  # suites CMocka (TDD)

7. Estado y hoja de ruta

7.1 Núcleo cerrado — de la red a la pantalla

Todos con suites CMocka + ASan/UBSan limpio (66 suites, 21 targets de fuzzing).

Capa Módulo(s) Garantía clave
Red/TLS secure_fetch (sf_), tls_impersonate (ti_) TLS 1.3 mínimo, KE híbrido PQ preferido; cada redirección re-aplica TODA la política. Impersonación JA3/JA4 por triple opt-in.
URL/enlaces url (url_), link_nav (ln_) RFC 3986; downgrade a http / esquemas ajenos no representables.
Política de red request_policy (rp_), render_policy (rdp_), webcaps (wc_) Bloqueo de terceros por defecto, https-only, gate de imágenes/CSS/JS (todo opt-in).
Filtro de hosts hostblock (hb_), js_policy (jsp_) Lista negra + blanca formato /etc/hosts; la blanca gana y cubre subdominios. Puros, fallan abierto.
Enrutado net_realm (nr_) clearnet / .onion / .i2p → directo / Tor SOCKS5h / I2P HTTP / bloqueado. Puro, fail-closed.
Parser html_parse (hp_), dom (dom_) DOM inerte con Lexbor, strip de <script>/on*; índice de solo lectura con handles enteros.
JS/anti-FP js_sandbox/js_dom/js_env, anti_fp QuickJS-ng sin I/O; bindings sellados; relojes/pantalla normalizados; readback de canvas/audio envenenado por origen.
Aislamiento os_sandbox (os_), tab (tab_) fork+exec + seccomp-bpf fail-closed con W^X + anti-volcado + Landlock + unshare user/net/ipc/uts. El worker NO toca red.
Estado cifrado local_store, disk_store, prefs, profile AEAD + Argon2id; escritura atómica 0600. AUTH-fail ⇒ defaults sin clobber.
Render page_view (pv_), render_doc (rd_), box_tree (bt_), flex_layout (fx_), block_flow (bf_), compositor (cx_) DOM → display list → cajas (block/flex/grid) → stacking context (7 capas CSS 2.1 App E). Posicionamiento, z-index, opacity, blend, transform matricial, clipping, float, colapso de márgenes verticales (block_flow, CSS 2.1 §8.3.1) y colocación de grilla por nombre (grid-template-areas, spec/grid_areas.md).
CSS css (css_), css_length (cl_), css_select (csel_), css_color (cc_), interp Parser + cascada pura. Selectores (tipo/clase/id/grupos, 4 combinadores, atributos, pseudo-clases, ::before/::after), !important, @media, @keyframes, custom properties + var(), calc()/min()/max()/clamp(), flex/grid, gradientes, sombras, filtros, transform, todas las unidades de <length> de CSS Values 4 por un ÚNICO resolvedor (css_length: px/pt/pc/cm/mm/Q/in, em/rem/ex/ch/cap/ic/lh/rlh, vw/vh/vi/vb/vmin/vmax + variantes s/l/d). Fail-closed: url() de @import/@font-face descartados, topes anti-DoS, fuzzeado. Inventario completo en spec/css.md.
Imágenes image_decode (img_), data_url (du_) PNG + JPEG + WebP + GIF estático dentro del worker confinado; topes anti-DoS; ARGB listo para Cairo. GIF con decoder LZW propio.
Vídeo/Audio media_decoder (md_), hls H.264/H.265 desde MPEG-TS o HLS en proceso aislado; reproducción a ritmo de PTS (md_pacer puro).
Formularios form (fm_), textfield GET/POST nativos sin JS; target no-https no representable.
Shaping text_shape (tsh_) HarfBuzz + FreeType. Ligaduras, kerning GPOS, formas contextuales. Solo lado confiable, fuzzeado.
Export pdf_export (pe_), zoom (zm_), download (dl_) PDF vectorial; zoom 50–300 %; descargas con nombre fail-closed y escritura atómica 0600.
Prefetch prefetch (pf_) Pre-scanner puro + pool de 6 hilos por el MISMO fetcher gateado; sigue el grafo de módulos ES (imports estáticos + import map).
DevTools freebug (fb_), dom_debug (dd_) Consola JS (F12, --dump-console) con nivel y file:line:col; --dump-dom/--dump-layout/--dump-css.
UI ui/browser (puros) + gui/browser_ui.c (orquestador) Toolbar, tabs, omnibox, scroll, menú, multi-pestaña, atajos, temas.
SVG svg_render (sv_), svg_paint (svp_) <svg> en línea: parser puro y fuzzeado + pintor Cairo. La gramática no tiene forma de URL ⇒ cero red.
Auditoría spec/threat-model.md Activos/adversarios/fronteras → mitigaciones.

7.2 Doctrina vigente (no re-litigar)

Cada línea es la decisión + su porqué; el detalle vive en spec/, en git log y en la memoria.

Red, TLS y soberanía

Aislamiento y superficie JS

Buscador y navegación

Render y presentación

Invariantes de build y de proceso

7.3 Hitos cerrados (una línea por hito)

Comprimido 2026-07-17, 07-31 y 2026-10-29. El detalle vive en git log, spec/ y la memoria.

8. Reglas para el asistente (IA)

Project Knowledge Base (MUST read before coding)

Generated offline by ReadMenator (zero-token static analysis). Humans: KNOWLEDGE_BASE.md.

  1. Memory: cat readmenator-agent/MEMORY.md (business rules, workflow, constraints, style, done criteria, session log). Record new decisions with readmenator . remember "<note>" --kind decision.
  2. Freshness: readmenator . fresh (exit 1 means stale: run readmenator . --rebuild). Without the CLI, compare git_commit in readmenator-agent/MANIFEST.json with git log -1.
  3. Orient: ls *.md readmenator-agent/ readmenator-wiki/, then read readmenator-wiki/index.md (big picture, communities, god nodes).
  4. Locate: grep -n '<keyword>' readmenator-agent/INDEX*.md readmenator-agent/SYMBOLS*.md before any glob over sources; for questions use readmenator . ask "<question>" (GraphRAG, --global for overviews).
  5. Context: cat readmenator-agent/KB_<subsystem>.md for the subsystem you touch.
  6. Before editing: grep -n '<file>' readmenator-agent/GOTCHAS.md readmenator-agent/SECURITY.md (blast radius, cycles, findings).

Also: API*.md (public functions, one line each), ARCHITECTURE*.md (dependency pairs), recipes/*.md (grounded task steps). Large docs are paged as NAME_p2.md, so always grep with NAME*.md.

pip install readmenator && readmenator . --rebuild <!-- /readmenator-agent-kb-link -->