Skip to content

Codebase analyst — deferred findings 2026-05-30 #59

Description

@LiukScot

Deferred findings dal run del 2026-05-30. Ognuno è actionable in una run dedicata (es. `implementa deferred `).

Issue creato automaticamente dal Codebase Analyst. Linkato al PR: da aggiornare.


Deferred — Rate limiting login endpoint

Fingerprint: login-rate-limit@internal/auth/auth.go:64
File: internal/auth/auth.go:64, internal/server/server.go:205
Severità: HIGH
Soluzione proposta: Aggiungere rate limiting per-IP o per-email sul login endpoint. Il dummy bcrypt per utenti inesistenti previene l'email enumeration ma non limita i tentativi brute-force.
Patch indicativa:

// Aggiungere middleware token-bucket prima di handleLogin
// Opzione: golang.org/x/time/rate per semplicità, oppure redis-based per distribuzione
limiter := rate.NewLimiter(rate.Every(time.Second), 5) // 5 req/s per IP

Decision points: Per-IP vs per-email; in-memory vs Redis; lockout permanente vs temporaneo; CAPTCHA dopo N tentativi.
Trade-off: In-memory non funziona con deployment multi-istanza. Redis aggiunge dependency. Lockout permanente può essere usato per DoS.
Test richiesto: Test tabellare che verifica 429 dopo N tentativi consecutivi.


Deferred — Full file scan in GetRecentBans

Fingerprint: fail2ban-full-scan@internal/collectors/fail2ban.go:117
File: internal/collectors/fail2ban.go:117
Severità: HIGH
Soluzione proposta: Leggere il file fail2ban.log dalla fine (seek-from-end + reverse scan) per evitare di caricare in memoria l'intero file su ogni API call. Su server attivi con anni di history il file può essere centinaia di MB.
Patch indicativa:

// Seek from end, read backward in chunks, collect events until limit reached
// See: https://pkg.go.dev/os#File.Seek with io.SeekEnd

Decision points: Dimensione del buffer di lettura backward; comportamento su log ruotati (fail2ban.log.1, .gz).
Trade-off: Logica di lettura backward è più complessa e bug-prone. Alternativa: tail -n 5000 | grep Ban tramite exec.
Test richiesto: Test con file da >500 righe, verifica che solo limit eventi vengano letti.


Deferred — N+1 fail2ban subprocess calls

Fingerprint: fail2ban-n1-jails@internal/collectors/fail2ban.go:58
File: internal/collectors/fail2ban.go:58
Severità: HIGH
Soluzione proposta: Eseguire le chiamate fail2ban-client status <jail> in parallelo con goroutine pool bounded invece di serialmente. Con N jail il tempo è O(N) invece di O(1).
Patch indicativa:

// Goroutine pool simile a docker.go, bounded a runtime.NumCPU()
results := make(chan *JailStatus, len(jailNames))
sem := make(chan struct{}, runtime.NumCPU())
for _, name := range jailNames { /* goroutine with sem */ }

Decision points: Dimensione pool; timeout per singola jail call; se usare sync.WaitGroup o channel.
Trade-off: fail2ban daemon usa un socket Unix serializzato — parallelismo potrebbe non portare beneficio se il daemon è il bottleneck.
Test richiesto: Benchmark GetStatus con N jail simulando exec fittizi.


Deferred — Full log file read in GetLogs

Fingerprint: log-full-scan@internal/collectors/logs.go:78
File: internal/collectors/logs.go:78
Severità: MEDIUM
Soluzione proposta: readLogFile() legge ogni riga di ogni log file per tenere solo le ultime 500. Su file multi-GB è un full-scan. Reverse-scan dal fondo o seek-based approach eliminerebbe il problema.
Patch indicativa:

// Seek to end, read backward in chunks accumulating up to maxLines
// Stop early once maxLines collected

