CI/CD pratique pour les applications WinForms / WPF — Automatiser du build à la signature et à la distribution avec GitHub Actions

· · CI/CD, GitHub Actions, WinForms, WPF, C#, .NET, Signature de code, MSIX, Déploiement, Développement Windows, Tableau de décision

« La release, on ne peut la builder que sur le PC de telle personne. » — c’est une phrase que nous entendons vraiment très souvent dans les consultations sur les applications métier WinForms ou WPF. On fait un build Release dans Visual Studio en local, on compresse en zip, et on le dépose dans un dossier partagé. Ça fonctionne, mais personne ne peut dire si un correctif pourra être publié le jour où ce développeur sera absent.

Les informations sur le CI/CD pour les applications web abondent, mais dès qu’on aborde les applications de bureau, elles se raréfient soudainement. Il y a une différence fondamentale — « la cible de déploiement est le PC du client, pas un serveur » — qui fait qu’on ne peut effectivement pas copier tel quel un article destiné au web. Cela dit, jusqu’à l’automatisation du build et des tests, une application de bureau demande presque aussi peu d’effort qu’une application web. Le mur se situe plus loin, du côté de la signature et de la distribution, où la solution pragmatique diffère selon le format de distribution.

Sur ce blog, nous avons déjà expliqué comment choisir un format de distribution dans « Tableau de décision pour les méthodes de distribution des applications Windows », et comment aborder la signature dans « SmartScreen and Code Signing ». En prenant ces deux articles comme base, celui-ci détaille, d’un point de vue pratique, jusqu’où on peut automatiser le build, les tests, la numérotation de version, la signature et la création des livrables d’une application WinForms / WPF avec GitHub Actions.

1. L’essentiel d’abord

  • Le plus grand risque, c’est l’état où « ça ne peut se builder que sur le PC d’un développeur ». Le premier objectif du CI/CD n’est pas l’automatisation complète de la distribution, mais la reproductibilité du build sans dépendre du PC de qui que ce soit.
  • Une configuration minimale — juste l’automatisation du build et des tests — a déjà une grande valeur à elle seule. On peut la construire dans un seul fichier YAML avec windows-latest + actions/checkout + actions/setup-dotnet + dotnet build / test + actions/upload-artifact.12
  • WinForms / WPF supposent un runner Windows. Comme elles ciblent un TFM exclusivement Windows tel que net8.0-windows,3 exécuter les tests jusqu’au bout en CI nécessite un environnement Windows.
  • La numérotation de version pilotée par tag est la solution pragmatique. On pousse un tag v1.2.3 pour déclencher le build de release, et on injecte la valeur du tag dans la propriété Version de MSBuild.4
  • La signature est le plus grand obstacle à l’automatisation. Depuis juin 2023, la clé privée d’un certificat OV public doit obligatoirement être stockée sur un HSM, si bien que l’ancien classique « mettre un PFX dans un secret et utiliser signtool » ne peut plus être utilisé tel quel. Pour que le CI aille jusqu’au bout, passer par un service de signature cloud est la voie réaliste.5
  • La facilité d’intégration au CI varie fortement selon le format de distribution. Dans l’ordre : xcopy (zip) est le plus simple, MSIX exige une signature6, MSI passe par un outil en CLI comme WiX, et ClickOnce, qui nécessite msbuild /target:publish, a pas mal de particularités.7
  • Ne faites pas des tests UI automatisés un contrôle obligatoire du CI. Les tests unitaires doivent être obligatoires en CI, tandis que les tests UI, limités à des tests de fumée, doivent tourner dans un job séparé — c’est la solution réaliste.

2. En quoi le CI/CD des applications de bureau diffère-t-il du web ?

Commençons par examiner pourquoi on ne peut pas importer tel quel le schéma de CI/CD des applications web (push → build → tests → déploiement sur serveur).

