* feat(gsd): add directory safeguards to prevent running in system/home paths GSD previously had no protection against being launched from dangerous directories like $HOME, /, /usr, or /etc. This adds layered validation: - Blocked system paths (hard stop): /, /usr, /etc, /var, $HOME, tmpdir, etc. - High entry count heuristic (>200 entries triggers confirmation dialog) - Symlink resolution via realpathSync to prevent bypass - Integrated at three chokepoints: projectRoot(), showSmartEntry(), bootstrapGsdDirectory() Includes 19 tests covering all blocked categories, boundary conditions, and the assertSafeDirectory throw/return behavior. * fix: make directory safeguard tests cross-platform (Windows CI) - Skip Unix-specific blocked path tests on Windows (/, /usr, /etc, etc.) - Add Windows-specific blocked path tests (C:\, C:\Windows) - Use platform-appropriate path separator in trailing slash test - Fix root path normalization for Windows drive letters (C:\ not C:)
38 lines
1.7 KiB
Markdown
38 lines
1.7 KiB
Markdown
# Directory Safeguards Plan
|
|
|
|
## Problem
|
|
GSD had zero protection against being launched from dangerous directories like `$HOME`, `/`, `/usr`, `/etc`, etc. Running `gsd init` from these locations would create `.gsd/` and write planning files into system directories.
|
|
|
|
## Solution
|
|
Added a `validate-directory.ts` module with layered safeguards:
|
|
|
|
### Layer 1: Blocked system paths (hard stop)
|
|
- Filesystem roots: `/`, `/usr`, `/bin`, `/sbin`, `/etc`, `/var`, `/dev`, `/proc`, `/sys`, `/boot`, `/lib`, `/lib64`
|
|
- macOS: `/System`, `/Library`, `/Applications`, `/Volumes`, `/private`
|
|
- Windows: `C:\`, `C:\Windows`, `C:\Program Files`
|
|
- User's `$HOME` directory itself (subdirs are fine)
|
|
- System temp directory root (`os.tmpdir()`)
|
|
|
|
### Layer 2: High entry count heuristic (warning)
|
|
- Directories with >200 top-level entries trigger a confirmation dialog
|
|
- User can override if they really want to proceed
|
|
|
|
### Layer 3: Symlink resolution
|
|
- All paths are resolved through `realpathSync()` before checking
|
|
- Prevents bypassing via symlinks (e.g., `ln -s / ~/myproject`)
|
|
|
|
## Integration Points
|
|
1. `projectRoot()` in `commands.ts` — gateway for all `/gsd` subcommands (throws on blocked)
|
|
2. `showSmartEntry()` in `guided-flow.ts` — smart entry wizard (shows error/confirmation UI)
|
|
3. `bootstrapGsdDirectory()` in `init-wizard.ts` — final safety check before writing files (throws on blocked)
|
|
|
|
## Test Coverage
|
|
19 tests covering:
|
|
- All blocked path categories (/, /usr, /etc, /var, /usr/local/bin)
|
|
- Home directory (with and without trailing slash)
|
|
- Temp directory root
|
|
- Normal project directories (pass)
|
|
- Empty directories (pass)
|
|
- 200-entry boundary (pass) vs 210-entry (warning)
|
|
- assertSafeDirectory throw behavior
|
|
- Trailing slash normalization
|