diff --git a/README.md b/README.md index 70d77c1fb..7349d6147 100644 --- a/README.md +++ b/README.md @@ -39,7 +39,7 @@ Release. No MSIX certificate, Developer Mode, Visual Studio, Windows SDK, or `Add-AppxPackage` is required to install a release EXE. See [installation guidance](docs/user/installation.md) and the -[1.1.0 release-candidate notes](docs/releases/1.1.0.md). +[1.1.0 release notes](docs/releases/1.1.0.md). ## Core features diff --git a/docs/releases/1.1.0.md b/docs/releases/1.1.0.md index 1daa8b38b..ed23dabf5 100644 --- a/docs/releases/1.1.0.md +++ b/docs/releases/1.1.0.md @@ -41,5 +41,10 @@ Primary x64 assets: Publisher: `helloThisWorld`. Tag: `v1.1.0`. +## Signing + +The v1.1.0 Setup EXE is not code-signed. Windows may display a SmartScreen +warning; verify the downloaded file against `SHA256SUMS.txt` before running it. + Release artifacts must not be published until the acceptance matrix in `docs/v1.1-acceptance.md` and the release-gate report are complete. diff --git a/scripts/winterm/generate-release-artifacts.ps1 b/scripts/winterm/generate-release-artifacts.ps1 index 4cfb8d6d7..2fa3fefc0 100644 --- a/scripts/winterm/generate-release-artifacts.ps1 +++ b/scripts/winterm/generate-release-artifacts.ps1 @@ -84,6 +84,32 @@ function Write-JsonWithoutBom [Text.UTF8Encoding]::new($false)) } +function Ensure-ReleaseNotesSigningDisclosure +{ + param( + [Parameter(Mandatory)] + [string]$Path, + + [Parameter(Mandatory)] + [ValidateSet('trusted-signed', 'unsigned')] + [string]$Status + ) + + $notes = Get-Content -LiteralPath $Path -Raw + if ($Status -eq 'unsigned' -and $notes -notmatch '(?i)unsigned|not code-signed') + { + $disclosure = @( + '## Signing' + '' + 'The Setup EXE is not code-signed. Windows may display a SmartScreen warning; verify the downloaded file against `SHA256SUMS.txt` before running it.' + ) -join [Environment]::NewLine + $updatedNotes = $notes.TrimEnd() + [Environment]::NewLine + [Environment]::NewLine + $disclosure + [Environment]::NewLine + [IO.File]::WriteAllText($Path, $updatedNotes, [Text.UTF8Encoding]::new($false)) + } + + return Get-Item -LiteralPath $Path +} + $repositoryRoot = (Resolve-Path (Join-Path $PSScriptRoot '..\..')).Path $versionMetadata = Get-Content -LiteralPath (Join-Path $repositoryRoot 'src\winterm\Branding\version.json') -Raw | ConvertFrom-Json $outputRoot = if ([IO.Path]::IsPathRooted($OutputDirectory)) @@ -140,6 +166,7 @@ try $ReleaseNotesPath } $notesAsset = Copy-ReleaseFile -Source $notesSource -TargetName "winTerm-$Version-release-notes.md" + $notesAsset = Ensure-ReleaseNotesSigningDisclosure -Path $notesAsset.FullName -Status $SigningStatus $releaseInputs = @($installerAsset, $portableAsset, $noticesAsset, $notesAsset) $artifactRecords = @($releaseInputs | ForEach-Object { diff --git a/scripts/winterm/test-release-workflow.ps1 b/scripts/winterm/test-release-workflow.ps1 index 9875b84d8..8a1fdd7d2 100644 --- a/scripts/winterm/test-release-workflow.ps1 +++ b/scripts/winterm/test-release-workflow.ps1 @@ -15,6 +15,7 @@ try $wingetWorkflow = Get-Content -LiteralPath (Join-Path $repositoryRoot '.github\workflows\winget.yml') -Raw $fullBuildWorkflow = Get-Content -LiteralPath (Join-Path $repositoryRoot '.github\workflows\winterm-full-build.yml') -Raw $wingetGenerator = Get-Content -LiteralPath (Join-Path $repositoryRoot 'scripts\winterm\generate-winget-manifests.ps1') -Raw + $releaseGenerator = Get-Content -LiteralPath (Join-Path $repositoryRoot 'scripts\winterm\generate-release-artifacts.ps1') -Raw foreach ($required in @( "- 'v*'", @@ -69,6 +70,17 @@ try { throw 'Release workflow does not implement optional trusted signing with an explicit unsigned fallback.' } + foreach ($required in @( + 'Ensure-ReleaseNotesSigningDisclosure', + 'The Setup EXE is not code-signed.', + 'SHA256SUMS.txt' + )) + { + if (-not $releaseGenerator.Contains($required)) + { + throw "Release artifact generation is missing required signing disclosure boundary '$required'." + } + } foreach ($workflowToInspect in @($workflow, $wingetWorkflow, $fullBuildWorkflow)) {