Aspect Application web Application de bureau WinForms / WPF
Cible de déploiement Un serveur qu’on gère soi-même PC du client / du site (hors de notre contrôle)
Unité de distribution Bascule globale sur le serveur MSI / MSIX / ClickOnce / zip, etc. — le moment du déploiement dépend de l’autre partie
Rollback Réversible côté serveur Difficile à annuler sur les PC déjà équipés. La conservation des anciens installateurs est indispensable
Signature Généralement inutile (TLS géré côté infrastructure) La signature de code de l’exécutable/du package est de fait indispensable
Environnement de build Fonctionne souvent bien sur un runner Linux Suppose un runner Windows
Tests Fonctionne souvent bien en mode headless Les tests unitaires sont identiques ; les tests UI nécessitent une session de bureau
Signification de « déployer » Jusqu’à la mise en production Le périmètre du CI s’arrête à « la production du livrable ». L’installation est une étape distincte

La dernière ligne est la plus importante. Pour une application de bureau, le point de sortie du pipeline CI/CD n’est pas « la mise en production », mais « un livrable signé, déposé dans un endroit d’où on peut toujours le récupérer ». Tout ce qui vient après (le déploiement chez le client, la mise à jour automatique) relève de la conception du mode de distribution, un territoire couvert dans « A Decision Table for Distribution Methods ». Inversement, une fois qu’on accepte de définir la sortie ainsi, le CI/CD d’une application de bureau peut se construire avec exactement les mêmes outils que pour le web.

3. La configuration minimale — build + tests avec GitHub Actions

Voici la première — et pour l’instant la seule — chose à mettre en place. Comme les runners hébergés par GitHub se voient attribuer une nouvelle VM à chaque job,1 chaque push exécute le build et les tests sur une machine Windows vierge, et toute dépendance à « un SDK installé seulement sur le PC de telle personne » se révèle immédiatement.

name: build-and-test

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build:
    runs-on: windows-latest   # WinForms / WPF nécessitent un runner Windows
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '8.0.x'

      - name: Restore
        run: dotnet restore

      - name: Build
        run: dotnet build --configuration Release --no-restore

      - name: Test
        run: dotnet test --configuration Release --no-build

      - name: Publish
        run: dotnet publish src/MyApp/MyApp.csproj -c Release -o publish

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: MyApp
          path: publish

Trois points méritent d’être précisés.

Premièrement, runs-on: windows-latest est la base. Un projet WinForms / WPF a un TargetFramework qui est un TFM exclusivement Windows comme net8.0-windows, et c’est un projet du SDK de bureau .NET avec UseWindowsForms ou UseWPF activé.3 À strictement parler, si on ne cherchait qu’à compiler, on pourrait activer EnableWindowsTargeting et builder même sur un runner Linux — mais une étape impliquant une exécution réelle, comme dotnet test, nécessite un environnement Windows, donc pour une configuration comme celle-ci, qui fait tourner les tests dans le même job, autant utiliser directement un runner Windows. Pour .NET Framework 4.x (l’ancien format de csproj), on utilise MSBuild et le CLI NuGet au lieu de dotnet build, mais les deux sont préinstallés sur le runner Windows, et le principe reste le même.

Deuxièmement, conservez toujours les livrables avec actions/upload-artifact. Le fait que « l’ensemble des livrables d’un build donné puisse être récupéré depuis GitHub » est ce qui constitue, concrètement, la sortie de la dépendance à un PC individuel. Même une version de vérification rapide se résume alors à télécharger un zip depuis l’écran Actions.

Troisièmement, à ce stade, on ne s’occupe encore ni de la signature ni de la distribution. Cette configuration minimale suffit à obtenir deux garanties — « main peut toujours être buildée et testée » et « n’importe qui peut récupérer le même livrable » — et d’après notre expérience, cela résout déjà la majorité des difficultés d’une petite équipe.

4. La numérotation automatique des versions — releases pilotées par tag

L’étape suivante consiste à résoudre le problème « ce zip, c’est quelle version, déjà ? ». Dans une organisation basée sur des builds locaux, oublier de modifier Version dans le csproj et se retrouver avec le même 1.0.0 sur plusieurs générations est un grand classique. La solution pragmatique est la release pilotée par tag : on pose un tag comme v1.2.3 sur le commit qu’on veut publier, cela déclenche un workflow, et on injecte dans le build la version extraite du nom du tag.

name: release

on:
  push:
    tags: [ 'v*' ]

