mirror of https://github.com/garrytan/gstack.git
Merge 99a07e5580 into a3259400a3
This commit is contained in:
commit
c05897c14a
|
|
@ -245,6 +245,18 @@ export class WorktreeManager {
|
||||||
} catch { /* non-fatal */ }
|
} catch { /* non-fatal */ }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Verify a path resolves inside worktreeBase (defends against symlink-plant attacks). */
|
||||||
|
private safeInsideWorktrees(p: string): boolean {
|
||||||
|
try {
|
||||||
|
const real = fs.realpathSync.native(p);
|
||||||
|
const baseReal = fs.realpathSync.native(this.worktreeBase);
|
||||||
|
const rel = path.relative(baseReal, real);
|
||||||
|
return !!rel && !rel.startsWith('..') && !path.isAbsolute(rel);
|
||||||
|
} catch {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/** Remove worktrees from previous runs that weren't cleaned up. */
|
/** Remove worktrees from previous runs that weren't cleaned up. */
|
||||||
pruneStale(): void {
|
pruneStale(): void {
|
||||||
try {
|
try {
|
||||||
|
|
@ -264,6 +276,11 @@ export class WorktreeManager {
|
||||||
const stat = fs.statSync(entryPath);
|
const stat = fs.statSync(entryPath);
|
||||||
const ageMs = Date.now() - stat.mtimeMs;
|
const ageMs = Date.now() - stat.mtimeMs;
|
||||||
if (ageMs < 3600_000) continue;
|
if (ageMs < 3600_000) continue;
|
||||||
|
// Defend against symlink-plant: ensure it resolves inside worktreeBase
|
||||||
|
if (!this.safeInsideWorktrees(entryPath)) {
|
||||||
|
process.stderr.write(` WORKTREE: skip suspicious path: ${entryPath}\n`);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
fs.rmSync(entryPath, { recursive: true, force: true });
|
fs.rmSync(entryPath, { recursive: true, force: true });
|
||||||
} catch { /* non-fatal */ }
|
} catch { /* non-fatal */ }
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue