Hash estable (tel normalizado > email > nombre normalizado) para importaciones
idempotentes: re-importar el mismo .vcf matchea la fila existente sin depender de
UIDs opacos ni de nombres que el pipeline de import transforma. Prefijo v1- para
versionar el algoritmo. Funcion pura + 5 tests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
El escape de valores vCard solo escapaba el salto de linea, no el retorno de
carro crudo. Un \r sin \n sobrevivia al escape y los parsers que lo normalizan
a salto de linea (como _unfold_lines de osint_web) leian propiedades inyectadas
(p.ej. X-OSINT-DNI), burlando el control de no exponer datos OSINT al movil.
Ahora _vcard_escape elimina el \r, en paridad con el escape iCal. Test de
regresion anadido.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
CRÍTICO: read_only=True protege la base de datos pero NO el sistema de ficheros. Un
SELECT con read_csv/read_blob/glob/COPY...TO podía leer ficheros arbitrarios (claves SSH)
o escribirlos (camino a RCE). Añadido parámetro sandbox (default True) que abre la conexión
con enable_external_access=false, bloqueando todo acceso a FS/red desde la query. Los SELECT
normales sobre tablas siguen funcionando. Único consumidor (osint_db /api/query) queda
protegido sin cambios. Tests nuevos: sandbox bloquea read_csv; sandbox=False lo permite.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
El indexer rechaza funciones impure con error_type vacío. Ambas funciones del grupo dav
declaran error_go_core como el resto de las funciones DAV Python del registry.
Cinco funciones nuevas para soportar DuckDB como fuente de verdad del project osint:
Grupo duckdb (escritura, complementan a duckdb_query_readonly):
- duckdb_execute_py_infra (impure): ejecuta INSERT/UPDATE/DELETE/DDL en read-write, commit, {status,rowcount}. 6 tests.
- duckdb_upsert_py_infra (impure): UPSERT ON CONFLICT actualizando solo update_cols → ownership selectivo (un re-upsert no pisa columnas excluidas). 7 tests.
Grupo dav (libretas de contactos + vCard multi-valor):
- dav_make_addressbook_py_infra (impure): crea una libreta CardDAV nueva via extended MKCOL (RFC 5689). Idempotente. 12 tests.
- dav_list_addressbooks_py_infra (impure): lista las libretas del contacts-home (PROPFIND Depth:1). 7 tests.
- build_vcard_py_core (pure): serializa un contacto a vCard 3.0 multi-valor (N TEL/EMAIL/ADR + X-OSINT-*). 5 tests.
Paginas de capacidad duckdb.md y dav.md actualizadas.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Dos funciones nuevas del grupo de capacidad `dav`:
- expand_rrule_py_infra (pure): expande una RRULE iCalendar a las fechas de
cada ocurrencia dentro de un rango [from, to]. Solo stdlib (datetime, re).
Soporta FREQ DAILY/WEEKLY/MONTHLY/YEARLY, INTERVAL, COUNT, UNTIL, BYDAY. 9 tests.
- dav_make_calendar_py_infra (impure): crea una coleccion de calendario nueva
via MKCALENDAR + PROPPATCH de nombre/color. Idempotente si ya existe. 11 tests.
Consumidas por la app osint_web (eventos recurrentes + creacion de agendas).
Pagina del grupo dav actualizada con ambas.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Funciones reutilizables creadas esta sesion para el sistema self-hosted de contactos/calendario (Xandikos) y la app osint_web:
- grupo dav (infra): split_vcards, split_vevents_to_vcalendars, extract_or_make_uid, carddav_put_vcard, caldav_put_event, dav_list_resources, dav_get_resource, dav_list_calendars
- pipelines: import_vcf_to_carddav, import_ics_to_caldav
- obsidian: build_obsidian_graph (grafo agregado del vault)
Completa el CRUD del grupo dav (put/get/list/get-collection/delete). HTTP DELETE
con Basic auth, If-Match opcional para borrado condicional, maneja 404 como
idempotente. Solo stdlib. 7 tests deterministas (monkeypatch urlopen). Probado
contra Xandikos real durante la limpieza del ciclo de sync OSINT.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
dav_get_collection trae TODOS los recursos de una coleccion CardDAV/CalDAV en
UNA peticion REPORT (addressbook-query / calendar-query) con el contenido vCard
/ VCALENDAR inline, evitando el patron N+1 (PROPFIND + un GET por recurso). Para
1064 contactos baja de ~9s a ~1s. dav_collection_ctag lee el ctag de la
coleccion (PROPFIND Depth:0 barato) para validar caches sin descargar cuando
nada cambio. Ambas: solo stdlib, basic auth, verify_tls, error-safe, tests que
mockean el multistatus. Grupo dav, verificadas contra Xandikos real.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Snapshot de WIP acumulado de sesiones previas antes de merge wave 1
del flow 0008 (kanban_cpp + agent_runner_api + DoD schema).
Incluye:
- dev/flows/0008-kanban-cpp-and-agent-workflows.md
- dev/issues/0112-0119*.md (7 sub-issues)
- WIP previo en cmd/fn/doctor.go, registry/*, modules/, cpp/, etc.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- 0050: jupyter_exec reescrito sin Y.js (REST + KernelClient). Bug raíz adicional: HEAD /api/contents da 405 → cambiado a GET. 9 tests (5 unit + 4 e2e).
- 0052: footprint_aurgi cerrado. Bug fix en setup_geo_stack_docker_pipeline (verify aborta si compose up falla; nombre de contenedor incorrecto).
- Nueva primitiva docker_container_running_py_infra (7 tests).
- /full-git-push y /full-git-pull pasan a modo automático: auto-commit + push sin preguntar, aborta solo si detecta secrets.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
3 helpers puros para construir KPIs con display=smartscalar y comparacion
vs n-1 sin que Metabase v0.59 pida breakout temporal. Replican el patron
del dashboard Informe Lean (UNION ALL de 2 filas periodo/valor) y rellenan
la firma exacta de template-tags que el frontend MBQL5 acepta.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
GLiREL declara proxies/resume_download como required-keyword en
_from_pretrained, pero huggingface_hub 1.x dejo de pasarlos en su
from_pretrained. Aplicamos un classmethod monkey-patch idempotente
que inyecta valores neutros si faltan. Verificado contra glirel==1.2.1
y huggingface_hub==1.13.0 con jackboyla/glirel-large-v0.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Pipeline en cascada que combina extract_iocs (regex, coste 0), GLiNER
(zero-shot NER), GLiREL (zero-shot RE) y un fallback LLM opcional para
chunks con baja confianza o pocas entidades. Devuelve listas concatenadas
listas para deduplicate_entities/deduplicate_relations.
Cierra 0040.
17 casos: helpers de tokenizacion/mapeo, schema basico con head_pos/tail_pos,
fallback por head_text, threshold, max_pairs, self-loops, ImportError, cache,
device='auto'.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- glirel_load_model: cache por (model_name, device); device='auto' resuelve via torch
- extract_relations_glirel: tokeniza por whitespace, mapea spans char->token,
llama predict_relations y devuelve RelationCandidate; fallback text.find si la
entidad llega sin offsets; max_pairs=N -> top-N por score
- pyproject.toml: glirel en extra nlp
Closes#0039
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
11 tests sin necesidad de descargar el modelo (200 MB):
- StubModel duck-typed que valida el contrato de predict_entities
- Threshold y flat_ner se propagan al modelo
- Schema vacio lanza ValueError; schema sin labels validos warning + []
- Excepcion del modelo se captura
- Label desconocido se descarta
- gliner_load_model: ImportError simulado, cache hit, _resolve_device
auto cae a cpu si torch no esta presente
Refs #0038
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Funciones nuevas en python/functions/datascience/:
- gliner_load_model: carga + cachea modelo GLiNER por (name, device).
device='auto' resuelve a cuda/cpu segun torch.cuda.is_available, sin
fallar si torch no esta instalado. ImportError claro si falta gliner.
- extract_entities_gliner: contrato drop-in de extract_entities_llm
(mismo entity_schema, mismo list[EntityCandidate]). El caller inyecta
el modelo (cargado UNA vez por proceso). Anota offsets start/end en
attributes para reconciliar con extract_iocs (issue 0040).
Diferencias vs LLM extractor:
- 50-200x mas rapido en GPU, 0 USD/token.
- Malo con IoCs tecnicos (lo cubre 0037).
- Threshold y flat_ner ajustables por dominio.
pyproject.toml: gliner como extra opcional `[nlp]` para no inflar el
.venv de quien no use NER. Instalacion: `uv pip install -e '.[nlp]'`.
Refs #0038 — Desbloquea 0039 (GLiREL) y 0040 (pipeline hibrido).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
30 tests cubriendo positivos y negativos por tipo:
- IPv4 valida/invalida + rangos limite
- IPv6 forma completa/comprimida
- Emails (caracteres validos en local part)
- Dominios con TLD valido vs desconocido
- Hashes MD5/SHA1/SHA256/SHA512 por longitud
- Wallets BTC legacy/bech32 y ETH
- CVEs 4 y 7 digitos
- MAC con `:` y `-` (separadores mezclados rechazados)
- Telefonos E.164 y ES local 9 digitos
- Pipeline filtrado por types y deduplicacion de spans contenidos
Refs #0037
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Extractores nuevos en python/functions/cybersecurity/:
- extract_ip_addresses (IPv4 + IPv6 con validacion ipaddress)
- extract_emails (RFC 5322 simplificado)
- extract_domains (FQDNs con TLD valido, lista estatica)
- extract_file_hashes (MD5/SHA1/SHA256/SHA512, algoritmo por longitud)
- extract_crypto_wallets (BTC legacy + bech32, ETH 0x+40hex)
- extract_cve_ids (CVE-YYYY-NNNN+)
- extract_mac_addresses (xx:xx:xx + xx-xx-xx, separador uniforme)
- extract_phone_numbers (E.164 + ES local 9 digitos)
Pipeline:
- extract_iocs corre todos, deduplica spans contenidos. Mantiene
purity:pure (kind:function con uses_functions no vacio) porque la
regla del registry exige que los pipelines sean impuros.
Todas devuelven list[dict] con value/start/end/type para que el
caller (issues 0038-0040) pueda reconciliar offsets con spans NER
sin reparsing.
Refs #0037
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Nueva funcion write_analysis_md_bash_infra genera analysis.md con frontmatter.
El pipeline ahora acepta --project para crear analisis directamente en
projects/{proyecto}/analysis/{nombre}/, valida que el proyecto exista,
genera analysis.md con dir_path correcto y ejecuta fn index al final.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Nuevos exports: snippets, notifications, dashboard_filters, export_card,
create_model, prosemirror_card_embed. registry.db regenerado con todas las
funciones nuevas indexadas.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Cards: export_card (CSV/XLSX/JSON), create_model (type=model para fuentes MBQL).
Documents: prosemirror_card_embed helper (resizeNode envolviendo cardEmbed),
validacion automatica contra whitelist TipTap antes de enviar, copy_document
refactorizado al endpoint nativo POST /api/document/:id/copy.
Docs: dataset_query legacy vs MBQL5, template-tags, whitelist de nodos.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Añade un conjunto amplio de funciones al paquete python/functions/metabase:
- Nuevos modulos: collections.py, documents.py, maintenance.py, permissions.py, validation.py (+ test).
- Ampliacion de cards.py, dashboards.py, client.py e __init__.py para exponer las nuevas operaciones.
- Funciones de documentos (create/get/update/delete/archive/copy/move + comentarios), grupos y memberships, permission/collection graphs, copy/move de cards y dashboards, validacion de MBQL/SQL y payloads, actualizacion segura de dashboards y fix_null_ratio.
- .md por funcion con frontmatter para que fn index los registre.
- Actualiza pyproject.toml y uv.lock con las dependencias resultantes.
Impacto: ampliamente mas cobertura de la API de Metabase desde el registry, reutilizable por apps y analisis. No toca Go ni frontend.