jobs:
  release:
    runs-on: windows-latest
    steps:
      - uses: actions/checkout@v4

      - uses: actions/setup-dotnet@v4
        with:
          dotnet-version: '8.0.x'

      # Un push de tag ne déclenche pas le workflow build+tests du chapitre 3,
      # donc on fait aussi passer les tests ici avant de produire le livrable de release
      - name: Test
        run: dotnet test --configuration Release

      - name: Publish with version from tag
        shell: pwsh
        run: |
          $version = $env:GITHUB_REF_NAME.TrimStart('v')   # v1.2.3 -> 1.2.3
          dotnet publish src/MyApp/MyApp.csproj `
            -c Release -o publish `
            -p:Version=$version

      - name: Upload artifact
        uses: actions/upload-artifact@v4
        with:
          name: MyApp-${{ github.ref_name }}
          path: publish

En le passant comme propriété MSBuild, par exemple -p:Version=1.2.3, un projet SDK .NET génère par défaut AssemblyVersion et FileVersion à partir du préfixe de Version (la partie sans le suffixe), et InformationalVersion à partir de Version lui-même.4 On ne garde dans le csproj qu’une valeur provisoire de développement, et la version officielle de release n’existe que sur le tag — une gestion centralisée en un seul endroit.

Une mise en garde. Les livrables d’actions/upload-artifact ont une durée de conservation définie au niveau du dépôt (90 jours par défaut), et disparaissent une fois ce délai écoulé. Une application de bureau doit conserver les anciens installateurs sur le long terme pour permettre un retour en arrière, donc publiez les livrables des builds de tag vers un emplacement permanent, par exemple en les attachant à une GitHub Release, et considérez l’artefact Actions comme un simple relais temporaire.

L’avantage, c’est que toute l’opération reste confinée à Git. « Quel commit correspond à la version 1.2.3 chez le client ? » est déterminé par le tag, et la version de fichier affichée dans les propriétés de l’EXE correspond mécaniquement au tag Git. De plus, depuis le SDK .NET 8, le hash de commit Git (SourceRevisionId) est ajouté par défaut à InformationalVersion,4 donc en l’affichant sur un écran de version, on peut identifier directement le commit à partir d’un livrable.

5. Intégrer la signature de code au CI — le plus grand obstacle

Les équipes qui ont réussi à automatiser sans accroc le build et la gestion des versions butent presque toujours sur la signature. Nous avons déjà expliqué pourquoi la signature de code est de fait indispensable pour une application Windows distribuée hors du Store (SmartScreen, produits de sécurité d’entreprise, détection d’altération) dans « SmartScreen and Code Signing », donc nous nous concentrons ici uniquement sur où, dans le CI, et comment l’exécuter.

5.1. La forme de base de signtool

L’exécution de la signature elle-même tient en une commande. signtool fait partie du Windows SDK et est disponible aussi sur les runners Windows de GitHub. Dans les versions actuelles du SDK, spécifier à la fois /fd (l’empreinte du fichier) et /td (l’empreinte de l’horodatage) est obligatoire, SHA256 étant recommandé.8

signtool sign /f MyCert.pfx /p $env:PFX_PASSWORD `
  /fd SHA256 /tr http://timestamp.digicert.com /td SHA256 `
  publish\MyApp.exe

L’horodatage (/tr) est techniquement facultatif, mais ajoutez-le systématiquement. Avec un horodatage, on peut vérifier, même après l’expiration du certificat, que « la signature était valide au moment où elle a été apposée », ce qui maintient vivante la signature des fichiers déjà distribués.86

5.2. Types de certificats et réalité de l’intégration au CI

Le problème n’est pas la commande, mais l’endroit où se trouve la clé privée. La forme sous laquelle on obtient le certificat change fondamentalement la façon de l’intégrer au CI.

