Note di Matteo


#dev

DNSimple spiega come gestiscono le repository GitHub con Terraform. Quando iniziano a diventare centinaia, gestirle manualmente genera inconsistenze:

  • Repositories had different settings, even when they should have been identical
  • Labels for issue triage varied from repository to repository, making cross-project tracking difficult
  • Some repositories had issue templates, while others didn't
  • Permission management was manual and error-prone
  • Security features like vulnerability alerts weren't consistently enabled
  • Pull request templates were copy-pasted (when they existed at all)

Dopo un tentativo con Repocop, per automatizzare il setup, hanno deciso di usare Terraform con aggiornamento delle configurazioni tramite Pull Request e Terraform Cloud.

#305 /
23 gennaio 2026
/
14:46
/ #dev#github

2FA for developers

Ho aggiunto il supporto all'autenticazione a due fattori su DMARCwise e ho fatto fatica a trovare informazioni su best practice attorno alla 2FA con OTP, per cui segno quello che ho scoperto qui.

Intanto, l'algoritmo si chiama Time-based One-Time Password (TOTP) e permette di generare un codice di N cifre ogni T secondi partendo da un secret. Non tutte le app "authenticator" supportano tutte le configurazioni, per cui la più comune è:

  • Codici di 6 cifre.
  • Intervallo di tempo T di 30 secondi.
  • Algoritmo HMAC-SHA1.

Il secret nella maggior parte dei casi è di 20 byte (160 bit) e viene codificato in Base32 (es. CVEBO7GKWLFDRBJRPPTOZ7I6VEPDIGIT). Va generato diverso per ogni utente.

Per la verifica del TOTP la RFC consiglia di usare una tolleranza (drift window) di +/- un intervallo di tempo T (quindi vale sia il codice precedente che quello successivo).

Il secret andrebbe cifrato prima di essere inserito nel database. Nel mio caso ho scelto AES-256 GCM. Nel db vanno quindi salvati il secret cifrato (Base64) più il nonce e il tag AES.

Per la validazione dei codici ho usato la libreria Otp.NET per .NET/C#. Per AES ho usato l'implementazione nativa di .NET.

Per la configurazione iniziale del secondo fattore, all'utente vanno forniti il secret e i vari parametri menzionati sopra (o anche no, dato che quelli indicati qui sopra sono di solito il default), oppure un QR code che contiene un URI con questo formato (inizialmente definito da Google ma ora standard de facto):

otpauth://totp/{label}:{accountName}?secret={secret}&issuer={issuer}";

I parametri vanno URL encoded. La prima etichetta viene mostrata nella UI dell'applicazione authenticator di turno (Google Authenticator, Ente Auth, ecc.) assieme al nome dell'account, mentre l'issuer dovrebbe essere a uso interno.

Il codice QR lo genero server-side in SVG con ZXing.QrCode e lo ritorno nella risposta JSON delle API. Probabilmente si può fare anche client-side, ma avevo già generato QR in C# in un altro progetto per cui ho riciclato il codice.

Per confermare l'abilitazione della 2FA l'utente deve inserire un primo codice TOTP generato dall'app authenticator. C'è la possibilità che l'utente abbandoni il processo a metà, per cui ci vuole un cleanup delle configurazioni che non sono ancora state abilitate dopo 24/48 ore.

Andrebbero poi generati e forniti dei codici di backup/recupero. Nel mio caso sono 10 codici di 8 caratteri presi dall'alfabeto ABCDEFGHJKLMNPQRSTUVWXYZ23456789 (es. BVEZ-MMWP). Sono hashati con Argon2id, come le password, e salvati in una tabella del db. Di conseguenza nel momento della verifica del backup code bisogna verificarli tutti uno a uno per trovare se c'è un match, e poi segnare il codice individuato come già usato.

Come si implementa la verifica del secondo fattore in fase di login? Il login restituisce un token di tipo TwoFactorPending e il frontend fa redirect alla pagina di verifica. Questo token temporaneo permette di usare solo l'endpoint di verifica 2FA. Se il codice inserito dall'utente è corretto viene invalidato il token temporaneo (che ha comunque scadenza breve, es. 5 minuti) e ne viene creato uno nuovo "standard".

La disattivazione del secondo fattore deve richiedere la password dell'utente, mentre la rigenerazione dei codici di backup deve richiedere un codice TOTP valido (per verificare che l'utente sia effettivamente ancora in possesso del secondo fattore).

Bonus: il 95% del codice è stato scritto da Claude Code e dall'inizio alla fine ci abbiamo impiegato circa 3 giorni (progettazione, implementazione di 6 endpoint backend, integration test e tutta la UI con SvelteKit).

#291 /
16 gennaio 2026
/
20:25
/ #dev#security

certs.email

Ho pubblicato certs.email: un mini-servizio per essere notificati all'avvicinamento della scadenza dei certificati SSL/TLS dei propri domini.

È gratis e open source e in realtà mi serve prevalentemente per avere un dominio in più che invia email, per poter testare meglio DMARCwise.

#290 /
15 gennaio 2026
/
17:32
/ #dev#security

Segmentation fault in una build TypeScript mi giunge nuova:

EDIT: era colpa di una libreria con binding Rust, il che ha ancora meno senso in realtà.

#264 /
26 dicembre 2025
/
18:05
/ #dev

Nuovo mini progetto work in progress:

#262 /
24 dicembre 2025
/
15:28
/ #dev

Un sito ben fatto, Logging Sucks, per spiegare due concetti di logging nelle applicazioni:

  • Structured logging, cioè spezzare il messaggio testuale nelle sue componenti in modo che siano filtrabili (ogni log line è un oggetto JSON, in pratica).
  • Wide events, cioè avere una singola log line per ciascun evento nel senso più ampio possibile. Ad esempio una richiesta HTTP produce un log che contiene tutte le info di contesto su ciò che è successo durante l'elaborazione, al posto di avere le informazioni sparse tra più righe di log.

