From bbf473a6d599229f479af58fc0e02bc1f81e461e Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Tue, 6 Aug 2024 16:04:37 -0700 Subject: [PATCH 1/4] Generate https & codesigning cert in pipeline --- .github/actions/spelling/expect.txt | 3 - azure-pipelines.yml | 61 ++++++----------- src/AppInstallerCLIE2ETests/Constants.cs | 3 - src/AppInstallerCLIE2ETests/HashCommand.cs | 8 +-- src/AppInstallerCLIE2ETests/SetUpFixture.cs | 4 -- .../TestData/AppInstallerTest.cer | Bin 1104 -> 0 bytes .../TestData/IndexPackageIntRoot.cer | Bin 1460 -> 0 bytes .../TestData/localsource.json | 11 +-- src/LocalhostWebServer/InstallDevCert.ps1 | 15 ---- src/LocalhostWebServer/Program.cs | 2 +- .../Run-LocalhostWebServer.ps1 | 13 +++- templates/e2e-setup.yml | 64 ++++++++++-------- templates/e2e-test.template.yml | 4 +- 13 files changed, 84 insertions(+), 104 deletions(-) delete mode 100644 src/AppInstallerCLIE2ETests/TestData/AppInstallerTest.cer delete mode 100644 src/AppInstallerCLIE2ETests/TestData/IndexPackageIntRoot.cer delete mode 100644 src/LocalhostWebServer/InstallDevCert.ps1 diff --git a/.github/actions/spelling/expect.txt b/.github/actions/spelling/expect.txt index 261cb571f8..3e46e03d6d 100644 --- a/.github/actions/spelling/expect.txt +++ b/.github/actions/spelling/expect.txt @@ -30,7 +30,6 @@ appname appshutdown APPTERMINATION archs -argumentlist ARMNT arp arphelper @@ -390,7 +389,6 @@ Peet peetdev PEGI pfn -pfxpath pgp Pherson pid @@ -469,7 +467,6 @@ savepoint schematab Scm sddl -SECUREFILEPATH secureobject securestring seof diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 648159d211..2cb8174392 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -140,7 +140,7 @@ jobs: platform: '$(buildPlatform)' solution: 'src\AppInstallerTestMsixInstaller\AppInstallerTestMsixInstaller.wapproj' configuration: '$(buildConfiguration)' - msbuildArguments: '/p:AppxPackageOutput="$(Build.ArtifactStagingDirectory)\AppInstallerTestMsixInstaller.msix" + msbuildArguments: '/p:AppxPackageOutput="$(artifactsDir)\E2ETests\TestData\AppInstallerTestMsixInstaller.msix" /p:AppxBundle=Never /p:UapAppxPackageBuildMode=SideLoadOnly /p:AppxPackageSigningEnabled=false' @@ -255,22 +255,17 @@ jobs: SourceFolder: '$(buildOutDir)\LocalhostWebServer' TargetFolder: '$(artifactsDir)\E2ETests\LocalhostWebServer' - # Invoke E2E setup to generate the TestLocalIndex; could optimize out some of its steps if needed - - template: templates/e2e-setup.yml - parameters: - sourceDir: $(Build.SourcesDirectory) - localhostWebServerArgs: '-BuildRoot $(artifactsDir)\E2ETests\LocalhostWebServer -StaticFileRoot $(Agent.TempDirectory)\TestLocalIndex -LocalSourceJson $(Build.SourcesDirectory)\src\AppInstallerCLIE2ETests\TestData\localsource.json -TestDataPath $(Build.SourcesDirectory)\src\AppInstallerCLIE2ETests\TestData -SourceCert $(Build.SourcesDirectory)\src\AppInstallerCLIE2ETests\TestData\AppInstallerTest.cer -ExitBeforeRun' - - task: CopyFiles@2 - displayName: 'Copy TestLocalIndex' + displayName: 'Copy TestData' inputs: - SourceFolder: '$(Agent.TempDirectory)\TestLocalIndex' - TargetFolder: '$(artifactsDir)\E2ETests\TestLocalIndex' + SourceFolder: '$(Build.SourcesDirectory)\src\AppInstallerCLIE2ETests\TestData\' + TargetFolder: '$(artifactsDir)\E2ETests\TestData' - task: CopyFiles@2 - displayName: 'Copy TestData' + displayName: 'Copy AppInstallerTestExeInstaller.exe' inputs: - SourceFolder: '$(Build.SourcesDirectory)\src\AppInstallerCLIE2ETests\TestData\' + Contents: AppInstallerTestExeInstaller.exe + SourceFolder: '$(buildOutDir)\AppInstallerTestExeInstaller' TargetFolder: '$(artifactsDir)\E2ETests\TestData' - task: CopyFiles@2 @@ -302,28 +297,6 @@ jobs: verbosity: 'Verbose' alertWarningLevel: 'High' - # Run BimSkim for all the binaries - - task: BinSkim@4 - displayName: 'Run BinSkim ' - inputs: - arguments: 'analyze - "$(buildOutDir)\AppInstallerCLI\winget.exe" - "$(buildOutDir)\WinGetUtil\WinGetUtil.dll" - "$(buildOutDir)\WindowsPackageManager\WindowsPackageManager.dll" - "$(buildOutDir)\Microsoft.Management.Deployment.InProc\Microsoft.Management.Deployment.InProc.dll" - "$(Build.SourcesDirectory)\src\WinGetUtilInterop\bin\WinGetUtil*Interop.dll" - "$(buildOutDir)\UndockedRegFreeWinRT\winrtact.dll" - "$(buildOutDir)\Microsoft.WinGet.Client.Cmdlets\Microsoft.WinGet.Client*.dll" - "$(buildOutDir)\ConfigurationRemotingServer\ConfigurationRemoting*Server.dll" - "$(buildOutDir)\ConfigurationRemotingServer\ConfigurationRemoting*Server.exe" - "$(buildOutDir)\ConfigurationRemotingServer\Microsoft.Management.Configuration*.dll" - "$(buildOutDir)\Microsoft.Management.Configuration\Microsoft.Management.Configuration*.dll" - "$(buildOutDir)\Microsoft.Management.Configuration.OutOfProc\Microsoft.Management.Configuration*.dll" - --config default --recurse' - - - task: securedevelopmentteam.vss-secure-development-tools.build-task-publishsecurityanalysislogs.PublishSecurityAnalysisLogs@3 - displayName: 'Publish Security Analysis Logs' - # Test job runs tests using build artifacts - job: 'Test' @@ -431,7 +404,7 @@ jobs: - template: templates/e2e-setup.yml parameters: sourceDir: $(Build.SourcesDirectory) - localhostWebServerArgs: '-BuildRoot $(buildOutDir)\E2ETests\LocalhostWebServer -StaticFileRoot $(buildOutDir)\E2ETests\TestLocalIndex -SourceCert $(Build.SourcesDirectory)\src\AppInstallerCLIE2ETests\TestData\AppInstallerTest.cer' + localhostWebServerArgs: '-BuildRoot $(buildOutDir)\E2ETests\LocalhostWebServer -StaticFileRoot $(Agent.TempDirectory)\TestLocalIndex -LocalSourceJson $(buildOutDir)\E2ETests\TestData\localsource.json -TestDataPath $(buildOutDir)\E2ETests\TestData' - template: templates/e2e-test.template.yml parameters: @@ -511,6 +484,10 @@ jobs: arguments: '-TargetLocation $(artifactsDir)\ConfigOOPTestsLog' condition: succeededOrFailed() + - powershell: Get-Process LocalhostWebServer | Stop-Process + displayName: Stop LocalhostWebServer + condition: succeededOrFailed() + - task: PublishPipelineArtifact@1 displayName: Publish Pipeline Artifacts inputs: @@ -524,6 +501,8 @@ jobs: timeoutInMinutes: 120 dependsOn: 'Build' condition: succeeded('Build') + variables: + buildOutDir: $(Pipeline.Workspace)\Build.x64Release steps: - task: DownloadPipelineArtifact@2 @@ -532,7 +511,7 @@ jobs: - task: CopyFiles@2 displayName: 'Copy x64 PowerShell Binaries to Output' inputs: - SourceFolder: '$(Pipeline.Workspace)\Build.x64release\PowerShell' + SourceFolder: '$(buildOutDir)\PowerShell' Contents: '**\*' TargetFolder: '$(Build.ArtifactStagingDirectory)' @@ -566,14 +545,14 @@ jobs: targetType: 'inline' script: | Get-ChildItem AppxPackages\AppInstallerCLIPackage_0.0.2.0_Test\Dependencies\x64 -Filter *.appx | %{ Add-AppxPackage $_.FullName } - workingDirectory: $(Pipeline.Workspace)\Build.x64release\ + workingDirectory: $(buildOutDir) - template: templates/e2e-setup.yml parameters: sourceDir: $(Build.SourcesDirectory) - localhostWebServerArgs: '-BuildRoot $(Pipeline.Workspace)\Build.x64release\E2ETests\LocalhostWebServer -StaticFileRoot $(Pipeline.Workspace)\Build.x64release\E2ETests\TestLocalIndex -SourceCert $(Build.SourcesDirectory)\src\AppInstallerCLIE2ETests\TestData\AppInstallerTest.cer' + localhostWebServerArgs: '-BuildRoot $(buildOutDir)\E2ETests\LocalhostWebServer -StaticFileRoot $(Agent.TempDirectory)\TestLocalIndex -LocalSourceJson $(buildOutDir)\E2ETests\TestData\localsource.json -TestDataPath $(buildOutDir)\E2ETests\TestData' - - pwsh: .\RunTests.ps1 -testModulesPath $(Build.ArtifactStagingDirectory) -outputPath $(Pipeline.Workspace)\PesterTest -packageLayoutPath $(Pipeline.Workspace)\Build.x64release\DevPackage + - pwsh: .\RunTests.ps1 -testModulesPath $(Build.ArtifactStagingDirectory) -outputPath $(Pipeline.Workspace)\PesterTest -packageLayoutPath $(buildOutDir)\DevPackage workingDirectory: $(Build.SourcesDirectory)\src\PowerShell\tests\ displayName: Run PowerShell 7 Tests @@ -582,6 +561,10 @@ jobs: displayName: Run Windows PowerShell Tests condition: succeededOrFailed() + - powershell: Get-Process LocalhostWebServer | Stop-Process + displayName: Stop LocalhostWebServer + condition: succeededOrFailed() + - task: PublishTestResults@2 displayName: Publish Pester Test Results PowerShell 7 inputs: diff --git a/src/AppInstallerCLIE2ETests/Constants.cs b/src/AppInstallerCLIE2ETests/Constants.cs index 378ce3b3af..da1510292c 100644 --- a/src/AppInstallerCLIE2ETests/Constants.cs +++ b/src/AppInstallerCLIE2ETests/Constants.cs @@ -45,9 +45,6 @@ public class Constants public const string TestSourceType = "Microsoft.PreIndexed.Package"; public const string TestSourceIdentifier = @"WingetE2E.Tests_8wekyb3d8bbwe"; - public const string AppInstallerTestCert = "AppInstallerTest.cer"; - public const string AppInstallerTestCertThumbprint = "d03e7a688b388b1edde8476a627531c49db88017"; - public const string AICLIPackageFamilyName = "WinGetDevCLI_8wekyb3d8bbwe"; public const string AICLIPackageName = "WinGetDevCLI"; public const string AICLIPackagePublisherHash = "8wekyb3d8bbwe"; diff --git a/src/AppInstallerCLIE2ETests/HashCommand.cs b/src/AppInstallerCLIE2ETests/HashCommand.cs index 86b8ae5885..22e8f2f123 100644 --- a/src/AppInstallerCLIE2ETests/HashCommand.cs +++ b/src/AppInstallerCLIE2ETests/HashCommand.cs @@ -21,9 +21,9 @@ public class HashCommand : BaseCommand [Test] public void HashFile() { - var result = TestCommon.RunAICLICommand("hash", TestCommon.GetTestDataFile("AppInstallerTest.cer")); + var result = TestCommon.RunAICLICommand("hash", TestCommon.GetTestDataFile("AppInstallerTestMsiInstaller.msi")); Assert.AreEqual(Constants.ErrorCode.S_OK, result.ExitCode); - Assert.True(result.StdOut.Contains("9b4c49ad7e47afd97d2e666e93347745e1647c55f1a7ebba6d31b7dd5f69ee68")); + Assert.True(result.StdOut.Contains("21d90ee9b3569590c624836ef50bf39791c7184869c227eedc00585e1f39b4de")); } /// @@ -44,9 +44,9 @@ public void HashMSIX() [Test] public void HashInvalidMSIX() { - var result = TestCommon.RunAICLICommand("hash", TestCommon.GetTestDataFile("AppInstallerTest.cer") + " -m"); + var result = TestCommon.RunAICLICommand("hash", TestCommon.GetTestDataFile("AppInstallerTestMsiInstaller.msi") + " -m"); Assert.AreEqual(Constants.ErrorCode.OPC_E_ZIP_MISSING_END_OF_CENTRAL_DIRECTORY, result.ExitCode); - Assert.True(result.StdOut.Contains("9b4c49ad7e47afd97d2e666e93347745e1647c55f1a7ebba6d31b7dd5f69ee68")); + Assert.True(result.StdOut.Contains("21d90ee9b3569590c624836ef50bf39791c7184869c227eedc00585e1f39b4de")); Assert.True(result.StdOut.Contains("Please verify that the input file is a valid, signed MSIX.")); } diff --git a/src/AppInstallerCLIE2ETests/SetUpFixture.cs b/src/AppInstallerCLIE2ETests/SetUpFixture.cs index 0abd729ea8..422eb1bc1f 100644 --- a/src/AppInstallerCLIE2ETests/SetUpFixture.cs +++ b/src/AppInstallerCLIE2ETests/SetUpFixture.cs @@ -41,8 +41,6 @@ public void Setup() shouldRevertDefaultFileTypeRiskOnExit = this.DecreaseFileTypeRisk(".exe;.msi", false); - Assert.True(TestCommon.RunCommand("certutil.exe", "-addstore -f \"TRUSTEDPEOPLE\" " + TestCommon.GetTestDataFile(Constants.AppInstallerTestCert)), "Add AppInstallerTestCert"); - if (testParams.PackagedContext) { if (testParams.LooseFileRegistration) @@ -83,8 +81,6 @@ public void TearDown() this.DecreaseFileTypeRisk(defaultFileTypes, true); } - TestCommon.RunCommand("certutil.exe", $"-delstore \"TRUSTEDPEOPLE\" {Constants.AppInstallerTestCertThumbprint}"); - TestCommon.PublishE2ETestLogs(); if (TestSetup.Parameters.PackagedContext) diff --git a/src/AppInstallerCLIE2ETests/TestData/AppInstallerTest.cer b/src/AppInstallerCLIE2ETests/TestData/AppInstallerTest.cer deleted file mode 100644 index 02f5ddf96c4df5358ce0923a2f794405b5825637..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1104 zcmXqLV(~F(VzyYo%*4pVB#UR%uKSZ3-ibnU`LYpJymwzy}g!7iJGiP07vAOEHu)kO7Hs35)t> zCKu%w=ckn@IOi7?}*8JHRv7y_ZW z0T4tDkh_`~l?-^7U=E0=hlbU5NYi--Gg7xO%^PfEJ zX2vn+ZaI2qesSCO%Kn<`sx6aZAJ09x{o$X^MXz^==f>Ttql)6;4x6PcJ9 z85kEg-ZyBxW55qg0kXo3jQ?3!4S?y4!9X4)pvod)AjZa_&Bn;e%FfKp#sy@tFgBTU zG4mQUE(fV#WNDml&^V_-;NWtFNAKo)%!_BI57|BMVK-`l^; z$l|!jXj1&_%CbYVjQ+Uo;t%hgtv}_!q2J8xk%N9%L=!%57_O&oFo zzrq?_rZ+qh^=kWZ-C^xkwv3duCzI5ch;}UT&b<*Y5nr*9>(|!@mwxI2FdN_cthgSj(!=1ebdec+~V>Jj)~MRCzdP z>-^{~Yx!3^PI~w{rtPAdw}2>^Wbf$z+f0f0JI`mfaXYrK!k#Zfp>glGK0m4 zVe21FWJf0_($4FVrrjo#C58Cx#2U%f42meD5BK4o-%xL z<5f#iK6Q)r=51=Huy}svaLV$fVC$t`oUEu|Z_@|iL}_NhifBGz{xO17#7d%mNrPZ{xdH8zv()+O$oQZ1@J$aRJMsAsp zwK_f~aw4Y%y^^BVx+7gb3 zCw1_O;~e~ize;7H2C)+%Gh+e8Bf`xl`IDnJ{kvn{A1v=Ex3 zi^@^;1D&dK`2nhPy|V5!uM0F#9f`I?!Voa7{chNH0sy9OU(iP+gG?|HiGUyg#(+^s z6l7CWRD#375Zxdk4q!vW1RMb(G@PBW0q8(H5D6p$41fi#7|3A*aR#IlA#Vb7N`x?L zM@xnjB7~R_x7o>~f7^KI145050TiC(f<;$DW-hg^q@LkWSk~qiJoshKgf-lpI)Q2A zgzldtruj>WYJ{MGDvXZR=&@M7wEG%HY_3zXnvoJ-#j0PTsiVcab=|F29c4z?a-)dy zq-nmUXtV+giW|GXkKfxG_SBD3<={38gf*?Wk7Uj-JKlPnweFL9=5T$p#5A!?Aj#`A zN>YgAd^KN_cX9M^Qk$0g3X!S*>+z^uvBX1bpCLbxfebrz#QkwH4uD{tR#KLSPzP(XSoLNXj$Q z?Gi~BXK5i1l&^2P)STOLSalu~g{9j!ebsghgYAtNaFiU1h$VCK3g~rhw$uibyrw*p zAz*mV%jpu8@^^MOjsI?O{_B?F$eVRtDPe4ZOU&Me>( zajD;uT$gX&+PGGZ&9vOSYkA-$dy^==qFZRc*p4cRuC1eoHuT)ijL|7u7LAbl" }, { "Type": "msi", "Name": "AppInstallerTestMsiInstaller/AppInstallerTestMsiInstaller.msi", - "Input": "%BUILD_SOURCESDIRECTORY%/src/AppInstallerCLIE2ETests/TestData/AppInstallerTestMsiInstaller.msi", + "Input": "%BUILDOUTDIR%/E2ETests/TestData/AppInstallerTestMsiInstaller.msi", "HashToken": "" }, { "Type": "msi", "Name": "AppInstallerTestMsiInstaller/AppInstallerTestMsiInstallerV2.msi", - "Input": "%BUILD_SOURCESDIRECTORY%/src/AppInstallerCLIE2ETests/TestData/AppInstallerTestMsiInstallerV2.msi", + "Input": "%BUILDOUTDIR%/E2ETests/TestData/AppInstallerTestMsiInstallerV2.msi", "HashToken": "" }, { "Type": "msix", "Name": "AppInstallerTestMsixInstaller/AppInstallerTestMsixInstaller.msix", - "Input": "%BUILD_ARTIFACTSTAGINGDIRECTORY%/AppInstallerTestMsixInstaller.msix", + "Input": "%BUILDOUTDIR%/E2ETests/TestData/AppInstallerTestMsixInstaller.msix", "HashToken": "", "SignatureToken": "" } @@ -44,6 +44,7 @@ } ], "Signature": { - "CertFile": "%APPINSTALLERTEST_SECUREFILEPATH%" + "CertFile": "%TestSigningCert_PfxPath%", + "Password": "%TestSigningCert_Password%" } } diff --git a/src/LocalhostWebServer/InstallDevCert.ps1 b/src/LocalhostWebServer/InstallDevCert.ps1 deleted file mode 100644 index 3299d819ea..0000000000 --- a/src/LocalhostWebServer/InstallDevCert.ps1 +++ /dev/null @@ -1,15 +0,0 @@ -param( - [Parameter(Mandatory=$true)] - [string]$pfxpath, - - [Parameter(Mandatory=$true)] - [string]$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 "Root", LocalMachine -$store.Open([System.Security.Cryptography.X509Certificates.OpenFlags]"ReadWrite") -$store.Add($cert) -$store.Close() \ No newline at end of file diff --git a/src/LocalhostWebServer/Program.cs b/src/LocalhostWebServer/Program.cs index 7419830023..11e06a0b58 100644 --- a/src/LocalhostWebServer/Program.cs +++ b/src/LocalhostWebServer/Program.cs @@ -164,7 +164,7 @@ private static void CopyDirectoryRecursive(string sourceDir, string destDir) foreach (string file in files) { string dest = Path.Combine(destDir, Path.GetFileName(file)); - File.Copy(file, dest); + File.Copy(file, dest, overwrite: true); } string[] directories = Directory.GetDirectories(sourceDir); diff --git a/src/LocalhostWebServer/Run-LocalhostWebServer.ps1 b/src/LocalhostWebServer/Run-LocalhostWebServer.ps1 index 6172b0125b..e3fa05c033 100644 --- a/src/LocalhostWebServer/Run-LocalhostWebServer.ps1 +++ b/src/LocalhostWebServer/Run-LocalhostWebServer.ps1 @@ -54,8 +54,19 @@ if (-not [System.String]::IsNullOrEmpty($sourceCert)) Push-Location $BuildRoot -$Local:process = Start-Process -FilePath "LocalhostWebServer.exe" -ArgumentList "StaticFileRoot=$StaticFileRoot CertPath=$CertPath CertPassword=$CertPassword OutCertFile=$OutCertFile LocalSourceJson=$LocalSourceJson TestDataPath=$TestDataPath ExitBeforeRun=$ExitBeforeRun" -PassThru +$startProcessArguments = @{ + FilePath = Join-Path $BuildRoot "LocalhostWebServer.exe" + ArgumentList = "StaticFileRoot=$StaticFileRoot CertPath=$CertPath CertPassword=$CertPassword OutCertFile=$OutCertFile LocalSourceJson=$LocalSourceJson TestDataPath=$TestDataPath ExitBeforeRun=$ExitBeforeRun" + PassThru = $true +} + +if (-not [System.string]::IsNullOrEmpty($env:BUILD_ARTIFACTSTAGINGDIRECTORY)) +{ + $startProcessArguments.RedirectStandardOutput = Join-Path $env:BUILD_ARTIFACTSTAGINGDIRECTORY "LocalhostWebServer.out" + $startProcessArguments.RedirectStandardError = Join-Path $env:BUILD_ARTIFACTSTAGINGDIRECTORY "LocalhostWebServer.err" +} +$Local:process = Start-Process @startProcessArguments if ($ExitBeforeRun) { diff --git a/templates/e2e-setup.yml b/templates/e2e-setup.yml index adb1f496aa..5a5f078abb 100644 --- a/templates/e2e-setup.yml +++ b/templates/e2e-setup.yml @@ -6,33 +6,43 @@ parameters: type: string steps: - - task: DownloadSecureFile@1 - name: AppInstallerTest - displayName: 'Download Source Package Certificate' - inputs: - secureFile: 'AppInstallerTest.pfx' - - - task: DownloadSecureFile@1 - name: HTTPSDevCert - displayName: 'Download Kestrel Certificate' - inputs: - secureFile: 'HTTPSDevCertV2.pfx' - - - task: PowerShell@2 - displayName: Install Root Certificate - inputs: - filePath: '${{ parameters.sourceDir }}\src\LocalhostWebServer\InstallDevCert.ps1' - arguments: '-pfxpath $(HTTPSDevCert.secureFilePath) -password microsoft' - - - task: PowerShell@2 + - pwsh: | + $newCertArguments = @{ + Type = "Custom" + Subject = "CN=Microsoft Corporation, O=Microsoft Corporation, L=Redmond, S=Washington, C=US" + KeyUsage = "DigitalSignature" + TextExtension = @("2.5.29.37={text}1.3.6.1.5.5.7.3.3", "2.5.29.19={text}") + CertStoreLocation = "Cert:\CurrentUser\My" + } + $cert = New-SelfSignedCertificate @newCertArguments + + $certPfxPath = Join-Path $(Agent.TempDirectory) TestSigningCert.pfx + $certCerPath = Join-Path $(Agent.TempDirectory) TestSigningCert.cer + $certPassword = (New-Guid).ToString() + $certSecurePassword = ConvertTo-SecureString $certPassword -AsPlainText + + Export-PfxCertificate -Cert $cert -FilePath $certPfxPath -Password $certSecurePassword + Export-Certificate -Cert $cert -FilePath $certCerPath + + Write-Host "##vso[task.setvariable variable=TestSigningCert.PfxPath;]$certPfxPath" + Write-Host "##vso[task.setvariable variable=TestSigningCert.CerPath;]$certCerPath" + Write-Host "##vso[task.setvariable variable=TestSigningCert.Password;]$certPassword" + displayName: Create test codesigning cert + + - pwsh: | + $httpsCertPath = Join-Path $(Agent.TempDirectory) HttpsCert.pfx + $httpsCertPassword = (New-Guid).ToString() + dotnet dev-certs https --export-path $httpsCertPath --password $httpsCertPassword + + $securePassword = ConvertTo-SecureString $httpsCertPassword -AsPlainText + Import-PfxCertificate -FilePath $httpsCertPath -Password $securePassword -CertStoreLocation Cert:\LocalMachine\Root + + Write-Host "##vso[task.setvariable variable=HttpsCert.Path;]$httpsCertPath" + Write-Host "##vso[task.setvariable variable=HttpsCert.Password;]$httpsCertPassword" + displayName: Create and install localhost HTTPS cert + + - pwsh: ${{ parameters.sourceDir }}\src\LocalhostWebServer\Run-LocalhostWebServer.ps1 -CertPath $(HttpsCert.Path) -CertPassword $(HttpsCert.Password) -OutCertFile $(Agent.TempDirectory)\servercert.cer -SourceCert $(TestSigningCert.CerPath) ${{ parameters.localhostWebServerArgs }} displayName: Launch LocalhostWebServer - inputs: - filePath: '${{ parameters.sourceDir }}\src\LocalhostWebServer\Run-LocalhostWebServer.ps1' - arguments: '-CertPath $(HTTPSDevCert.secureFilePath) -CertPassword microsoft -OutCertFile $(Agent.TempDirectory)\servercert.cer ${{ parameters.localhostWebServerArgs }}' - - task: PowerShell@2 + - pwsh: ${{ parameters.sourceDir }}\src\AppInstallerCLIE2ETests\TestData\Configuration\Init-TestRepository.ps1 -Force displayName: Setup Local PS Repository - inputs: - filePath: '${{ parameters.sourceDir }}\src\AppInstallerCLIE2ETests\TestData\Configuration\Init-TestRepository.ps1' - arguments: '-Force' - pwsh: true diff --git a/templates/e2e-test.template.yml b/templates/e2e-test.template.yml index 9b4e6a4025..5dd8f453da 100644 --- a/templates/e2e-test.template.yml +++ b/templates/e2e-test.template.yml @@ -28,7 +28,7 @@ steps: -AICLIPackagePath $(packageLayoutDir) -AICLIPath wingetdev.exe -LooseFileRegistration true - -StaticFileRootPath $(buildOutDir)\E2ETests\TestLocalIndex + -StaticFileRootPath $(Agent.TempDirectory)\TestLocalIndex -PowerShellModulePath $(buildOutDir)\PowerShell\Microsoft.WinGet.Client\Microsoft.WinGet.Client.psd1 -LocalServerCertPath $(Agent.TempDirectory)\servercert.cer -SkipTestSource true @@ -36,7 +36,7 @@ steps: ${{ else }}: overrideTestrunParameters: '-PackagedContext false -AICLIPath $(packageLayoutDir)\AppInstallerCLI\winget.exe - -StaticFileRootPath $(buildOutDir)\E2ETests\TestLocalIndex + -StaticFileRootPath $(Agent.TempDirectory)\TestLocalIndex -PowerShellModulePath $(buildOutDir)\PowerShell\Microsoft.WinGet.Client\Microsoft.WinGet.Client.psd1 -LocalServerCertPath $(Agent.TempDirectory)\servercert.cer -SkipTestSource true From 9b2cf5e1e17ee3fce0ff5f5acefac54a3f453651 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Wed, 21 Aug 2024 16:34:19 -0700 Subject: [PATCH 2/4] Create local index in build --- azure-pipelines.yml | 29 +++++++++++++------ .../TestData/localsource.json | 8 ++--- templates/e2e-setup.yml | 8 +++-- templates/e2e-test.template.yml | 4 +-- 4 files changed, 32 insertions(+), 17 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 2cb8174392..0341e603ab 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -140,7 +140,7 @@ jobs: platform: '$(buildPlatform)' solution: 'src\AppInstallerTestMsixInstaller\AppInstallerTestMsixInstaller.wapproj' configuration: '$(buildConfiguration)' - msbuildArguments: '/p:AppxPackageOutput="$(artifactsDir)\E2ETests\TestData\AppInstallerTestMsixInstaller.msix" + msbuildArguments: '/p:AppxPackageOutput="$(Build.ArtifactStagingDirectory)\AppInstallerTestMsixInstaller.msix" /p:AppxBundle=Never /p:UapAppxPackageBuildMode=SideLoadOnly /p:AppxPackageSigningEnabled=false' @@ -255,17 +255,28 @@ jobs: SourceFolder: '$(buildOutDir)\LocalhostWebServer' TargetFolder: '$(artifactsDir)\E2ETests\LocalhostWebServer' + # Invoke E2E setup to generate the TestLocalIndex; could optimize out some of its steps if needed + - template: templates/e2e-setup.yml + parameters: + sourceDir: $(Build.SourcesDirectory) + localhostWebServerArgs: '-BuildRoot $(artifactsDir)\E2ETests\LocalhostWebServer -StaticFileRoot $(Agent.TempDirectory)\TestLocalIndex -LocalSourceJson $(Build.SourcesDirectory)\src\AppInstallerCLIE2ETests\TestData\localsource.json -TestDataPath $(Build.SourcesDirectory)\src\AppInstallerCLIE2ETests\TestData -ExitBeforeRun' + - task: CopyFiles@2 - displayName: 'Copy TestData' + displayName: 'Copy Test signing cert' inputs: - SourceFolder: '$(Build.SourcesDirectory)\src\AppInstallerCLIE2ETests\TestData\' - TargetFolder: '$(artifactsDir)\E2ETests\TestData' + Contents: $(Agent.TempDirectory)\TestSigningCert.cer + TargetFolder: '$(artifactsDir)\E2ETests' + + - task: CopyFiles@2 + displayName: 'Copy TestLocalIndex' + inputs: + SourceFolder: '$(Agent.TempDirectory)\TestLocalIndex' + TargetFolder: '$(artifactsDir)\E2ETests\TestLocalIndex' - task: CopyFiles@2 - displayName: 'Copy AppInstallerTestExeInstaller.exe' + displayName: 'Copy TestData' inputs: - Contents: AppInstallerTestExeInstaller.exe - SourceFolder: '$(buildOutDir)\AppInstallerTestExeInstaller' + SourceFolder: '$(Build.SourcesDirectory)\src\AppInstallerCLIE2ETests\TestData\' TargetFolder: '$(artifactsDir)\E2ETests\TestData' - task: CopyFiles@2 @@ -404,7 +415,7 @@ jobs: - template: templates/e2e-setup.yml parameters: sourceDir: $(Build.SourcesDirectory) - localhostWebServerArgs: '-BuildRoot $(buildOutDir)\E2ETests\LocalhostWebServer -StaticFileRoot $(Agent.TempDirectory)\TestLocalIndex -LocalSourceJson $(buildOutDir)\E2ETests\TestData\localsource.json -TestDataPath $(buildOutDir)\E2ETests\TestData' + localhostWebServerArgs: '-BuildRoot $(buildOutDir)\E2ETests\LocalhostWebServer -StaticFileRoot $(buildOutDir)\E2ETests\TestLocalIndex -SourceCert $(buildOutDir)\E2ETests\TestSigningCert.cer' - template: templates/e2e-test.template.yml parameters: @@ -550,7 +561,7 @@ jobs: - template: templates/e2e-setup.yml parameters: sourceDir: $(Build.SourcesDirectory) - localhostWebServerArgs: '-BuildRoot $(buildOutDir)\E2ETests\LocalhostWebServer -StaticFileRoot $(Agent.TempDirectory)\TestLocalIndex -LocalSourceJson $(buildOutDir)\E2ETests\TestData\localsource.json -TestDataPath $(buildOutDir)\E2ETests\TestData' + localhostWebServerArgs: '-BuildRoot $(buildOutDir)\E2ETests\LocalhostWebServer -StaticFileRoot $(buildOutDir)\E2ETests\TestLocalIndex -SourceCert $(buildOutDir)\E2ETests\TestSigningCert.cer' - pwsh: .\RunTests.ps1 -testModulesPath $(Build.ArtifactStagingDirectory) -outputPath $(Pipeline.Workspace)\PesterTest -packageLayoutPath $(buildOutDir)\DevPackage workingDirectory: $(Build.SourcesDirectory)\src\PowerShell\tests\ diff --git a/src/AppInstallerCLIE2ETests/TestData/localsource.json b/src/AppInstallerCLIE2ETests/TestData/localsource.json index 5e7349a880..77eb3bd41d 100644 --- a/src/AppInstallerCLIE2ETests/TestData/localsource.json +++ b/src/AppInstallerCLIE2ETests/TestData/localsource.json @@ -8,25 +8,25 @@ { "Type": "exe", "Name": "AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.exe", - "Input": "%BUILDOUTDIR%/E2ETests/TestData/AppInstallerTestExeInstaller.exe", + "Input": "%BUILDOUTDIR%/AppInstallerTestExeInstaller/AppInstallerTestExeInstaller.exe", "HashToken": "" }, { "Type": "msi", "Name": "AppInstallerTestMsiInstaller/AppInstallerTestMsiInstaller.msi", - "Input": "%BUILDOUTDIR%/E2ETests/TestData/AppInstallerTestMsiInstaller.msi", + "Input": "%BUILD_SOURCESDIRECTORY%/src/AppInstallerCLIE2ETests/TestData/AppInstallerTestMsiInstaller.msi", "HashToken": "" }, { "Type": "msi", "Name": "AppInstallerTestMsiInstaller/AppInstallerTestMsiInstallerV2.msi", - "Input": "%BUILDOUTDIR%/E2ETests/TestData/AppInstallerTestMsiInstallerV2.msi", + "Input": "%BUILD_SOURCESDIRECTORY%/src/AppInstallerCLIE2ETests/TestData/AppInstallerTestMsiInstallerV2.msi", "HashToken": "" }, { "Type": "msix", "Name": "AppInstallerTestMsixInstaller/AppInstallerTestMsixInstaller.msix", - "Input": "%BUILDOUTDIR%/E2ETests/TestData/AppInstallerTestMsixInstaller.msix", + "Input": "%BUILD_ARTIFACTSTAGINGDIRECTORY%/AppInstallerTestMsixInstaller.msix", "HashToken": "", "SignatureToken": "" } diff --git a/templates/e2e-setup.yml b/templates/e2e-setup.yml index 5a5f078abb..97893d0e99 100644 --- a/templates/e2e-setup.yml +++ b/templates/e2e-setup.yml @@ -41,8 +41,12 @@ steps: Write-Host "##vso[task.setvariable variable=HttpsCert.Password;]$httpsCertPassword" displayName: Create and install localhost HTTPS cert - - pwsh: ${{ parameters.sourceDir }}\src\LocalhostWebServer\Run-LocalhostWebServer.ps1 -CertPath $(HttpsCert.Path) -CertPassword $(HttpsCert.Password) -OutCertFile $(Agent.TempDirectory)\servercert.cer -SourceCert $(TestSigningCert.CerPath) ${{ parameters.localhostWebServerArgs }} + - pwsh: ${{ parameters.sourceDir }}\src\LocalhostWebServer\Run-LocalhostWebServer.ps1 -CertPath $(HttpsCert.Path) -CertPassword $(HttpsCert.Password) -OutCertFile $(Agent.TempDirectory)\servercert.cer ${{ parameters.localhostWebServerArgs }} displayName: Launch LocalhostWebServer - - pwsh: ${{ parameters.sourceDir }}\src\AppInstallerCLIE2ETests\TestData\Configuration\Init-TestRepository.ps1 -Force + - task: PowerShell@2 displayName: Setup Local PS Repository + inputs: + filePath: '${{ parameters.sourceDir }}\src\AppInstallerCLIE2ETests\TestData\Configuration\Init-TestRepository.ps1' + arguments: '-Force' + pwsh: true diff --git a/templates/e2e-test.template.yml b/templates/e2e-test.template.yml index 5dd8f453da..9b4e6a4025 100644 --- a/templates/e2e-test.template.yml +++ b/templates/e2e-test.template.yml @@ -28,7 +28,7 @@ steps: -AICLIPackagePath $(packageLayoutDir) -AICLIPath wingetdev.exe -LooseFileRegistration true - -StaticFileRootPath $(Agent.TempDirectory)\TestLocalIndex + -StaticFileRootPath $(buildOutDir)\E2ETests\TestLocalIndex -PowerShellModulePath $(buildOutDir)\PowerShell\Microsoft.WinGet.Client\Microsoft.WinGet.Client.psd1 -LocalServerCertPath $(Agent.TempDirectory)\servercert.cer -SkipTestSource true @@ -36,7 +36,7 @@ steps: ${{ else }}: overrideTestrunParameters: '-PackagedContext false -AICLIPath $(packageLayoutDir)\AppInstallerCLI\winget.exe - -StaticFileRootPath $(Agent.TempDirectory)\TestLocalIndex + -StaticFileRootPath $(buildOutDir)\E2ETests\TestLocalIndex -PowerShellModulePath $(buildOutDir)\PowerShell\Microsoft.WinGet.Client\Microsoft.WinGet.Client.psd1 -LocalServerCertPath $(Agent.TempDirectory)\servercert.cer -SkipTestSource true From d926ed0f6319a50844ac428d01c1eeb8097401d5 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Wed, 21 Aug 2024 17:30:49 -0700 Subject: [PATCH 3/4] Fix localhost server log path --- azure-pipelines.yml | 3 ++- src/LocalhostWebServer/Run-LocalhostWebServer.ps1 | 6 +++--- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 0341e603ab..2867d6d783 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -264,7 +264,8 @@ jobs: - task: CopyFiles@2 displayName: 'Copy Test signing cert' inputs: - Contents: $(Agent.TempDirectory)\TestSigningCert.cer + Contents: | + $(Agent.TempDirectory)\TestSigningCert.cer TargetFolder: '$(artifactsDir)\E2ETests' - task: CopyFiles@2 diff --git a/src/LocalhostWebServer/Run-LocalhostWebServer.ps1 b/src/LocalhostWebServer/Run-LocalhostWebServer.ps1 index e3fa05c033..d3d0352038 100644 --- a/src/LocalhostWebServer/Run-LocalhostWebServer.ps1 +++ b/src/LocalhostWebServer/Run-LocalhostWebServer.ps1 @@ -60,10 +60,10 @@ $startProcessArguments = @{ PassThru = $true } -if (-not [System.string]::IsNullOrEmpty($env:BUILD_ARTIFACTSTAGINGDIRECTORY)) +if (-not [System.string]::IsNullOrEmpty($env:artifactsDir)) { - $startProcessArguments.RedirectStandardOutput = Join-Path $env:BUILD_ARTIFACTSTAGINGDIRECTORY "LocalhostWebServer.out" - $startProcessArguments.RedirectStandardError = Join-Path $env:BUILD_ARTIFACTSTAGINGDIRECTORY "LocalhostWebServer.err" + $startProcessArguments.RedirectStandardOutput = Join-Path $env:artifactsDir "LocalhostWebServer.out" + $startProcessArguments.RedirectStandardError = Join-Path $env:artifactsDir "LocalhostWebServer.err" } $Local:process = Start-Process @startProcessArguments From 7fe612e90c06f6e9bf3e0e061d756e98b911fb85 Mon Sep 17 00:00:00 2001 From: Flor Elisa Chacon Ochoa Date: Wed, 21 Aug 2024 21:30:32 -0700 Subject: [PATCH 4/4] Create cert in location --- azure-pipelines.yml | 8 +------- templates/e2e-setup.yml | 5 ++++- 2 files changed, 5 insertions(+), 8 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 2867d6d783..250b63f452 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -260,13 +260,7 @@ jobs: parameters: sourceDir: $(Build.SourcesDirectory) localhostWebServerArgs: '-BuildRoot $(artifactsDir)\E2ETests\LocalhostWebServer -StaticFileRoot $(Agent.TempDirectory)\TestLocalIndex -LocalSourceJson $(Build.SourcesDirectory)\src\AppInstallerCLIE2ETests\TestData\localsource.json -TestDataPath $(Build.SourcesDirectory)\src\AppInstallerCLIE2ETests\TestData -ExitBeforeRun' - - - task: CopyFiles@2 - displayName: 'Copy Test signing cert' - inputs: - Contents: | - $(Agent.TempDirectory)\TestSigningCert.cer - TargetFolder: '$(artifactsDir)\E2ETests' + signingCertOutDir: $(artifactsDir)\E2ETests - task: CopyFiles@2 displayName: 'Copy TestLocalIndex' diff --git a/templates/e2e-setup.yml b/templates/e2e-setup.yml index 97893d0e99..bbdaf25562 100644 --- a/templates/e2e-setup.yml +++ b/templates/e2e-setup.yml @@ -4,6 +4,9 @@ parameters: type: string - name: localhostWebServerArgs type: string +- name: signingCertOutDir + type: string + default: $(Agent.TempDirectory) steps: - pwsh: | @@ -17,7 +20,7 @@ steps: $cert = New-SelfSignedCertificate @newCertArguments $certPfxPath = Join-Path $(Agent.TempDirectory) TestSigningCert.pfx - $certCerPath = Join-Path $(Agent.TempDirectory) TestSigningCert.cer + $certCerPath = Join-Path ${{ parameters.signingCertOutDir }} TestSigningCert.cer $certPassword = (New-Guid).ToString() $certSecurePassword = ConvertTo-SecureString $certPassword -AsPlainText