Forme du certificat Emplacement de la clé privée Intégration au CI Remarques
Service de signature cloud (Azure Artifact Signing = ex-Trusted Signing, etc.) Côté cloud Facile à intégrer (l’option privilégiée). Conçu dès le départ pour s’intégrer avec GitHub Actions et consorts Restreint à certains pays/régions (pour les entreprises : États-Unis, Canada, UE, Royaume-Uni, etc.)5
Certificat OV (émis à partir de juin 2023) HSM / jeton USB obligatoire Impossible tel quel, un jeton ne pouvant pas être branché sur un runner. Possible via une option de HSM cloud proposée par l’autorité de certification Selon les exigences du CA/Browser Forum5
Certificat EV HSM / jeton USB Idem L’effet de confiance immédiate pour SmartScreen a été supprimé en 2024. À considérer, en pratique de signature, comme équivalent à l’OV5
Ancien fichier PFX (émis par le passé, autorité de certification interne, ou auto-signé) Un fichier Stocké en Base64 dans un secret puis restauré (voir ci-dessous) Cette forme ne peut en principe plus être obtenue pour une émission nouvelle destinée à la distribution publique

Autrement dit, la configuration « mettre un PFX dans un secret GitHub et signer avec signtool », qu’on trouve souvent en cherchant, reste valable pour une autorité de certification interne ou un PFX existant, mais son hypothèse de base s’effondre pour quiconque doit obtenir un certificat public à partir de maintenant. Pour une mise en place neuve, il est réaliste de raisonner autour d’un service de signature cloud qui prend en charge l’intégration CI dès le départ.5 Si vous fonctionnez avec un jeton USB, vous obtenez une configuration hybride où seule l’étape de signature reste sur un PC local ou sur un runner auto-hébergé avec le jeton branché.

5.3. Précautions de gestion des secrets

Voici les bonnes pratiques standard pour intégrer l’approche PFX (autorité de certification interne, certificat existant) au CI.

  • Stockez le PFX sous forme de chaîne Base64 dans un secret GitHub, puis restaurez-le en fichier à l’intérieur du job. C’est la procédure que recommande la documentation GitHub pour traiter des données binaires comme un secret.9
  • Placez le mot de passe dans un secret distinct. Les valeurs des secrets sont automatiquement masquées dans les journaux,9 mais ce masquage ne s’étend pas aux valeurs dérivées que vous auriez transformées. Évitez de les passer en variable d’environnement à autre chose que l’étape de signature.
  • Les secrets ne sont pas transmis aux pull requests provenant d’un fork (à l’exception de GITHUB_TOKEN).9 Cependant, le job lui-même s’exécute quand même, avec des secrets vides, ce qui fait échouer l’étape de restauration ci-dessus en tentant de décoder en Base64 une chaîne vide. Isolez l’étape de signature dans un workflow de release déclenché par tag comme au chapitre 4 (qui ne se déclenche pas sur une PR de fork), ou ajoutez une condition explicite comme if: github.event_name != 'pull_request' pour la sauter délibérément.
      - name: Restore signing certificate
        shell: pwsh
        run: |
          $bytes = [Convert]::FromBase64String($env:PFX_BASE64)
          [IO.File]::WriteAllBytes("$env:RUNNER_TEMP\sign.pfx", $bytes)
        env:
          PFX_BASE64: ${{ secrets.SIGNING_PFX_BASE64 }}

Un autre point critique : restreignez les workflows qui peuvent accéder à la clé de signature. Quiconque dispose d’un accès en écriture au dépôt peut modifier un workflow, donc placez le secret de signature dans un Environment avec des approbateurs requis, de sorte que seul le workflow de release puisse y accéder. Un binaire signé constitue la preuve même que « c’est notre entreprise qui l’a créé », donc traitez la gestion de la clé avec le même niveau de rigueur en matière de frontière de confiance que pour une infrastructure de diffusion de mises à jour automatiques (voir aussi « The Security of Auto-Updates » sur ce point).

6. Tableau de décision pour l’intégration CI/CD selon le format de distribution

Une fois la signature en place, il ne reste plus que la forme du livrable. Nous laissons le choix du format lui-même à « A Decision Table for Distribution Methods », et nous comparons ici uniquement du point de vue du CI/CD.

