From b397e5c76f3a946099a5ff2419c10d0a5884ed51 Mon Sep 17 00:00:00 2001 From: Copilot <223556219+Copilot@users.noreply.github.com> Date: Mon, 23 Mar 2026 14:02:13 -0700 Subject: [PATCH] docs: add case-insensitive path comparison to windows-compatibility skill MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit During StorageProvider Phase 1, a cross-platform audit found that startsWith() is case-sensitive but Windows and macOS filesystems are case-insensitive. This gap was missed by 4 rounds of security review because the existing skill covered timestamps, git commands, and path separators — but not path comparison semantics. Adding platform-aware comparison pattern and anti-pattern example so future agents catch this automatically via skill-aware routing. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../skills/windows-compatibility/SKILL.md | 24 +++++++++++++++++++ .../skills/windows-compatibility/SKILL.md | 24 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/packages/squad-cli/templates/skills/windows-compatibility/SKILL.md b/packages/squad-cli/templates/skills/windows-compatibility/SKILL.md index 3bb991edd..6242b88c4 100644 --- a/packages/squad-cli/templates/skills/windows-compatibility/SKILL.md +++ b/packages/squad-cli/templates/skills/windows-compatibility/SKILL.md @@ -30,6 +30,23 @@ Squad runs on Windows, macOS, and Linux. Several bugs have been traced to platfo - **Never assume CWD is repo root:** Always use `TEAM ROOT` from spawn prompt or run `git rev-parse --show-toplevel` - **Use path.join() or path.resolve():** Don't manually concatenate with `/` or `\` +### Path Comparison (Case Sensitivity) +- **Never use case-sensitive `startsWith` or `===` for path comparison on Windows or macOS:** These filesystems are case-insensitive — `C:\Users\` and `c:\users\` refer to the same location +- **Use platform-aware comparison:** Check `process.platform === 'win32' || process.platform === 'darwin'` and lowercase both sides before comparing +- **Pattern:** + ```typescript + const CASE_INSENSITIVE = process.platform === 'win32' || process.platform === 'darwin'; + + function pathStartsWith(fullPath: string, prefix: string): boolean { + if (CASE_INSENSITIVE) { + return fullPath.toLowerCase().startsWith(prefix.toLowerCase()); + } + return fullPath.startsWith(prefix); + } + ``` +- **Where it matters:** Security checks (path traversal prevention), rootDir confinement, any path-contains-path validation +- **Linux is case-sensitive:** Do NOT lowercase on Linux — `/Home/` and `/home/` are different directories + ## Examples ✓ **Correct:** @@ -72,3 +89,10 @@ exec('git commit -m "First line\nSecond line"'); // FAILS silently in PowerShell - Assuming Unix-style paths work everywhere - Using `git -C` because it "looks cleaner" (it doesn't work) - Skipping `git diff --cached --quiet` check (creates empty commits) +- **Wrong — case-sensitive path check on Windows and macOS:** + ```typescript + if (!resolved.startsWith(rootDir + path.sep)) { + throw new Error('Path traversal blocked'); + } + // Fails: 'c:\\Users\\temp\\file'.startsWith('C:\\Users\\temp\\') → false + ``` diff --git a/packages/squad-sdk/templates/skills/windows-compatibility/SKILL.md b/packages/squad-sdk/templates/skills/windows-compatibility/SKILL.md index 3bb991edd..6242b88c4 100644 --- a/packages/squad-sdk/templates/skills/windows-compatibility/SKILL.md +++ b/packages/squad-sdk/templates/skills/windows-compatibility/SKILL.md @@ -30,6 +30,23 @@ Squad runs on Windows, macOS, and Linux. Several bugs have been traced to platfo - **Never assume CWD is repo root:** Always use `TEAM ROOT` from spawn prompt or run `git rev-parse --show-toplevel` - **Use path.join() or path.resolve():** Don't manually concatenate with `/` or `\` +### Path Comparison (Case Sensitivity) +- **Never use case-sensitive `startsWith` or `===` for path comparison on Windows or macOS:** These filesystems are case-insensitive — `C:\Users\` and `c:\users\` refer to the same location +- **Use platform-aware comparison:** Check `process.platform === 'win32' || process.platform === 'darwin'` and lowercase both sides before comparing +- **Pattern:** + ```typescript + const CASE_INSENSITIVE = process.platform === 'win32' || process.platform === 'darwin'; + + function pathStartsWith(fullPath: string, prefix: string): boolean { + if (CASE_INSENSITIVE) { + return fullPath.toLowerCase().startsWith(prefix.toLowerCase()); + } + return fullPath.startsWith(prefix); + } + ``` +- **Where it matters:** Security checks (path traversal prevention), rootDir confinement, any path-contains-path validation +- **Linux is case-sensitive:** Do NOT lowercase on Linux — `/Home/` and `/home/` are different directories + ## Examples ✓ **Correct:** @@ -72,3 +89,10 @@ exec('git commit -m "First line\nSecond line"'); // FAILS silently in PowerShell - Assuming Unix-style paths work everywhere - Using `git -C` because it "looks cleaner" (it doesn't work) - Skipping `git diff --cached --quiet` check (creates empty commits) +- **Wrong — case-sensitive path check on Windows and macOS:** + ```typescript + if (!resolved.startsWith(rootDir + path.sep)) { + throw new Error('Path traversal blocked'); + } + // Fails: 'c:\\Users\\temp\\file'.startsWith('C:\\Users\\temp\\') → false + ```