Skip to content
Draft
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
342 changes: 342 additions & 0 deletions .github/workflows/h3-r7b1b1-toolchain-preflight.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,342 @@
# ContinuityOS H3-G1 R5: SDK shared-header path correction for read-only inventory.
# INVENTORY ONLY: no H3 C0/T11/T12 broker-security or production qualification.
# No checkout, installation, build, native RPC registration, or artifacts.
name: H3 G1 Windows SDK component inventory R5

on:
pull_request:
types: [opened, synchronize, reopened]
paths:
- '.github/workflows/h3-r7b1b1-toolchain-preflight.yml'

permissions:
contents: read

concurrency:
group: h3-r7b1b1-toolchain-${{ github.event.pull_request.number }}
cancel-in-progress: true

jobs:
inventory:
name: win-2025 / independent SDK shared RPC header
if: ${{ github.event.pull_request.head.repo.full_name == github.repository && github.event.pull_request.base.ref == 'master' }}
runs-on: windows-2025-vs2026
timeout-minutes: 8
defaults:
run:
shell: pwsh
steps:
- name: Verify exact context and inventory preinstalled toolchain
env:
EXPECTED_REPOSITORY: bitmaster162/continuityos
EXPECTED_BASE_SHA: 719ed32a64301fc8083a5aad0c4ed7bed316040e
PR_BASE_SHA: ${{ github.event.pull_request.base.sha }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }}
run: |
Set-StrictMode -Version Latest
$ErrorActionPreference = 'Stop'
$ProgressPreference = 'SilentlyContinue'

if ($env:GITHUB_REPOSITORY -cne $env:EXPECTED_REPOSITORY) {
throw 'H3_REPOSITORY_DRIFT'
}
if ($env:GITHUB_EVENT_NAME -cne 'pull_request') {
throw 'H3_UNAPPROVED_EVENT'
}
if ($env:PR_BASE_SHA -cne $env:EXPECTED_BASE_SHA) {
throw 'H3_PROTECTED_MASTER_BASE_SHA_DRIFT'
}
if ($env:PR_HEAD_SHA -notmatch '^[0-9a-f]{40}$') {
throw 'H3_HEAD_SHA_INVALID'
}
if ($env:RUNNER_OS -cne 'Windows' -or $env:RUNNER_ARCH -cne 'X64') {
throw 'H3_UNEXPECTED_RUNNER_PLATFORM'
}

function Get-FileEvidence {
param(
[Parameter(Mandatory = $true)][string] $Label,
[AllowNull()][string] $Path,
[bool] $Required = $true
)
$record = [ordered]@{
label = $Label
required = $Required
present = $false
path = $null
bytes = $null
file_version = $null
sha256 = $null
}
if (-not [string]::IsNullOrWhiteSpace($Path) -and
(Test-Path -LiteralPath $Path -PathType Leaf)) {
$file = Get-Item -LiteralPath $Path -ErrorAction Stop
if (($file.Attributes -band [IO.FileAttributes]::ReparsePoint) -ne 0) {
throw "H3_REPARSE_TOOLCHAIN_FILE_BLOCKED: $Label"
}
$record.present = $true
$record.path = $file.FullName
$record.bytes = [long]$file.Length
$record.file_version = [string]([Diagnostics.FileVersionInfo]::GetVersionInfo($file.FullName).FileVersion)
$record.sha256 = (Get-FileHash -LiteralPath $file.FullName -Algorithm SHA256).Hash.ToLowerInvariant()
}
[pscustomobject]$record
}

$pf86 = [Environment]::GetEnvironmentVariable('ProgramFiles(x86)')
if ([string]::IsNullOrWhiteSpace($pf86)) {
throw 'H3_PROGRAMFILES_X86_MISSING'
}

