Skip to content

Commit 98fadf2

Browse files
EliahKaganclaude
andcommitted
Add a diagnostic job demonstrating the TokenOwner mechanism
Temporarily add a `diag-token` job to `.github/workflows/cygwin-test.yml` that creates a directory through four code paths and reports its NTFS Owner. The intent is to empirically establish the cause of the Owner asymmetry described in the next commit ("Cover submodule working trees in safe.directory on Cygwin"): a Cygwin or Cygwin-derived runtime (`cygwin1.dll` for Cygwin git; `msys-2.0.dll` loaded by Git for Windows's bundled MSYS2 `sh.exe`) rewrites the process token's `TokenOwner` field at DLL initialization, and `CreateProcessW` propagates that mutation to every descendant. The four tests are: | Test | Chain | Predicted Owner | | ---- | ---------------------------------------------- | ------------------------ | | A | PowerShell `New-Item` | `BUILTIN\Administrators` | | D | Cygwin `mkdir` | `runneradmin` (197108) | | F | Cygwin bash -> Git for Windows `git init` | `runneradmin` (197108) | | G | PowerShell -> Git Bash -> PowerShell `New-Item`| `runneradmin` (197108) | A is the Win32 baseline. The kernel-default `TokenOwner` for `runneradmin`'s full administrative token is `BUILTIN\Administrators`, because `runneradmin` is the built-in local Administrator (RID 500) and `FilterAdministratorToken=0` exempts it from UAC token filtering. D is the Cygwin baseline. Cygwin's `cygheap_user::init` calls `NtSetInformationToken(TokenOwner, &user_sid, ...)` at DLL init, and the resulting Owner reflects the rewritten token. F is the load-bearing case. The child is a Win32 binary that loads no Cygwin runtime of its own. It produces a user-owned `.git`, proving that the rewrite performed by the parent Cygwin bash propagates through `CreateProcessW`'s token duplication to a Win32 descendant. G strengthens the case: the first and last links are pure Win32 (a fresh PowerShell using its own `New-Item` builtin), and only the middle link is a Cygwin-family runtime (Git for Windows's bundled MSYS2 `bash.exe`, linked against `msys-2.0.dll`). The directory is still user-owned, proving the mechanism does not depend on git, on shell-dispatch via `git submodule`, or on any property of the final-link binary -- only on whether *some* process in the ancestry has loaded a Cygwin-family runtime. This `diag-token` job, like the `reproduce-safe-dir` matrix added in the previous commit, is temporary and should be removed before this work is integrated. Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent fb11430 commit 98fadf2

1 file changed

Lines changed: 67 additions & 0 deletions

File tree

‎.github/workflows/cygwin-test.yml‎

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,73 @@ jobs:
102102
run: |
103103
pytest --color=yes -p no:sugar --instafail -vv ${{ matrix.additional-pytest-args }}
104104
105+
diag-token:
106+
runs-on: windows-latest
107+
108+
env: *cygwin-env
109+
110+
defaults: *cygwin-defaults
111+
112+
steps:
113+
- *force-lf
114+
- *checkout
115+
- *install-cygwin
116+
117+
- name: PowerShell-side token state and file-creation tests
118+
shell: pwsh
119+
run: |
120+
$repo = "D:\a\GitPython\GitPython"
121+
Write-Host "==================== whoami /all (PowerShell) ===================="
122+
whoami /all
123+
Write-Host ""
124+
Write-Host "==================== Test A: PowerShell New-Item directory ===================="
125+
$td = "$repo\test-pwsh-mkdir"
126+
New-Item -ItemType Directory -Path $td -Force | Out-Null
127+
$acl = Get-Acl -LiteralPath $td
128+
Write-Host "Owner of $td : $($acl.Owner)"
129+
Remove-Item $td -Force
130+
Write-Host ""
131+
Write-Host "==================== Test G: PowerShell -> Git Bash -> PowerShell New-Item ===================="
132+
$td4 = "$repo\test-pwsh-bash-pwsh-mkdir"
133+
$scriptPath = "$repo\inner-mkdir.ps1"
134+
"New-Item -ItemType Directory -Path '$td4' -Force | Out-Null" |
135+
Set-Content -Path $scriptPath -Encoding utf8
136+
$env:MSYS2_ARG_CONV_EXCL = '*'
137+
try {
138+
& "C:\Program Files\Git\bin\bash.exe" -c "powershell.exe -NoProfile -ExecutionPolicy Bypass -File '$scriptPath'" 2>&1 | Out-Null
139+
} finally {
140+
Remove-Item Env:MSYS2_ARG_CONV_EXCL -ErrorAction SilentlyContinue
141+
}
142+
if (Test-Path -LiteralPath $td4) {
143+
$acl = Get-Acl -LiteralPath $td4
144+
Write-Host "Owner of $td4 (PowerShell -> bash -> PowerShell New-Item) : $($acl.Owner)"
145+
Remove-Item $td4 -Force
146+
} else {
147+
Write-Host "Owner of $td4 (PowerShell -> bash -> PowerShell New-Item) : (directory not created)"
148+
}
149+
Remove-Item $scriptPath -Force -ErrorAction SilentlyContinue
150+
151+
- name: Cygwin-side token state and file-creation tests
152+
run: |
153+
set +e
154+
echo "==================== id (Cygwin) ===================="
155+
id
156+
echo
157+
echo "==================== Test D: Cygwin mkdir ===================="
158+
td="$(pwd)/test-cygwin-mkdir"
159+
mkdir "$td"
160+
echo "Owner: $(stat -c '%U(%u)' "$td")"
161+
rmdir "$td"
162+
echo
163+
echo "==================== Test F: Cygwin-spawned Git for Windows git init ===================="
164+
td3="$(pwd)/test-cygwin-spawns-wingit"
165+
mkdir "$td3"
166+
( cd "$td3" && /cygdrive/c/Program\ Files/Git/bin/git.exe init -q )
167+
echo "Owner of $td3 (Cygwin-mkdir) : $(stat -c '%U(%u)' "$td3")"
168+
echo "Owner of $td3/.git (Cygwin->Win git init): $(stat -c '%U(%u)' "$td3/.git")"
169+
rm -rf "$td3"
170+
true
171+
105172
reproduce-safe-dir:
106173
strategy:
107174
matrix:

0 commit comments

Comments
 (0)