François
François

Reputation: 3274

How to Sign a UWP app on Azure Pipelines?

The doc about setting up Azure Pipelines for a UWP doesn't say how to sign the package. It does say that the cert file should be in the repo but it doesn't explain how to sign the package with that cert.

So my question is how do I sign a UWP package on Azure Pipelines? Am I supposed to create a powershell script to run SignTool?

Upvotes: 2

Views: 1450

Answers (2)

Sibeesh Venu
Sibeesh Venu

Reputation: 21779

Basically, following these tasks would do the trick.

  1. Create the certificate
  2. Download the certificate
  3. Install the certificate
  4. Build
  5. Copy
  6. Public Artifacts
  7. Distribute to App Center if you have any (Optional)

Here is the full content of the YAML file, I have this tested and running in my pipeline.

# Universal Windows Platform

# Build a Universal Windows Platform project using Visual Studio.
# Add steps that test and distribute an app, save build artifacts, and more:
# https://aka.ms/yaml

# A pipeline with no CI trigger
trigger: none
pr: none
name: $(MajorVersion).$(MinorVersion).$(date:yy)$(DayOfYear)$(rev:.r)
pool:
  vmImage: 'windows-latest'

variables:
- group: uwp-pipeline
- name: solution
  value: '**/*.sln'
- name: buildPlatform
  value: 'x86|x64'
- name: buildConfiguration
  value: 'Release'
- name: appxPackageDir
  value: '$(build.artifactStagingDirectory)\AppxPackages\\'
- name: MajorVersion
  value: 1
- name: MinorVersion
  value: 0
- name: customBuildNumber
  value: '$(MajorVersion).$(MinorVersion).$(date:yy)$(DayOfYear)$(rev:.r)'

steps:
- task: NuGetToolInstaller@1

- task: NuGetCommand@2
  inputs:
    restoreSolution: '$(solution)'

- task: DownloadSecureFile@1
  name: mySecureFile
  displayName: 'Download CA certificate'
  inputs:
    secureFile: '$(signingCert.secureFilePath)'

- task: PowerShell@2
  inputs:
    targetType: 'inline'
    script: |
      Write-Host "Start adding the PFX file to the certificate store."

      $pfxpath = '$(mySecureFile.secureFilePath)'
      $password = '$(signingCert.password)'      

      Add-Type -AssemblyName System.Security
      $cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
      $cert.Import($pfxpath, $password, [System.Security.Cryptography.X509Certificates.X509KeyStorageFlags]"PersistKeySet")
      $store = new-object system.security.cryptography.X509Certificates.X509Store -argumentlist "MY", CurrentUser
      $store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]"ReadWrite")
      $store.Add($cert)
      $store.Close()

- task: VersionAPPX@2
  inputs:
    Path: '$(Build.SourcesDirectory)'
    VersionNumber: '$(Build.BuildNumber)'
    InjectVersion: False
    VersionRegex: '(0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])(\.(0|[1-9][0-9]{0,3}|[1-5][0-9]{4}|6[0-4][0-9]{3}|65[0-4][0-9]{2}|655[0-2][0-9]|6553[0-5])){3}'
    OutputVersion: 'OutputedVersion'

- task: VSBuild@1
  inputs:
    platform: 'x86'
    solution: '$(solution)'
    configuration: '$(buildConfiguration)'
    msbuildArgs: '/p:AppxBundlePlatforms="$(buildPlatform)" 
                  /p:AppxPackageDir="$(appxPackageDir)" 
                  /p:AppxBundle=Always 
                  /p:UapAppxPackageBuildMode=StoreUpload 
                  /p:AppxPackageSigningEnabled=true
                  /p:PackageCertificateThumbprint="$(signingCert.thumbprint)" 
                  /p:PackageCertificateKeyFile="$(mySecureFile.secureFilePath)"
                  /p:PackageCertificatePassword="$(signingCert.password)"'

- task: CopyFiles@2
  displayName: 'Copy Files to: $(build.artifactstagingdirectory)'
  inputs:
    SourceFolder: '$(system.defaultworkingdirectory)'
    Contents: '**\bin\$(BuildConfiguration)\**'
    TargetFolder: '$(build.artifactstagingdirectory)'

- task: PublishBuildArtifacts@1
  displayName: 'Publish Artifact: drop'
  inputs:
    PathtoPublish: '$(build.artifactstagingdirectory)'

- task: ArchiveFiles@2
  inputs:
    rootFolderOrFile: '$(build.artifactstagingdirectory)'
    includeRootFolder: true
    archiveType: 'zip'
    archiveFile: '$(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip'
    replaceExistingArchive: true

- task: AppCenterDistribute@3
  inputs:
    serverEndpoint: 'release to app center'
    appSlug: '$(appSlug)'
    buildVersion: '$(Build.BuildNumber)'
    appFile: '$(Build.ArtifactStagingDirectory)/$(Build.BuildId).zip'
    releaseNotesOption: 'input'
    releaseNotesInput: 'New release!'
    destinationType: 'groups'
    distributionGroupId: '$(distributionGroupId)'

I had written a detailed article on the same, please feel free to read it here: UWP Application Signin, Release, Distribute, Deploy With Azure DevOps Pipeline

Upvotes: 6

McNline
McNline

Reputation: 178

Depends what you want to do with the app. I currently use signtool to sign with our in house cert.

signtool sign /a /d "{certName}" /fd sha256 /n "{publisherName}" /td sha256 /tr "http://timestamp.comodoca.com" /v "$(TargetPath)"

Please see https://learn.microsoft.com/en-us/windows/desktop/seccrypto/using-signtool-to-sign-a-file

You can also use the WACK to verify the app and then install the cert that's produced during deploy.

https://learn.microsoft.com/en-us/windows/uwp/debug-test-perf/windows-app-certification-kit

Upvotes: 0

Related Questions