6af9a56c28
Fase 5b del issue 0172. Backend stdlib http (solo 127.0.0.1) que orquesta las funciones del grupo obsidian del fn_registry para servir el vault OSINT: grafo agregado (/api/graph), tablas por tipo (/api/nodes), fichas con attachments (/api/node, /api/attachment con bloqueo de path traversal) y busqueda (/api/search). Cache en memoria con POST /api/refresh. Tests pytest (10) sobre vault fixture: grafo golden, tipo filtrado, ficha con attachments, wikilink dangling, slug con acentos, traversal bloqueado, vault inexistente (exit 2) y e2e HTTP en puerto efimero. Frontend (React + Vite + Mantine + sigma.js) queda para la fase siguiente. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
95 lines
3.8 KiB
Markdown
95 lines
3.8 KiB
Markdown
---
|
|
name: osint_web
|
|
lang: py
|
|
domain: tools
|
|
version: 0.1.0
|
|
description: "App web local para explorar el vault OSINT de Obsidian: grafo sigma.js, tablas por tipo y fichas con galería de attachments. Backend Python stdlib que orquesta el grupo obsidian; escucha solo en 127.0.0.1 (datos sensibles)."
|
|
tags: [osint, web, graph, sigma, obsidian, vault, dashboard, mantine]
|
|
uses_functions:
|
|
- build_obsidian_graph_py_obsidian
|
|
- list_obsidian_notes_py_obsidian
|
|
- read_obsidian_note_py_obsidian
|
|
- extract_obsidian_embeds_py_obsidian
|
|
- resolve_obsidian_embed_py_obsidian
|
|
- slugify_obsidian_name_py_obsidian
|
|
- search_obsidian_notes_py_obsidian
|
|
uses_types: []
|
|
framework: "react-vite-mantine"
|
|
entry_point: "server/main.py"
|
|
dir_path: "projects/osint/apps/osint_web"
|
|
repo_url: "https://gitea-dgg044oo04woo4ggcsws4gk0.organic-machine.com/dataforge/osint_web"
|
|
e2e_checks:
|
|
- id: tests
|
|
cmd: "../../../../python/.venv/bin/python3 -m pytest server -q"
|
|
timeout_s: 120
|
|
- id: vault_missing
|
|
cmd: "../../../../python/.venv/bin/python3 server/main.py --vault /no/existe"
|
|
expect_exit: 2
|
|
timeout_s: 30
|
|
---
|
|
|
|
## Qué es
|
|
|
|
App del issue 0172 (project `osint`). Lee directamente los `.md` del vault de
|
|
Obsidian `~/Obsidian/osint` (sin BD intermedia — decisión KISS) y ofrece tres
|
|
vistas: grafo explorable (sigma.js), tablas filtradas por tipo y fichas con la
|
|
galería de attachments de cada nodo.
|
|
|
|
Registry-first: el backend NO parsea el vault — orquesta las funciones del
|
|
grupo de capacidad `obsidian` (`build_obsidian_graph`, `read_obsidian_note`,
|
|
`resolve_obsidian_embed`, ...) declaradas en `uses_functions`.
|
|
|
|
## Arrancar el backend
|
|
|
|
```bash
|
|
cd projects/osint/apps/osint_web
|
|
../../../../python/.venv/bin/python3 server/main.py --vault ~/Obsidian/osint --port 8470
|
|
```
|
|
|
|
El servidor cachea el grafo en memoria al arrancar; `POST /api/refresh`
|
|
re-escanea el vault bajo demanda (botón "refrescar" del frontend).
|
|
|
|
## Endpoints
|
|
|
|
| Método | Ruta | Devuelve |
|
|
|---|---|---|
|
|
| GET | `/api/health` | estado + nº de nodos/aristas cacheados |
|
|
| GET | `/api/graph` | grafo completo `{nodes, edges}` para sigma.js |
|
|
| GET | `/api/nodes?tipo=persona` | filas de la tabla de ese tipo (id, label, tipo, frontmatter) |
|
|
| GET | `/api/node/<slug>` | ficha: frontmatter + body Markdown + attachments + wikilinks |
|
|
| GET | `/api/attachment?path=<rel>` | binario del attachment (path relativo al vault, allowlist) |
|
|
| GET | `/api/search?q=...` | nodos cuyo contenido matchea la query |
|
|
| POST | `/api/refresh` | re-escanea el vault y reconstruye la caché |
|
|
|
|
## Seguridad
|
|
|
|
- El vault contiene datos personales sensibles (DNIs, fotos): el server escucha
|
|
**solo en `127.0.0.1`** — no hay flag para exponerlo a red y NO es un service
|
|
desplegable a VPS (sin tag `service`).
|
|
- `/api/attachment` bloquea path traversal: `realpath` del candidato debe quedar
|
|
estrictamente bajo el `realpath` del vault; cualquier otro caso → 403.
|
|
- Vault inexistente al arrancar → error claro en stderr + exit 2 (nunca 500
|
|
silencioso).
|
|
|
|
## Tests
|
|
|
|
```bash
|
|
cd projects/osint/apps/osint_web
|
|
../../../../python/.venv/bin/python3 -m pytest server -q
|
|
```
|
|
|
|
Cubren el DoD backend del issue 0172: grafo golden, tabla por tipo, ficha con
|
|
attachments, wikilink dangling (nodo fantasma), slug con acentos
|
|
(`[[María del Mar Pérez]]` → `maria-del-mar-perez`), path traversal bloqueado,
|
|
vault inexistente y un e2e HTTP contra el server real en puerto efímero.
|
|
|
|
## Estado / pendiente
|
|
|
|
- **Hecho (fase 5b)**: scaffold del sub-repo + backend completo con tests.
|
|
- **Pendiente (fase siguiente)**: `frontend/` React + Vite + Mantine v9 +
|
|
`@fn_library` con sigma.js + graphology (GraphView, TablesView, NodeCard).
|
|
Onboarding previsto: `pnpm dev` en `frontend/` + backend en 8470 → abrir
|
|
`http://127.0.0.1:5173`.
|
|
- Cuando exista el manifest de sub-repos del project (issue 0171), añadir esta
|
|
app a `projects/osint/subrepos.yaml`.
|