Files
fn_registry/python/functions/cybersecurity/save_scan_to_osint.md
T
egutierrez 935008ec3f feat(recon): grupo de reconocimiento de red + servicios + fingerprint web
Añade el capability group `recon` (dominio cybersecurity + pipelines, Python),
con la política de archivado OSINT y página madre docs/capabilities/recon.md.

Lookups y sondeo (wrappers de CLI):
- whois_lookup, rdap_lookup, dns_records, ping_host, traceroute_host, nmap_scan
- save_scan_to_osint (sink común) + recon_osint (pipeline one-shot scan+archivado)

Escaneo de puertos/servicios nativo (stdlib, sin nmap ni sudo):
- scan_tcp_ports: connect-scan TCP concurrente (open/closed/filtered)
- grab_service_banner: banner grab + identificación de servicio/versión real
- identify_port_service: puro, puerto -> servicio IANA esperado (~120 puertos)
- scan_port_services: pipeline one-shot (scan -> identify + banner por puerto abierto)

Fingerprint de tecnología web (estilo Wappalyzer), patrón pura/impura:
- fetch_http_fingerprint: GET stdlib, recoge headers/html/cookies (solo nombres)
- detect_web_tech: puro, matchea ~50 firmas regex -> tecnologías por categoría
- fingerprint_web_stack: pipeline one-shot url -> tecnologías

Todas devuelven dict {status} sin lanzar. Tests: 43 verdes, sin red externa.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-14 15:12:07 +02:00

4.8 KiB

name, kind, lang, domain, version, purity, signature, description, tags, uses_functions, uses_types, returns, returns_optional, error_type, imports, tested, tests, test_file_path, file_path, params, output
name kind lang domain version purity signature description tags uses_functions uses_types returns returns_optional error_type imports tested tests test_file_path file_path params output
save_scan_to_osint function py cybersecurity 1.0.0 impure def save_scan_to_osint(target: str, scan_type: str, raw: str, summary: dict | None = None, vault_dir: str = '~/Obsidian/osint', service_url: str = 'http://127.0.0.1:8771', tool: str | None = None) -> dict Sink comun OSINT: persiste el resultado de cualquier escaneo de red (whois|rdap|dns|nmap|traceroute|ping) en el ecosistema OSINT del repo. Dos capas: (1) capa nota SIEMPRE (fuente de verdad) que escribe una nota Markdown tipada en el vault Obsidian bajo dominios/<slug>/recon/<scan_type>-<ts>.md con el raw en bloque de codigo, componiendo create_obsidian_note; (2) capa registro estructurado best-effort que hace POST al service osint_db (DuckDB single-writer) en /api/scan. Si el service esta caido o el endpoint no existe (404), degrada a solo-nota con register_warning sin fallar. No lanza: devuelve dict de estado.
recon
osint
cybersecurity
obsidian
sink
create_obsidian_note_py_obsidian
false error_py_core
false
python/functions/cybersecurity/save_scan_to_osint.py
name desc
target Objetivo del scan (dominio, host o IP). Define el slug de la carpeta en el vault.
name desc
scan_type Tipo de scan (whois|rdap|dns|nmap|traceroute|ping). Texto libre que se sanea a slug seguro para nombre de archivo y tags.
name desc
raw Salida cruda del scan (texto). Se embebe en un bloque de codigo en la nota; si supera ~200KB se trunca dejando una marca.
name desc
summary dict opcional con campos resumidos del scan (registrar, ips, puertos, rtt...). Se anade al frontmatter de la nota y se envia al registro estructurado. None -> {}.
name desc
vault_dir Raiz del vault OSINT. Se expande ~. Default ~/Obsidian/osint.
name desc
service_url Base del service osint_db (FastAPI + DuckDB). Default http://127.0.0.1:8771. Se le concatena /api/scan.
name desc
tool Nombre de la herramienta usada (nmap, dig, whois...). Si None usa el scan_type saneado.
dict de estado. Caso ok: {status:'ok', target, slug, scan_type, note_path (rel al vault), note_abs (ruta absoluta), registered (bool: si el POST a osint_db tuvo exito), register_warning (str|None: motivo si el registro DuckDB fallo), scan_id (str|None: id devuelto por el service)}. Caso error (solo si falla la escritura critica de la nota): {status:'error', error: str}.

Ejemplo

import sys, os
sys.path.insert(0, os.path.join("python", "functions"))
from cybersecurity.save_scan_to_osint import save_scan_to_osint

res = save_scan_to_osint(
    "example.com",
    "whois",
    "Domain: EXAMPLE.COM\nRegistrar: X",
    summary={"registrar": "X"},
)
print(res["note_path"])   # dominios/example.com/recon/whois-YYYYMMDD-HHMM.md
print(res["registered"])  # True si osint_db esta vivo y expone POST /api/scan, False si degrado

Cuando usarla

Tras cualquier escaneo de red (whois/rdap/dns/nmap/traceroute/ping), para que el resultado quede archivado y navegable en el vault OSINT. Llamar SIEMPRE despues de un scan. Es el sink comun del ecosistema: cualquier funcion de scan del registry (whois_lookup, dns_records, scan_port_tcp, etc.) deberia volcar aqui su salida.

Gotchas

  • Impura: escribe en disco (el vault Obsidian) y hace una request HTTP de red.
  • overwrite=True: un re-scan del mismo target+tipo dentro del mismo minuto pisa la nota anterior (el timestamp del nombre de archivo tiene granularidad de minuto, YYYYMMDD-HHMM).
  • Registro DuckDB best-effort: la capa 2 depende de que el service osint_db este vivo y exponga POST /api/scan. Si esta caido (ConnectionError) o el endpoint no existe todavia (404), la funcion NO falla: degrada a solo-nota y devuelve registered=False + register_warning con el motivo. status sigue siendo "ok" porque la capa critica (la nota) se guardo.
  • Single-writer DuckDB: la DB esta abierta por el service osint_db. NUNCA abrir osint.duckdb directo en paralelo; el registro estructurado pasa SIEMPRE por HTTP.
  • Solo status:"error" si falla la escritura de la nota (capa critica). Un fallo de red nunca produce error.
  • Contrato del endpoint (lo crea el service osint_db): POST /api/scan con JSON {target, target_slug, scan_type, tool, note_path, summary, scan_ts}; respuesta 2xx, opcionalmente {"id": "..."} que se devuelve como scan_id.

Notas

Compone create_obsidian_note_py_obsidian (del grupo obsidian) para la capa nota y usa urllib.request de stdlib para la capa de registro (sin dependencias nuevas). El timeout HTTP es de 5s. El raw se envuelve en un bloque de codigo fenced con backticks suficientes para no colisionar con backticks internos del propio raw.