$vswhere = Join-Path $pf86 'Microsoft Visual Studio\Installer\vswhere.exe'
$vsRoot = $null
$vcVersion = $null
$cl = $null
$link = $null
if (Test-Path -LiteralPath $vswhere -PathType Leaf) {
$installations = @(& $vswhere -latest -products '*' -requires 'Microsoft.VisualStudio.Component.VC.Tools.x86.x64' -property installationPath)
if ($LASTEXITCODE -ne 0) {
throw 'H3_VSWHERE_QUERY_FAILED'
}
$installations = @($installations | Where-Object { -not [string]::IsNullOrWhiteSpace($_) })
if ($installations.Count -eq 1) {
$vsRoot = [string]$installations[0].Trim()
$msvcRoot = Join-Path $vsRoot 'VC\Tools\MSVC'
if (Test-Path -LiteralPath $msvcRoot -PathType Container) {
$versions = @(Get-ChildItem -LiteralPath $msvcRoot -Directory | Sort-Object -Property @{ Expression = { [version]$_.Name }; Descending = $true })
if ($versions.Count -gt 0) {
$vcVersion = $versions[0].Name
$vcBin = Join-Path $versions[0].FullName 'bin\Hostx64\x64'
$cl = Join-Path $vcBin 'cl.exe'
$link = Join-Path $vcBin 'link.exe'
}
}
}
}