Format de distribution Facilité de fabrication en CI Moyen de fabrication en CI Exigence de signature Mise à jour automatique
xcopy (distribution zip) La plus simple Uniquement dotnet publish + compression Signature de l’EXE/DLL (recommandée) Aucune (déploiement manuel)
xcopy + updater maison Simple (pour le build). La conception de la diffusion des mises à jour est un chantier lourd à part dotnet publish + génération de manifeste Signature de l’EXE + conception obligatoire de la vérification des fichiers de mise à jour Maison (nécessite de concevoir une frontière de confiance)
MSI Modérée Exécution d’un outil comme WiX en CLI Signature du fichier MSI (recommandée, quasi indispensable) Aucune (nécessite un mécanisme de distribution séparé)
MSIX Modérée MSBuild / MakeAppx + signtool La signature du package est obligatoire (un package non signé ne peut pas être installé)6 Possible via App Installer, etc.
ClickOnce Plein de particularités msbuild /target:publish + profil de publication (non pris en charge par le CLI dotnet)7 Signature du manifeste + signature de l’EXE Intégrée (l’objectif principal du format)

Quelques précisions.

  • xcopy (zip) : les workflows des chapitres 3 et 4 constituent quasiment la forme finale telle quelle. Quel que soit le format de distribution final, faire d’abord fonctionner cette forme est le chemin le plus court.
  • MSI : incluez la définition de l’installateur (WiX, etc.) dans le dépôt et buildez-la via le CLI. L’essentiel n’est pas la génération elle-même, mais la conception de « ce qu’on met dans le MSI » (enregistrement de service, per-machine/per-user).
  • MSIX : Windows n’autorise pas l’installation d’un MSIX non signé, donc la mise en CI n’est complète que si elle s’accompagne de l’automatisation de la signature.6 Inversement, une fois l’infrastructure de signature en place, c’est un format facile à intégrer au CI. Pour une distribution via le Microsoft Store, il existe une autre solution : la resignature côté Store rend inutile un certificat propre.5
  • ClickOnce : impossible à publier depuis le CLI dotnet — il faut utiliser msbuild /target:publish /p:PublishProfile=... en spécifiant un profil de publication (.pubxml). Le numéro de révision (ApplicationRevision), incrémenté automatiquement à chaque publication dans l’IDE, ne l’est pas en ligne de commande,7 ce qui rend indispensable le passage explicite de la version, piloté par tag comme au chapitre 4. À ce sujet, attention : la détection de mise à jour de ClickOnce ne se base pas sur -p:Version (les informations d’assembly) mais sur la version côté déploiement (ApplicationVersion / ApplicationRevision), donc si vous ne passez pas séparément la valeur à quatre parties construite à partir du tag, par exemple via /p:ApplicationVersion=1.2.3.0, une nouvelle release ne sera pas reconnue comme une mise à jour. Le mécanisme et les cas d’usage adaptés ou non sont détaillés dans « What Is ClickOnce ».

Du seul point de vue du CI/CD, « commencer par le zip, puis ajouter MSIX ou MSI comme job une fois les exigences de distribution stabilisées » est l’approche qui minimise le travail incrémental. Les étapes antérieures (build, tests, version) sont communes à tous les formats, donc remplacer plus tard l’étape de format de distribution ne gaspille aucun des investissements précédents.

7. Jusqu’où pousser l’automatisation des tests

Pour finir, traçons la limite de ce qu’il faut exiger comme contrôle obligatoire (gate) du CI.

Couche de test Traitement en CI Raison
Tests unitaires (logique) Contrôle obligatoire, exécuté à chaque pull request Rapide, stable, fonctionne tel quel sur un runner Windows
Tests d’intégration sans interface (BD, E/S fichiers) Obligatoires en principe ; séparés en exécution nocturne si trop lents L’initialisation des dépendances externes demande un certain effort, mais la valeur de l’automatisation est élevée
Tests UI automatisés (fumée) Un petit nombre, dans un job séparé — du lancement jusqu’aux principales transitions d’écran Nécessitent une session de bureau, avec de nombreuses sources d’instabilité
Tests UI automatisés (couverture exhaustive) Ne pas en faire un contrôle du CI Le coût de maintenance dépasse souvent le bénéfice

Pour une application de bureau, la valeur d’automatisation la plus élevée ne se trouve pas dans l’UI, mais en dessous. Si la logique métier est enfouie dans le code-behind, on ne peut pas écrire de tests unitaires, donc séparer la logique de l’écran est en soi un investissement préalable au CI/CD. La solution réaliste consiste à limiter les tests UI automatisés à un test de fumée — « lancer, se connecter, les principaux écrans s’ouvrent » — exécuté via un déclencheur séparé, par exemple nocturne. Les tests UI sur un runner sont truffés de pièges liés à la session d’écran, à la résolution et au timing ; ce sujet, y compris les pièges du CI et de l’exécution sans supervision, est traité dans « Automated UI Testing for Windows Desktop Apps ».

