Conversation
b895e47 to
3635e17
Compare
72e1d72 to
91612cb
Compare
6ebe186 to
ad4b2dc
Compare
4a896a4 to
16adc12
Compare
| async function savedAcl(pathname: string): Promise<string> { | ||
| return withAclBackup(async (backup) => { | ||
| await execFile(system32("icacls.exe"), [pathname, "/save", backup]); | ||
| return await fs.readFile(backup, "utf16le"); |
There was a problem hiding this comment.
Why does this have to be utf-16 ?
icacls /save Defaults to UTF-16LE
When the extension runs icacls.exe [target] /save [backup], it asks Windows to dump the Access Control List (ACL) of the target SSH config file into a text file. By default, Windows writes this backup file using UTF-16LE (Little Endian) encoding.
There was a problem hiding this comment.
This was written in the prod file, but I've added a small comment here as well 🙏
There was a problem hiding this comment.
just gotta make sure utf-16 files and strings don't leak out to much, are used minimally. I do see it in the prod code; I'm not a fan of alternative content encoding, as they can cause unintended data pollution.
icacls.exe
I think another windows expert should give this PR a better review
Repair included fragments with built-in Windows tools and retain best-effort SSH setup. Inject permission repair as a collaborator so the config writer stays platform agnostic, skip files whose permissions already verify, and drive the real Windows tools from the native tests. Fixes #1108 Generated by Coder Agents.
Keep vitest.config.mts declarative, and record why the icacls backup is read as UTF-16LE.
16adc12 to
dddc9e9
Compare
|
is there any reason you didn't use the Scripts ran by the Windows Script Host are super sketchy patterns that AVs love to flag for no reason. Spawning PowerShell is similar but less so. |
8cf3d1c to
dd84e8c
Compare
Replace the WSH setter and runtime ACL parsing with checked icacls commands. Repair existing deployment fragments on upgrade, retain path and link guards, and consolidate ACL helpers and tests.
dd84e8c to
98bbb22
Compare
Summary
Fixes #1108. On Windows, OpenSSH refuses to read an
Includewhen any file it matches is too permissive, so connections fail withBad owner or permissions. This repairs the permissions of the extension's own SSH config directory using built-in commands, with no Windows Script Host, ADSI, native dependency, or elevation.whoami.exeto find the current user, thenicacls.exe /resetand/inheritance:r /grant:ron%APPDATA%\coder.coder-remote\ssh. Only that user, SYSTEM, and Administrators keep inheritable full control.*.confmatch to inherit the directory, which also repairs other deployments and editors on the first connection after an upgrade, plus the temporary file before its rename.SshConfigtakes an optionalManagedPermissions. Its absence is the marker for "not Coder-managed", which is why it has no no-op default: a default would make the extension enumerate~/.sshon every save on every platform.createManagedPermissions()returnsundefinedoff Windows, so the whole repair path stays Windows-only.What each file changes
src/remote/windowsAcl.tsWINDOWS_ACL,createManagedPermissions, andsystem32; everything else is private, ordered by first use.src/remote/sshConfig.tsManagedPermissionsinterface. Splitssave()intogetFileMode,repairIncludedFiles,writeTemp,repairPermissions, andreplaceWithTemp, and makes the temp write exclusive (wx).src/remote/remote.tscreateManagedPermissions()to the per-deploymentSshConfig.test/unit/remote/windowsAcl.test.tsicacls.exeandwhoami.exe: the command transcript, 9 rejection rows, failure propagation, and 12 path-form rows through the public API.test/unit/remote/windowsAcl.native.test.tsicacls.exe,whoami.exe, and OpenSSH, skipped off Windows.test/unit/remote/sshConfig.test.tstest/env-check.ts,vitest.config.mtsprocess.archdoes not matchEXPECTED_ARCH..github/workflows/ci.yamlwindows-11-armunit-test job and setsEXPECTED_ARCH.CONTRIBUTING.md,CHANGELOG.md.gitattributes,.vscodeignoreTotal: 865 added, 16 removed across 13 files.
Simplification pass
The last commit reworks the first implementation rather than adding to it:
WindowsAclclass with aWINDOWS_ACLconst holding two functions. The old class tracked the last prepared directory so thatsecure()could refuse a file outside it, butSshConfig.save()is the only caller and already calls them in order. Removing that state removed three tests with it.parseWhoamiUserSidintocurrentUserSidand stopped exportingisFullyQualifiedWindowsPath, which existed only so a test could assert on it. The same decision is reachable throughWINDOWS_ACL.secure().FilePermissionstoManagedPermissions. It prepares a directory, so "File" was wrong, and the name now hints that absence means unmanaged.src/remote/windows/acl.tstosrc/remote/windowsAcl.ts, since the directory held one file.it.eachtables, command assertions became flat transcript strings instead of nested arrays, and the 60-second native test lost a duplicate fixture.CONTRIBUTING.mdsection and rewrote the changelog entry around the error users see.Validation
pnpm test: 2,710 passed, 6 skipped, 181 files. The native Windows tests are among the skips on Linux.pnpm typecheckandpnpm lintpass.*.confdirectory case against OpenSSH 9.6p1 on Linux: glibc opens a directory successfully, so OpenSSH reads zero lines and ignores it unless it is group-writable or unreadable. The Windows CRT fails the open instead, which aborts the wholeInclude, so the extension reports that entry rather than trying to fix it with an ACL change.Limits
A directory-preparation failure stops the write. A single file-reset failure logs a warning and still attempts the connection, so OpenSSH may reject a fragment the repair missed. The two directory commands are not atomic: a failure after
/resetcan leave the directory with its parent's grants. The path and link checks stop mistakes, not an attacker racing the check.Generated by Coder Agents on behalf of @EhabY.