-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add GitHub Workflow Actions and Bug Fixes (#13)
1. Moves the CI-build pipeline from Azure DevOps to GitHub Actions 2. Add SDL compliance (using DevSkim) pipeline 3. Add release pipeline - Updates the manifest version - Signs the PowerShell scripts - Creates a GitHub release - Publishes the module to the PowerShell Gallery 4. Fix PSScriptAnalyzer issues 5. Bug fixes - Suppress nested confirm prompts Co-authored-by: TinaMor <[email protected]>
- Loading branch information
Showing
29 changed files
with
1,253 additions
and
364 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,64 @@ | ||
########################################################################### | ||
# # | ||
# Copyright (c) Microsoft Corporation. All rights reserved. # | ||
# # | ||
# This code is licensed under the MIT License (MIT). # | ||
# # | ||
########################################################################### | ||
|
||
name: Sign PowerShell Scripts | ||
description: Sign PowerShell scripts in the Containers-Toolkit repository | ||
|
||
inputs: | ||
Directory: | ||
description: The directory containing files to sign | ||
default: "./" | ||
required: false | ||
AzureKeyVaultUrl: | ||
description: "The URL to an Azure Key Vault." | ||
required: true | ||
AzureKeyVaultClientId: | ||
description: "The Client ID (Application ID) to authenticate to the Azure Key Vault." | ||
required: true | ||
AzureKeyVaultClientSecret: | ||
description: "The client secret of your Azure application to authenticate to the Azure Key Vault." | ||
required: true | ||
AzureKeyVaultTenantId: | ||
description: "The Tenant Id to authenticate to the Azure Key Vault." | ||
required: true | ||
AzureKeyVaultCertificate: | ||
description: "The name of the certificate in Azure Key Vault." | ||
required: true | ||
|
||
runs: | ||
using: "composite" | ||
steps: | ||
- name: Setup .NET Core # Required to execute ReportGenerator | ||
uses: actions/setup-dotnet@v3 | ||
with: | ||
dotnet-version: 8.x | ||
dotnet-quality: "ga" | ||
|
||
- uses: actions/cache@v3 | ||
with: | ||
path: ~/.dotnet/tools | ||
# Look to see if there is a cache hit for the corresponding requirements file | ||
key: ${{ runner.os }}-nuget-azuresigntool | ||
|
||
- name: Install AzureSignTool | ||
shell: pwsh | ||
run: dotnet tool install --global AzureSignTool | ||
|
||
# https://learn.microsoft.com/en-us/windows/msix/desktop/cicd-keyvault | ||
# https://learn.microsoft.com/en-us/previous-versions/windows/hardware/design/dn653556(v=vs.85) | ||
- name: Sign PowerShell scripts | ||
shell: pwsh | ||
run: | | ||
$akvParams = @{ | ||
'AzureKeyVaultClientId' = ${{ inputs.AzureKeyVaultClientId }} | ||
'AzureKeyVaultTenantId' = ${{ inputs.AzureKeyVaultTenantId }} | ||
'AzureKeyVaultClientSecret' = ${{ inputs.AzureKeyVaultClientSecret }} | ||
'AzureKeyVaultUrl' = ${{ inputs.AzureKeyVaultUrl }} | ||
'AzureKeyVaultCertificate' = ${{ inputs.AzureKeyVaultCertificate }} | ||
} | ||
.github/actions/sign-scripts/sign-scripts.ps1 -Directory "${{ inputs.Directory }}" @akvParams |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
########################################################################### | ||
# # | ||
# Copyright (c) Microsoft Corporation. All rights reserved. # | ||
# # | ||
# This code is licensed under the MIT License (MIT). # | ||
# # | ||
########################################################################### | ||
|
||
<# | ||
.SYNOPSIS | ||
Sign PowerShell scripts (ps1, psm1, psd1, ps1xml) using AzureSignTool. | ||
.PARAMETER Directory | ||
Directory containing PowerShell script files. | ||
Defaults to the current working directory (.). | ||
.PARAMETER AzureKeyVaultUrl | ||
The URL to an Azure Key Vault. | ||
.PARAMETER AzureKeyVaultClientId | ||
The Client ID (Application ID) to authenticate to the Azure Key Vault. | ||
.PARAMETER AzureKeyVaultClientSecret | ||
The client secret of your Azure application to authenticate to the Azure Key Vault. | ||
.PARAMETER AzureKeyVaultTenantId | ||
The Tenant Id to authenticate to the Azure Key Vault. | ||
.PARAMETER AzureKeyVaultCertificate | ||
The name of the certificate in Azure Key Vault. | ||
#> | ||
|
||
|
||
[CmdletBinding()] | ||
param ( | ||
[Parameter(Mandatory = $false)] | ||
[String]$Directory = ".", | ||
[Parameter(Mandatory = $true)] | ||
[String]$AzureKeyVaultUrl, | ||
[Parameter(Mandatory = $true)] | ||
[String]$AzureKeyVaultClientId, | ||
[Parameter(Mandatory = $true)] | ||
[String]$AzureKeyVaultClientSecret, | ||
[Parameter(Mandatory = $true)] | ||
[String]$AzureKeyVaultTenantId, | ||
[Parameter(Mandatory = $true)] | ||
[String]$AzureKeyVaultCertificate | ||
) | ||
|
||
$Script:Directory = $Directory | ||
$Script:AzureKeyVaultUrl = $AzureKeyVaultUrl | ||
$Script:AzureKeyVaultClientId = $AzureKeyVaultClientId | ||
$Script:AzureKeyVaultClientSecret = $AzureKeyVaultClientSecret | ||
$Script:AzureKeyVaultTenantId = $AzureKeyVaultTenantId | ||
$Script:AzureKeyVaultCertificate = $AzureKeyVaultCertificate | ||
|
||
function Invoke-ExecutableCommand { | ||
param ( | ||
[parameter(Mandatory)] | ||
[String] $executable, | ||
[parameter(Mandatory)] | ||
[String] $arguments | ||
) | ||
|
||
$pinfo = New-Object System.Diagnostics.ProcessStartInfo | ||
$pinfo.FileName = $executable | ||
$pinfo.RedirectStandardError = $true | ||
$pinfo.RedirectStandardOutput = $true | ||
$pinfo.UseShellExecute = $false | ||
$pinfo.Arguments = $arguments | ||
$p = New-Object System.Diagnostics.Process | ||
$p.StartInfo = $pinfo | ||
$p.Start() | Out-Null | ||
$p.WaitForExit() | ||
|
||
return $p | ||
} | ||
|
||
function Invoke-AzureSignTool { | ||
# Get scripts to sign | ||
$scripts = Get-ChildItem -Path "$Script:Directory" -ErrorAction Stop -Exclude ".github" | ` | ||
Get-ChildItem -Recurse -ErrorAction Stop | ` | ||
Where-Object { $_.name -match "ps[d|m]?1(xml)?" } | ||
|
||
# Sign the scripts | ||
foreach ($script in $scripts) { | ||
Write-Output "Signing file: $($script.Name)" | ||
|
||
$params = @{ | ||
'kvu' = "`"$Script:AzureKeyVaultUrl`"" | ||
'kvi' = "`"$Script:AzureKeyVaultClientId`"" | ||
'kvs' = "`"$Script:AzureKeyVaultClientSecret`"" | ||
'kvt' = "`"$Script:AzureKeyVaultTenantId`"" | ||
'kvc' = "`"$Script:AzureKeyVaultCertificate`"" | ||
# timestamp-rfc3161 | ||
'tr' = 'http://timestamp.digicert.com ' | ||
} | ||
|
||
# Convert params to string | ||
$arguments = "sign" | ||
foreach ($kv in $params.GetEnumerator()) { | ||
$arguments += " -$($kv.Name) $($kv.Value)" | ||
} | ||
|
||
$arguments += " -v $($script.FullName)" | ||
|
||
$output = Invoke-ExecutableCommand -Executable 'AzureSignTool' -Arguments $arguments | ||
if ($output.ExitCode -ne 0) { | ||
$err = $output.StandardError.ReadToEnd() | ||
if ([string]::IsNullOrEmpty($err)) { | ||
$err = $output.StandardOutput.ReadToEnd() | ||
} | ||
|
||
Write-Error "Failed to sign script $($script.Name). Error code: ($($output.ExitCode))." | ||
Throw $err | ||
} | ||
} | ||
} | ||
|
||
# Execute | ||
Invoke-AzureSignTool |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
########################################################################### | ||
# # | ||
# Copyright (c) Microsoft Corporation. All rights reserved. # | ||
# # | ||
# This code is licensed under the MIT License (MIT). # | ||
# # | ||
########################################################################### | ||
|
||
name: CI Build | ||
|
||
on: | ||
workflow_dispatch: | ||
inputs: | ||
runner: | ||
description: "Windows runner image" | ||
required: false | ||
default: windows-2022 | ||
type: choice | ||
options: | ||
- windows-latest | ||
- windows-2022 | ||
- windows-2019 | ||
|
||
pull_request: | ||
branches: ["main", "releases/**"] | ||
paths-ignore: | ||
- "docs/**" | ||
- "*.md" | ||
- en-US/**" | ||
|
||
env: | ||
MODULE_DIR: .\Containers-Toolkit | ||
BUILD_SCRIPTS_DIR: .\build\scripts | ||
PESTER_RESULTS_DIR: .\TestResults | ||
MODULE_ARTIFACT: CTK.Module.Scripts | ||
REPO_ARTIFACT: CTK.Scripts | ||
|
||
jobs: | ||
lint: | ||
runs-on: ${{ github.event.inputs.RUNNER || 'windows-2022' }} | ||
steps: | ||
- name: Checkout code | ||
uses: actions/checkout@v4 | ||
|
||
# FIXME: Fix cache not working | ||
- name: Setup PowerShell module cache | ||
id: cacher | ||
uses: actions/cache@v3 | ||
with: | ||
path: "C:\\program files\\powershell\\7\\Modules" | ||
key: ${{ runner.os }}-CTK | ||
|
||
- name: Install required PowerShell modules | ||
if: steps.cacher.outputs.cache-hit != 'true' | ||
shell: pwsh | ||
run: | | ||
Set-PSRepository PSGallery -InstallationPolicy Trusted | ||
$ModuleName = 'PSScriptAnalyzer' | ||
if (-not (Get-Module -ListAvailable -Name $ModuleName)) { | ||
Write-Output "Modules to install: '$ModuleName'" | ||
Install-Module $ModuleName -ErrorAction Stop -AllowClobber -SkipPublisherCheck -Force | ||
} | ||
- name: Run code analysis with PSScriptAnalyzer | ||
id: code_analysis | ||
shell: pwsh | ||
run: | | ||
${{ env.BUILD_SCRIPTS_DIR }}\script-analyzer.ps1 | Out-File -FilePath lintsummary.md -Encoding utf8 -Force | ||
cat lintsummary.md >> $env:GITHUB_STEP_SUMMARY | ||
$fileExists = Test-Path ./psscriptanalysis.xml | ||
echo "LINTSUMMARY_EXISTS=$fileExists" >> $env:GITHUB_OUTPUT | ||
- name: Publish PSScriptAnalyzer results file | ||
if: steps.code_analysis.outputs.LINTSUMMARY_EXISTS == 'true' | ||
uses: actions/upload-artifact@v4 | ||
with: | ||
name: PSScriptAnalyzer.Results | ||
path: psscriptanalysis.xml | ||
if-no-files-found: error | ||
overwrite: true | ||
|
||
pester: | ||
# TODO: Add Windows ARM64 support | ||
runs-on: ${{ github.event.inputs.RUNNER || 'windows-2022' }} | ||
steps: | ||
- name: Checkout code | ||
uses: actions/checkout@v4 | ||
|
||
# FIXME: Fix cache not working | ||
- name: Setup PowerShell module cache | ||
id: cacher | ||
uses: actions/cache@v3 | ||
with: | ||
path: "C:\\program files\\powershell\\7\\Modules" | ||
key: ${{ runner.os }}-CTK | ||
|
||
- name: Install required PowerShell modules | ||
if: steps.cacher.outputs.cache-hit != 'true' | ||
shell: pwsh | ||
run: | | ||
Set-PSRepository PSGallery -InstallationPolicy Trusted | ||
$requiredModules = @('Pester', 'ThreadJob', 'HNS') | ||
$missingModules = $requiredModules | Where-Object { -not (Get-Module -ListAvailable -Name $_) } | ||
if ($missingModules) { | ||
Write-Output "Modules to install: $($missingModules -join ', ')" | ||
Install-Module $missingModules -ErrorAction Stop -AllowClobber -SkipPublisherCheck -Force | ||
} | ||
- name: Run Pester tests | ||
shell: pwsh | ||
run: | | ||
$ErrorActionPreference = 'Continue' | ||
${{ env.BUILD_SCRIPTS_DIR }}\run-tests.ps1 | ||
- name: Publish Pester results | ||
uses: actions/upload-artifact@v4 | ||
with: | ||
name: CTK.Pester.Results | ||
path: ${{ env.PESTER_RESULTS_DIR }}\Test-Results.xml | ||
if-no-files-found: error | ||
overwrite: true | ||
|
||
- name: Publish code coverage results | ||
uses: actions/upload-artifact@v4 | ||
with: | ||
name: CTK.Coverage.Summary | ||
path: ${{ env.PESTER_RESULTS_DIR }}\coverage.xml | ||
if-no-files-found: error | ||
overwrite: true | ||
|
||
test-coverage: | ||
needs: pester | ||
runs-on: ubuntu-latest | ||
steps: | ||
- name: Download coverage results artifact | ||
uses: actions/download-artifact@v4 | ||
with: | ||
name: CTK.Coverage.Summary | ||
|
||
- name: Setup .NET Core # Required to execute ReportGenerator | ||
uses: actions/setup-dotnet@v3 | ||
with: | ||
dotnet-version: 8.x | ||
dotnet-quality: "ga" | ||
|
||
- name: ReportGenerator | ||
uses: danielpalme/[email protected] | ||
with: | ||
reports: coverage.xml | ||
targetdir: coveragereport | ||
reporttypes: HtmlInline;MarkdownSummaryGithub;Badges | ||
historydir: coveragehistory | ||
|
||
- name: Upload coverage report artifact | ||
uses: actions/upload-artifact@v4 | ||
with: | ||
name: coveragereport # Artifact name | ||
path: coveragereport # Directory containing files to upload | ||
|
||
- name: Publish coverage summary | ||
uses: marocchino/sticky-pull-request-comment@v2 | ||
continue-on-error: true | ||
with: | ||
path: coveragereport/SummaryGithub.md | ||
|
||
- name: Post results | ||
run: | | ||
cat coveragereport/SummaryGithub.md >> $GITHUB_STEP_SUMMARY |
Oops, something went wrong.