Skip to content

Build AppControl Manager MSIX Package #18

Build AppControl Manager MSIX Package

Build AppControl Manager MSIX Package #18

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
run: dotnet build "AppControl Manager/AppControl Manager.sln" --configuration Release --verbosity minimal
- name: Generating the MSIX Package
run: dotnet msbuild "AppControl Manager/AppControl Manager.sln" /p:Configuration=Release /p:AppxPackageDir="MSIXOutput\" /p:GenerateAppxPackageOnBuild=true
- 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@v1
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@v1
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