Compare commits
5
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d3d70f381b | ||
|
|
70b555bd56 | ||
|
|
db417d1525 | ||
|
|
0ef3d319b8 | ||
|
|
7584fa19cc |
No files matched your search
@@ -179,7 +179,7 @@ jobs:
|
||||
# An App token lets the generated PR trigger CI; GITHUB_TOKEN does not.
|
||||
- name: Release PR token
|
||||
id: app
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
||||
uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3.3.0
|
||||
with:
|
||||
client-id: ${{ vars.RELEASE_APP_CLIENT_ID }}
|
||||
private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
|
||||
|
||||
@@ -79,7 +79,7 @@ jobs:
|
||||
global-json-file: global.json
|
||||
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3
|
||||
uses: github/codeql-action/init@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4.39.0
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
build-mode: ${{ contains(fromJSON('["actions","javascript-typescript","python","ruby"]'), matrix.language) && 'none' || inputs.build-mode }}
|
||||
@@ -99,7 +99,7 @@ jobs:
|
||||
eval "$BUILD_COMMAND"
|
||||
|
||||
- name: Analyze
|
||||
uses: github/codeql-action/analyze@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3
|
||||
uses: github/codeql-action/analyze@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4.39.0
|
||||
with:
|
||||
category: /language:${{ matrix.language }}
|
||||
output: codeql-sarif
|
||||
|
||||
@@ -199,7 +199,7 @@ jobs:
|
||||
- name: Prepare owned binary signing catalog
|
||||
if: inputs.sign
|
||||
id: signing
|
||||
uses: KofTwentyTwo/standards/.github/actions/windows-signing@f896215ec96854b18883191759259fd9866ee9be # reviewed signing helpers on main
|
||||
uses: KofTwentyTwo/standards/.github/actions/windows-signing@70b555bd5658273090769991bfc4c9b6681dde18 # reviewed signing helpers on main
|
||||
with:
|
||||
operation: prepare
|
||||
signing-files: ${{ inputs.signing-files }}
|
||||
@@ -255,7 +255,7 @@ jobs:
|
||||
|
||||
- name: Verify signed binaries
|
||||
if: inputs.sign
|
||||
uses: KofTwentyTwo/standards/.github/actions/windows-signing@f896215ec96854b18883191759259fd9866ee9be # reviewed signing helpers on main
|
||||
uses: KofTwentyTwo/standards/.github/actions/windows-signing@70b555bd5658273090769991bfc4c9b6681dde18 # reviewed signing helpers on main
|
||||
with:
|
||||
operation: verify
|
||||
manifest: ${{ steps.signing.outputs.manifest }}
|
||||
@@ -269,7 +269,7 @@ jobs:
|
||||
|
||||
- name: Verify the exact binaries shipped in NuGet packages
|
||||
if: inputs.sign
|
||||
uses: KofTwentyTwo/standards/.github/actions/windows-signing@f896215ec96854b18883191759259fd9866ee9be # reviewed signing helpers on main
|
||||
uses: KofTwentyTwo/standards/.github/actions/windows-signing@70b555bd5658273090769991bfc4c9b6681dde18 # reviewed signing helpers on main
|
||||
with:
|
||||
operation: verify-distribution
|
||||
directory: artifacts/nuget
|
||||
|
||||
@@ -131,7 +131,7 @@ jobs:
|
||||
|
||||
- name: Settings read token
|
||||
id: app
|
||||
uses: actions/create-github-app-token@bcd2ba49218906704ab6c1aa796996da409d3eb1 # v3.2.0
|
||||
uses: actions/create-github-app-token@64ab729a6294000f5aa4a4bc0b73d1f32bc45510 # v3.3.0
|
||||
with:
|
||||
client-id: ${{ vars.RELEASE_APP_CLIENT_ID }}
|
||||
private-key: ${{ secrets.RELEASE_APP_PRIVATE_KEY }}
|
||||
|
||||
@@ -108,6 +108,10 @@ on:
|
||||
description: Newline-separated required owned file names or publish-relative patterns, including the optional CLI; required when sign is true.
|
||||
type: string
|
||||
default: ""
|
||||
msi:
|
||||
description: Generate a per-user MSI alongside Setup.exe and portable ZIP; requires the same signing and verification.
|
||||
type: boolean
|
||||
default: false
|
||||
outputs:
|
||||
version:
|
||||
description: The released version (tag without the leading v).
|
||||
@@ -333,7 +337,7 @@ jobs:
|
||||
- name: Prepare owned binary signing catalog
|
||||
if: inputs.sign
|
||||
id: signing
|
||||
uses: KofTwentyTwo/standards/.github/actions/windows-signing@f896215ec96854b18883191759259fd9866ee9be # reviewed signing helpers on main
|
||||
uses: KofTwentyTwo/standards/.github/actions/windows-signing@70b555bd5658273090769991bfc4c9b6681dde18 # reviewed signing helpers on main
|
||||
with:
|
||||
operation: prepare
|
||||
root: publish
|
||||
@@ -426,7 +430,7 @@ jobs:
|
||||
|
||||
- name: Verify signed binaries and preserved dependencies
|
||||
if: inputs.sign
|
||||
uses: KofTwentyTwo/standards/.github/actions/windows-signing@f896215ec96854b18883191759259fd9866ee9be # reviewed signing helpers on main
|
||||
uses: KofTwentyTwo/standards/.github/actions/windows-signing@70b555bd5658273090769991bfc4c9b6681dde18 # reviewed signing helpers on main
|
||||
with:
|
||||
operation: verify
|
||||
manifest: ${{ steps.signing.outputs.manifest }}
|
||||
@@ -494,6 +498,8 @@ jobs:
|
||||
|
||||
- name: Velopack pack
|
||||
shell: pwsh
|
||||
env:
|
||||
VPK_MSI: ${{ inputs.msi }}
|
||||
run: |
|
||||
$sign = @()
|
||||
if ($env:K22_SIGN -eq 'true')
|
||||
@@ -505,7 +511,7 @@ jobs:
|
||||
$sign = @('--signTemplate', $command, '--signExclude', $exclude)
|
||||
}
|
||||
$env:VELOPACK_TEMP = Join-Path $env:RUNNER_TEMP 'k22-velopack'
|
||||
vpk pack --runtime $env:K22_RUNTIME --packId $env:K22_APP_ID --packVersion $env:K22_VERSION --packDir publish/app --mainExe $env:K22_MAIN_EXE --channel $env:K22_CHANNEL --icon $env:K22_ICON --outputDir Releases @sign
|
||||
vpk pack --runtime $env:K22_RUNTIME --packId $env:K22_APP_ID --packVersion $env:K22_VERSION --packDir publish/app --mainExe $env:K22_MAIN_EXE --channel $env:K22_CHANNEL --icon $env:K22_ICON --outputDir Releases --instLocation PerUser @sign
|
||||
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
|
||||
|
||||
# Keeps only what this build produced, as `vpk upload` does: the files listed in
|
||||
@@ -534,6 +540,108 @@ jobs:
|
||||
Write-Output "Assets: $($names -join ', '); feed: $feedName; setup: $setup"
|
||||
"setup=$setup" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
|
||||
|
||||
- name: Extract required MSI payload
|
||||
if: inputs.msi
|
||||
id: msi
|
||||
shell: pwsh
|
||||
run: |
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$installers = @(Get-ChildItem -LiteralPath release -Filter '*.msi' -File)
|
||||
if ($installers.Count -ne 1) { throw 'Exactly one MSI installer is required.' }
|
||||
$root = Join-Path $env:RUNNER_TEMP ('k22-msi-' + [guid]::NewGuid().ToString('N'))
|
||||
"root=$root" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
|
||||
$image = Join-Path $root 'image'
|
||||
$assets = Join-Path $root 'assets'
|
||||
New-Item -ItemType Directory -Path $image, $assets -Force | Out-Null
|
||||
$start = [Diagnostics.ProcessStartInfo]::new('msiexec.exe')
|
||||
$start.UseShellExecute = $false
|
||||
$start.CreateNoWindow = $true
|
||||
foreach ($argument in @('/a', $installers[0].FullName, '/qn', "TARGETDIR=$image", '/l*v', (Join-Path $root 'extract.log')))
|
||||
{
|
||||
$start.ArgumentList.Add($argument)
|
||||
}
|
||||
$process = [Diagnostics.Process]::Start($start)
|
||||
try
|
||||
{
|
||||
if (-not $process.WaitForExit(180000)) { $process.Kill(); throw 'MSI extraction timed out.' }
|
||||
if ($process.ExitCode -ne 0) { throw "MSI extraction failed: $($process.ExitCode)." }
|
||||
}
|
||||
finally { $process.Dispose() }
|
||||
$manifests = @(Get-ChildItem -LiteralPath $image -Recurse -File -Filter sq.version)
|
||||
if ($manifests.Count -ne 1 -or $manifests[0].Directory.Name -ne 'current') { throw 'Expected one installed MSI application payload.' }
|
||||
$payload = $manifests[0].Directory.Parent.FullName
|
||||
[IO.Compression.ZipFile]::CreateFromDirectory($payload, (Join-Path $assets 'msi-Portable.zip'))
|
||||
"directory=$assets" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
|
||||
|
||||
# Reuse the existing archive verifier for MSI's administratively extracted
|
||||
# payload: every owned/third-party byte and generated launcher is checked.
|
||||
- name: Verify exact signed MSI payload
|
||||
if: inputs.msi && inputs.sign
|
||||
uses: KofTwentyTwo/standards/.github/actions/windows-signing@70b555bd5658273090769991bfc4c9b6681dde18 # reviewed signing helpers on main
|
||||
with:
|
||||
operation: verify-distribution
|
||||
directory: ${{ steps.msi.outputs.directory }}
|
||||
manifest: ${{ steps.signing.outputs.manifest }}
|
||||
expected-subject: ${{ vars.ARTIFACT_SIGNING_SUBJECT || vars.TRUSTED_SIGNING_SUBJECT }}
|
||||
|
||||
- name: Verify MSI installs, launches and uninstalls
|
||||
if: inputs.msi
|
||||
shell: pwsh
|
||||
env:
|
||||
MSI_ROOT: ${{ steps.msi.outputs.root }}
|
||||
run: |
|
||||
$ErrorActionPreference = 'Stop'
|
||||
$msi = @(Get-ChildItem -LiteralPath release -Filter '*.msi' -File)
|
||||
if ($msi.Count -ne 1) { throw 'Exactly one MSI installer is required.' }
|
||||
$installer = New-Object -ComObject WindowsInstaller.Installer
|
||||
$database = $installer.OpenDatabase($msi[0].FullName, 0)
|
||||
$view = $database.OpenView('SELECT `Value` FROM `Property` WHERE `Property` = ''ProductCode''')
|
||||
$view.Execute()
|
||||
$product = $view.Fetch().StringData(1)
|
||||
if ($product -notmatch '^\{[0-9A-Fa-f-]{36}\}$') { throw 'Invalid MSI product identity.' }
|
||||
$target = Join-Path $env:MSI_ROOT 'installed'
|
||||
$application = $null
|
||||
try
|
||||
{
|
||||
$install = Start-Process msiexec.exe -ArgumentList @('/i', ('"' + $msi[0].FullName + '"'), '/qn', ('VELOPACK_INSTALLDIR="' + $target + '"'), '/l*v', ('"' + (Join-Path $env:MSI_ROOT 'install.log') + '"')) -WindowStyle Hidden -PassThru
|
||||
if (-not $install.WaitForExit(180000)) { $install.Kill(); throw 'MSI installation timed out.' }
|
||||
if ($install.ExitCode -ne 0) { throw "MSI installation failed: $($install.ExitCode)." }
|
||||
$executable = Join-Path $target "current/$env:K22_MAIN_EXE"
|
||||
if (-not (Test-Path -LiteralPath $executable -PathType Leaf)) { throw 'MSI did not install the application.' }
|
||||
$application = Start-Process -FilePath $executable -PassThru
|
||||
$deadline = [DateTime]::UtcNow.AddSeconds(30)
|
||||
do
|
||||
{
|
||||
$application.Refresh()
|
||||
if ($application.HasExited) { throw 'MSI-installed application exited before opening its window.' }
|
||||
if ($application.MainWindowHandle -ne [IntPtr]::Zero) { break }
|
||||
Start-Sleep -Milliseconds 200
|
||||
} while ([DateTime]::UtcNow -lt $deadline)
|
||||
if ($application.MainWindowHandle -eq [IntPtr]::Zero) { throw 'MSI-installed application did not open a window.' }
|
||||
if (-not $application.CloseMainWindow() -or -not $application.WaitForExit(10000)) { $application.Kill(); throw 'MSI-installed application did not close normally.' }
|
||||
}
|
||||
finally
|
||||
{
|
||||
if ($null -ne $application -and -not $application.HasExited) { $application.Kill() }
|
||||
$uninstall = Start-Process msiexec.exe -ArgumentList @('/x', $product, '/qn', '/l*v', ('"' + (Join-Path $env:MSI_ROOT 'uninstall.log') + '"')) -WindowStyle Hidden -PassThru
|
||||
if (-not $uninstall.WaitForExit(180000)) { $uninstall.Kill(); throw 'MSI uninstall timed out.' }
|
||||
if ($uninstall.ExitCode -notin 0, 1605) { throw "MSI uninstall failed: $($uninstall.ExitCode)." }
|
||||
}
|
||||
if (Test-Path -LiteralPath (Join-Path $target "current/$env:K22_MAIN_EXE")) { throw 'MSI uninstall left the application installed.' }
|
||||
Write-Output "MSI $product installed, opened its window, closed and uninstalled successfully."
|
||||
|
||||
- name: Remove temporary MSI extraction
|
||||
if: always() && inputs.msi
|
||||
shell: pwsh
|
||||
env:
|
||||
MSI_ROOT: ${{ steps.msi.outputs.root }}
|
||||
run: |
|
||||
if ([string]::IsNullOrWhiteSpace($env:MSI_ROOT)) { exit 0 }
|
||||
$root = [IO.Path]::GetFullPath($env:MSI_ROOT)
|
||||
$temporaryRoot = [IO.Path]::TrimEndingDirectorySeparator([IO.Path]::GetFullPath($env:RUNNER_TEMP))
|
||||
if ([IO.Path]::GetDirectoryName($root) -ne $temporaryRoot -or [IO.Path]::GetFileName($root) -notmatch '^k22-msi-[0-9a-f]{32}$') { throw 'Unexpected MSI scratch directory.' }
|
||||
if (Test-Path -LiteralPath $root) { Remove-Item -LiteralPath $root -Recurse -Force }
|
||||
|
||||
- name: Zip CLI
|
||||
if: inputs.cli-project != ''
|
||||
shell: pwsh
|
||||
@@ -541,7 +649,7 @@ jobs:
|
||||
|
||||
- name: Verify final installer, portable, full update and CLI assets
|
||||
if: inputs.sign
|
||||
uses: KofTwentyTwo/standards/.github/actions/windows-signing@f896215ec96854b18883191759259fd9866ee9be # reviewed signing helpers on main
|
||||
uses: KofTwentyTwo/standards/.github/actions/windows-signing@70b555bd5658273090769991bfc4c9b6681dde18 # reviewed signing helpers on main
|
||||
with:
|
||||
operation: verify-distribution
|
||||
directory: release
|
||||
@@ -648,6 +756,13 @@ jobs:
|
||||
subject-path: release/*-cli-*.zip
|
||||
sbom-path: sbom/${{ inputs.app-id }}-cli-${{ needs.build.outputs.version }}.cdx.json
|
||||
|
||||
- name: Attest MSI SBOM
|
||||
if: inputs.msi
|
||||
uses: actions/attest-sbom@c604332985a26aa8cf1bdc465b92731239ec6b9e # v4.1.0
|
||||
with:
|
||||
subject-path: release/*.msi
|
||||
sbom-path: sbom/${{ inputs.app-id }}-${{ needs.build.outputs.version }}.cdx.json
|
||||
|
||||
- name: Upload SBOMs
|
||||
uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
|
||||
with:
|
||||
|
||||
@@ -34,7 +34,7 @@ jobs:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Run Scorecard
|
||||
uses: ossf/scorecard-action@2d1146689b8cda280b9bc96326124645441f03bc # v2.4.4
|
||||
uses: ossf/scorecard-action@fa7117db83c52d787ae5a89f350999701505d78e # v2.5.0
|
||||
with:
|
||||
results_file: scorecard.sarif
|
||||
results_format: sarif
|
||||
@@ -48,7 +48,7 @@ jobs:
|
||||
retention-days: 30
|
||||
|
||||
- name: Upload SARIF to code scanning
|
||||
uses: github/codeql-action/upload-sarif@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3
|
||||
uses: github/codeql-action/upload-sarif@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4.39.0
|
||||
with:
|
||||
sarif_file: scorecard.sarif
|
||||
category: scorecard
|
||||
@@ -86,7 +86,7 @@ jobs:
|
||||
- name: Upload SARIF to code scanning
|
||||
# Fork pull requests get a read-only token, so only same-repository runs upload.
|
||||
if: always() && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository)
|
||||
uses: github/codeql-action/upload-sarif@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3
|
||||
uses: github/codeql-action/upload-sarif@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4.39.0
|
||||
with:
|
||||
sarif_file: trivy.sarif
|
||||
category: trivy-sca
|
||||
@@ -145,7 +145,7 @@ jobs:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Set up uv
|
||||
uses: astral-sh/setup-uv@c18668ad3cf93ea998bef934396af7bb5c839dc7 # v10.2.0
|
||||
uses: astral-sh/setup-uv@1c37ad07a6a961277cf70c0d37d6f313000f5884 # v10.3.0
|
||||
with:
|
||||
enable-cache: false
|
||||
|
||||
@@ -156,7 +156,7 @@ jobs:
|
||||
|
||||
- name: Upload SARIF to code scanning
|
||||
if: always() && (github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository)
|
||||
uses: github/codeql-action/upload-sarif@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3
|
||||
uses: github/codeql-action/upload-sarif@6f2ac81f5cd81fe351a197ba0b00d91d03cd2aee # v4.39.0
|
||||
with:
|
||||
sarif_file: zizmor.sarif
|
||||
category: zizmor
|
||||
|
||||
@@ -1 +1 @@
|
||||
{".":"1.1.2"}
|
||||
{".":"1.2.1"}
|
||||
@@ -3,6 +3,28 @@
|
||||
<!-- Generated by Release Please and GitHub; permit native spacing, links and repeated categories. -->
|
||||
<!-- markdownlint-disable MD012 MD022 MD024 MD032 MD034 -->
|
||||
|
||||
## 1.2.1 (2026-10-13)
|
||||
|
||||
<!-- Release notes generated using configuration in .github/release.yml at main -->
|
||||
|
||||
## What's Changed
|
||||
### Changes
|
||||
* fix(releases): record MSI checklist preflight recovery by @KofTwentyTwo in https://github.com/KofTwentyTwo/standards/pull/49
|
||||
|
||||
|
||||
**Full Changelog**: https://github.com/KofTwentyTwo/standards/compare/v1.2.0...v1.2.1
|
||||
|
||||
## 1.2.0 (2026-10-13)
|
||||
|
||||
<!-- Release notes generated using configuration in .github/release.yml at main -->
|
||||
|
||||
## What's Changed
|
||||
### Changes
|
||||
* feat(releases): publish signed per-user MSI installers by @KofTwentyTwo in https://github.com/KofTwentyTwo/standards/pull/47
|
||||
|
||||
|
||||
**Full Changelog**: https://github.com/KofTwentyTwo/standards/compare/v1.1.2...v1.2.0
|
||||
|
||||
## 1.1.2 (2026-10-13)
|
||||
|
||||
<!-- Release notes generated using configuration in .github/release.yml at main -->
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# MSI builder release recovery
|
||||
|
||||
The signed v1.2.0 tag is reserved by a preflight failure: its annotation omitted
|
||||
the required MINOR-release checklist. No1.2.0 assets were published. Preserve
|
||||
that tag and recover through a new1.2.1 release proposal and signed tag.
|
||||
|
||||
The optional MSI implementation is unchanged from merged PR47. Hosted checks
|
||||
and40 signing regressions pass; native MSI compilation and the actual wrapped
|
||||
extraction body preserve all6 signed fixture application binaries. Production
|
||||
MSI signing, installation and distributed-payload verification remain mandatory.
|
||||
|
||||
Before tagging the recovery, complete and link the release checklist, retain full
|
||||
conformance/scanning evidence and verify main/release-proposal gates. Include the
|
||||
checklist URL in the signed annotation even for this PATCH recovery. Publish only
|
||||
after its protected deployment and verify all actual bundle hashes/provenance.
|
||||
|
||||
This preserves existing EXE callers, signing identity/profile/trust, branch/tag
|
||||
protections and public1.1.2 assets. No account onboarding is repeated.
|
||||
+1
-1
@@ -1 +1 @@
|
||||
1.1.2
|
||||
1.2.1
|
||||
Reference in new issue
Block a user