Skip to content
Merged
Show file tree
Hide file tree
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
30 changes: 30 additions & 0 deletions Tools/windows/PACKAGING.md
Original file line number Diff line number Diff line change
Expand Up @@ -79,3 +79,33 @@ DLLs, metadata, manifests, file sets, and checksums. Its OS signature-trust
decisions are simulated without modifying certificate stores; it is not a
production Authenticode or signed-installer lifecycle proof. It runs before the
existing real-product packaging/lifecycle suite under `validate.ps1 -Task packaging`.

## Retained provider sources

Both exact public provider pins have the annotated source-retention tag
`graphcode-windows-baseline-2026-09-17`:

| Provider | Pinned commit | Retained branch |
|---|---|---|
| [coneilen/winghostty](https://github.com/coneilen/winghostty/tree/graphcode-windows-baseline-2026-09-17) | `f5abc059e4ca58b376eb209313aca7784659c679` | `graphcode-host` |
| [coneilen/zmx](https://github.com/coneilen/zmx/tree/graphcode-windows-baseline-2026-09-17) | `029e11d2b19162fb3bdf90c8270237d303b8bfb4` | `graphcode-quickchat-hang` |

As verified on 2026-09-17, each fork has an active ruleset forbidding updates or
deletion of `refs/tags/graphcode-windows-*`, without bypass actors. Separate
active rulesets prevent deletion and non-fast-forward changes of the branches
above; normal forward development is allowed. The Winghostty tag/branch ruleset
IDs are `23625509`/`23625510`; zmx's are `23625508`/`23625511`.
Administrators can still change rulesets or repository availability; these
settings are retention controls, not an irrevocable archival guarantee.

These tags preserve source, not signed product releases. No installer or binary
asset is published by creating them. Public CI can fetch them without provider
credentials; collaborator permissions were not changed.

`graphcode-windows\provider-pins.json` remains the source of truth. Bootstrap and
packaging still use exact commit SHAs, not moving branch or tag resolution.
The terminal gate checks every provider field against its investigation copy,
including repository, remote URL, SHA, artifact path, and Zig version.
`ProviderPins.Tests.ps1` proves drift in either file is rejected, while JSON
property order and explanatory fallback wording are immaterial. Run it directly
or through `validate.ps1 -Task terminal-gate`.
73 changes: 73 additions & 0 deletions Tools/windows/Tests/ProviderPins.Tests.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
[CmdletBinding()]
param()

$ErrorActionPreference = "Stop"
$repoRoot = (Resolve-Path (Join-Path $PSScriptRoot "..\..\..")).Path
$contract = Join-Path $PSScriptRoot "TerminalGate.Tests.ps1"
$productPath = Join-Path $repoRoot "graphcode-windows\provider-pins.json"
$gatePath = Join-Path $repoRoot "investigation\spikes\windows-terminal-gate\provider-pins.json"
$fixture = Join-Path $repoRoot ".build\provider-pin-contract-$([guid]::NewGuid())"
$pwsh = (Get-Process -Id $PID).Path

function Test-Pins([string] $label, [scriptblock] $mutate, [string] $failure) {
$product = Get-Content -LiteralPath $productPath -Raw | ConvertFrom-Json -AsHashtable
$gate = Get-Content -LiteralPath $gatePath -Raw | ConvertFrom-Json -AsHashtable
& $mutate $product $gate
$product | ConvertTo-Json -Depth 10 | Set-Content (Join-Path $fixture "product.json")
$gate | ConvertTo-Json -Depth 10 | Set-Content (Join-Path $fixture "gate.json")
$output = & $pwsh -NoProfile -File $contract `
-ProductPinsPath (Join-Path $fixture "product.json") `
-GatePinsPath (Join-Path $fixture "gate.json") 2>&1 | Out-String
if ($failure) {
if ($LASTEXITCODE -eq 0) { throw "RED: $label was accepted" }
if ($output -notmatch [regex]::Escape($failure)) {
throw "$label failed for the wrong reason: $output"
}
} elseif ($LASTEXITCODE -ne 0) {
throw "$label did not pass: $output"
}
}

try {
New-Item -ItemType Directory -Path $fixture | Out-Null
foreach ($provider in @("winghostty", "zmx")) {
foreach ($field in @("repository", "remoteUrl", "sha", "artifact", "minimumZig")) {
foreach ($side in @("product", "gate")) {
Test-Pins "$side $provider.$field drift" {
param($product, $gate)
$pins = if ($side -eq "product") { $product } else { $gate }
$pins[$provider][$field] += "-drift"
} "provider pins differ: $provider.$field"
}
}
Test-Pins "$provider missing field" {
param($product, $gate)
$gate[$provider].Remove("artifact")
} "provider pins differ: $provider.artifact"
Test-Pins "$provider additional field" {
param($product, $gate)
$product[$provider].newPinField = "future-value"
} "provider pins differ: $provider.newPinField"
Test-Pins "$provider field type" {
param($product, $gate)
$product[$provider].minimumZig = 152
} "provider pins differ: $provider.minimumZig"
}
Test-Pins "schema drift" {
param($product, $gate)
$product.schemaVersion = 2
} "provider pin schemas differ"
Test-Pins "matching sources" { param($product, $gate) } ""
Test-Pins "order and explanatory metadata" {
param($product, $gate)
$reordered = [ordered]@{}
@($product.winghostty.Keys) | Sort-Object -Descending | ForEach-Object {
$reordered[$_] = $product.winghostty[$_]
}
$product.winghostty = $reordered
$product.localFallback.reason = "different explanatory wording"
} ""
Write-Output "Provider pin no-divergence contracts: PASS"
} finally {
Remove-Item -LiteralPath $fixture -Recurse -Force
}
30 changes: 28 additions & 2 deletions Tools/windows/Tests/TerminalGate.Tests.ps1
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
[CmdletBinding()]
param(
[switch] $List
[switch] $List,
[string] $ProductPinsPath,
[string] $GatePinsPath
)

$ErrorActionPreference = "Stop"
Expand Down Expand Up @@ -36,8 +38,32 @@ foreach ($path in @(
"required gate file is missing: $path"
}

$pins = Get-Content -LiteralPath (Join-Path $gateRoot "provider-pins.json") -Raw |
if (-not $ProductPinsPath) {
$ProductPinsPath = Join-Path $repoRoot "graphcode-windows\provider-pins.json"
}
if (-not $GatePinsPath) {
$GatePinsPath = Join-Path $gateRoot "provider-pins.json"
}
$pins = Get-Content -LiteralPath $GatePinsPath -Raw |
ConvertFrom-Json
$productPins = Get-Content -LiteralPath $ProductPinsPath -Raw | ConvertFrom-Json
Assert-Contract ($productPins.schemaVersion -eq $pins.schemaVersion) "provider pin schemas differ"
foreach ($provider in @("winghostty", "zmx")) {
$product = $productPins.$provider
$gate = $pins.$provider
Assert-Contract ($product -is [pscustomobject] -and $gate -is [pscustomobject]) `
"provider pins differ: $provider"
$fields = @(@($product.PSObject.Properties.Name) + @($gate.PSObject.Properties.Name)) |
Sort-Object -Unique -CaseSensitive
foreach ($field in $fields) {
Assert-Contract (
$product.PSObject.Properties.Name -ccontains $field -and
$gate.PSObject.Properties.Name -ccontains $field -and
$product.$field -is [string] -and $gate.$field -is [string] -and
$product.$field -ceq $gate.$field
) "provider pins differ: $provider.$field"
}
}
Assert-Contract ($pins.schemaVersion -eq 1) "provider pin schema is not 1"
Assert-Contract ($pins.winghostty.sha -eq
"f5abc059e4ca58b376eb209313aca7784659c679") "Winghostty SHA is not exact"
Expand Down
3 changes: 3 additions & 0 deletions Tools/windows/Tests/ValidationRunner.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,9 @@ try {
if ($runnerSource -notmatch '(?s)"packaging" \{\s*& .*?Packaging\.Signing\.Tests\.ps1.*?Packaging\.Tests\.ps1') {
throw "RED: packaging validation does not run signed catalog integrity contracts"
}
if ($runnerSource -notmatch '(?s)"terminal-gate" \{\s*& .*?ProviderPins\.Tests\.ps1.*?TerminalGate\.Tests\.ps1') {
throw "RED: terminal validation does not run provider pin no-divergence contracts"
}
foreach ($source in @($runnerSource, $hardeningSource)) {
if ($source -notmatch '-StubResponseDelayMilliseconds 150') {
throw "RED: shell validation does not exercise delayed correlated responses"
Expand Down
1 change: 1 addition & 0 deletions Tools/windows/validate.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -563,6 +563,7 @@ function Invoke-Task([string] $name) {
Write-Host "Privacy checks passed"
}
"terminal-gate" {
& (Join-Path $repoRoot "Tools\windows\Tests\ProviderPins.Tests.ps1")
& (Join-Path $repoRoot "Tools\windows\Tests\TerminalGate.Tests.ps1")
if ($LASTEXITCODE -ne 0) {
throw "Windows terminal gate contract failed with exit code $LASTEXITCODE"
Expand Down
1 change: 1 addition & 0 deletions Tools/windows/validation-matrix.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ The Windows port must have runnable commands before implementation fleets begin.
| Production Swift platform package | `pwsh Tools/windows/validate.ps1 -Task swift-production` |
| Deterministic release hardening fixtures | `pwsh Tools/windows/validate.ps1 -Task hardening` |
| Signed catalog integrity and publisher policy | `pwsh Tools\windows\Tests\Packaging.Signing.Tests.ps1` |
| Product/investigation provider pin consistency | `pwsh Tools\windows\Tests\ProviderPins.Tests.ps1` |
| Real-product packaging/install/upgrade/rollback | `pwsh Tools\windows\validate.ps1 -Task packaging` |
| Shared Swift package | `swift test --package-path <shared-package>` once extracted |
| macOS app/daemon/CLI | `make test` |
Expand Down
12 changes: 12 additions & 0 deletions investigation/spikes/windows-terminal-gate/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,18 @@ Both commits are published on dedicated branches in the public `coneilen`
provider repositories. The bootstrap creates detached, exact-revision
checkouts without copying provider source into GraphCode.

The annotated `graphcode-windows-baseline-2026-09-17` tag preserves each exact
pin. The provider forks protect these tags against updates/deletion and the
dedicated branches against deletion/history rewrites; see
`Tools\windows\PACKAGING.md` for the recorded ruleset IDs and retention limits.
These are source-retention tags, not signed Windows releases.

`graphcode-windows\provider-pins.json` is authoritative. The terminal gate's
contract compares its schema and all provider fields against this copy, and
`Tools\windows\Tests\ProviderPins.Tests.ps1` injects drift into both sides.
Changing only one copy must fail validation; JSON property order and explanatory
fallback wording do not change the provider identity.

## Build

Build Winghostty's host artifact at its pinned local SHA, build zmx at its
Expand Down
Loading