Skip to content

Harden release integrity, licensing, and provenance #34

Harden release integrity, licensing, and provenance

Harden release integrity, licensing, and provenance #34

name: Release candidate package
on:
pull_request:
branches: [main]
paths:
- "Directory.Build.props"
- "LICENSE"
- "NOTICE"
- "COMMERCIAL-LICENSE.md"
- "COPYRIGHT.md"
- "TRADEMARK.md"
- "THIRD_PARTY_NOTICES.md"
- "docs/LICENSING.md"
- "docs/ASSET_PROVENANCE.md"
- "docs/QUICK_START.pdf"
- "docs/USER_MANUAL.pdf"
- "src/**"
- "tests/**"
- "scripts/publish-windows-portable.ps1"
- "scripts/verify-release-package.ps1"
- "scripts/generate-release-pdfs.py"
- "scripts/generate-sbom.ps1"
- "scripts/repository-health.ps1"
- "scripts/validate-public-content.py"
- "docs/RELEASE_NOTES_v*.md"
- ".github/workflows/candidate-package.yml"
- ".github/workflows/release-package.yml"
workflow_dispatch:
permissions:
contents: read
concurrency:
group: candidate-package-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
DOTNET_NOLOGO: true
DOTNET_CLI_TELEMETRY_OPTOUT: true
jobs:
candidate:
name: Build verified Windows x64 candidate
if: github.event_name == 'workflow_dispatch' || startsWith(github.head_ref, 'stabilization/') || startsWith(github.head_ref, 'architecture/') || startsWith(github.head_ref, 'legal/') || startsWith(github.head_ref, 'hardening/')
runs-on: windows-2025
timeout-minutes: 40
steps:
- name: Checkout tested ref
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7
with:
fetch-depth: 0
- name: Setup .NET
uses: actions/setup-dotnet@26b0ec14cb23fa6904739307f278c14f94c95bf1 # v5
with:
dotnet-version: 8.0.4xx
- name: Install document validation dependencies
run: python -m pip install --disable-pip-version-check reportlab==4.4.9 pypdf==6.4.1
- name: Resolve build identity
id: identity
shell: pwsh
run: |
[xml]$props = Get-Content .\Directory.Build.props -Raw
$prefix = $props.SelectSingleNode('/Project/PropertyGroup/VersionPrefix').InnerText.Trim()
$suffixNode = $props.SelectSingleNode('/Project/PropertyGroup/VersionSuffix')
$suffix = if ($null -eq $suffixNode) { '' } else { $suffixNode.InnerText.Trim() }
$version = if ([string]::IsNullOrWhiteSpace($suffix)) { $prefix } else { "$prefix-$suffix" }
$builtCommit = (git rev-parse HEAD).Trim()
$sourceHead = if ('${{ github.event_name }}' -eq 'pull_request') { '${{ github.event.pull_request.head.sha }}' } else { $builtCommit }
$testedMerge = $builtCommit
$sourceRef = if ('${{ github.event_name }}' -eq 'pull_request') { '${{ github.head_ref }}' } else { '${{ github.ref_name }}' }
"version=$version" | Out-File $env:GITHUB_OUTPUT -Append -Encoding utf8
"built_commit=$builtCommit" | Out-File $env:GITHUB_OUTPUT -Append -Encoding utf8
"source_head=$sourceHead" | Out-File $env:GITHUB_OUTPUT -Append -Encoding utf8
"tested_merge=$testedMerge" | Out-File $env:GITHUB_OUTPUT -Append -Encoding utf8
"source_ref=$sourceRef" | Out-File $env:GITHUB_OUTPUT -Append -Encoding utf8
- name: Verify generated PDFs and public wording
run: |
python .\scripts\generate-release-pdfs.py --check
python .\scripts\validate-public-content.py
- name: Repository health gate
shell: pwsh
run: .\scripts\repository-health.ps1 -ExpectedVersion '${{ steps.identity.outputs.version }}'
- name: Restore, build, and test
shell: pwsh
run: |
dotnet restore .\ProcessBusSuite.sln
dotnet build .\ProcessBusSuite.sln -c Release --no-restore /p:ContinuousIntegrationBuild=true
dotnet test .\ProcessBusSuite.sln -c Release --no-build --logger "trx;LogFileName=candidate-tests.trx" --results-directory .\TestResults
- name: Publish portable package
shell: pwsh
env:
SOURCE_HEAD_COMMIT: ${{ steps.identity.outputs.source_head }}
TESTED_MERGE_COMMIT: ${{ steps.identity.outputs.tested_merge }}
SOURCE_REF: ${{ steps.identity.outputs.source_ref }}
run: .\scripts\publish-windows-portable.ps1 -Version '${{ steps.identity.outputs.version }}' -Configuration Release -Runtime win-x64
- name: Verify portable package
shell: pwsh
run: |
$zip = ".\artifacts\release\ProcessBusInsight-v${{ steps.identity.outputs.version }}-win-x64-portable.zip"
.\scripts\verify-release-package.ps1 -PackageZip $zip -ExpectedVersion '${{ steps.identity.outputs.version }}'
- name: Create candidate manifest
shell: pwsh
run: |
$manifest = [ordered]@{
product = 'Process Bus Insight'
version = '${{ steps.identity.outputs.version }}'
candidate = $true
builtCommit = '${{ steps.identity.outputs.built_commit }}'
sourceHeadCommit = '${{ steps.identity.outputs.source_head }}'
testedMergeCommit = '${{ steps.identity.outputs.tested_merge }}'
sourceRef = '${{ steps.identity.outputs.source_ref }}'
runtime = 'win-x64'
framework = 'net8.0-windows'
communityLicense = 'GPL-3.0-or-later'
historicalBoundary = '85d43a0fe58a5888a9e8008c168ab76d2333ea87'
signatureRequired = $false
timestampUtc = (Get-Date).ToUniversalTime().ToString('o')
}
$manifest | ConvertTo-Json | Set-Content .\artifacts\release\candidate-manifest.json -Encoding utf8
- name: Upload verified candidate
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: ProcessBusInsight-v${{ steps.identity.outputs.version }}-win-x64-candidate-${{ github.run_number }}
path: |
artifacts/release/ProcessBusInsight-v${{ steps.identity.outputs.version }}-win-x64-portable.zip
artifacts/release/SHA256SUMS.txt
artifacts/release/SOURCE.md
artifacts/release/ProcessBusInsight-SBOM.cdx.json
artifacts/release/candidate-manifest.json
TestResults/**
if-no-files-found: error
retention-days: 14