Build AppControl Manager MSIX Package #34
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
name: Build AppControl Manager MSIX Package | |
permissions: | |
id-token: write | |
actions: read | |
contents: write | |
pull-requests: write | |
attestations: write | |
on: | |
workflow_dispatch: | |
jobs: | |
build: | |
runs-on: windows-latest | |
steps: | |
- name: Check out the repository code | |
uses: actions/checkout@v4 | |
- name: Setting up and downloading Winget | |
shell: pwsh | |
run: | | |
# Retrieve the latest Winget release information | |
[string]$WingetRepoURL = 'https://api.github.com/repos/microsoft/winget-cli/releases' | |
$WingetReleases = Invoke-RestMethod -Uri $WingetRepoURL | |
$LatestRelease = $WingetReleases | Select-Object -First 1 | |
# Direct links to the latest Winget release assets | |
[string]$WingetURL = $LatestRelease.assets.browser_download_url | Where-Object -FilterScript { $_.EndsWith('.msixbundle') } | Select-Object -First 1 | |
[string]$WingetLicense = $LatestRelease.assets.browser_download_url | Where-Object -FilterScript { $_.EndsWith('License1.xml') } | Select-Object -First 1 | |
[string]$LatestWingetReleaseDependenciesZipURL = $LatestRelease.assets.browser_download_url | Where-Object -FilterScript { $_.EndsWith('DesktopAppInstaller_Dependencies.zip') } | Select-Object -First 1 | |
[hashtable]$Downloads = @{ | |
# 'Winget.msixbundle' = 'https://aka.ms/getwinget' This is updated slower than the GitHub release | |
'DesktopAppInstaller_Dependencies.zip' = $LatestWingetReleaseDependenciesZipURL | |
'Winget.msixbundle' = $WingetURL | |
'License1.xml' = $WingetLicense | |
} | |
$Downloads.GetEnumerator() | ForEach-Object -Parallel { | |
Invoke-RestMethod -Uri $_.Value -OutFile $_.Key | |
} | |
Expand-Archive -Path 'DesktopAppInstaller_Dependencies.zip' -DestinationPath .\ -Force | |
# Get the paths to all of the dependencies | |
[string[]]$DependencyPaths = (Get-ChildItem -Path .\x64 -Filter '*.appx' -File -Force).FullName | |
Add-AppxProvisionedPackage -Online -PackagePath 'Winget.msixbundle' -DependencyPackagePath $DependencyPaths -LicensePath 'License1.xml' | |
# Add the dependency paths to the GitHub environment to be used in the next step | |
Add-Content -Path $env:GITHUB_ENV -Value "WINGET_DEPENDENCY1=$($DependencyPaths[0])" | |
Add-Content -Path $env:GITHUB_ENV -Value "WINGET_DEPENDENCY2=$($DependencyPaths[1])" | |
- name: Finishing setting up Winget | |
shell: powershell | |
run: | | |
Add-AppPackage -Path 'Winget.msixbundle' -DependencyPath "${{ env.WINGET_DEPENDENCY1 }}", "${{ env.WINGET_DEPENDENCY2 }}" -ForceTargetApplicationShutdown -ForceUpdateFromAnyVersion | |
# Add-AppPackage on Windows Server throws error so we use Windows PowerShell for this section. | |
- name: Installing the necessary programs | |
run: | | |
winget source update | |
winget install --id Microsoft.DotNet.SDK.9 --exact --accept-package-agreements --accept-source-agreements --uninstall-previous --force --source winget | |
winget install --id Microsoft.VisualStudio.2022.BuildTools --exact --accept-package-agreements --accept-source-agreements --uninstall-previous --force --source winget | |
winget install --id Microsoft.WindowsSDK.10.0.26100 --exact --accept-package-agreements --accept-source-agreements --uninstall-previous --force --source winget | |
# https://github.com/microsoft/winget-cli/issues/1705 | |
winget install --id Microsoft.AppInstaller --exact --accept-package-agreements --accept-source-agreements --uninstall-previous --force --source winget | |
winget install --id Microsoft.VCRedist.2015+.x64 --exact --accept-package-agreements --accept-source-agreements --uninstall-previous --force --source winget | |
- name: Building the AppControl Manager | |
shell: pwsh | |
working-directory: './AppControl Manager' | |
# Setting up working directory to ensure dotnet build will see the global.json file in the "AppControl Manager" sub-directory | |
# https://learn.microsoft.com/en-us/dotnet/core/tools/dotnet-build | |
# https://learn.microsoft.com/en-us/visualstudio/msbuild/msbuild-command-line-reference | |
# https://learn.microsoft.com/en-us/visualstudio/msbuild/common-msbuild-project-properties | |
run: | | |
Write-Host -Object "`nChecking .NET info`n`n" | |
dotnet --info | |
Write-Host -Object "`nListing installed .NET SDKs`n`n" | |
dotnet --list-sdks | |
dotnet build "AppControl Manager.sln" --configuration Release --verbosity normal /p:Platform=x64 | |
- name: Generating the MSIX Package | |
working-directory: './AppControl Manager' | |
run: dotnet msbuild "AppControl Manager.sln" /p:Configuration=Release /p:AppxPackageDir="MSIXOutput\" /p:GenerateAppxPackageOnBuild=true /p:Platform=x64 -v:normal | |
- name: Capturing the Generated MSIX file Path | |
shell: pwsh | |
run: | | |
[string]$MSIXPath = (Get-ChildItem -File -Path '.\AppControl Manager\MSIXOutput\AppControl Manage*\AppControl Manager*.msix').FullName | |
[string]$MSIXName = (Get-ChildItem -File -Path '.\AppControl Manager\MSIXOutput\AppControl Manage*\AppControl Manager*.msix').Name | |
[XML]$CSProjXMLContent = Get-Content -Path '.\AppControl Manager\AppControl Manager.csproj' -Force | |
[string]$MSIXVersion = $CSProjXMLContent.Project.PropertyGroup.FileVersion | |
[string]$MSIXVersion = $MSIXVersion.Trim() # It would have trailing whitespaces | |
if ([string]::IsNullOrWhiteSpace($MSIXPath) -or [string]::IsNullOrWhiteSpace($MSIXName) -or [string]::IsNullOrWhiteSpace($MSIXVersion)) { throw "Couldn't find the generated MSIX package" } | |
# Write the MSIXPath, MSIXName and MSIXVersion to GITHUB_ENV to set it as an environment variable for the entire workflow | |
Add-Content -Path $env:GITHUB_ENV -Value "MSIX_PATH=$MSIXPath" | |
Add-Content -Path $env:GITHUB_ENV -Value "MSIX_NAME=$MSIXName" | |
Add-Content -Path $env:GITHUB_ENV -Value "MSIX_VERSION=$MSIXVersion" | |
- name: Generating Artifact Attestation | |
uses: actions/attest-build-provenance@v2 | |
with: | |
subject-path: ${{ env.MSIX_PATH }} | |
- name: Generating SBOM | |
uses: anchore/sbom-action@v0 | |
with: | |
dependency-snapshot: true | |
upload-release-assets: false | |
upload-artifact: true | |
output-file: ./HardenWindowsSecurityRepoSBOM.spdx | |
artifact-name: HardenWindowsSecurityRepoSBOM.spdx | |
- name: Generating SBOM attestation | |
uses: actions/attest-sbom@v2 | |
with: | |
subject-path: ${{ env.MSIX_PATH }} | |
sbom-path: ./HardenWindowsSecurityRepoSBOM.spdx | |
show-summary: true | |
- name: Finding the Latest Draft Release | |
id: find_draft_release | |
shell: pwsh | |
run: | | |
# Find the latest draft release via GitHub REST API | |
$Response = Invoke-RestMethod -Uri "https://api.github.com/repos/${{ github.repository }}/releases" -Headers @{ Authorization = "token ${{ secrets.GITHUB_TOKEN }}" } | |
$DraftRelease = $Response | Where-Object -FilterScript { $_.draft -eq $true } | Select-Object -First 1 | |
if (!$DraftRelease) { | |
throw "No draft release found" | |
} | |
# Capture the draft release ID and tag | |
$DRAFT_RELEASE_ID = $DraftRelease.id | |
$DRAFT_RELEASE_TAG = $DraftRelease.tag_name | |
# Save both the release ID and tag to environment variables for later steps | |
Add-Content -Path $env:GITHUB_ENV -Value "DRAFT_RELEASE_ID=$DRAFT_RELEASE_ID" | |
Add-Content -Path $env:GITHUB_ENV -Value "DRAFT_RELEASE_TAG=$DRAFT_RELEASE_TAG" | |
Write-Host -Object "GitHub Draft ID: $DRAFT_RELEASE_ID" | |
Write-Host -Object "GitHub Draft Tag: $DRAFT_RELEASE_TAG" | |
- name: Uploading the MSIX Package to the Draft Release | |
shell: pwsh | |
run: | | |
[string]$DraftReleaseId = $env:DRAFT_RELEASE_ID | |
[string]$FilePath = "${{ env.MSIX_PATH }}" | |
[string]$FileName = "${{ env.MSIX_NAME }}" | |
[string]$UploadUrl = "https://uploads.github.com/repos/${{ github.repository }}/releases/$DraftReleaseId/assets?name=$FileName" | |
# Upload the package to the draft release | |
$Response = Invoke-RestMethod -Uri $UploadUrl -Method Put -InFile $FilePath -Headers @{ | |
"Authorization" = "token ${{ secrets.GITHUB_TOKEN }}" | |
"Content-Type" = "application/octet-stream" | |
} | |
Write-Host -Object "Uploaded package to draft release: $Response.name" | |
- name: Uploading the SBOM file to the Draft Release | |
shell: pwsh | |
run: | | |
[string]$DraftReleaseId = $env:DRAFT_RELEASE_ID | |
[string]$FilePath = "HardenWindowsSecurityRepoSBOM.spdx" | |
[string]$FileName = "HardenWindowsSecurityRepoSBOM.spdx" | |
[string]$UploadUrl = "https://uploads.github.com/repos/${{ github.repository }}/releases/$DraftReleaseId/assets?name=$FileName" | |
$Response = Invoke-RestMethod -Uri $UploadUrl -Method Put -InFile $FilePath -Headers @{ | |
"Authorization" = "token ${{ secrets.GITHUB_TOKEN }}" | |
"Content-Type" = "application/octet-stream" | |
} | |
Write-Host -Object "Uploaded the SBOM file to the draft release: $Response.name" | |
- name: Updating The MSIX Download Link and Version via Pull Request | |
shell: pwsh | |
env: | |
GH_TOKEN: ${{ github.token }} | |
run: | | |
[string]$MSIXName = "${{ env.MSIX_NAME }}" | |
# Spaces in files added to the GitHub assets will be replaced with dots, so we need to do the same when constructing the download link | |
[string]$AdjustedMSIXName = $MSIXName.Replace('AppControl Manager', 'AppControl.Manager') | |
[string]$DRAFT_RELEASE_TAG = "${{ env.DRAFT_RELEASE_TAG }}" | |
[string]$GitHubRepository = "${{ github.repository }}" | |
[string]$MSIX_VERSION = "${{ env.MSIX_VERSION }}" | |
# Construct the download URL using the draft release tag and MSIX file name | |
[string]$DownloadURL = "https://github.com/$GitHubRepository/releases/download/$DRAFT_RELEASE_TAG/$AdjustedMSIXName" | |
# Path to the files that will be updated | |
[string]$DownloadURLFilePath = '.\AppControl Manager\DownloadURL.txt' | |
[string]$VersionFilePath = '.\AppControl Manager\version.txt' | |
# Update the file content with the new URL | |
Set-Content -Path $DownloadURLFilePath -Value $DownloadURL -Force | |
Write-Host -Object "Updated DownloadURL.txt with download URL: $DownloadURL" | |
Set-Content -Path $VersionFilePath -Value $MSIX_VERSION -Force | |
Write-Host -Object "Updated version.txt with version: $MSIX_VERSION" | |
# Configure Git for committing changes | |
git config --global user.email '[email protected]' | |
git config --global user.name 'HotCakeX' | |
# Create a new branch for the pull request, making sure branch name has valid characters | |
[string]$NewBranchName = 'AppControl-Manager-DownloadLink-Version-Update' | |
git checkout -b $NewBranchName | |
[string]$CommitMessageAndPRTitle = "AppControl-Manager-DownloadLink-Version-Update-Version-$MSIX_VERSION" | |
# Stage and commit the change | |
git add $DownloadURLFilePath | |
git add $VersionFilePath | |
git commit -m $CommitMessageAndPRTitle | |
# Push the new branch to the remote repository | |
git push -u origin $NewBranchName | |
[string]$PRBody = @" | |
This PR updates DownloadURL.txt to | |
`````` | |
$DownloadURL | |
`````` | |
And version.txt to | |
`````` | |
$MSIX_VERSION | |
`````` | |
For the file: $AdjustedMSIXName | |
"@ | |
# Create the pull request | |
gh pr create --title $CommitMessageAndPRTitle --body $PRBody --base main --label 'Automated 🤖' --assignee HotCakeX |