Salta al contenuto principale

104 - ML-Ops: usare bene l'open source, dalle licenze al contributo

Valutare una dipendenza, leggere una licenza (MIT, Apache 2.0, GPL), controllare licenze e vulnerabilità del proprio ambiente e fare una prima contribuzione.

Cosa ne pensi di questo articolo?

104 - ML-Ops: usare bene l'open source, dalle licenze al contributo
Machine Learning Engineerfedericocalo.dev

In Breve

Valutare una dipendenza, leggere una licenza (MIT, Apache 2.0, GPL), controllare licenze e vulnerabilità del proprio ambiente e fare una prima contribuzione.

Open source: usarlo bene, capirne le licenze, contribuire

Quasi tutto lo stack di un progetto di machine learning è open source: Python, NumPy, scikit-learn, pandas, pytest, MLflow, FastAPI, Git stesso. Usarlo non costa nulla in denaro, ma ha un costo diverso: ogni libreria è una promessa che qualcun altro continuerà a mantenerla, con una licenza che dice cosa puoi fare con essa. Questa lezione ti insegna tre cose pratiche: scegliere una dipendenza senza farti male, leggere una licenza senza essere avvocato, e fare una prima contribuzione utile a un progetto che usi già. Parte dalla lezione su GitHub e le pull request, di cui riusa i comandi.

Le parole dell'open source

