fix(browse): restrictDirectoryPermissions warns and skips symlinked dirs

Closes the Windows Free Tests red: recent lane failures showed a
platform-unguarded POSIX mode-bit assertion ('Expected: 493' — a
symlink-skip test) from PR-branch variants; the KNOWN_WINDOWS_SAFE
force-include reason ('mode-bitmask hits are POSIX-branch only') did
not hold for that shape, and main had neither the guard nor the
behavior.

- product: lstat first; a symlinked dir gets a warning and a skip on
  both platforms — chmod AND icacls dereference the link, so
  restricting through a symlink hardens an unvetted target (and
  /inheritance:r could lock out its real owner). All callers already
  treat hardening as best-effort (try/catch).
- test: the symlink regression test, platform-aware — symlinkSync in
  the house try/catch skip pattern (Windows runners without Developer
  Mode can't create symlinks), mode-bit assertion guarded off win32,
  behavior assertions (no throw, warning text, target readable)
  everywhere; POSIX still proves the skip (0o755 unchanged, not 0o700)
- KNOWN_WINDOWS_SAFE reason updated to the now-true premise

20/20 pass on Linux.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-08-29 04:57:22 +00:00
co-authored by Claude Fable 5
parent 72a5246aae
commit 0d2f703f28
3 changed files with 75 additions and 2 deletions
+21
View File
@@ -140,8 +140,29 @@ export function restrictFilePermissions(filePath: string): void {
* (CI = container inherit) inherit the single-user-full ACL — important
* because child creations in `fs.writeFileSync(...)` without explicit
* `restrictFilePermissions` still end up owner-only.
*
* Symlinked dirs are warned about and SKIPPED, never followed: both
* `chmod` and `icacls` dereference the link, so restricting through a
* symlink hardens whatever the link points at — a target the caller never
* vetted (and, with `/inheritance:r`, one we could lock its real owner out
* of). Skipping is best-effort-consistent with the rest of this module:
* the filesystem stays functional, we just don't hit the hardening target.
*/
export function restrictDirectoryPermissions(dirPath: string): void {
try {
if (fs.lstatSync(dirPath).isSymbolicLink()) {
// biome-ignore lint/suspicious/noConsole: intentional user-facing warning
console.warn(
`[gstack] Refusing to restrict permissions through symlink ${dirPath} — skipping.\n` +
` Restricting through a symlink would alter the link target instead. ` +
`Harden the real directory directly.`
);
return;
}
} catch {
// Path doesn't exist (or lstat failed) — fall through; both platform
// branches below already swallow failures on missing paths.
}
if (process.platform === 'win32') {
try {
const user = currentUserPrincipal();