Skip to content

(#281) Prevents Creation Of Unrequired Self-Signed Certificate #96

(#281) Prevents Creation Of Unrequired Self-Signed Certificate

(#281) Prevents Creation Of Unrequired Self-Signed Certificate #96

Workflow file for this run

name: Test Deployment
on:
workflow_dispatch:
inputs:
ignore_cache:
description: Does not restore a package cache if selected.
required: false
type: boolean
vm_size:
description: The size of VM to spin up.
default: Standard_B4ms # Standard_B4as_v2
images:
description: The Azure images to test on.
default: Win2022AzureEditionCore, Win2019Datacenter
type: string
variants:
description: The configurations to test with.
default: self-signed, single, wildcard
pull_request_target:
paths-ignore:
- .github/workflows/**
types:
- opened
- reopened
- synchronize
- ready_for_review
# May want to remove this, as though it's neat to only have one job running per
# ref, it may cancel before cleanup has happened.
# concurrency:
# group: ${{ github.workflow }}-${{ github.ref }}
# cancel-in-progress: true
defaults:
run:
shell: pwsh
jobs:
matrix:
name: Generate Testing Parameters
runs-on: ubuntu-latest
steps:
- name: Generate Test Matrix
id: test-matrix
shell: pwsh
run: |
$EventType = '${{ github.event_name }}'
$AuthHeaders = @{Headers = @{Authorization = 'Bearer ${{ secrets.GITHUB_TOKEN }}'}}
$GitHubApi = '${{ github.api_url }}'
switch ($EventType) {
'workflow_dispatch' {
# We have been triggered manually. Run the inputs!
$Images = (-split '${{ inputs.images }}').Trim(',;')
$Variants = (-split '${{ inputs.variants }}').Trim(',;')
}
'pull_request_target' {
# This is a pull request. If it's from a known maintainer, run a test - otherwise, exit.
$Trigger = Invoke-RestMethod "$GitHubApi/repos/${{ github.repository }}/collaborators/${{ github.actor }}/permission" @AuthHeaders
if ($Trigger.Permission -in @("admin", "write")) {
$Images = "Win2022AzureEditionCore", "Win2019Datacenter"
$Variants = "self-signed", "single", "wildcard"
} else {
Write-Error "Action was triggered by '${{ github.actor }}', who has '$TriggerPermission': Cancelling build."
exit 1
}
}
}
"images=$($Images | ConvertTo-Json -Compress -AsArray)" >> $env:GITHUB_OUTPUT
"variants=$($Variants | ConvertTo-Json -Compress -AsArray)" >> $env:GITHUB_OUTPUT
outputs:
matrix-os: ${{ steps.test-matrix.outputs.images }}
matrix-variant: ${{ steps.test-matrix.outputs.variants }}
build:
name: Build Package Cache
needs: matrix
if: success()
runs-on: windows-latest
steps:
- name: Check out code
uses: actions/checkout@v4
with:
ref: "refs/pull/${{ github.event.number }}/merge"
- name: Create License File
run: |
if (-not (Test-Path C:\choco-setup\files)) {
New-Item -Path C:\choco-setup\files -ItemType Junction -Value $PWD.Path
}
$LicenseDir = Join-Path $env:ChocolateyInstall 'license'
if (-not (Test-Path $LicenseDir)) {$null = mkdir $LicenseDir}
Set-Content -Path $LicenseDir\chocolatey.license.xml -Value $(
[System.Text.Encoding]::UTF8.GetString(
[System.Convert]::FromBase64String('${{ secrets.LICENSE }}')
)
)
- name: Setup Package Cache
uses: actions/cache@v4
if: inputs.ignore_cache != true
with:
path: |
C:/choco-setup/files/files/*.nupkg
C:/choco-setup/files/files/*.zip
!**/chocolatey-license.*.nupkg
key: "${{ hashFiles('files/*.json') }}"
- name: Begin Setup
run: C:\choco-setup\files\OfflineInstallPreparation.ps1
- name: Upload Built Artifact
id: build-upload
uses: actions/upload-artifact@v4
with:
name: choco-packages
path: |
C:\choco-setup\files\*
!C:\choco-setup\files\.git*
!chocolatey-license.*.nupkg
!C:\choco-setup\files\files\chocolatey.license.xml
outputs:
artifact-url: ${{ steps.build-upload.outputs.artifact-url }}
runner_test_deploy:
strategy:
matrix:
os: ${{ fromJson(needs.matrix.outputs.matrix-os) }}
variant: ${{ fromJson(needs.matrix.outputs.matrix-variant) }}
fail-fast: false
name: ${{ matrix.os }} with ${{ matrix.variant }} certificate
runs-on: windows-latest
needs: [build, matrix]
if: success()
steps:
- name: Check out code
uses: actions/checkout@v4
with:
ref: "refs/pull/${{ github.event.number }}/merge"
- name: Login to Azure
uses: azure/login@v2
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
enable-AzPSSession: true
- name: Deploy '${{ matrix.os }}' VM
id: deploy-vm
uses: azure/powershell@v2
with:
inlineScript: |
Import-Module .\.github\workflows\Helpers.psm1
$Location = 'eastus2'
$ResourceGroupName = "qsg-testing"
if ('${{ github.run_id }}' -ne "`$`{{ github.run_id }}") {$ResourceGroupName += '-${{ github.run_id }}'}
if (-not (Get-AzResourceGroup -ResourceGroupName $ResourceGroupName -ErrorAction SilentlyContinue)) {
$null = New-AzResourceGroup -ResourceGroupName $ResourceGroupName -Location $Location -Force -Tag @{
CreatedBy = '${{ github.triggering_actor }}'
Ref = '${{ github.ref }}'
Until = (Get-Date (Get-Date).AddHours(1) -F 'yyyy/MM/dd')
Commit = '${{ github.sha }}'
}
}
$VMArgs = @{
Image = '${{ matrix.os }}'
Size = [string]::IsNullOrEmpty('${{ inputs.vm_size }}') ? 'Standard_B4as_v2' : '${{ inputs.vm_size }}'
}
try {
$VM = New-TestVM -ResourceGroupName $ResourceGroupName @VMArgs
# Set NSG to have access
Request-WinRmAccessForTesting -ResourceGroupName $ResourceGroupName -VmName $VM.Name
$Session = New-HoplessRemotingSession -ComputerName $Vm.FullyQualifiedDomainName -Credential $Vm.Credential
} catch {
if ($VM) {
$VM | Remove-AzVm -AsJob -Force -Confirm:$false
}
# Try again...
$VM = New-TestVM -ResourceGroupName $ResourceGroupName @VMArgs
# Set NSG to have access
Request-WinRmAccessForTesting -ResourceGroupName $ResourceGroupName -VmName $VM.Name
$Session = New-HoplessRemotingSession -ComputerName $Vm.FullyQualifiedDomainName -Credential $Vm.Credential
}
# Windows Server 2019 may require Dotnet 4.8 to be installed, and have a reboot
$DotnetInstall = Install-Dotnet -Session $Session
if ($DotnetInstall -eq 1641 -or $DotnetInstall -eq 3010) {
Write-Host ".NET Framework 4.8 was installed, but a reboot is required before using Chocolatey CLI."
$Reboot = Restart-AzVm -ResourceGroupName $ResourceGroupName -Name $VM.Name
if ($Reboot.Status -eq 'Succeeded') {
Write-Host "Reboot was successful after $($Reboot.Endtime - $Reboot.Starttime)"
}
# Recreate the session
$Session = New-HoplessRemotingSession -ComputerName $Vm.FullyQualifiedDomainName -Credential $Vm.Credential
}
try {
$DownloadUrl = if ('${{ needs.build.outputs.artifact-url }}' -match 'https://github.com/(?<Owner>.+)/(?<Repository>.+)/actions/runs/(?<RunId>\d+)/artifacts/(?<ArtifactId>\d+)') {
"https://api.github.com/repos/$($Matches.Owner)/$($Matches.Repository)/actions/artifacts/$($Matches.ArtifactId)/zip"
} else {
'${{ needs.build.outputs.artifact-url }}'
}
Write-Host "Downloading Build Artifact '$DownloadUrl' to '$($VM.Name)' @$(Get-Date -Format o)"
Invoke-Command -Session $Session -ScriptBlock {
if (-not (Test-Path C:\choco-setup\files)) {$null = mkdir C:\choco-setup\files -Force}
$ProgressPreference = "SilentlyContinue"
$Response = Invoke-WebRequest -Uri $using:DownloadUrl -UseBasicParsing -Headers @{
Authorization = "Bearer ${{ secrets.GITHUB_TOKEN }}"
Accept = "application/vnd.github+json"
"X-GitHub-Api-Version" = "2022-11-28"
} -OutFile C:\choco-setup\files.zip
Expand-Archive -Path C:\choco-setup\files.zip -DestinationPath C:\choco-setup\files\
}
} finally {
Write-Host "Finished Downloading @$(Get-Date -Format o)"
}
Write-Host "Creating License File on '$($VM.Name)'"
Invoke-Command -Session $Session -ScriptBlock {
Set-Content -Path C:\choco-setup\files\files\chocolatey.license.xml -Value $(
[System.Text.Encoding]::UTF8.GetString(
[System.Convert]::FromBase64String('${{ secrets.LICENSE }}')
)
)
}
Write-Host "Setting up '${{ matrix.variant }}' Certificate"
$Certificate = switch ('${{ matrix.variant }}') {
'self-signed' {
Write-Host "Using a Self-Signed Certificate for '$($Vm.Name)'"
$CertDetails = @{FQDN = $Vm.Name}
@{}
}
'single' {
$CertDetails = Invoke-Command -Session $Session -ScriptBlock {
$Cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new(
[Convert]::FromBase64String('${{ secrets.SINGLE_CERT }}'),
(ConvertTo-SecureString '${{ secrets.SINGLE_PASS }}' -AsPlainText -Force),
("Exportable", "PersistKeySet", "MachineKeySet")
)
$Store = [System.Security.Cryptography.X509Certificates.X509Store]::new("TrustedPeople", "LocalMachine")
$Store.Open("ReadWrite")
$null = $Store.Add($Cert)
Add-Content $env:windir\system32\drivers\etc\hosts -Value "127.0.0.1 $($Cert.Subject -replace '^CN=')"
@{
Thumbprint = $Cert.Thumbprint
FQDN = $Cert.Subject -replace '^CN='
}
}
Write-Host "Using Certificate with Thumbprint '$($Thumbprint)'"
@{Thumbprint = $CertDetails.Thumbprint}
}
'wildcard' {
$CertDetails = Invoke-Command -Session $Session -ScriptBlock {
$Cert = [System.Security.Cryptography.X509Certificates.X509Certificate2]::new(
[Convert]::FromBase64String('${{ secrets.WILDCARD_CERT }}'),
(ConvertTo-SecureString '${{ secrets.WILDCARD_PASS }}' -AsPlainText -Force),
("Exportable", "PersistKeySet", "MachineKeySet")
)
$Store = [System.Security.Cryptography.X509Certificates.X509Store]::new("TrustedPeople", "LocalMachine")
$Store.Open("ReadWrite")
$null = $Store.Add($Cert)
Add-Content $env:windir\system32\drivers\etc\hosts -Value "127.0.0.1 $($Cert.Subject -replace '^CN=\*',$env:ComputerName)"
@{
Thumbprint = $Cert.Thumbprint
FQDN = $Cert.Subject -replace '^CN=\*',$env:ComputerName
}
}
Write-Host "Using Wildcard with Thumbprint '$($Thumbprint)'"
@{Thumbprint = $CertDetails.Thumbprint; CertificateDnsName = $CertDetails.FQDN}
}
}
try {
Write-Host "Installing QuickStart Guide on '$($VM.Name)'"
$DatabaseCredential = [PSCredential]::new(
'ccmdbuser',
(ConvertTo-SecureString "$(New-Guid)" -AsPlainText -Force)
)
$Timer = [System.Diagnostics.Stopwatch]::StartNew()
Invoke-Command -Session $Session -ScriptBlock {
C:\choco-setup\files\Start-C4bSetup.ps1
C:\choco-setup\files\Start-C4BNexusSetup.ps1
C:\choco-setup\files\Start-C4bCcmSetup.ps1 -DatabaseCredential $using:DatabaseCredential
C:\choco-setup\files\Start-C4bJenkinsSetup.ps1
C:\choco-setup\files\Set-SslSecurity.ps1 @using:Certificate
}
$Timer.Stop()
"deployment-time=$($Timer.Elapsed)" >> $env:GITHUB_OUTPUT
# Run Tests
Write-Host "Running Verification Tests on '$($VM.Name)'"
$RemotingArgs = @{
ComputerName = $VM.FullyQualifiedDomainName
Credential = $VM.Credential
UseSSL = $true
SessionOption = New-PSSessionOption -SkipCACheck -SkipCNCheck
}
$TestResults = Invoke-Command -Session $Session -ScriptBlock {
if (-not (Get-Module Pester -ListAvailable).Where{$_.Version -gt "5.0"}) {
Write-Host "Installing Pester 5 to run validation tests"
$chocoArgs = @('install', 'pester', '-y', '--source="ChocolateyInternal"', '--no-progress')
& choco @chocoArgs | Write-Host
}
(Get-ChildItem C:\choco-setup\files\tests\ -Recurse -Filter *.tests.ps1).Fullname
} | ForEach-Object {
Invoke-Command @RemotingArgs -ScriptBlock {
param(
$Path
)
Import-Module C:\choco-setup\files\modules\C4B-Environment
$configuration = New-PesterConfiguration @{
Run = @{
Container = New-PesterContainer -Path $Path -Data @{ Fqdn = $using:CertDetails.FQDN }
Passthru = $true
}
Output = @{
Verbosity = 'Detailed'
}
TestResult = @{
Enabled = $true
OutputFormat = 'NUnitXml'
OutputPath = "C:\choco-setup\test-results\${{ matrix.os }}-${{ matrix.variant }}-$((Split-Path $Path -Leaf) -replace '.tests.ps1$')-verification.results.xml"
}
}
Invoke-Pester -Configuration $configuration
} -ArgumentList $_
}
} finally {
Write-Host "Copying Results from '$($VM.Name)' @$(Get-Date -Format o)"
if (-not (Test-Path .\logs\ -PathType Container)) {$null = mkdir .\logs\}
Copy-Item -FromSession $Session -Path C:\choco-setup\logs\* -Destination .\logs\ -ErrorAction SilentlyContinue
Copy-Item -FromSession $Session -Path C:\choco-setup\test-results\* -Destination .\logs\ -ErrorAction SilentlyContinue
}
azPSVersion: latest
- name: Publish Test Results
uses: EnricoMi/publish-unit-test-result-action/windows@v2
if: success()
with:
check_name: C4bVerification-${{ matrix.os }}-${{ matrix.variant }}
comment_mode: failures
files: |
logs\*-verification.results.xml
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Publish Log Files
uses: actions/upload-artifact@v4
if: success() || failure()
with:
name: choco-setup-logs-${{ matrix.os }}-${{ matrix.variant }}
path: logs\*.txt
cleanup:
name: Cleanup Test Resources
runs-on: ubuntu-latest
needs: [build, runner_test_deploy]
if: always()
steps:
- name: Login to Azure
uses: azure/login@v2
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
enable-AzPSSession: true
- name: Destroy Remaining Resources
uses: azure/powershell@v2
with:
inlineScript: |
if ('${{ needs.build.outputs.artifact-url }}' -match 'https://github.com/(?<Owner>.+)/(?<Repository>.+)/actions/runs/(?<RunId>\d+)/artifacts/(?<ArtifactId>\d+)') {
$DeleteArgs = @{
Uri = "https://api.github.com/repos/$($Matches.Owner)/$($Matches.Repository)/actions/artifacts/$($Matches.ArtifactId)"
Method = "DELETE"
Headers = @{
Authorization = "Bearer ${{ secrets.GITHUB_TOKEN }}"
Accept = "application/vnd.github+json"
"X-GitHub-Api-Version" = "2022-11-28"
}
}
Invoke-RestMethod @DeleteArgs -ErrorAction SilentlyContinue
}
$ResourceGroupName = "qsg-testing"
if ('${{ github.run_id }}' -ne "`$`{{ github.run_id }}") {$ResourceGroupName += '-${{ github.run_id }}'}
if (Get-AzResourceGroup -ResourceGroupName $ResourceGroupName -ErrorAction SilentlyContinue) {
Remove-AzResourceGroup -ResourceGroupName $ResourceGroupName -Force
}
azPSVersion: latest