Il copyright (diritto d'autore) assegna per impostazione predefinita i diritti a chi scrive un'opera, e nessun altro può copiarla o modificarla senza permesso: il codice che trovi in rete senza licenza è in questa condizione, puoi leggerlo ma non riusarlo. La licenza è il permesso scritto con cui l'autore concede certi usi a chiunque, a certe condizioni, come il cartello "ingresso libero, vietato fotografare". Le licenze si dividono in due famiglie: le permissive (MIT, BSD, Apache) chiedono poco, cioè di tenere l'avviso di copyright; le copyleft (GPL, AGPL) chiedono che il lavoro derivato resti libero alle stesse condizioni, una specie di ereditarietà della licenza. È la differenza tra "prendi pure la ricetta" e "prendi la ricetta, ma se la pubblichi con modifiche devi pubblicare anche le tue".

Una dipendenza diretta l'hai scelta tu; le transitive sono quelle di cui hanno bisogno le tue dipendenze, e a loro volta le loro, come la filiera dietro la farina che ordini (il mulino, il grano, il trasporto). Il manutentore (maintainer) è chi cura un progetto: risponde alle segnalazioni, rivede le modifiche, pubblica le versioni, e spesso è un volontario. Una issue è una segnalazione (errore, richiesta, domanda) aperta sulla pagina del progetto. Una vulnerabilità è un difetto sfruttabile per fare danni e un CVE è il numero di catalogo pubblico con cui viene registrata, così tutti parlano dello stesso difetto. SPDX è l'elenco standard di sigle per le licenze (MIT, Apache-2.0, BSD-3-Clause, GPL-3.0-only), che evita ambiguità come "MIT-like"; l'elenco è su spdx.org/licenses.

L'analogia: costruire una casa con materiali comuni

Quando costruisci casa non produci i mattoni, né l'acciaio, né le tubature. Li compri da fornitori, e ti fidi se hanno certificazioni, storia e assistenza. Un mattone senza marchio può reggere tre anni o cinque minuti. Una libreria open source è un mattone: la domanda non è "funziona?" (sul tuo portatile quasi tutte funzionano) ma "regge nel tempo, e posso usarla per quello che voglio?".

Cosa significa "open source"

Un software è open source quando il suo codice è leggibile e una licenza ti concede, a certe condizioni, di usarlo, modificarlo e ridistribuirlo. Il punto delicato sta nelle condizioni: non significa "senza regole". Significa che le regole sono scritte, pubbliche e identiche per tutti. L'elenco delle licenze approvate è tenuto dalla Open Source Initiative.

Leggere una licenza: le famiglie che incontrerai

LicenzaCosa ti chiedeEsempi nel nostro mondo
MIT, BSDConserva l'avviso di copyright e il testo della licenza. Per il resto, libertà quasi totale, anche in prodotti commerciali chiusi.pytest, FastAPI (MIT); scikit-learn, pandas, NumPy (BSD)
Apache 2.0Come MIT, più una concessione esplicita dei brevetti e l'obbligo di segnalare le modifiche ai file.MLflow
GPL (copyleft)Se distribuisci un software che incorpora codice GPL, devi distribuire anche il tuo sotto GPL. Vale per la distribuzione.Alcuni strumenti di sistema
AGPLCome GPL, ma l'obbligo scatta anche se offri il software come servizio in rete, senza consegnarlo a nessuno.Alcuni database e strumenti server

La colonna degli esempi per le prime due righe l'ho controllata sui metadati dei pacchetti installati il 2026-11-12: pytest e FastAPI dichiarano MIT, scikit-learn e pandas BSD-3-Clause, MLflow la classificazione "Apache Software License"; NumPy dichiara un'espressione composta (BSD-3-Clause AND 0BSD AND MIT AND Zlib AND CC0-1.0), perché include componenti con licenze diverse. Per le righe GPL e AGPL gli esempi sono generici, non verificati. Per le prime due righe la regola pratica è: puoi usarle quasi ovunque, purché conservi gli avvisi. Per GPL e AGPL fermati e leggi, soprattutto se il tuo codice sarà distribuito o esposto come servizio a terzi. Questa è una guida, non una consulenza legale: se il progetto è commerciale e la licenza è dubbia, la domanda va a un legale. choosealicense.com mette a confronto le licenze in modo leggibile.

Le licenze dei modelli sono un'altra faccenda

Il codice e i pesi di un modello hanno spesso licenze diverse, e molte licenze di modelli non sono licenze open source nel senso classico: possono limitare gli usi (per esempio sopra certe dimensioni di utenza o per certi scopi). La regola vale per qualunque modello: prima di costruirci sopra, apri la scheda del modello, leggi la licenza e le condizioni d'uso e verifica che coprano il tuo caso. Lo stesso per i dataset: "è pubblico" non significa "è riutilizzabile".

Scegliere una dipendenza: sette domande

Aggiungere una dipendenza è un impegno. Prima di farlo, apri la pagina del progetto e rispondi:

  1. Licenza: è compatibile con l'uso che ne farò?
  2. Manutenzione: quando è uscita l'ultima versione? C'è attività recente?
  3. Persone: ha più di un manutentore, o dipende da una persona sola?
  4. Problemi aperti: le segnalazioni ricevono risposta, anche negative?
  5. Peso: quante dipendenze si porta dietro? Ogni dipendenza transitiva è superficie di rischio.
  6. Sicurezza: ci sono vulnerabilità note, e vengono corrette in fretta?
  7. Alternativa: la libreria standard di Python basta? Dieci righe tue possono costare meno di un pacchetto.

Le sette domande non hanno un ordine di importanza fisso: la licenza è un cancello (se è incompatibile il resto non conta), mentre le altre si pesano insieme. Una libreria con licenza giusta ma un solo manutentore e nessun commit da due anni può restare una scelta ragionevole per una funzione di contorno e pessima per il cuore del progetto.

Controllare le licenze nel proprio ambiente

Quanto sopra va verificato su ciò che hai davvero installato, comprese le dipendenze transitive. Python espone i metadati dei pacchetti installati. Questo script, eseguito il 2026-11-12 su un ambiente creato con UV (Python 3.12.13; uv add scikit-learn pandas mlflow pytest senza fissare versioni: scikit-learn 1.9.1, pandas 3.1.1, MLflow 3.18.0, pytest 9.2.0, NumPy 2.5.4), li elenca. L'ordinamento è per numero e poi per nome, così l'uscita è identica a ogni esecuzione.

from importlib.metadata import distributions
from collections import Counter

def licenza(meta):
    # I pacchetti dichiarano la licenza in tre modi diversi: bisogna guardarli tutti.
    expr = meta.get("License-Expression")
    if expr:
        return expr
    for c in meta.get_all("Classifier") or []:
        if c.startswith("License ::"):
            return c.split("::")[-1].strip()
    return (meta.get("License") or "").strip()[:40] or "NON DICHIARATA"

conteggio = Counter(licenza(d.metadata) for d in distributions())
for lic, n in sorted(conteggio.items(), key=lambda kv: (-kv[1], kv[0])):
    print(f"{n:3d}  {lic}")
print("totale", sum(conteggio.values()))

# Output (le prime righe e la fine; 19 voci in tutto):
#  23  MIT
#  16  BSD-3-Clause
#  13  Apache-2.0
#  11  BSD License
#   8  MIT License
#   7  Apache Software License
#   ...
#   2  NON DICHIARATA
#   ...
# totale 94

Le 94 distribuzioni installate nascono da quattro dipendenze dirette (uv tree --depth 1 ne elenca esattamente quattro): quella è la superficie che stai accettando. Le righe mostrano anche perché serve la funzione: la stessa licenza compare con scritture diverse (MIT, MIT License; BSD-3-Clause, BSD License), e un controllo che confronta stringhe le tratterebbe come licenze distinte. La trappola sta nel commento: una versione dello script che leggeva solo il campo moderno License-Expression e le classificazioni ha segnalato 12 pacchetti su 94 "senza licenza". Dieci avevano la licenza scritta nel campo storico License (per esempio MIT, Apache-2.0 o BSD). I pacchetti realmente senza licenza dichiarata erano due: il progetto stesso (churn) e huey. Uno strumento che legge un solo campo produce falsi allarmi, e un falso allarme ripetuto insegna a ignorare gli allarmi. Verifica sempre che il tuo controllo non abbia un punto cieco prima di fidarti dell'esito. Il modulo che espone i metadati è descritto in importlib.metadata.

La prima contribuzione: piccola, utile, accettabile

Contribuire non significa riscrivere un modulo. Il punto d'ingresso migliore è una correzione piccola e verificabile in un progetto che usi già, perché ne capisci il problema: un refuso o un esempio sbagliato nella documentazione, un messaggio di errore poco chiaro che ti ha fatto perdere mezz'ora, un test mancante per un caso che hai trovato. Anche una segnalazione ben fatta (issue) è un contributo, con versione, passi per riprodurre, comportamento atteso e ottenuto. La guida Open Source Guides elenca le stesse forme di contributo.

La procedura, coi comandi della lezione precedente, ha un ordine che conviene rispettare:

  1. Leggi CONTRIBUTING.md e il codice di condotta del progetto: spiegano come vogliono ricevere i contributi.
  2. Cerca se esiste già una issue o una PR sullo stesso tema.
  3. Fai fork, crea un branch, cambia una cosa sola, aggiungi o aggiorna il test.
  4. Apri la PR spiegando il problema, la correzione e come l'hai verificata.
  5. Accetta la revisione con pazienza: i manutentori sono spesso volontari, e una richiesta di modifica non è un rifiuto.

I primi due passi evitano il lavoro sprecato: una PR che ignora le regole del progetto o duplica una già aperta viene rimandata indietro senza essere letta. Il terzo è la regola del cambiamento minimo, che rende la revisione possibile a un volontario con mezz'ora a disposizione.

Trappole e trade-off

La prima trappola è credere che "è su GitHub, quindi è libero": un repository senza file di licenza non ti concede alcun diritto di riuso. La seconda riguarda le versioni fissate: proteggono da cambiamenti improvvisi (come vedi in UV, ambienti e dipendenze) ma ti fanno perdere le correzioni di sicurezza se non aggiorni mai, quindi serve una routine di aggiornamento. Copiare codice da una risposta in rete non lo libera dai vincoli di licenza che quel codice ha. E più dipendenze accelerano oggi e rallentano domani: ogni pacchetto è un fornitore da sorvegliare.

Quanto sta in piedi la dipendenza? Guardarla con comandi

Le sette domande hanno risposte che si leggono, non si indovinano. Per la manutenzione la pagina del progetto su PyPI (l'indice dei pacchetti Python) mostra la data dell'ultima versione, e da un clone git log -1 --format=%cd stampa la data dell'ultimo commit: un progetto fermo da due anni non è automaticamente morto (può essere "finito"), ma va saputo. Per il peso, uv tree stampa l'albero di tutte le dipendenze, dirette e transitive. Per la sicurezza esistono strumenti che confrontano le versioni che hai con i database pubblici di vulnerabilità; ho eseguito pip-audit 2.10.1 (progetto sostenuto dalla Python Packaging Authority) sul lock esportato dal progetto di prova:

uv export --no-dev --format requirements-txt --no-hashes -o requirements.txt
uvx pip-audit -r requirements.txt --no-deps --disable-pip
# No known vulnerabilities found
# Name Skip Reason
# ---- -----------------------------------------------------
# -e   - could not deduce package version from URL requirement

La prima riga trasforma il lockfile in un elenco "pacchetto==versione" (uv export); uvx esegue lo strumento in un ambiente temporaneo senza installarlo nel progetto; --no-deps dice di non risolvere altre dipendenze (l'elenco è già completo e bloccato) e --disable-pip di non usare pip per farlo. Lo strumento stampa anche due avvisi sul fatto che sarebbe meglio avere gli hash, perché qui li ho tolti con --no-hashes. Un'unica voce è stata saltata, il progetto stesso (-e), che non ha una versione pubblicata da confrontare. Il significato è ristretto: "nessuna vulnerabilità nota a quella data". Un esito pulito oggi non lo è domani, quindi il controllo va rieseguito periodicamente.

La licenza del tuo progetto

Anche il tuo repository, se lo rendi pubblico, ha bisogno di una licenza: senza, nessuno può legalmente riusarlo, per quanto sia online. Per codice che vuoi far riusare liberamente, la scelta più comune è MIT o Apache-2.0; se vuoi che chi lo migliora debba restituire i miglioramenti, GPL. Il procedimento pratico è sempre lo stesso: scegli la licenza (choosealicense.com aiuta con domande semplici), metti il testo in un file LICENSE alla radice e dichiarala nei metadati, in pyproject.toml con license = "MIT" usando l'identificatore SPDX, così gli strumenti, compreso lo script di prima, la leggono senza ambiguità.

Licenze di modelli e di dati: un controllo in più

Ciò che vale per il codice vale, in più, per due oggetti tipici del machine learning. I pesi del modello sono spesso pubblicati con una licenza propria, scritta apposta per i modelli, che può limitare gli usi (per esempio vietare certi scopi, o imporre condizioni oltre una certa dimensione d'uso); non è detto che sia "open source" nel senso della definizione ufficiale, quindi controlla la scheda del modello. I dati hanno licenze a loro volta: le famiglie Creative Commons sono le più diffuse, e CC BY chiede l'attribuzione, CC BY-NC vieta l'uso commerciale, CC0 rinuncia ai diritti. In più, i dati personali hanno il vincolo aggiuntivo della normativa sulla privacy, indipendente dalla licenza: "scaricabile" non vuol dire "riusabile per qualunque scopo".

Il modo più sicuro per un progetto ML è un piccolo file (anche solo un README o una tabella) che elenca, per ogni modello e dataset, nome, versione, licenza e fonte. Costa dieci minuti e risponde alla prima domanda di qualunque cliente o revisore.

Una prima contribuzione, passo per passo

Supponi di aver trovato un errore nella documentazione di una libreria che usi: un esempio non funziona. Ecco il percorso completo con i comandi della lezione su GitHub (nomi di repository di fantasia). I blocchi che seguono sono uno schema da adattare e non sono stati eseguiti, perché richiedono un account GitHub e un repository reale.

gh repo fork organizzazione/libreria --clone      # fork su GitHub + clone locale
cd libreria
git remote -v                                      # origin = il tuo fork, upstream = l'originale
git switch -c docs/correggi-esempio-quickstart

gh repo fork ... --clone (GitHub CLI) crea la tua copia sull'account e la clona, impostando anche upstream. Poi un branch con un nome che dice cosa fai.

# ... correggi il file della documentazione ...
git diff                                           # rileggi ciò che hai cambiato
git commit -am "docs: corregge l'esempio del quickstart"
git push -u origin docs/correggi-esempio-quickstart
gh pr create --fill

Il diff prima del commit è la tua revisione personale. gh pr create --fill apre la pull request riempiendo titolo e descrizione dal commit; poi modifica la descrizione secondo il modello della lezione su GitHub: cosa, perché, come l'hai verificato. Nel caso di un esempio sbagliato, la verifica è "ho eseguito l'esempio corretto e produce l'output che la documentazione dichiara".

Cosa aspettarsi dopo: un manutentore può rispondere in ore o in settimane; può chiederti di cambiare qualcosa (rispondi con nuovi commit sullo stesso branch); può chiudere la PR spiegando che la direzione non coincide con il progetto. Nulla di personale: in tutti e tre i casi hai imparato qualcosa e, nel primo, hai migliorato uno strumento che usi ogni giorno.

Segnalare bene un errore (issue)

Anche una segnalazione ben fatta è un contributo, e spesso quello più prezioso. Una buona issue ha sempre le stesse parti:

Titolo: search_runs ignora order_by quando il nome della metrica contiene un punto

Versioni: mlflow 3.18.0, python 3.12.x, backend sqlite
Passi per riprodurre:
  1. ...
  2. ...
Atteso: le run ordinate per auc decrescente
Ottenuto: ordine di inserimento
Note: ho provato con ... e il comportamento resta uguale

Il testo è puramente illustrativo del formato: non descrive un errore reale di MLflow. Le versioni e un procedimento minimo e ripetibile sono ciò che trasforma "non funziona" in qualcosa su cui un manutentore può lavorare.

Il perché: non puoi costruire tutto, e ciò che non costruisci è un rischio che accetti

Un progetto di machine learning di dimensioni modeste importa poche librerie dirette e, come visto con il conteggio sopra, quasi cento pacchetti in tutto. Nessuno li ha scritti da solo e nessuno potrebbe: il valore del software libero è proprio che il lavoro di moltissime persone sia disponibile gratis. Ma "gratis" non significa "senza costi": significa che i costi si sono spostati. Non paghi più una licenza; paghi in attenzione. Devi sapere che cosa stai importando, a quali condizioni, e cosa farai quando una dipendenza cambia, smette di essere mantenuta o ha un difetto.

Il termine che descrive l'insieme di questi rischi è catena di fornitura del software (software supply chain). La metafora è quella di una catena alimentare industriale: il tuo prodotto finale dipende da fornitori che dipendono da altri fornitori, e un problema a monte arriva a valle senza che tu lo abbia visto. I rischi tipici sono di quattro famiglie, e vale la pena distinguerle perché hanno difese diverse. L'abbandono è il tempo che passa senza attacchi: il progetto non viene più mantenuto, le vulnerabilità non si correggono e la libreria smette di funzionare con le versioni nuove di Python; la difesa è scegliere con le sette domande e sapere quanto è difficile sostituirla.

Il difetto è un errore di sicurezza o di logica, e le difese sono gli strumenti di audit (pip-audit), gli aggiornamenti regolari e i test che catturano i cambi di comportamento. Il cambio di condizioni è la licenza che cambia o il progetto che passa a un modello commerciale: si legge la licenza della versione che usi e si sa in anticipo cosa si farebbe. La manomissione è qualcuno che pubblica un pacchetto malevolo, a volte con un nome quasi identico a uno noto (typosquatting, la stessa idea della truffa con un sito dall'indirizzo simile a quello della banca), oppure compromette un pacchetto legittimo; contro di essa i lockfile con gli hash impediscono la sostituzione silenziosa di un file già bloccato, e serve installare solo ciò che hai deciso e controllare l'ortografia dei nomi quando aggiungi una dipendenza.

Non serve la paranoia: serve sapere che ogni uv add è una decisione e non un gesto automatico.

Adottare, avvolgere, evitare: tre risposte a una dipendenza

Davanti a una libreria candidata non c'è solo "uso o non uso". Ci sono tre atteggiamenti, in ordine crescente di cautela.

Adottare. La libreria è diffusa, mantenuta, ha una licenza compatibile e il suo ruolo è centrale (pensa a NumPy o a scikit-learn). La si usa direttamente, senza giri, perché l'astrazione extra costerebbe più del rischio. Il costo di cambiarla sarebbe comunque enorme (è tutto il progetto), quindi la si sceglie con cura una volta e poi la si tiene aggiornata.

Avvolgere. La libreria serve ma è meno consolidata, o è un dettaglio che potresti voler cambiare (un client per un servizio esterno, un parser per un formato di nicchia). Si scrive un piccolo strato tuo (una funzione o una classe) che la usa, e il resto del codice parla solo con quello strato. Se un giorno devi sostituirla, cambi un file. Il costo è una funzione in più da mantenere e testare, che vale la pena pagare solo dove la sostituzione è davvero plausibile.

Evitare. Se per una funzione di dieci righe aggiungi una dipendenza con decine di pacchetti transitivi, hai fatto un cattivo affare. A volte la libreria standard di Python basta, a volte conviene scrivere la funzione. La regola pratica: più la dipendenza è piccola rispetto a ciò che porta con sé, meno la vuoi.

Un esempio di politica a livello di progetto: cosa questo sito sceglie di non usare

Le decisioni sulle dipendenze non riguardano solo le librerie, ma anche i servizi. Nelle regole del progetto (il file CLAUDE.md alla radice del repository) c'è un elenco esplicito di servizi esterni rifiutati: l'API di GitHub, S3, Plausible, Sentry, con l'indicazione di usare alternative autogestite o gratuite (riga verificata il 2026-11-12). Indipendentemente da cosa pensi della scelta, è un buon modello di metodo: la decisione è scritta, motivata in una riga, e vale per tutti i contributori futuri. Chi arriva dopo non deve indovinare, e un'eventuale deroga deve passare dalla discussione invece di accadere per distrazione.

Il progetto fa anche una distinzione utile: nominare un prodotto come argomento (un articolo che confronta strumenti, un tool che dichiara compatibilità con vari assistenti) è lecito; dichiararlo come proprio fornitore quando non lo è sarebbe falso. È la stessa distinzione che, in un progetto ML, separa "il paper con cui ci confrontiamo" da "il componente che usiamo": le dipendenze reali e quelle citate vanno tenute distinte in ogni documento, scheda del modello compresa.

Compatibilità tra licenze: quando combini codice di fonti diverse

Il problema nasce quando il tuo progetto combina componenti con licenze diverse. Due regole di base, da leggere come orientamento e non come parere legale.

Una licenza permissiva (MIT, BSD, Apache 2.0) può essere inclusa in un progetto con licenza qualsiasi, anche proprietaria o copyleft, purché si rispettino i suoi obblighi (conservare l'avviso). È il motivo per cui le librerie fondamentali dell'ecosistema ML sono permissive: si possono usare ovunque.

Una licenza copyleft forte (GPL) impone che il lavoro derivato, se distribuito, sia a sua volta rilasciato sotto GPL. Quindi incorporare codice GPL in un prodotto distribuito proprietario è un problema. La parola chiave è "distribuito": se usi un programma GPL internamente, senza darne copie a nessuno, in genere non scatta l'obbligo. L'AGPL chiude proprio questa scappatoia: considera "distribuzione" anche l'offerta del software come servizio in rete. Per un servizio ML esposto in rete, che incorpora una libreria AGPL, l'obbligo può scattare. È il caso in cui vale la pena fermarsi e chiedere.

Esistono poi progetti con licenza "source-available" (il codice è leggibile ma le condizioni non sono quelle della definizione di open source: per esempio, vietano l'uso come servizio concorrente). Sono legittimi, ma non sono open source nel senso della lezione, e vanno letti con la stessa attenzione dei modelli con licenza propria. La sigla SPDX nei metadati o nel file LICENSE è il primo posto dove guardare.

Contribuire: il certificato di origine e le regole della casa

Molti progetti chiedono, insieme alla tua modifica, una dichiarazione che hai il diritto di contribuirla. Due forme comuni. Il CLA (contributor license agreement) è un accordo formale firmato una volta. Il DCO (developer certificate of origin, testo su developercertificate.org) è più leggero: una riga Signed-off-by: Nome <email> in ogni commit, con cui dichiari di averne i diritti. Git la aggiunge da solo con l'opzione -s:

git commit -s -m "docs: prova sign-off"
git log -1 --format=%B
# docs: prova sign-off
#
# Signed-off-by: Test <a@b.c>

Il -s (--signoff) ha aggiunto in fondo al messaggio la riga con il nome e l'email configurati in Git (come si imposta, lo vedi in Git, la macchina del tempo del tuo progetto); l'ho eseguito in un repository di prova con Git 2.53. Leggi sempre le regole del progetto prima di contribuire: i file CONTRIBUTING.md e CODE_OF_CONDUCT.md dicono come vogliono i contributi, in che lingua, con quale stile e con quali test, e una PR che li ignora viene rimandata indietro senza essere letta.

Aprire un tuo progetto: il minimo perché sia davvero riutilizzabile

Se un giorno pubblichi un tuo progetto (un modello, uno strumento, un dataset), alcuni file fanno la differenza tra "una cartella pubblica" e "un progetto che gli altri possono usare". Il repository di questo sito ha un modello per i propri progetti pubblici, nella cartella scripts/templates/oss-repo/: un README da compilare, un CITATION.template.cff (il file che permette di citare correttamente il software o il dataset), uno script di controllo dei segreti prima di pubblicare (secret-scan.sh) e una lista di controllo (la cartella contiene questi file, verificato con ls). Gli elementi essenziali, in ordine di importanza:

  1. README: cosa fa il progetto in due frasi, come installarlo ed eseguire un esempio in tre comandi, come contribuire. Chi non capisce il progetto in trenta secondi non lo prova.
  2. LICENSE: senza, il progetto non è riutilizzabile.
  3. Un modo per riprodurre: pyproject.toml e uv.lock, così "installa ed esegui" funziona.
  4. Test (pytest) e, se hai una CI, un segno verde in cima al README.
  5. Nessun segreto nella storia: prima di pubblicare, scansiona tutta la storia di Git, non solo i file attuali, perché un segreto cancellato resta nei vecchi commit.
  6. Una scheda per ogni modello o dataset (model card, dataset card): da dove vengono i dati, con quale licenza, quali limiti e usi sconsigliati.

Queste voci sono, in fondo, le stesse domande di questa lezione viste dal lato di chi pubblica: rendi facile per un altro rispondere alle sette domande sul tuo progetto. L'ordine conta: senza README nessuno arriva al resto, senza LICENSE nessuno può usare ciò che trova.

Restituire qualcosa: oltre il codice

Non tutti i contributi sono codice, e spesso i più utili non lo sono: documentazione corretta, esempi che funzionano, traduzioni, risposte a chi ha gli stessi problemi, segnalazioni riproducibili, e il semplice ringraziamento a un manutentore. Se la tua azienda o il tuo progetto dipende da una libreria, sostenerla economicamente (molti progetti hanno modi per farlo) o dedicarle ore pagate è il modo più diretto di ridurre il rischio di abbandono, il primo della lista. Un sistema che dipende da lavoro volontario senza dare nulla in cambio sta, in fondo, sfruttando un'assicurazione che qualcun altro paga.

Prova tu: quattro esercizi guidati

Esercizio 1: audit delle licenze del tuo ambiente

In un progetto UV con almeno qualche dipendenza (per esempio uv add scikit-learn pandas), salva lo script delle licenze in licenze.py ed eseguilo con uv run python licenze.py. Confrontalo con il numero di pacchetti: uv run python -c "from importlib.metadata import distributions; print(len(list(distributions())))". Cosa verificare: nel mio progetto, 94 pacchetti (il tuo numero dipenderà dalle versioni risolte quel giorno), con licenze quasi tutte permissive (MIT, BSD, Apache) e una sola Mozilla Public License 2.0. Cerca quelle che il tuo script segnala "NON DICHIARATA" e controlla, aprendo la pagina del pacchetto su PyPI, se la licenza esiste davvero. Cosa impari: che i metadati sono eterogenei e che uno strumento di controllo va provato sui casi limite.

Esercizio 2: l'audit di sicurezza

Esporta il lock e controllalo: uv export --no-dev --format requirements-txt --no-hashes -o requirements.txt, poi uvx pip-audit -r requirements.txt --no-deps --disable-pip. Dovresti vedere un riepilogo che dice se esistono vulnerabilità note per le versioni bloccate (nella mia prova, No known vulnerabilities found). Ripeti dopo qualche settimana, o su un lock vecchio, e confronta. Cosa impari: che "pulito oggi" non è "pulito domani".

Esercizio 3: valutare una dipendenza con le sette domande

Scegli una libreria che usi e che non sia una colonna portante (non NumPy: una libreria "di contorno"). Compila una tabella con le sette domande della lezione usando la sua pagina su PyPI e il suo repository. Per il "peso" usa uv tree --package nome-della-libreria o confronta uv tree prima e dopo l'aggiunta. Cosa impari: a decidere con dati invece che per abitudine, e a scoprire che alcune dipendenze costano molto più di quanto sembri. Annota la decisione (adotto, avvolgo, evito) con una riga di motivazione.

Esercizio 4: la firma di origine e una prima segnalazione

In un repository di prova, fai un commit con git commit -s e leggi il messaggio con git log -1 --format=%B: dovresti vedere in fondo la riga Signed-off-by: Nome <email> con i dati configurati in Git. Poi cerca, in una libreria che usi, un'issue aperta che ti riguarda o una frase poco chiara nella documentazione, e scrivi (anche solo in un file di testo) la segnalazione nel formato della lezione: titolo, versioni, passi, atteso e ottenuto. Cosa impari: che il lavoro di contribuzione comincia da una descrizione precisa, e che quasi sempre ciò che sembra "un mio problema" è un'informazione utile al manutentore.

Gli esercizi 1 e 2 si fanno in pochi minuti e hanno un valore pratico immediato per qualunque tuo progetto: sapere cosa c'è dentro il tuo ambiente è il primo passo per fidarsene.

Cosa sai fare adesso

Sai dire che open source significa regole scritte, non assenza di regole, e distinguere le licenze permissive (MIT, BSD, Apache 2.0) da quelle che impongono obblighi sul tuo codice (GPL, AGPL). Sai che modelli e dataset hanno licenze proprie da leggere prima di costruirci sopra, e che prima di aggiungere una dipendenza si pongono sette domande. Sai controllare le licenze e le vulnerabilità del tuo ambiente, e sai che il controllo va provato sui casi limite, perché il primo script di licenze di questa lezione aveva un punto cieco. Sai infine come si comincia a contribuire: con una correzione piccola e verificata. Prossima lezione: UV, ambienti e dipendenze che si ripetono uguali.

Nella stessa serie trovi anche ML-Ops: Dockerfile multi-stage per un servizio ML, utente non root e healthcheck e ML-Ops: registry di container, tag, digest e versioni che non cambiano sotto i piedi.

Fonti

Lo script delle licenze è stato eseguito due volte (Python 3.12.13, UV 0.12.21, ambiente creato il 2026-11-12) con uscita identica; pip-audit e git commit -s sono stati eseguiti una volta con le uscite riportate. Non sono stati eseguiti i comandi gh e il fork, che richiedono un account GitHub. Il numero 94 e le versioni cambiano a ogni risoluzione delle dipendenze. La riga sui servizi rifiutati viene dal file CLAUDE.md del repository del sito (grep del 2026-11-12). Il titolo di issue di MLflow nel modello è inventato.

Commenti

Caricamento commenti...

Accedi per commentare

Discuti questo articolo nella community

Unisciti al gruppo Telegram per discutere con altri sviluppatori, fare domande e condividere le tue esperienze.

Ti è piaciuto questo articolo?

Esplora altri contenuti sul blog o scopri i miei progetti