Decision points: Stessa complessità del finding fail2ban; valutare se i log sono sempre crescenti o vengono ruotati.
Trade-off: Logica backward è più complessa. Alternativa: limitare dimensione file via logrotate config.
Test richiesto: Test con file 10x maxLines, misurare che solo l'ultima parte venga letta.


Deferred — Redundant crontab parse in HiddenJobCount

Fingerprint: cron-redundant-parse@internal/collectors/cron.go:244
File: internal/collectors/cron.go:244
Severità: MEDIUM
Soluzione proposta: HiddenJobCount() chiama ReadJobs() che ri-legge e ri-parsa ogni crontab da disco per costruire il set di fingerprint necessari a pruneStaleHidden. Se il frontend polling questo endpoint, c'è I/O disco ridondante rispetto a Week(). Caching con file-mtime check o query DB diretta.
Patch indicativa:

// Alternative: pure DB query
SELECT COUNT(*) FROM cron_hidden_jobs h
JOIN cron_jobs j ON h.job_id = j.fingerprint

Decision points: Cache TTL vs file-mtime invalidation; se sincronizzare fingerprints via upsertJobs periodicamente per permettere query DB-only.
Trade-off: La cache può essere stale se crontab cambia tra due poll. La query DB funziona solo se upsertJobs è sempre called prima.
Test richiesto: Benchmark HiddenJobCount vs Week su directory con N crontab.


Deferred — CSP style-src unsafe-inline

Fingerprint: csp-unsafe-inline-style@internal/server/csp.go:106
File: internal/server/csp.go:106
Severità: MEDIUM
Soluzione proposta: Rimuovere 'unsafe-inline' da style-src tramite nonce-based injection o build-time CSS extraction. Tailwind v4 (già in package.json) potrebbe supportare questo.
Patch indicativa:

// Valutare @tailwindcss/vite plugin con modalità build-time
// che emette solo classi usate, eliminando il bisogno di runtime injection

Decision points: Compatibilità con SvelteKit SSR; se Tailwind v4 supporta nonce injection.
Trade-off: Cambiamento al build pipeline. Rischio regressione visiva su componenti che usano dynamic classes.
Test richiesto: Playwright test che verifica che i componenti principali renderino correttamente dopo la migrazione.


Deferred — swapPercent type mismatch in cpuHistory

Fingerprint: cpuhistory-type-mismatch@frontend/src/routes/+page.svelte:153
File: frontend/src/routes/+page.svelte:153, frontend/src/lib/api.ts:34
Severità: LOW
Soluzione proposta: api.cpuHistory() è tipata per restituire SystemMetrics[] ma il campo timestamp è string nel tipo TS mentre il frontend lo usa come new Date(h.timestamp). Allineare il tipo di ritorno a HistorySample[] usando l'endpoint /api/v1/system/history?range=1h già usato per netSeed, oppure aggiungere il campo timestamp come number a SystemMetrics.
Decision points: Cambiare l'endpoint che alimenta cpuHistory vs aggiungere campo al tipo SystemMetrics.
Trade-off: Cambiare endpoint potrebbe alterare il comportamento del grafico live.
Test richiesto: TypeScript strict mode check senza errori.


Deferred — Docker resource limits missing

Fingerprint: docker-resource-limits@docker-compose.yml:1
File: docker-compose.yml
Severità: LOW
Soluzione proposta: Aggiungere deploy.resources.limits a docker-compose.yml. Il container usa network_mode: host e monta /var/run/docker.sock — senza memory cap un OOM può starvare l'host.
Patch indicativa:

deploy:
  resources:
    limits:
      memory: 512m

Decision points: Valore memory limit da adattare alla macchina di deployment.
Trade-off: Limite troppo basso può causare OOM kill durante picchi legittimi.
Test richiesto: docker stats sotto carico per determinare il consumo reale.


🤖 Generated by Codebase Analyst — 2026-05-30

Metadata

Metadata

Assignees

Labels

codebase-analyst-deferredDeferred findings tracked by weekly codebase analyst

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions