2.4 KiB
2.4 KiB
Stage 4: Paths
Status: ⬜ Not Started Blocked By: None (can run parallel with Handlers) Unlocks: Documents
Objective
Replace hardcoded paths with XDG-compliant paths and add path security.
XDG Directory Reference
| Function | Path | Purpose |
|---|---|---|
getConfigDir(name) |
~/.config/{name} |
Configuration files |
getCacheDir(name) |
~/.cache/{name} |
Cache files |
getDataDir(name) |
~/.local/share/{name} |
Persistent data |
getStateDir(name) |
~/.local/state/{name} |
Runtime state |
Files to Migrate
{{#each PATH_FILES}}
{{this.file}}
- Line: {{this.line}}
- Current:
{{this.current}} - Pattern: {{this.pattern}}
Migration
- Replace with XDG function
- Add
securePath()if user-provided - Update tests
// Before
{{this.beforeCode}}
// After
{{this.afterCode}}
{{/each}}
Path Security
For user-provided paths, use securePath():
import { securePath } from "@outfitter/file-ops";
const validatePath = (userPath: string, baseDir: string) => {
const result = securePath(userPath, { base: baseDir });
if (result.isErr()) {
return Result.err(new ValidationError("Invalid path", { path: userPath }));
}
return Result.ok(result.value);
};
Security checks:
- Path traversal (
../) - Symlink following
- Base directory escape
- Null bytes
Common Patterns
Config File
// Before
const configPath = path.join(os.homedir(), ".myapp", "config.json");
// After
import { getConfigDir } from "@outfitter/config";
const configPath = path.join(getConfigDir("myapp"), "config.json");
Cache Directory
// Before
const cacheDir = path.join(os.homedir(), ".cache", "myapp");
// After
import { getCacheDir } from "@outfitter/config";
const cacheDir = getCacheDir("myapp");
User-Provided Path
// Before
const filePath = args.file;
await fs.readFile(filePath);
// After
import { securePath } from "@outfitter/file-ops";
const pathResult = securePath(args.file, { base: process.cwd() });
if (pathResult.isErr()) return pathResult;
await fs.readFile(pathResult.value);
Completion Checklist
- All
os.homedir()replaced with XDG functions - All
~/literals replaced - User-provided paths validated with
securePath() - Tests use
withTempDir()fixture - No hardcoded absolute paths
Notes
{{PATH_NOTES}}