Hai già un job di build che produce un wheel e un repository privato che dovrebbe riceverlo. L'errore è lasciare che un secondo job ricostruisca da un ramo e chiamare il risultato la stessa release. Sposta il file che è stato testato, nominalo in base al digest e tieni la credenziale di caricamento all'interno. La procedura sotto segue un artefatto da un runner CI pubblico a un publisher interno.

Compila dove il codice sorgente è già

Esegui la build nel job che ha già il codice sorgente, la toolchain e la suite di test. Nulla di un repository privato richiede che quel job lo raggiunga. Installa il frontend di build nell'ambiente che il progetto già usa, poi produci entrambi i formati di distribuzione se il progetto li fornisce entrambi.

python -m build --sdist --wheel --outdir dist
python -m twine check dist/*

Mantieni la directory di output piccola e usa e getta. Le uniche cose che vale la pena portare avanti sono i file che il job successivo pubblicherà, più i loro hash. Tutto il resto, compresi ambienti virtuali e cache, può essere ricostruito dalla revisione registrata del codice sorgente. Un artefatto snello è anche più facile da rivedere, perché ogni file al suo interno è un file che qualcuno può ispezionare.

Registra che cosa li ha prodotti: il nome del pacchetto e la versione dai nomi dei file, la revisione del codice sorgente e l'esecuzione del workflow che li ha creati. Una stringa di versione da sola non identifica un file, perché la stessa versione può essere compilata due volte da commit diversi. Scrivi la revisione accanto ai nomi dei file nella descrizione dell'artefatto e tratta quel registro come parte della consegna.

Sposta byte, non istruzioni per ricostruire

Una seconda build è un secondo prodotto. Timestamp, dipendenze incluse e versioni degli strumenti possono tutti cambiare i byte, quindi una ricostruzione richiede prove di test proprie e una revisione propria. Promuovi invece i file già revisionati.

Carica i file di distribuzione nello store di artefatti fornito dalla tua piattaforma CI e dai al job interno un riferimento a quell'artefatto specifico, non a un nome di ramo.

sha256sum dist/*.whl dist/*.tar.gz
# keep the digests beside the run id in the artifact description

Se la tua piattaforma supporta la provenienza firmata, chiedile di attestare l'artefatto e in seguito di verificare il repository, il workflow e la revisione del codice sorgente attesi. La documentazione sulle attestazioni di GitHub descrive affermazioni di quella forma. Una firma valida è prova di origine, non una scansione delle vulnerabilità e non una decisione di autorizzazione.

Verifica all'interno prima di caricare

Il job interno inizia controllando che il file ricevuto sia il file che è stato approvato. Confronta i digest con il registro del job di build, non con un valore ricalcolato da ciò che è arrivato.

sha256sum -c digests.txt
python -m twine check dist/*

Poi leggi i metadati. Il nome del pacchetto, la versione e le dipendenze dichiarate dovrebbero corrispondere alla revisione che hai approvato. Un wheel il cui nome sembra corretto ma i cui pin delle dipendenze sono cambiati è un altro pacchetto con la stessa etichetta. Se i metadati si sono spostati, tratta l'artefatto come non approvato e scopri quale build lo ha prodotto.

Se i digest non corrispondono, fermati. Non caricare e non riparare il file ricostruendolo sul posto; questo cancella la prova che qualcosa è cambiato in transito. Una discrepanza significa che lo store di artefatti, il passaggio di download o il registro sono sbagliati, e ciascuno di essi merita una spiegazione prima che una release venga pubblicata.

Gestisci la risposta di versione duplicata

I repository privati di solito rifiutano di sovrascrivere una versione esistente, e quel rifiuto è una funzionalità. Quando un caricamento fallisce perché la versione esiste, ispeziona il registro del repository per quella versione e confronta i file che contiene con i digest che intendevi pubblicare.

Una versione esistente può significare che un caricamento precedente è riuscito e la risposta è andata persa, oppure che qualcuno ha pubblicato contenuti diversi sotto lo stesso numero.

Non eliminare la versione e non inventare un nuovo numero per aggirare l'errore. Decidi con il responsabile della release se il contenuto memorizzato è accettabile, poi registra l'esito. Se il contenuto è diverso, hai un problema di versionamento, non un problema di pipeline.

Tieni la credenziale di caricamento su un solo lato

Solo il publisher interno ha bisogno delle credenziali del repository, e solo per la durata del caricamento. Limita il token al repository di destinazione e alle operazioni di caricamento, conservalo nel vault dei segreti del sistema interno e tienilo completamente fuori dal job di build. Se il job di build può pubblicare, allora chiunque possa modificare la build può pubblicare.

Limita anche quali workflow interni possono avviare il publisher. Un trigger manuale con approvazione obbligatoria è un valore predefinito ragionevole per le release; un push verso qualsiasi ramo non lo è.

La release finita dovrebbe lasciare tre cose dietro di sé: i file di distribuzione, i loro digest con la revisione del codice sorgente e un registro del repository che mostra la stessa versione.

Articoli correlati