mirror of
https://github.com/rcourtman/Pulse.git
synced 2026-09-10 02:25:56 +00:00
ci(signing): bound certificate store mutation
This commit is contained in:
@@ -158,23 +158,59 @@ jobs:
|
||||
$certificate.Export([Security.Cryptography.X509Certificates.X509ContentType]::Cert)
|
||||
)
|
||||
|
||||
function Invoke-BoundedCertUtil {
|
||||
param(
|
||||
[Parameter(Mandatory)] [string[]] $Arguments,
|
||||
[Parameter(Mandatory)] [string] $Description
|
||||
)
|
||||
|
||||
$startInfo = [Diagnostics.ProcessStartInfo]::new()
|
||||
$startInfo.FileName = Join-Path $env:SystemRoot 'System32\certutil.exe'
|
||||
$startInfo.UseShellExecute = $false
|
||||
$startInfo.RedirectStandardOutput = $true
|
||||
$startInfo.RedirectStandardError = $true
|
||||
foreach ($argument in $Arguments) {
|
||||
[void] $startInfo.ArgumentList.Add($argument)
|
||||
}
|
||||
|
||||
$process = [Diagnostics.Process]::new()
|
||||
$process.StartInfo = $startInfo
|
||||
try {
|
||||
if (-not $process.Start()) {
|
||||
throw "Failed to start certutil for $Description."
|
||||
}
|
||||
$stdout = $process.StandardOutput.ReadToEndAsync()
|
||||
$stderr = $process.StandardError.ReadToEndAsync()
|
||||
if (-not $process.WaitForExit(30000)) {
|
||||
$process.Kill($true)
|
||||
$process.WaitForExit()
|
||||
throw "certutil timed out after 30 seconds while $Description."
|
||||
}
|
||||
$stdoutText = $stdout.GetAwaiter().GetResult()
|
||||
$stderrText = $stderr.GetAwaiter().GetResult()
|
||||
if (-not [string]::IsNullOrWhiteSpace($stdoutText)) { Write-Host $stdoutText.TrimEnd() }
|
||||
if (-not [string]::IsNullOrWhiteSpace($stderrText)) { Write-Warning $stderrText.TrimEnd() }
|
||||
if ($process.ExitCode -ne 0) {
|
||||
throw "certutil failed while $Description with exit code $($process.ExitCode)."
|
||||
}
|
||||
}
|
||||
finally {
|
||||
$process.Dispose()
|
||||
}
|
||||
}
|
||||
|
||||
$trustedStoreNames = @()
|
||||
try {
|
||||
foreach ($storeName in @('Root', 'TrustedPublisher')) {
|
||||
Write-Host "Adding test signer $thumbprint to CurrentUser/$storeName on the ephemeral runner."
|
||||
$store = [Security.Cryptography.X509Certificates.X509Store]::new(
|
||||
Invoke-BoundedCertUtil -Arguments @(
|
||||
'-user',
|
||||
'-f',
|
||||
'-addstore',
|
||||
$storeName,
|
||||
[Security.Cryptography.X509Certificates.StoreLocation]::CurrentUser
|
||||
)
|
||||
try {
|
||||
$store.Open([Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
|
||||
$store.Add($certificate)
|
||||
$trustedStoreNames += $storeName
|
||||
}
|
||||
finally {
|
||||
$store.Close()
|
||||
$store.Dispose()
|
||||
}
|
||||
$certificatePath
|
||||
) -Description "adding the test signer to CurrentUser/$storeName"
|
||||
$trustedStoreNames += $storeName
|
||||
}
|
||||
|
||||
Write-Host 'Locating signtool.exe.'
|
||||
@@ -210,6 +246,7 @@ jobs:
|
||||
$stderr = $process.StandardError.ReadToEndAsync()
|
||||
if (-not $process.WaitForExit(90000)) {
|
||||
$process.Kill($true)
|
||||
$process.WaitForExit()
|
||||
throw "SignTool verification timed out after 90 seconds for $ArtifactPath."
|
||||
}
|
||||
$stdoutText = $stdout.GetAwaiter().GetResult()
|
||||
@@ -270,18 +307,13 @@ jobs:
|
||||
}
|
||||
finally {
|
||||
foreach ($storeName in $trustedStoreNames) {
|
||||
$store = [Security.Cryptography.X509Certificates.X509Store]::new(
|
||||
Write-Host "Removing test signer $thumbprint from CurrentUser/$storeName."
|
||||
Invoke-BoundedCertUtil -Arguments @(
|
||||
'-user',
|
||||
'-delstore',
|
||||
$storeName,
|
||||
[Security.Cryptography.X509Certificates.StoreLocation]::CurrentUser
|
||||
)
|
||||
try {
|
||||
$store.Open([Security.Cryptography.X509Certificates.OpenFlags]::ReadWrite)
|
||||
$store.Remove($certificate)
|
||||
}
|
||||
finally {
|
||||
$store.Close()
|
||||
$store.Dispose()
|
||||
}
|
||||
$thumbprint
|
||||
) -Description "removing the test signer from CurrentUser/$storeName"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -529,8 +529,12 @@ class ReleasePromotionPolicyTest(unittest.TestCase):
|
||||
self.assertIn("signedArtifactsUploadedAsGitHubArtifact = $false", workflow)
|
||||
self.assertIn("nonProduction = $true", workflow)
|
||||
self.assertIn("WaitForExit(90000)", workflow)
|
||||
self.assertIn("X509Store]::new", workflow)
|
||||
self.assertIn("OpenFlags]::ReadWrite", workflow)
|
||||
self.assertIn("System32\\certutil.exe", workflow)
|
||||
self.assertIn("WaitForExit(30000)", workflow)
|
||||
self.assertIn("certutil timed out after 30 seconds", workflow)
|
||||
self.assertIn("'-addstore'", workflow)
|
||||
self.assertIn("'-delstore'", workflow)
|
||||
self.assertNotIn("X509Store]::new", workflow)
|
||||
self.assertNotIn("Import-Certificate", workflow)
|
||||
self.assertIn("path: signpath-test-signing-evidence.json", workflow)
|
||||
self.assertEqual(
|
||||
|
||||
Reference in New Issue
Block a user