Molto d'accordo sul primo (anche se preferisco una forma ibrida con messaggio formattato + variabili scorporate), meno sul secondo. Righe di log separate con un id di correlazione lo troverei più comodo (a meno di logging su scale enormi che finora non mi sono capitate).

#254 /
22 dicembre 2025
/
13:27
/ #dev

Postmortem di Railway, la creazione di un indice PostgreSQL ha tirato giù tutto:

A routine change to this Postgres database introduced a new column with an index to a table containing approximately 1 billion records. This table is critical in our backend API’s infrastructure, used by nearly all API operations.

The index creation did not use Postgres’ CONCURRENTLY option, causing an exclusive lock on the entire table. During the lock period, all queries against the database were queued behind the index operation. [...] Manual intervention attempts to terminate the index creation failed.

Le misure:

We’re going to introduce several changes to prevent errors of this class from happening again:

  • In CI, we will enforce CONCURRENTLY usage for all index creation operations, blocking non-compliant pull requests before merge.
  • PgBouncer connection pool limits will be adjusted to prevent overwhelming the underlying Postgres instance's capacity.
  • Database user connection limits will be configured to guarantee administrative access during incidents, ensuring maintenance operations remain possible under all conditions.
#228 /
14 dicembre 2025
/
10:58
/ #database#dev#cloud

Mistral vibe

Oui oui baguette 😂

#220 /
10 dicembre 2025
/
21:53
/ #ai#dev


Ottimizzazioni di un'altra era nell'app Facebook:

In 2012 we took this wild ride at mobile infra at Facebook when trying to reduce the several-seconds long load time for “Newsfeed”. A few people worked on different approaches. Something we quickly realized was that setting up a connection with TCP and TLS was incredibly slow on mobile networks at the time. The fix was to have just one, keep it alive and multiplex. Shaved a whole second off. But it was still slow. Several people were convince that us sending JSON was the problem, so two different teams started to work on compact binary encoding. After a lot of experimentation what actually worked out best was to send JSON with ordered fields and a compile-time generated parser. Turns out both our iOS and Android app would do something silly like: 1) read all JSON data from server into a buffer, 2) decode that buffer with a generic JSON decoder into lists & dicts, 3) traverse those structures and build the final struct/class tree. Oh and another neat thing we eventually did—when the network connection needed to be setup—was to send an optimistic UDP packet to the server saying “get started fetching data for the following query”; once the real connection was established, TLS handshake completed and user session authenticated, the response was already ready to be sent back.

#198 /
3 dicembre 2025
/
23:39
/ #dev#reti


Review your own git pull requests

When you create a pull request in GitHub, click on the Files changed tab, and scroll through the diff. Anywhere you’ve done something new that’s not already explained by in-code comments, add a comment in the GUI about what you did and why.

  • Often, it’s stuff that’s not important enough for in-code commentary, but is useful for the reviewer to know.
  • Sometimes, it’s stuff that should actually be documented in the code, and this is a good time to go back and add it.
  • Every now and then, you’ll notice a bug in your own code because you’re reading it with fresh eyes, in a different format than your text editor.

It’s a simple behavior change that adds maybe 5 or 10 minutes to the time it takes to setup a PR, but it’s saved me so many headaches, and makes life for whoever reviews your PR a lot easier, too!

(Chris Ferdinandi)

#161 /
17 novembre 2025
/
22:56
/ #dev#git

TIL con un file .git-blame-ignore-revs si possono ignorare determinati commit dall'output "blame" su GitHub (o con git blame --ignore-revs-file .git-blame-ignore-revs), utile quando si fanno refactoring o si modifica la formattazione ma non la funzionalità.

(fonte, esempio)

#151 /
15 novembre 2025
/
16:16
/ #dev#git


Google sta riscrivendo pezzi di Android che prima erano in C++ in Rust, con notevoli risultati dal punto di vista della sicurezza:

With roughly 5 million lines of Rust in the Android platform and one potential memory safety vulnerability found (and fixed pre-release), our estimated vulnerability density for Rust is 0.2 vuln per 1 million lines (MLOC).

Our historical data for C and C++ shows a density of closer to 1,000 memory safety vulnerabilities per MLOC. Our Rust code is currently tracking at a density orders of magnitude lower: a more than 1000x reduction.

#147 /
14 novembre 2025
/
10:02
/ #google#android#dev



Interessante 0github.com:

To try it, replace github.com with 0github.com in any GitHub pull request url. Under the hood, we clone the repo into a VM, spin up gpt-5-codex for every diff, and ask it to output a JSON data structure that we parse into a colored heatmap.

#125 /
1 novembre 2025
/
13:41
/ #dev#ai

TIL le build del toolchain Go sono riproducibili al byte:

They made it so every version of Go starting with 1.21 could be easily reproduced from its source code. Every time you compile a Go toolchain, it produces the exact same Zip archive, byte-for-byte, regardless of the current time, your operating system, your architecture, or other aspects of your environment (such as the directory from which you run the build).

#120 /
30 ottobre 2025
/
11:32
/ #dev

At Netflix, we’d often find that backend services had slow memory leaks, which took a long time to discover and fix because instances rarely lived longer than 48 hours, due to autoscaling policies. If we had chosen to focus on memory leaks instead of autoscaling, Netflix would have been unable to scale to meet demand, and would’ve been a much smaller business.

Matthew Hawthorne, ex ingegnere Netflix.

#108 /
26 ottobre 2025
/
14:21
/ #dev

Pagina 1 di 2 Successiva →