935008ec3f
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>
4.8 KiB
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. |
|
|
false | error_py_core | false | python/functions/cybersecurity/save_scan_to_osint.py |
|
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_dbeste vivo y expongaPOST /api/scan. Si esta caido (ConnectionError) o el endpoint no existe todavia (404), la funcion NO falla: degrada a solo-nota y devuelveregistered=False+register_warningcon el motivo.statussigue siendo"ok"porque la capa critica (la nota) se guardo. - Single-writer DuckDB: la DB esta abierta por el service
osint_db. NUNCA abrirosint.duckdbdirecto 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/scancon JSON{target, target_slug, scan_type, tool, note_path, summary, scan_ts}; respuesta 2xx, opcionalmente{"id": "..."}que se devuelve comoscan_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.