mirror of
https://github.com/safedep/pmg.git
synced 2026-08-03 07:24:09 +02:00
* feat: Initial implementation of landlock based sandbox driver * fix: Handle seccom probe failure * fix: Remove unnecessary seccomp probe * fix: Use file based policy load * fix: Keep bpf filter in memory * fix: Use TSYNC for seccom filter * fix: Use TSYNC for seccom filter * fix: Update landlock translator * fix: Landlock sandbox implementation * fix: Landlock + seccomp based sandboxing on Linux * fix: Misc fixes * fix: Cleanup sandbox files * fix: Handle mandatory deny API change post merge * fix: Landlock write access translation * chore: Fix linter issues * ci: Use /tmp for npm cache for landlock
111 lines
3.2 KiB
Go
111 lines
3.2 KiB
Go
//go:build linux
|
|
|
|
package platform
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
|
|
"github.com/safedep/dry/log"
|
|
"github.com/safedep/pmg/sandbox/util"
|
|
)
|
|
|
|
// expandGlobstarPattern expands patterns containing ** (recursive glob),
|
|
// which filepath.Glob does not support. Splits the pattern at ** into a base
|
|
// path and a suffix, walks the base with a depth limit, and collects entries
|
|
// whose path ends with the suffix.
|
|
//
|
|
// If the base path does not yet exist, returns []string{basePath} so callers
|
|
// can still grant coverage to the parent directory (matters for fresh
|
|
// node_modules / pnpm caches that haven't been created yet).
|
|
func expandGlobstarPattern(pattern string, maxDepth, maxPaths int) ([]string, error) {
|
|
parts := strings.Split(pattern, "**")
|
|
if len(parts) != 2 {
|
|
return nil, fmt.Errorf("only one ** globstar supported per pattern")
|
|
}
|
|
|
|
basePath := strings.TrimSuffix(parts[0], "/")
|
|
suffix := strings.TrimPrefix(parts[1], "/")
|
|
|
|
if basePath == "" {
|
|
log.Debugf("Skipping globstar pattern '%s' with empty base path (would walk from root)", pattern)
|
|
return []string{}, nil
|
|
}
|
|
|
|
expandedBase, err := util.ExpandVariables(basePath)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("failed to expand base path: %w", err)
|
|
}
|
|
basePath = expandedBase
|
|
|
|
if _, err := os.Stat(basePath); os.IsNotExist(err) {
|
|
return []string{basePath}, nil
|
|
}
|
|
|
|
matches := []string{}
|
|
if err := walkGlobWithDepthLimit(basePath, suffix, maxDepth, maxPaths, &matches); err != nil {
|
|
return nil, fmt.Errorf("failed to walk directory tree: %w", err)
|
|
}
|
|
return matches, nil
|
|
}
|
|
|
|
// walkGlobWithDepthLimit walks a directory tree from root, appending paths
|
|
// whose suffix matches `suffix`. Stops at maxDepth levels (when > 0) and
|
|
// after collecting maxPaths entries.
|
|
func walkGlobWithDepthLimit(root, suffix string, maxDepth, maxPaths int, matches *[]string) error {
|
|
return filepath.Walk(root, func(path string, info os.FileInfo, err error) error {
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
relPath, err := filepath.Rel(root, path)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
depth := 0
|
|
if relPath != "." {
|
|
depth = len(strings.Split(relPath, string(filepath.Separator)))
|
|
}
|
|
if maxDepth > 0 && depth > maxDepth {
|
|
if info.IsDir() {
|
|
return filepath.SkipDir
|
|
}
|
|
return nil
|
|
}
|
|
if suffix == "" || strings.HasSuffix(path, suffix) {
|
|
*matches = append(*matches, path)
|
|
if len(*matches) >= maxPaths {
|
|
return filepath.SkipAll
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
}
|
|
|
|
// extractGlobParentDir extracts the parent directory of a glob pattern. Used
|
|
// for coarse-grained fallback when expansion yields too many paths or the
|
|
// target tree is unsuitable for fine-grained rules.
|
|
//
|
|
// Examples:
|
|
// - ${CWD}/node_modules/** → ${CWD}/node_modules
|
|
// - ${HOME}/.cache/pnpm/** → ${HOME}/.cache/pnpm
|
|
// - /tmp/*.txt → /tmp
|
|
// - /usr/lib/**/*.so → /usr/lib
|
|
func extractGlobParentDir(pattern string) string {
|
|
pattern = strings.TrimSuffix(pattern, "/**")
|
|
pattern = strings.TrimSuffix(pattern, "/*")
|
|
|
|
idx := strings.IndexAny(pattern, "*?[")
|
|
if idx >= 0 {
|
|
pattern = pattern[:idx]
|
|
pattern = filepath.Dir(pattern)
|
|
}
|
|
pattern = strings.TrimSuffix(pattern, string(filepath.Separator))
|
|
|
|
if pattern == "" || pattern == string(filepath.Separator) {
|
|
return "."
|
|
}
|
|
return pattern
|
|
}
|