
Tracker statico dei risultati delle vulnerability con ricerca parallela su 11 database CVE, arricchimento EPSS, badge CISA KEV, flussi di lavoro per la divulgazione coordinata e supporto offline.
Un tracker statico lato client per i rilevamenti di vulnerabilità, costruito con Astro + React — disponibile anche come app desktop nativa per Linux (Tauri v2). Registra i rilevamenti di sicurezza, tienine traccia tramite la divulgazione coordinata, cerca in 11 database di vulnerabilità attivi in parallelo e sfoglia le ultime CVE — nel browser o come app desktop, senza bisogno di backend.
localStorage (nessun server, nessun account)Il tracker (/tracker) è un'app a pagina singola con cinque schede:
La vista di gestione per i rilevamenti registrati:
Interroga tutti i database abilitati in parallelo con una singola stringa di query:
Navigazione senza input tra le ultime vulnerabilità:
Il pannello di controllo per la connettività dei database:
.env definiti in fase di build{query} opzionale, chiave bearer opzionale), testala o rimuovila; i database personalizzati collegati compaiono come chip aggiuntive nella vista RicercaUn Finding è il record principale. Campi:
La validazione è applicata nel modulo: campi obbligatori, formato URL, lunghezza della descrizione e intervallo CVSS.
11 database integrati, più l'arricchimento EPSS. Sette si collegano direttamente senza chiave; quattro richiedono una credenziale da .env.
Non integrati (con motivazioni): Snyk (limitato all'organizzazione, nessuna API di ricerca pubblica), JFrog Xray (self-hosted, restituisce artefatti non record CVE), Trivy (scanner CLI, nessuna API REST), MSRC (documenti CVRF mensili, non ricercabili per parola chiave), VulnCheck (solo endpoint di backup bulk), Debian/Ubuntu (dump multi-GB, non ricercabili lato client), Exploit-DB/Sploitus (nessuna API pubblica), CNVD/CNNVD (download XML manuali), Sonatype OSS Index (basato su purl/componenti, non su parole chiave).
Sistema di design: il tema "Dark Sunset Boulevard" — superfici scure con sottotono viola intenso (ink-950 #1A2226, ink-900 #223036, ink-800 #264653), testo color sabbia calda (ink-100 #F2EAE0, ink-400 #A49A8C) e un accento arancio bruciato (#E76F51). Tutti i colori sono token Tailwind 4 definiti in src/styles/global.css — nessun hex hardcoded nei componenti.
Richiede Node.js >= 20.```bash
npm install
npm run dev
npm run check
npm run build
npm run preview
La build produce un sito completamente statico (`dist/`) — distribuibile su qualsiasi host statico (GitLab Pages, Netlify, Cloudflare Pages, GitHub Pages, nginx…). La stessa build è anche inclusa in un'app desktop nativa — vedi [App Desktop Nativa](#native-desktop-app).
---
## App Desktop Nativa
**Un unico codebase, ogni formato di distribuzione.** Lo stesso sorgente genera il sito web, le app desktop e un'app Android — non esistono branch separati per web/app. Le app sono la build statica racchiusa in un piccolo shell Rust **Tauri v2** che la renderizza nella webview di sistema (WebKitGTK su Linux, WKWebView su macOS, WebView2 su Windows, Android WebView). Nessun server, nessuna scheda del browser; impostazioni e risultati persistono nella directory dati dell'app.
### Linux (predefinito)
I bundle desktop distribuiti hanno come target Linux (`.deb`, `.rpm`, AppImage).
**Dipendenze di sistema (Debian/Ubuntu):**```bash
sudo apt install libwebkit2gtk-4.1-dev build-essential curl wget file libxdo-dev libssl-dev libayatana-appindicator3-dev librsvg2-dev
Sviluppa (hot-reload: server di sviluppo Astro + finestra Tauri):```bash npm run tauri:dev
**Crea pacchetti installabili** (`.deb`, `.rpm`, AppImage — output in `src-tauri/target/release/bundle/`):```bash
npm run tauri:build
La shell Rust è volutamente minimale — zero comandi IPC in v1; tutta la logica resta nel layer web, quindi la build del browser e l'app desktop si comportano in modo identico.
Il supporto desktop macOS non è abilitato nella configurazione predefinita — i bundle distribuiti sono solo per Linux. Il codebase stesso è completamente multipiattaforma (il layer web gira in qualsiasi browser e la shell Rust ha zero comandi IPC), quindi abilitare macOS è una piccola modifica alla configurazione più una build su un Mac. Vedi docs/macos-development.md per la guida completa: prerequisiti, abilitazione del target dmg, icone, firma e notarizzazione, e un esempio di GitLab CI.
Il supporto desktop Windows non è abilitato nella configurazione predefinita — i bundle distribuiti sono solo per Linux. Il codebase è completamente multipiattaforma e le build Windows girano su una macchina Windows 11 con la toolchain MSVC (WebView2 è preinstallato). Vedi docs/windows-development.md per la guida completa: prerequisiti, abilitazione dei target nsis / msi, icone, firma del codice e SmartScreen, e un esempio di GitLab CI.
Il target Android non è inizializzato nel repository — un solo comando lo inizializza (npm run tauri android init). Il codebase è completamente multipiattaforma (il layer web gira in Android WebView e la UI del tracker è già responsive per i telefoni). Vedi docs/android-development.md per la guida completa: prerequisiti (Android Studio, SDK, NDK, JDK 17), inizializzazione del target, creazione di APK/AAB e un esempio di GitLab CI.
Quattro fonti di ricerca richiedono credenziali. Copia .env.example in .env, inserisci le chiavi e ricompila:
Nota sulla sicurezza: questo è un sito statico — le variabili
PUBLIC_*vengono incorporate nel bundle client in fase di build e sono visibili nel sorgente della pagina. Usa chiavi a bassi privilegi o un proxy lato server per una reale segretezza. Le fonti senza chiave mostrano semplicemente un chip di errore; il resto della ricerca funziona comunque.
Suggerimento: puoi anche inserire queste chiavi nella scheda Settings dell'app — le chiavi runtime sovrascrivono i valori
.envdella build, senza bisogno di ricompilare.
I file .env sono in gitignore; viene committato solo .env.example.
Gli interruttori on/off del database e le chiavi API sono gestiti a runtime tramite la scheda Settings — nessuna modifica ai file o rebuild necessaria. I valori predefiniti si trovano in src/tracker/lib/dbConfig.ts e le sovrascritture runtime sono salvate nell'app (localStorage, chiave settings:all).
Precedenza: impostazioni runtime (scheda Settings) > valori .env della build > predefiniti di dbConfig.ts.
Ogni voce di configurazione ha:
enabled — lo stato predefinito; la scheda Settings può sovrascriverlo per sessionesearch / browse — a quali viste la fonte partecipaneedsKey + keyVar — contrassegna le fonti che leggono una credenziale (da .env o dalla scheda Settings)La UI è interamente derivata dalla configurazione effettiva: getSearchSources() (chip di Search) e getBrowseSources() (chip di Browse) vengono filtrati sulle fonti abilitate, e gli adapter vengono filtrati al momento della query — disattivare una fonte in Settings la rimuove subito dalla UI e dalle query.
I database personalizzati vengono salvati nelle stesse impostazioni runtime (customDbs). Ogni voce ha un nome, un URL (che può contenere un segnaposto {query} — altrimenti la query viene aggiunta come ?q=) e una chiave bearer opzionale. Sono solo di ricerca: appaiono come chip extra nella vista Search e vengono interrogati in parallelo con le fonti integrate. Le risposte sono accettate come CVE JSON 5.0 ({ "vulnerabilities": [{ "cve": ... }] }) o come un semplice array di record con nomi di campo flessibili.
Tutto l'accesso ai database risiede in src/tracker/lib/, suddiviso per responsabilità (dbSearch.ts è un barrel che riesporta la precedente superficie pubblica):
dbFetch.ts — helper fetch con timeout + costanti condivisedbAdapters.ts — gli 11 adapter di ricerca integrati + parser di recorddbBrowse.ts — i 4 adapter di browse + pipeline browseDatabasesdbCustom.ts — l'adapter per i database personalizzati configurati dall'utentedbPipeline.ts — meccanismo merge / KEV / EPSS + `searchDatabases````
query ──► Promise.all over enabled adapters ──► normalizeDbItem
──► mergeDbItems (dedup by CVE / ID / title, cross-merge)
──► attachKevBadges (CISA KEV catalog, cached)
──► enrichWithEpss (FIRST EPSS API, batched by CVE)
──► sorted results + per-source statuses + timing- **Adapter** — uno per sorgente, ciascuno restituisce `RawDbItem` normalizzati. Gli adapter con chiave generano un errore chiaro "no API key configured" quando manca la credenziale.
- **Merge** — la stessa CVE trovata in più sorgenti diventa una singola scheda; i campi (sommario, gravità, CVSS, CWE, riferimenti, sorgenti) vengono uniti da tutti i contributori.
- **Badge KEV** — il catalogo CISA viene recuperato una volta e messo in cache; gli elementi che vi compaiono ricevono un badge "Known Exploited".
- **EPSS** — ricerca in batch su `api.first.org`; ogni scheda mostra il punteggio EPSS e il percentile.
- **Isolamento dei guasti** — ogni adapter intercetta i propri errori e li segnala tramite la callback di stato; una sorgente non disponibile non blocca mai le altre.
La pipeline **Browse** usa lo stesso meccanismo di merge/KEV/EPSS sulle quattro sorgenti di browse, con paginazione (`hasMore` quando una qualsiasi sorgente ha restituito una pagina piena).
La **modalità offline** sostituisce la pipeline live con lo snapshot scaricato: Search e Browse leggono la cache IndexedDB (`src/tracker/lib/offline.ts`), saltano l'arricchimento EPSS e aggiungono i badge KEV solo se anche il feed KEV CISA è stato scaricato. Le sorgenti senza snapshot scaricato mostrano un chip "error / not downloaded" invece di rimanere appese. **Database personalizzati** vengono interrogati attraverso la stessa interfaccia adapter: il segnaposto `{query}` dell'URL viene sostituito (o si aggiunge `?q=`), una chiave bearer opzionale viene inviata come `Authorization` e le risposte vengono normalizzate da CVE JSON 5.0 o da un semplice array.
---
## Persistenza dei dati
I findings sono memorizzati in `localStorage` con la chiave `findings:all` — nessun server, nessun account, funziona offline.
- Le scritture sono soggette a debounce a ogni modifica e salvate automaticamente
- Se l'API di storage del browser non è disponibile (o è presente un'API host di archiviazione artefatti), l'app torna con eleganza a un fallback
- Un payload corrotto viene trattato come vuoto anziché causare un crash
- Un errore di salvataggio mostra un banner con un pulsante **Riprova**
> I dati vivono nel profilo del browser. La cancellazione dei dati del sito elimina i tuoi findings — esporta prima in CSV/Markdown se ti serve un backup.
Gli **snapshot offline** vivono in IndexedDB (database `vulnbook-offline`, store `items` + `meta`) — scaricati per sorgente dalla scheda Impostazioni e usati da Search/Browse mentre la modalità offline è attiva. Sopravvivono ai ricaricamenti e vengono rimossi solo quando clicchi **Rimuovi** per quella sorgente o cancelli i dati del sito.
---
## Esportazioni
Dalla vista Findings, esporta l'elenco **attualmente filtrato e ordinato**:
- **CSV** — 15 colonne (titolo, progetto, URL repo, gravità, CVSS, stato, CWE, CVE, versioni interessate, date di scoperta/segnalazione/divulgazione, riferimenti, note, tag). Virgolette/escaping corretti per virgole, virgolette e newline.
- **Markdown** — una tabella in stile GitHub con le stesse colonne.
I file sono nominati `findings-YYYY-MM-DD.csv` / `.md` e scaricati automaticamente.
---
## AI ChatBox
L'assistente AI integrato nel tracker — una **sidebar sovrapposta** che scorre sopra il contenuto senza modificarne il layout. Vedi **[docs/ai-chatbox.md](https://gitlab.com/t-beckett/vulnbook/-/blob/main/docs/ai-chatbox.md)** per la guida completa (configurazione del provider, note di sicurezza, risoluzione dei problemi).
- **Cinque provider** — OpenAI, Claude (Anthropic), Google Gemini, **Ollama** (locale, offline) e **OpenCode Zen** (include modelli del piano gratuito). Configurati nell'app (chiave + modello), persistiti in `localStorage` (`chat:config`), inviati solo all'endpoint del provider stesso
- **Specializzato sul progetto** — ogni conversazione è basata su un **knowledge pack** incluso su vulnbook (architettura, modello dati, sorgenti del database, convenzioni); attivabile/disattivabile tramite **Contesto progetto** nel pannello di configurazione
- **Risposte in streaming** — output markdown in tempo reale con un pulsante **Stop**; un fallback non streaming subentra automaticamente
- **Comandi slash** — digita `/` nel compositore: `/mcp` e `/skill` aprono l'AI Marketplace, `/new` avvia una conversazione, `/clear` la svuota, `/help` elenca i comandi
- **AI Marketplace** — una scheda nella sidebar che elenca le voci **MCP** e **Skill** disponibili in una griglia; **Connect** attiva/disattiva una voce (persistito), **Download** è nella roadmap (Coming soon)
- **Cronologia chat** — le conversazioni vengono salvate (`chat:history`, con limite e troncamento dai più vecchi)
> **Sicurezza:** le chiavi restano locali e vanno solo al provider; il markdown dell'assistente viene renderizzato tramite un sanitizer rigoroso (niente HTML grezzo); le voci MCP/skill connesse sono solo di stato nella v1 — non viene scaricato o eseguito nulla.
---
## Test
Il progetto non ha un framework di unit test (decisione consolidata) — la verifica è un gate a tre passaggi:```bash
# 1. Type-check
npm run check
# 2. Build
npm run build
# 3. E2E smoke test (Playwright, 16 checks)
npx http-server dist -p 8899 -a 127.0.0.1 &
NODE_PATH=<path-to-playwright-node_modules> node scripts/smoke.cjs
Il test smoke (scripts/smoke.cjs) copre: rendering della landing page + idratazione, idratazione dell'isola tracker, CRUD dei finding, persistenza di localStorage al ricaricamento, vista elenco + controlli di esportazione, modale dei dettagli (apertura/Escape), eliminazione, ricerca nel database che produce schede di risultati, la vista browse che produce schede di risultati, la scheda impostazioni (disattivare una sorgente rimuove il suo chip, riattivarla lo ripristina), modalità offline (l'interruttore mostra il banner offline in Search e ripristina la modalità live) e validazione del modulo per database personalizzati (URL non valido respinto).
PLAYWRIGHT_CHROMIUM_PATH o da un percorso di cache predefinitoPer le modifiche all'app nativa, eseguire anche npm run tauri:build (vedi App desktop nativa).
├── src/ │ ├── components/ # Shared Astro components + animation primitives │ │ └── anim/ # Skeleton, Spinner, FadeInUp, CountUp │ ├── layouts/ # SiteLayout (fonts, meta, theme) │ ├── pages/ # index.astro (landing), tracker.astro, 404.astro │ ├── styles/ # global.css — Tailwind 4 design tokens │ └── tracker/ │ ├── components/ # Tracker UI │ │ ├── TrackerApp.tsx # Shell: tabs, modals, state │ │ ├── Dashboard.tsx # Stats + charts + deadlines │ │ ├── FindingsList.tsx / FilterBar.tsx │ │ ├── DbSearchView.tsx / BrowseView.tsx / SettingsView.tsx │ │ ├── FindingFormModal.tsx / FindingDetailModal.tsx │ │ ├── ConfirmDeleteDialog.tsx / EmptyState.tsx / ErrorBanner.tsx │ │ ├── SourceChip.tsx / SearchResultCard.tsx / StatCard.tsx / badges.tsx │ └── lib/ # Logic │ ├── types.ts # Finding, DbItem, KevEntry, View, … │ ├── constants.ts # Severity/status order + styles, button classes │ ├── dbConfig.ts # ← per-source defaults (on/off, key vars) │ ├── settings.ts # ← runtime settings store (Settings tab overrides) │ ├── offline.ts # IndexedDB offline snapshot store (download/remove/query) │ ├── dbSearch.ts # barrel: re-exports the db layer (see "How the Search Pipeline Works") │ ├── dbFetch.ts # fetch-with-timeout helper + shared constants │ ├── dbAdapters.ts # 11 built-in search adapters + record parsers │ ├── dbBrowse.ts # browse adapters + browseDatabases pipeline │ ├── dbCustom.ts # user-configured custom database adapter │ ├── dbPipeline.ts # merge/KEV/EPSS pipeline + searchDatabases │ ├── findings.ts # CRUD + validation │ ├── storage.ts # localStorage + artifact-API fallback │ ├── export.ts # CSV / Markdown export │ └── format.ts # date/URL/id helpers, cvssToSeverity ├── scripts/smoke.cjs # Playwright E2E smoke test (16 checks) ├── docs/ # Developer guides (macOS, Windows 11, Android development) ├── src-tauri/ # Tauri v2 native shell (Rust, minimal) ├── research/ # Vulnerability database & tooling research notes ├── .env.example # Documented API-key template └── astro.config.mjs
---
## Note di ricerca
La directory `research/` contiene la ricerca di base che ha guidato le integrazioni con i database:
- **`vulnerability-databases.md`** — ~60 database catalogati (modello di accesso, disponibilità API, avvertenze), incluse le modifiche all'arricchimento del NVD di aprile 2026, i dettagli delle API di EUVD/OpenCVE/VulDB e l'elenco dei "perché no"
- **`vulnerability-finding-tools.md`** — il panorama più ampio degli strumenti di individuazione delle vulnerabilità (SAST/SCA/fuzzing/pentest) e una pipeline per il singolo professionista
---
## Workflow di progettazione e pianificazione
Questo progetto segue un flusso di lavoro progettazione → pianificazione → esecuzione.
Le nuove funzionalità partono con un documento di progettazione, vengono validate, quindi pianificate ed eseguite in micro-attività. Consulta `CONTRIBUTING.md` per le convenzioni complete (branching, gate di verifica, stile dei commit, regole di accessibilità).
---
## Licenza
[MIT](https://gitlab.com/t-beckett/vulnbook/-/blob/main/LICENSE) © 2026 T. Beckett
| Campo | Descrizione |
|---|
id | Identificatore univoco |
projectName | Progetto a cui appartiene il rilevamento (obbligatorio) |
repoUrl | URL del repository (obbligatorio, deve essere un URL valido) |
title | Titolo breve (obbligatorio) |
description | Descrizione dettagliata (obbligatoria, ≥ 10 caratteri) |
severity | Critical / High / Medium / Low |
cvssScore | Punteggio CVSS 0–10 (opzionale) |
cweId | Identificatore CWE, es. CWE-79 |
cveId | Identificatore CVE, es. CVE-2021-44228 |
affectedVersions | Intervalli di versioni interessate |
status | New / Reported / Acknowledged / Fixed / Disclosed |
discoveryDate | Quando lo hai trovato |
reportedDate | Quando lo hai segnalato al fornitore |
disclosureDeadline | Scadenza di divulgazione coordinata (gestisce gli avvisi della dashboard) |
referenceLinks | Elenco di URL di riferimento |
notes | Note libere |
tags | Elenco di tag (usati per il filtraggio) |
createdAt / updatedAt | Timestamp |
| # | Fonte | Accesso | Ricerca | Sfoglia | Note |
|---|
| 1 | NVD (NIST) | Diretto | ✅ | ✅ | NVD API 2.0; finestra di 30 giorni in Sfoglia |
| 2 | CIRCL | Diretto | ✅ | ✅ | Ricerca CVE + feed "last" (formati OSV/CSAF) |
| 3 | GitHub Advisories | Diretto | ✅ | ✅ | API GHSA |
| 4 | OSV (Google) | Diretto | ✅ | — | Vulnerabilità dell'ecosistema open-source |
| 5 | CISA KEV | Diretto | ✅ | ✅ | Catalogo delle vulnerabilità note sfruttate |
| 6 | Red Hat | Diretto | ✅ | — | Database CVE di Red Hat |
| 7 | EUVD (ENISA) | Diretto | ✅ | — | Database europeo delle vulnerabilità |
| 8 | Vulners | chiave .env | ✅ | — | PUBLIC_VULNERS_API_KEY |
| 9 | MEND | token .env | ✅ | — | PUBLIC_MEND_API_TOKEN (ricerca per ID CVE) |
| 10 | VulDB | chiave .env | ✅ | — | PUBLIC_VULDB_API_KEY (a crediti) |
| 11 | OpenCVE | token .env | ✅ | — | PUBLIC_OPENCVE_API_TOKEN |
| — | EPSS (FIRST) | Diretto | — | — | Solo arricchimento: assegna punteggi 0–1 alle CVE + percentile |
| Livello | Scelta |
|---|
| Framework | Astro 6 (output statico) |
| UI | React 19 islands |
| Stile | Tailwind CSS 4 (classi basate su token) |
| Grafici | Recharts |
| Icone | lucide-react |
| Animazioni | framer-motion |
| Desktop | Tauri v2 (Linux: deb / rpm / AppImage; Windows: vedi Sviluppo su Windows 11; macOS: vedi Sviluppo su macOS) |
| Mobile | Android tramite Tauri v2 — vedi Sviluppo Android |
| Chat IA | Chatbox integrata — OpenAI / Claude / Gemini / Ollama / OpenCode Zen (vedi AI ChatBox) |
| Linguaggio | TypeScript (strict) |
| Fonte | Variabile | Dove ottenerla |
|---|
| Vulners | PUBLIC_VULNERS_API_KEY | Account Vulners → chiavi API |
| MEND | PUBLIC_MEND_API_TOKEN | MEND SCA API 2.0 (token bearer JWT) |
| VulDB | PUBLIC_VULDB_API_KEY | Account VulDB → chiave API (a crediti) |
| OpenCVE | PUBLIC_OPENCVE_API_TOKEN | Organizzazione OpenCVE → token API |