# H3 G1 R5: bounded, independent component discovery; no toolchain execution.
# R3 had a composite early-exit that left four individual statuses null.
$sdkRoots = [System.Collections.Generic.List[object]]::new()
$seenRoots = [System.Collections.Generic.HashSet[string]]::new(
[System.StringComparer]::OrdinalIgnoreCase
)
function Add-SdkRoot {
param([string] $Origin, [AllowNull()][string] $Value)
if ([string]::IsNullOrWhiteSpace($Value)) { return }
$path = [IO.Path]::GetFullPath($Value.Trim().TrimEnd([char[]]@('\','/')))
if ($seenRoots.Add($path)) {
if ($sdkRoots.Count -ge 8) { throw 'H3_SDK_ROOT_LIMIT_EXCEEDED' }
$sdkRoots.Add([pscustomobject]@{
source = $Origin
path = $path
present = [bool](Test-Path -LiteralPath $path -PathType Container)
})
}
}

Add-SdkRoot -Origin 'ProgramFiles(x86)' -Value (Join-Path $pf86 'Windows Kits\10')
$pf = [Environment]::GetEnvironmentVariable('ProgramFiles')
if (-not [string]::IsNullOrWhiteSpace($pf)) {
Add-SdkRoot -Origin 'ProgramFiles' -Value (Join-Path $pf 'Windows Kits\10')
}
Add-SdkRoot -Origin 'WindowsSdkDir' -Value $env:WindowsSdkDir
$regKeys = @(
'HKLM:\SOFTWARE\Microsoft\Windows Kits\Installed Roots',
'HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows Kits\Installed Roots'
)
$registryReads = [System.Collections.Generic.List[object]]::new()
foreach ($regKey in $regKeys) {
$regValue = $null
$regStatus = 'MISSING_KEY_OR_VALUE'
try {
$regData = Get-ItemProperty -LiteralPath $regKey -ErrorAction Stop
$regValue = [string]$regData.KitsRoot10
if (-not [string]::IsNullOrWhiteSpace($regValue)) {
$regStatus = 'FOUND'
Add-SdkRoot -Origin $regKey -Value $regValue
}
} catch {
$regStatus = 'UNAVAILABLE'
}
$registryReads.Add([pscustomobject]@{ key=$regKey; status=$regStatus })
}

$sdkProbes = [System.Collections.Generic.List[object]]::new()
foreach ($rootEntry in $sdkRoots) {
if (-not $rootEntry.present) { continue }
$versions = [System.Collections.Generic.HashSet[string]]::new(
[System.StringComparer]::OrdinalIgnoreCase
)
# A bounded union of Bin/Include/Lib versions, not only Bin versions.
[void]$versions.Add('10.0.26100.0')
$envSDKVersion = [string]$env:WindowsSDKVersion
$envSDKVersion = $envSDKVersion.Trim().TrimEnd([char[]]@('\','/'))
if ($envSDKVersion -match '^10\.\d+\.\d+\.\d+$') {
[void]$versions.Add($envSDKVersion)
}
foreach ($directory in @('bin','Include','Lib')) {
$dir = Join-Path $rootEntry.path $directory
if (Test-Path -LiteralPath $dir -PathType Container) {
$kids = @(Get-ChildItem -LiteralPath $dir -Directory -ErrorAction Stop)
if ($kids.Count -gt 64) { throw 'H3_SDK_DIRECTORY_ENTRY_LIMIT_EXCEEDED' }
foreach ($child in $kids) {
if ($child.Name -match '^10\.\d+\.\d+\.\d+$') {
[void]$versions.Add($child.Name)
}
}
}
}
if ($versions.Count -gt 16) { throw 'H3_SDK_VERSION_LIMIT_EXCEEDED' }
$sorted = @($versions | Sort-Object -Property @{Expression={ [version]$_ };Descending=$true})
foreach ($ver in $sorted) {
if ($sdkProbes.Count -ge 128) { throw 'H3_SDK_PROBE_LIMIT_EXCEEDED' }
$dirVersion = Join-Path $rootEntry.path ("bin\$ver\x64")
$dirLegacy = Join-Path $rootEntry.path 'bin\x64'
$midlPath = Join-Path $dirVersion 'midl.exe'
$midlcPath = Join-Path $dirVersion 'midlc.exe'
$layout = 'versioned'
if (-not (Test-Path -LiteralPath $midlPath -PathType Leaf)) {
$legacyMidl = Join-Path $dirLegacy 'midl.exe'
if (Test-Path -LiteralPath $legacyMidl -PathType Leaf) {
$midlPath = $legacyMidl
$layout = 'legacy'
}
}
if (-not (Test-Path -LiteralPath $midlcPath -PathType Leaf)) {
$legacyMidlc = Join-Path $dirLegacy 'midlc.exe'
if (Test-Path -LiteralPath $legacyMidlc -PathType Leaf) {
$midlcPath = $legacyMidlc
$layout = 'mixed_or_legacy'
}
}
$headerPath = Join-Path $rootEntry.path ("Include\$ver\shared\rpcdce.h")
$libPath = Join-Path $rootEntry.path ("Lib\$ver\um\x64\Rpcrt4.lib")
$probe = [pscustomobject]@{
root = $rootEntry.path
version = $ver
layout = $layout
midl_path = $midlPath
midlc_path = $midlcPath
header_path = $headerPath
lib_path = $libPath
midl_present = [bool](Test-Path -LiteralPath $midlPath -PathType Leaf)
midlc_present = [bool](Test-Path -LiteralPath $midlcPath -PathType Leaf)
header_present = [bool](Test-Path -LiteralPath $headerPath -PathType Leaf)
lib_present = [bool](Test-Path -LiteralPath $libPath -PathType Leaf)
}
$sdkProbes.Add($probe)
}
}

# Independent presence per component; never infer absence from composite failure.
$componentFound = [ordered]@{
'midl.exe' = [bool](@($sdkProbes | Where-Object { $_.midl_present }).Count -gt 0)
'midlc.exe' = [bool](@($sdkProbes | Where-Object { $_.midlc_present }).Count -gt 0)
'rpcdce.h' = [bool](@($sdkProbes | Where-Object { $_.header_present }).Count -gt 0)
'Rpcrt4.lib' = [bool](@($sdkProbes | Where-Object { $_.lib_present }).Count -gt 0)
}
$coherentSets = @($sdkProbes | Where-Object {
$_.midl_present -and $_.midlc_present -and $_.header_present -and $_.lib_present
})
$coherentSet = if ($coherentSets.Count -gt 0) { $coherentSets[0] } else { $null }
$sdkVersion = if ($null -ne $coherentSet) { $coherentSet.version } else { $null }
$midl = $null
$midlc = $null
$header = $null
$importLib = $null
if ($null -ne $coherentSet) {
$midl = $coherentSet.midl_path
$midlc = $coherentSet.midlc_path
$header = $coherentSet.header_path
$importLib = $coherentSet.lib_path
} else {
$p = @($sdkProbes | Where-Object { $_.midl_present } | Select-Object -First 1)
if ($p.Count -gt 0) { $midl = $p[0].midl_path }
$p = @($sdkProbes | Where-Object { $_.midlc_present } | Select-Object -First 1)
if ($p.Count -gt 0) { $midlc = $p[0].midlc_path }
$p = @($sdkProbes | Where-Object { $_.header_present } | Select-Object -First 1)
if ($p.Count -gt 0) { $header = $p[0].header_path }
$p = @($sdkProbes | Where-Object { $_.lib_present } | Select-Object -First 1)
if ($p.Count -gt 0) { $importLib = $p[0].lib_path }
}

$files = @(
(Get-FileEvidence -Label 'vswhere.exe' -Path $vswhere)
(Get-FileEvidence -Label 'cl.exe' -Path $cl)
(Get-FileEvidence -Label 'link.exe' -Path $link)
(Get-FileEvidence -Label 'midl.exe' -Path $midl)
(Get-FileEvidence -Label 'rpcdce.h' -Path $header)
(Get-FileEvidence -Label 'Rpcrt4.lib' -Path $importLib)
(Get-FileEvidence -Label 'midlc.exe' -Path $midlc -Required $true)
)
$midlDriver = @($files | Where-Object { $_.label -ceq 'midl.exe' })[0]
$midlEngine = @($files | Where-Object { $_.label -ceq 'midlc.exe' })[0]
$midlPairVersionMatch = $false
if ($midlDriver.present -and $midlEngine.present) {
$midlPairVersionMatch = (
-not [string]::IsNullOrWhiteSpace($midlDriver.file_version) -and
-not [string]::IsNullOrWhiteSpace($midlEngine.file_version) -and
$midlDriver.file_version -ceq $midlEngine.file_version
)
}

$missing = @($files | Where-Object { $_.required -and -not $_.present } |
ForEach-Object { $_.label })

$missingIndependent = @($componentFound.Keys | Where-Object {
-not $componentFound[$_]
})
$coherentSdkFound = [bool]($null -ne $coherentSet)
$sdkRootRecords = @($sdkRoots | ForEach-Object {
[pscustomobject]@{ source=$_.source; path=$_.path; present=$_.present }
})
$sdkProbeRecords = @($sdkProbes | ForEach-Object {
[pscustomobject]@{
root=$_.root; version=$_.version; layout=$_.layout
midl_present=$_.midl_present; midlc_present=$_.midlc_present
header_present=$_.header_present; lib_present=$_.lib_present
}
})
$receipt = [ordered]@{
schema = 'continuityos.h3.g1.sdk-independent-inventory/v4'
expected_runner_label = 'windows-2025-vs2026'
scope = 'preinstalled local toolchain inventory only'
github_repository = $env:GITHUB_REPOSITORY
pr_base_sha = $env:PR_BASE_SHA
pr_head_sha = $env:PR_HEAD_SHA
runner_os = $env:RUNNER_OS
runner_arch = $env:RUNNER_ARCH
image_os = $env:ImageOS
image_version = $env:ImageVersion
windows_version = [Environment]::OSVersion.Version.ToString()
vs_installation_path = $vsRoot
msvc_version = $vcVersion
windows_sdk_version = $sdkVersion
files = $files
sdk_roots = $sdkRootRecords
sdk_registry_reads = @($registryReads)
sdk_probes = $sdkProbeRecords
independent_presence = $componentFound
missing_independent = $missingIndependent
coherent_sdk_found = $coherentSdkFound
missing_required = $missing
midl_driver_engine_versions_match = $midlPairVersionMatch
no_source_checkout = $true
no_compiler_execution = $true
no_network_command = $true
no_artifact_upload = $true
no_rpc_registration = $true
production = 'HOLD'
}
Write-Output ('H3_R7B1B1_READONLY_RECEIPT=' + ($receipt | ConvertTo-Json -Compress -Depth 8))
if (-not $coherentSdkFound) {
throw ('H3_G1_COHERENT_SDK_NOT_FOUND: absent_individually=' +
($missingIndependent -join ',') + '; no same-root same-version quartet')
}
if ($missing.Count -ne 0) {
throw ('H3_G1_TOOLCHAIN_INCOMPLETE: ' + ($missing -join ','))
}
if (-not $midlPairVersionMatch) {
throw 'H3_MIDL_DRIVER_ENGINE_VERSION_MISMATCH_OR_ABSENT'
}
Write-Output 'H3_G1_R5_TOOLCHAIN_INVENTORY=PASS_ONLY_NOT_NATIVE_BROKER_SECURITY_PASS'
Loading