fix(sandbox): reject overlapping Windows temp roots
This commit is contained in:
40
packages/sandbox/sandbox-windows-acl/src/path-boundary.ts
Normal file
40
packages/sandbox/sandbox-windows-acl/src/path-boundary.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* Canonical directory-boundary checks for the Windows ACL workspace and
|
||||
* private-temp capabilities.
|
||||
* @module @deepseek-ai/dsh-sandbox-windows-acl/path-boundary
|
||||
*/
|
||||
|
||||
import { realpathSync } from 'node:fs'
|
||||
import { isAbsolute, relative, sep } from 'node:path'
|
||||
|
||||
/** Whether `root` is the same canonical directory as `candidate` or contains it. */
|
||||
function containsDirectory(root: string, candidate: string): boolean {
|
||||
const relation = relative(realpathSync.native(root), realpathSync.native(candidate))
|
||||
return relation === '' || (!isAbsolute(relation) && relation !== '..' && !relation.startsWith(`..${sep}`))
|
||||
}
|
||||
|
||||
/**
|
||||
* Reject a temp parent that is inside the workspace: every child created
|
||||
* below it would inherit the standing workspace capability.
|
||||
* @param workspaceRoot - the canonical workspace root that receives the standing ACE.
|
||||
* @param tempRoot - the existing parent beneath which a private temp child would be created.
|
||||
*/
|
||||
export function assertTempRootOutsideWorkspace(workspaceRoot: string, tempRoot: string): void {
|
||||
if (containsDirectory(workspaceRoot, tempRoot)) {
|
||||
throw new Error(`Windows ACL temp root must be outside the workspace: workspace=${workspaceRoot}; temp=${tempRoot}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reject overlap between an actual private temp directory and any writable
|
||||
* directory: either inheritance direction would merge the two capabilities.
|
||||
* @param writableDirs - directories carrying the standing workspace capability.
|
||||
* @param tempDir - the existing directory carrying the revocable temp capability.
|
||||
*/
|
||||
export function assertPrivateTempDisjoint(writableDirs: readonly string[], tempDir: string): void {
|
||||
for (const writableDir of writableDirs) {
|
||||
if (containsDirectory(writableDir, tempDir) || containsDirectory(tempDir, writableDir)) {
|
||||
throw new Error(`AclSandbox private temp directory must be disjoint from writable directories: writable=${writableDir}; temp=${tempDir}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user