v1.90.0.0 feat: make browser cookie imports explicit and safe (#2964)

* fix(browse): prepare reliable cookie import wave for validation

* ci: sequence quality and behavior for validation branch

* fix(browse): isolate Windows qualification and preserve native diagnostics

* test(browse): cover cookie workflow quality and isolate Windows user paths

* test(browse): trace native member startup and initialize fresh folders

* fix(browse): keep Windows member stdin alive through EOF

* fix(browse): latch native timeouts and compare contained Edge startup

* test(browse): verify native version metadata and actual Windows argv

* test(browse): qualify Dia import on isolated macOS CI

* fix(browse): require picker origin for session mutations

* fix(browse): bound credential reads through stream completion

* test(browse): inspect owned Windows process arguments natively

* test(evals): preserve passing coverage during cookie repair reruns

* test(browse): isolate Dia qualification in a fresh macOS account

* test(browse): pass bounded integer timeouts to native Mac probes

* test(browse): distinguish Windows profile initialization from containment

* test(browse): await descendant pipe readiness before parent exit

* test(browse): initialize and restore isolated macOS Keychain state

* test(browse): initialize Windows fixture folders before qualification

* test(ci): pin the same Node runtime across Windows checks

* test(browse): distinguish native macOS browser preflight stages

* test(browse): isolate Windows descendant console lifetime

* test(browse): preserve native receipts and identify fixture lock holders

* test(browse): prepare dependency resolution before native Mac worker startup

* test(ci): include lock and close checks in native diagnostics

* test(browse): preserve native owner probe stages and subprocess deadlines

* fix(browse): classify Chromium profile-in-use exit precisely

* test(browse): retain Mac qualification evidence through cleanup failures

* test(browse): bound Mac fixture paths and retire its owned user domain

* test(browse): accept vanished fixture entries without weakening cleanup

* test(browse): identify probe-created macOS user domains safely

* test(browse): observe Mac user domains without targeting them first

* test(browse): use passive fresh-user ownership throughout Mac qualification

* test(browse): distinguish profile and registered-home Keychain lookups

* test(browse): qualify Dia under one registered account home

* test(browse): identify Dia startup and owned process-group failures

* test(browse): classify bounded Dia startup diagnostics without leaking output

* fix(test): preserve native Mac sandboxing and reap owned browser children

* fix(browse): preserve Chromium sandboxing for native profile imports

* test(browse): inspect signed Mach-O architecture without launching Xcode tools

* test(browse): sample pending Dia startup and reap on all cleanup paths

* test(browse): compare protected Dia launches in fresh Bun and Node accounts

* test(browse): inspect isolated Mac GUI readiness without browser access

* v1.90.0.0 fix: bind cookie picker actions to their document

* test: validate cookie guards and fit nested launch fixtures

* ci: configure the bundled Chromium sandbox helper

* fix(browse): classify Playwright authentication timeouts

* test: retain bounded Windows lifecycle diagnostics

* test(cso): reuse bounded NTFS precision candidates

* test(review): handle explicit preservation choices safely

* test(browse): remove owned fixture directories with explicit primitives

* test(review): distinguish descriptive reuse from edit commitments

* test: admit only the approved unscored cookie workflow refusal

* test: keep the Office Hours judge mock export-complete

* fix: keep dependency-free CI planners independent of the model SDK

* test: observe the exact holder after a native fixture unlink failure

* fix: start seeded PTY observations at owned readiness

* test: acquire identity-bound Windows deletion admission before profile resets

* test: preserve qualified Git index bits without authorizing mutations
This commit is contained in:
Garry Tan
2026-09-25 12:06:45 -04:00
committed by GitHub
parent 730a1017d1
commit a84b0b5b6d
111 changed files with 14996 additions and 1057 deletions
@@ -0,0 +1,125 @@
param(
[Parameter(Mandatory = $true)][string]$OutputRoot,
[switch]$Child,
[switch]$Initialized,
[string]$ExpectedSid,
[string]$BinDirectory,
[string]$GitDirectory
)
$ErrorActionPreference = 'Stop'
if (-not $IsWindows -or $env:GITHUB_ACTIONS -ne 'true' -or $env:CI -ne 'true') {
throw 'Native cookie qualification requires a disposable GitHub Actions Windows runner.'
}
$repository = (Resolve-Path (Join-Path $PSScriptRoot '..\..')).Path
if ($Child) {
$identity = [Security.Principal.WindowsIdentity]::GetCurrent()
if ($identity.User.Value -ne $ExpectedSid) { throw 'Unexpected qualification account identity.' }
$registered = (Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList\$ExpectedSid").ProfileImagePath
$registered = [Environment]::ExpandEnvironmentVariables($registered)
$env:USERPROFILE = $registered
$env:HOME = $registered
$folders = [Microsoft.Win32.Registry]::Users.OpenSubKey("$ExpectedSid\Software\Microsoft\Windows\CurrentVersion\Explorer\User Shell Folders")
if (-not $folders) { throw 'The new account known-folder registry is unavailable.' }
try {
$rawLocal = $folders.GetValue('Local AppData', $null, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames)
$rawRoaming = $folders.GetValue('AppData', $null, [Microsoft.Win32.RegistryValueOptions]::DoNotExpandEnvironmentNames)
if (-not $rawLocal -or -not $rawRoaming) { throw 'The new account app-data folders are undefined.' }
$env:LOCALAPPDATA = [Environment]::ExpandEnvironmentVariables($rawLocal)
$env:APPDATA = [Environment]::ExpandEnvironmentVariables($rawRoaming)
} finally { $folders.Dispose() }
if (-not $Initialized) {
& (Join-Path $PSHOME 'pwsh.exe') -NoLogo -NoProfile -NonInteractive -File $PSCommandPath -Child -Initialized -ExpectedSid $ExpectedSid -BinDirectory $BinDirectory -GitDirectory $GitDirectory -OutputRoot $OutputRoot
exit $LASTEXITCODE
}
$profile = [Environment]::GetFolderPath('UserProfile')
$local = [Environment]::GetFolderPath('LocalApplicationData', 'DoNotVerify')
$roaming = [Environment]::GetFolderPath('ApplicationData', 'DoNotVerify')
if ($profile -ne $registered -or -not $local.StartsWith($profile + '\', [StringComparison]::OrdinalIgnoreCase)) {
Write-Output (ConvertTo-Json -Compress @{ profileMatchesRegistered = ($profile -eq $registered); localInsideProfile = $local.StartsWith($profile + '\', [StringComparison]::OrdinalIgnoreCase); localEmpty = [string]::IsNullOrEmpty($local); localMatchesInherited = ($local -eq $env:LOCALAPPDATA) })
throw 'Qualification must use the new account real Windows profile.'
}
$keep = @('SystemRoot', 'WINDIR', 'ProgramFiles', 'ProgramFiles(x86)', 'ProgramData', 'PATHEXT')
Get-ChildItem Env: | Where-Object { $_.Name -notin $keep } | ForEach-Object { Remove-Item "Env:$($_.Name)" }
$env:USERPROFILE = $profile
$env:HOME = $profile
$env:LOCALAPPDATA = $local
$env:APPDATA = $roaming
$env:TEMP = Join-Path $local 'Temp'
$env:TMP = $env:TEMP
$env:PATH = "$BinDirectory;$GitDirectory\cmd;$GitDirectory\bin;$GitDirectory\usr\bin;$env:SystemRoot\System32;$env:SystemRoot"
$env:CI = 'true'
$env:GITHUB_ACTIONS = 'true'
New-Item -ItemType Directory -Force -Path $env:TEMP | Out-Null
Set-Location $repository
& (Join-Path $BinDirectory 'bun.exe') install --frozen-lockfile
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& (Join-Path $GitDirectory 'bin\bash.exe') browse/scripts/build-node-server.sh
if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE }
& (Join-Path $BinDirectory 'bun.exe') --no-env-file --no-install --no-macros --config=NUL browse/test/cookie-import-native-qualification.ts $OutputRoot
exit $LASTEXITCODE
}
$work = Join-Path $OutputRoot ('cookie-native-host-' + [Guid]::NewGuid().ToString('N'))
$bin = Join-Path $work 'bin'
$evidence = Join-Path $work 'evidence'
$snapshot = Join-Path $work 'repository'
New-Item -ItemType Directory -Path $work | Out-Null
$name = 'gstack' + [Guid]::NewGuid().ToString('N').Substring(0, 10)
$password = ConvertTo-SecureString ([Convert]::ToBase64String([Security.Cryptography.RandomNumberGenerator]::GetBytes(32)) + '!aA1') -AsPlainText -Force
$account = $null
$process = $null
$exitCode = 1
try {
$account = New-LocalUser -Name $name -Password $password -AccountExpires (Get-Date).AddHours(1) -Description 'Disposable gstack cookie qualification'
Add-LocalGroupMember -SID 'S-1-5-32-545' -Member $account
$principal = "$env:COMPUTERNAME\$name"
& icacls.exe $work /grant "${principal}:(OI)(CI)M" /Q | Out-Null
if ($LASTEXITCODE -ne 0) { throw 'Could not grant fixture output access.' }
New-Item -ItemType Directory -Path $bin, $evidence, $snapshot | Out-Null
$archive = Join-Path $work 'source.tar'
& git -C $repository archive --format=tar -o $archive HEAD
if ($LASTEXITCODE -ne 0) { throw 'Could not snapshot the candidate source.' }
& (Join-Path $env:SystemRoot 'System32\tar.exe') -xf $archive -C $snapshot
if ($LASTEXITCODE -ne 0) { throw 'Could not materialize the isolated source snapshot.' }
Copy-Item (Get-Command bun).Source (Join-Path $bin 'bun.exe')
Copy-Item (Get-Command node).Source (Join-Path $bin 'node.exe')
$gitDirectory = Split-Path (Split-Path (Get-Command git).Source)
if (-not (Test-Path (Join-Path $gitDirectory 'bin\bash.exe'))) { throw 'Git Bash is required for the isolated Node build.' }
$childScript = Join-Path $snapshot '.github\scripts\run-cookie-native-qualification.ps1'
$credential = [Management.Automation.PSCredential]::new($principal, $password)
$arguments = @('-NoLogo', '-NoProfile', '-NonInteractive', '-File', ('"' + $childScript + '"'), '-Child', '-ExpectedSid', $account.SID.Value,
'-BinDirectory', ('"' + $bin + '"'), '-GitDirectory', ('"' + $gitDirectory + '"'), '-OutputRoot', ('"' + $evidence + '"'))
$process = Start-Process -FilePath (Join-Path $PSHOME 'pwsh.exe') -ArgumentList $arguments -Credential $credential -LoadUserProfile -WorkingDirectory $snapshot -PassThru -WindowStyle Hidden -RedirectStandardOutput (Join-Path $work 'stdout.log') -RedirectStandardError (Join-Path $work 'stderr.log')
$null = $process.Handle
if (-not $process.WaitForExit(360000)) {
$process.Kill($true)
throw 'Native qualification exceeded its launcher deadline.'
}
if ($null -eq $process.ExitCode) { throw 'Native qualification did not return an exit status.' }
$exitCode = $process.ExitCode
foreach ($file in Get-ChildItem $evidence -Filter qualification.json -Recurse) {
$receipt = Get-Content $file.FullName -Raw | ConvertFrom-Json
if ($receipt.status -eq 'passed') {
$expected = (Get-FileHash (Join-Path $repository 'browse\dist\server-node.mjs') -Algorithm SHA256).Hash.ToLowerInvariant()
if ($receipt.qualifiedBuild.sourceHashes.'browse/dist/server-node.mjs' -ne $expected) {
throw 'The qualified Node bundle differs from the candidate workspace build.'
}
}
}
} finally {
try {
if ($process -and -not $process.HasExited) { $process.Kill($true) }
} finally {
try {
if (Test-Path (Join-Path $work 'stdout.log')) { Get-Content (Join-Path $work 'stdout.log') }
if (Test-Path (Join-Path $work 'stderr.log')) { Get-Content (Join-Path $work 'stderr.log') }
if (Test-Path $evidence) { Get-ChildItem $evidence -Directory -Filter 'cookie-native-qualification-*' | Copy-Item -Destination $OutputRoot -Recurse }
} finally {
try { if ($account) { Remove-LocalUser -SID $account.SID } }
finally { $password.Dispose() }
}
}
}
exit $exitCode