8. Résumé

  • Le CI/CD d’une application de bureau peut se construire avec le même outillage que pour le web, à condition de définir la sortie comme « la production d’un livrable signé ».
  • La configuration minimale est windows-latest + actions/checkout + actions/setup-dotnet + dotnet build / test + actions/upload-artifact. Cela suffit à éliminer le risque de « ne pouvoir builder que sur le PC d’un développeur ».12
  • WinForms / WPF supposent un runner Windows, car elles ciblent un TFM exclusivement Windows tel que net8.0-windows.3
  • Centralisez la version via une approche pilotée par tag : un tag v1.2.3 est injecté dans -p:Version.4
  • La signature est le plus grand obstacle à l’automatisation CI. Maintenant que les certificats OV exigent eux aussi un stockage HSM, un service de signature cloud est l’option privilégiée pour que le CI aille jusqu’au bout ; l’approche PFX + secret reste destinée à une autorité de certification interne ou un certificat existant.59
  • La facilité d’intégration au CI selon le format de distribution suit l’ordre : xcopy (zip) → MSI / MSIX → ClickOnce. MSIX exige une signature,6 et ClickOnce demande de faire attention à msbuild /target:publish et à l’absence d’incrémentation automatique de la révision.7
  • Faites des tests unitaires un contrôle obligatoire du CI, limitez les tests UI à des tests de fumée dans un job séparé, et considérez la séparation de la logique et de l’écran comme l’investissement préalable.

Articles connexes

Domaines de conseil associés

KomuraSoft LLC accompagne le développement d’applications WinForms / WPF, la migration depuis une exploitation basée sur des builds locaux vers le CI/CD, la conception de pipelines de build, de signature et de distribution avec GitHub Actions, ainsi que la mise en état testable (séparation de la logique) d’applications de bureau existantes.

Références

  1. GitHub Docs, GitHub-hosted runners reference. Sur les libellés de runner comme windows-latest, l’attribution d’une machine virtuelle neuve par job, et la gratuité des runners standard sur les dépôts publics.  2 3

  2. Microsoft Learn, GitHub Actions and .NET. Sur le CI/CD .NET via GitHub Actions, les rôles d’actions/checkout et actions/setup-dotnet, et l’utilisation de dotnet restore / build / test / publish dans un workflow.  2

  3. Microsoft Learn, MSBuild reference for .NET Desktop SDK projects. Sur les projets WinForms / WPF spécifiant un TFM propre à Windows tel que net8.0-windows, et l’activation du SDK de bureau .NET via UseWindowsForms / UseWPF 2 3

  4. Microsoft Learn, Set assembly attributes in a project file. Sur la génération par défaut d’AssemblyVersion / FileVersion (suffixe supprimé) et d’InformationalVersion à partir de la propriété Version, et sur l’ajout, à partir du SDK .NET 8, de SourceRevisionId (le hash de commit) à InformationalVersion 2 3 4

  5. Microsoft Learn, Code signing options for Windows app developers. Sur les exigences du CA/Browser Forum imposant depuis juin 2023 le stockage sur HSM/jeton matériel des clés privées des certificats OV, la suppression en 2024 du contournement immédiat de SmartScreen pour les certificats EV, Azure Artifact Signing (anciennement Trusted Signing) qui ne nécessite pas de jeton et s’intègre avec GitHub Actions et consorts tout en étant restreint à certaines régions, et la resignature par Microsoft des packages MSIX distribués via le Store.  2 3 4 5 6 7

  6. Microsoft Learn, Sign an MSIX package. Sur l’exigence par Windows d’une signature de code valide sur un package MSIX, et sur le maintien de la validité de la vérification de signature après l’expiration du certificat grâce à un horodatage.  2 3 4 5

  7. Microsoft Learn, Build .NET ClickOnce applications from the command line. Sur la nécessité de msbuild /target:publish avec un profil de publication spécifié pour la publication ClickOnce en .NET, et sur la non-incrémentation automatique d’ApplicationRevision dans les builds en ligne de commande.  2 3 4

  8. Microsoft Learn, SignTool. Sur l’inclusion de SignTool dans le Windows SDK, l’obligation dans les versions actuelles de spécifier /fd et /td avec SHA256 recommandé, et la spécification d’un horodatage RFC 3161 via /tr 2

  9. GitHub Docs, Using secrets in GitHub Actions. Sur le masquage automatique des valeurs de secrets dans les journaux, la procédure de stockage de données binaires comme les certificats en Base64 dans un secret puis leur restauration dans un job, et l’absence de transmission des secrets aux workflows déclenchés depuis un fork.  2 3 4

