mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
fix(sandbox): bind parent dir for globstar allow_write on bwrap (#321)
* fix(sandbox): bind parent dir for globstar allow_write on bwrap
Fine-grained per-path mounts under read-only project binds broke pip
install into in-project .venv directories. Always mount the parent tree
for ** write rules instead.
Fixes #315
* test(sandbox): tighten globstar bind assertions and ensure ~/.npm exists for e2e
Strengthen TestBubblewrapAllowWriteGlobstarBindsParentOnly to verify the
parent dir is writably bound and the child path is read-only bound, not
just substring presence. Pre-create ~/.npm in the e2e harness so
bubblewrap --bind-try does not skip the npm cache dir on fresh runners.
* switch pnpm to /tmp in sandbox e2e
* test(sandbox): update glob ** test for parent-bind semantics
Globstar allow_write now binds the parent dir only (e2e740d), so the
test should assert the parent is writably bound and child subdirs are
not individually bound, instead of substring-matching subdir names.
* fix(sandbox): bind correct base dir for in-pattern globstar allow_write
Globstar allow_write previously used extractGlobParentDir, which walks past
the first ** and yields the wrong root for patterns like /a/b/**/d/**/e.
Introduce extractGlobstarWriteBaseDir, which takes the prefix before the
first /**, and use it in processWriteRule. Also dedup the coarse-fallback
parent-bind loop to mirror the read-rule fallback.
This commit is contained in:
@@ -529,8 +529,21 @@ func (t *bubblewrapPolicyTranslator) processWriteRule(path string, boundPaths ma
|
||||
|
||||
// Check if path contains glob pattern
|
||||
if util.ContainsGlob(path) {
|
||||
// Check if the base directory is already bound (e.g., /tmp already bound, skip /tmp/**)
|
||||
baseDir := t.extractParentDir(path)
|
||||
|
||||
// Globstar write rules always bind the parent directory read-write. Per-path
|
||||
// binds interact badly with earlier read-only parent mounts (e.g. ${CWD}/**)
|
||||
// and miss files beyond maxGlobDepth — see https://github.com/safedep/pmg/issues/315.
|
||||
// Base dir is the path prefix before the first "/**" (see extractGlobstarWriteBaseDir).
|
||||
if strings.Contains(path, "**") {
|
||||
baseDir = extractGlobstarWriteBaseDir(path)
|
||||
args = append(args, "--bind-try", baseDir, baseDir)
|
||||
boundPaths[baseDir] = true
|
||||
log.Debugf("Globstar allow_write: bound parent directory '%s' (read-write)", baseDir)
|
||||
return args, nil
|
||||
}
|
||||
|
||||
// Check if the base directory is already bound (e.g., /tmp already bound, skip /tmp/**)
|
||||
if boundPaths[baseDir] {
|
||||
log.Debugf("Skipping pattern '%s' - base directory '%s' already bound", path, baseDir)
|
||||
return args, nil
|
||||
@@ -550,8 +563,7 @@ func (t *bubblewrapPolicyTranslator) processWriteRule(path string, boundPaths ma
|
||||
boundPaths[parentDir] = true
|
||||
log.Debugf("Coarse-grained fallback: bound parent directory '%s' (read-write)", parentDir)
|
||||
} else {
|
||||
// Path already bound, skip (likely already bound as read-only from essential paths)
|
||||
log.Debugf("Parent directory '%s' already bound, skipping duplicate bind", parentDir)
|
||||
log.Debugf("Parent directory '%s' already bound for write, skipping duplicate bind", parentDir)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
|
||||
Reference in New Issue
Block a user