chore: Cleanup sandbox

This commit is contained in:
Abhisek Datta
2026-01-08 16:32:49 +05:30
parent 45049b001d
commit eaeaff9cb8
3 changed files with 22 additions and 25 deletions
-1
View File
@@ -10,7 +10,6 @@ import (
) )
// NewSandbox creates a platform-specific sandbox instance for Windows. // NewSandbox creates a platform-specific sandbox instance for Windows.
// TODO: Implement AppContainer or Job Objects based sandbox.
func NewSandbox() (sandbox.Sandbox, error) { func NewSandbox() (sandbox.Sandbox, error) {
return nil, errors.New("sandbox not yet implemented for Windows") return nil, errors.New("sandbox not yet implemented for Windows")
} }
+15 -14
View File
@@ -13,17 +13,15 @@ import (
"github.com/safedep/pmg/sandbox" "github.com/safedep/pmg/sandbox"
) )
// seatbeltSandbox implements the Sandbox interface using macOS Seatbelt (sandbox-exec).
type seatbeltSandbox struct { type seatbeltSandbox struct {
translator *policyTranslator translator *seatbeltPolicyTranslator
tempProfilePath string // Path to temporary .sb file, cleaned up in Close() tempProfilePath string
cleanupCompleted bool // Track if cleanup already happened (idempotent Close) cleanupCompleted bool
} }
// newSeatbeltSandbox creates a new Seatbelt sandbox instance.
func newSeatbeltSandbox() (*seatbeltSandbox, error) { func newSeatbeltSandbox() (*seatbeltSandbox, error) {
return &seatbeltSandbox{ return &seatbeltSandbox{
translator: newPolicyTranslator(), translator: newSeatbeltPolicyTranslator(),
}, nil }, nil
} }
@@ -34,30 +32,33 @@ func newSeatbeltSandbox() (*seatbeltSandbox, error) {
// This implementation modifies the cmd in place and does NOT execute it. // This implementation modifies the cmd in place and does NOT execute it.
// Returns ExecutionResult with executed=false, indicating the caller must run cmd.Run(). // Returns ExecutionResult with executed=false, indicating the caller must run cmd.Run().
func (s *seatbeltSandbox) Execute(ctx context.Context, cmd *exec.Cmd, policy *sandbox.SandboxPolicy) (*sandbox.ExecutionResult, error) { func (s *seatbeltSandbox) Execute(ctx context.Context, cmd *exec.Cmd, policy *sandbox.SandboxPolicy) (*sandbox.ExecutionResult, error) {
// Translate PMG policy to Seatbelt profile
sbProfile, err := s.translator.translate(policy) sbProfile, err := s.translator.translate(policy)
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to translate sandbox policy: %w", err) return nil, fmt.Errorf("failed to translate sandbox policy: %w", err)
} }
// Write Seatbelt profile to temporary file
// The file will be cleaned up when Close() is called
tmpFile, err := os.CreateTemp("", "pmg-sandbox-*.sb") tmpFile, err := os.CreateTemp("", "pmg-sandbox-*.sb")
if err != nil { if err != nil {
return nil, fmt.Errorf("failed to create temporary sandbox profile: %w", err) return nil, fmt.Errorf("failed to create temporary sandbox profile: %w", err)
} }
// Store the path for cleanup in Close() defer func() {
if err := tmpFile.Close(); err != nil {
log.Warnf("failed to close temporary sandbox profile: %v", err)
}
}()
// Storing the path is required for cleanup in Close()
s.tempProfilePath = tmpFile.Name() s.tempProfilePath = tmpFile.Name()
if _, err := tmpFile.WriteString(sbProfile); err != nil { if _, err := tmpFile.WriteString(sbProfile); err != nil {
tmpFile.Close() if err := os.Remove(s.tempProfilePath); err != nil {
// Clean up on error log.Warnf("failed to remove temporary sandbox profile: %v", err)
os.Remove(s.tempProfilePath) }
s.tempProfilePath = "" s.tempProfilePath = ""
return nil, fmt.Errorf("failed to write sandbox profile: %w", err) return nil, fmt.Errorf("failed to write sandbox profile: %w", err)
} }
tmpFile.Close()
log.Debugf("Seatbelt profile written to %s", s.tempProfilePath) log.Debugf("Seatbelt profile written to %s", s.tempProfilePath)
log.Debugf("Seatbelt profile content:\n%s", sbProfile) log.Debugf("Seatbelt profile content:\n%s", sbProfile)
@@ -12,16 +12,13 @@ import (
"github.com/safedep/pmg/sandbox/util" "github.com/safedep/pmg/sandbox/util"
) )
// policyTranslator translates PMG sandbox policies to Seatbelt Profile Language (.sb). type seatbeltPolicyTranslator struct{}
type policyTranslator struct{}
// newPolicyTranslator creates a new policy translator. func newSeatbeltPolicyTranslator() *seatbeltPolicyTranslator {
func newPolicyTranslator() *policyTranslator { return &seatbeltPolicyTranslator{}
return &policyTranslator{}
} }
// translate converts a PMG SandboxPolicy to Seatbelt Profile Language. func (t *seatbeltPolicyTranslator) translate(policy *sandbox.SandboxPolicy) (string, error) {
func (t *policyTranslator) translate(policy *sandbox.SandboxPolicy) (string, error) {
var sb strings.Builder var sb strings.Builder
// Header // Header
@@ -62,7 +59,7 @@ func (t *policyTranslator) translate(policy *sandbox.SandboxPolicy) (string, err
} }
// translateFilesystem translates filesystem access rules. // translateFilesystem translates filesystem access rules.
func (t *policyTranslator) translateFilesystem(policy *sandbox.SandboxPolicy, sb *strings.Builder) error { func (t *seatbeltPolicyTranslator) translateFilesystem(policy *sandbox.SandboxPolicy, sb *strings.Builder) error {
sb.WriteString(";; Filesystem access\n") sb.WriteString(";; Filesystem access\n")
// Expand and add allow read rules // Expand and add allow read rules
@@ -137,7 +134,7 @@ func (t *policyTranslator) translateFilesystem(policy *sandbox.SandboxPolicy, sb
} }
// translateNetwork translates network access rules. // translateNetwork translates network access rules.
func (t *policyTranslator) translateNetwork(policy *sandbox.SandboxPolicy, sb *strings.Builder) error { func (t *seatbeltPolicyTranslator) translateNetwork(policy *sandbox.SandboxPolicy, sb *strings.Builder) error {
sb.WriteString(";; Network access\n") sb.WriteString(";; Network access\n")
// If there are allow outbound rules, allow network-outbound generally // If there are allow outbound rules, allow network-outbound generally
@@ -165,7 +162,7 @@ func (t *policyTranslator) translateNetwork(policy *sandbox.SandboxPolicy, sb *s
} }
// translateProcess translates process execution rules. // translateProcess translates process execution rules.
func (t *policyTranslator) translateProcess(policy *sandbox.SandboxPolicy, sb *strings.Builder) error { func (t *seatbeltPolicyTranslator) translateProcess(policy *sandbox.SandboxPolicy, sb *strings.Builder) error {
sb.WriteString(";; Process execution\n") sb.WriteString(";; Process execution\n")
// Add allow exec rules // Add allow exec rules