Articles récents partageant les mêmes étiquettes, pour approfondir des sujets proches.

Ces pages replacent le sujet dans un contexte plus large de services et de décisions.

Cet article est directement lié aux services suivants.

Questions fréquentes

Questions souvent posées lors d’une consultation sur le sujet de cet article.

Sur quel runner GitHub Actions faut-il builder une application WinForms / WPF ?
Utilisez un runner Windows tel que windows-latest. Les projets WinForms / WPF ciblent un framework cible exclusivement Windows comme net8.0-windows, et aussi bien la vérification du résultat du build que l'exécution des tests avec dotnet test nécessitent un environnement Windows. Comme les runners hébergés par GitHub se voient attribuer une machine virtuelle neuve à chaque job, on obtient des builds reproductibles qui ne dépendent du PC d'aucun développeur en particulier. Les runners standard sont gratuits sur les dépôts publics et facturés à la minute sur les dépôts privés.
La signature de code peut-elle être entièrement automatisée en CI ?
Cela dépend de la manière dont le certificat est détenu. L'approche classique consistant à placer un fichier PFX dans un secret et à signer avec signtool ne peut en général plus être utilisée pour un certificat nouvellement émis, car les exigences du CA/Browser Forum imposent depuis juin 2023 le stockage sur HSM (matériel) des clés privées des certificats OV publics. Un certificat sur jeton USB ne peut pas être branché sur un runner cloud, donc pour une automatisation complète en CI, la voie réaliste est un service de signature cloud comme Azure Artifact Signing (anciennement Trusted Signing), ou une option de HSM cloud proposée par l'autorité de certification. Si l'on reste en exploitation par jeton, seule l'étape de signature doit rester sur un poste local ou sur un runner auto-hébergé.
Par où faut-il commencer l'automatisation ?
Commencez uniquement par l'automatisation du build et des tests. Le simple fait d'arriver à un état où dotnet build / dotnet test s'exécutent sur un runner windows-latest à chaque push élimine le plus grand risque : « ça ne peut être buildé que sur le PC d'un développeur » et « personne ne remarque qu'une fusion a cassé le build avant d'être sur le point de publier ». L'automatisation de la signature, de la création d'installateurs et de la distribution peut être ajoutée progressivement ensuite — vouloir tout mettre en place d'un coup finit souvent par bloquer sur la signature.
La facilité de mise en place du CI/CD change-t-elle selon le format de distribution (MSI / MSIX / ClickOnce / xcopy) ?
Oui, considérablement. La distribution xcopy (zip) est la plus simple, puisqu'elle consiste juste à compresser la sortie de dotnet publish. MSIX peut être intégré au CI avec MSBuild et signtool, mais la signature du package y est obligatoire. MSI peut être automatisé en appelant depuis le CI un outil comme WiX. ClickOnce ne peut pas être publié via le CLI dotnet : il faut la combinaison de msbuild /target:publish et d'un profil de publication, et il faut aussi faire attention au fait que le numéro de révision ne s'incrémente pas automatiquement en ligne de commande. La facilité d'intégration au CI doit faire partie des critères pris en compte dès le choix du format de distribution.

Profil de l’auteur

Page de présentation de l’auteur de l’article.

Go Komura

Représentant de KomuraSoft LLC

Spécialisé dans le développement de logiciels Windows, le conseil technique et l’analyse de pannes, notamment pour les systèmes existants et les incidents difficiles à reproduire.

Retour au blog