Phase 2: Implement Execution Environment Abstraction (v0.3.0)
This commit implements Phase 2 of the CHORUS Task Execution Engine development plan, providing a comprehensive execution environment abstraction layer with Docker container sandboxing support. ## New Features ### Core Sandbox Interface - Comprehensive ExecutionSandbox interface with isolated task execution - Support for command execution, file I/O, environment management - Resource usage monitoring and sandbox lifecycle management - Standardized error handling with SandboxError types and categories ### Docker Container Sandbox Implementation - Full Docker API integration with secure container creation - Transparent repository mounting with configurable read/write access - Advanced security policies with capability dropping and privilege controls - Comprehensive resource limits (CPU, memory, disk, processes, file handles) - Support for tmpfs mounts, masked paths, and read-only bind mounts - Container lifecycle management with proper cleanup and health monitoring ### Security & Resource Management - Configurable security policies with SELinux, AppArmor, and Seccomp support - Fine-grained capability management with secure defaults - Network isolation options with configurable DNS and proxy settings - Resource monitoring with real-time CPU, memory, and network usage tracking - Comprehensive ulimits configuration for process and file handle limits ### Repository Integration - Seamless repository mounting from local paths to container workspaces - Git configuration support with user credentials and global settings - File inclusion/exclusion patterns for selective repository access - Configurable permissions and ownership for mounted repositories ### Testing Infrastructure - Comprehensive test suite with 60+ test cases covering all functionality - Docker integration tests with Alpine Linux containers (skipped in short mode) - Mock sandbox implementation for unit testing without Docker dependencies - Security policy validation tests with read-only filesystem enforcement - Resource usage monitoring and cleanup verification tests ## Technical Details ### Dependencies Added - github.com/docker/docker v28.4.0+incompatible - Docker API client - github.com/docker/go-connections v0.6.0 - Docker connection utilities - github.com/docker/go-units v0.5.0 - Docker units and formatting - Associated Docker API dependencies for complete container management ### Architecture - Interface-driven design enabling multiple sandbox implementations - Comprehensive configuration structures for all sandbox aspects - Resource usage tracking with detailed metrics collection - Error handling with retryable error classification - Proper cleanup and resource management throughout sandbox lifecycle ### Compatibility - Maintains backward compatibility with existing CHORUS architecture - Designed for future integration with Phase 3 Core Task Execution Engine - Extensible design supporting additional sandbox implementations (VM, process) This Phase 2 implementation provides the foundation for secure, isolated task execution that will be integrated with the AI model providers from Phase 1 in the upcoming Phase 3 development. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
		
							
								
								
									
										16
									
								
								vendor/github.com/stretchr/testify/suite/stats.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										16
									
								
								vendor/github.com/stretchr/testify/suite/stats.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -16,26 +16,30 @@ type TestInformation struct { | ||||
| } | ||||
|  | ||||
| func newSuiteInformation() *SuiteInformation { | ||||
| 	testStats := make(map[string]*TestInformation) | ||||
|  | ||||
| 	return &SuiteInformation{ | ||||
| 		TestStats: testStats, | ||||
| 		TestStats: make(map[string]*TestInformation), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (s SuiteInformation) start(testName string) { | ||||
| func (s *SuiteInformation) start(testName string) { | ||||
| 	if s == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	s.TestStats[testName] = &TestInformation{ | ||||
| 		TestName: testName, | ||||
| 		Start:    time.Now(), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (s SuiteInformation) end(testName string, passed bool) { | ||||
| func (s *SuiteInformation) end(testName string, passed bool) { | ||||
| 	if s == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	s.TestStats[testName].End = time.Now() | ||||
| 	s.TestStats[testName].Passed = passed | ||||
| } | ||||
|  | ||||
| func (s SuiteInformation) Passed() bool { | ||||
| func (s *SuiteInformation) Passed() bool { | ||||
| 	for _, stats := range s.TestStats { | ||||
| 		if !stats.Passed { | ||||
| 			return false | ||||
|   | ||||
							
								
								
									
										112
									
								
								vendor/github.com/stretchr/testify/suite/suite.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										112
									
								
								vendor/github.com/stretchr/testify/suite/suite.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -7,6 +7,7 @@ import ( | ||||
| 	"reflect" | ||||
| 	"regexp" | ||||
| 	"runtime/debug" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"testing" | ||||
| 	"time" | ||||
| @@ -15,7 +16,6 @@ import ( | ||||
| 	"github.com/stretchr/testify/require" | ||||
| ) | ||||
|  | ||||
| var allTestsFilter = func(_, _ string) (bool, error) { return true, nil } | ||||
| var matchMethod = flag.String("testify.m", "", "regular expression to select tests of the testify suite to run") | ||||
|  | ||||
| // Suite is a basic testing suite with methods for storing and | ||||
| @@ -116,6 +116,11 @@ func (suite *Suite) Run(name string, subtest func()) bool { | ||||
| 	}) | ||||
| } | ||||
|  | ||||
| type test = struct { | ||||
| 	name string | ||||
| 	run  func(t *testing.T) | ||||
| } | ||||
|  | ||||
| // Run takes a testing suite and runs all of the tests attached | ||||
| // to it. | ||||
| func Run(t *testing.T, suite TestingSuite) { | ||||
| @@ -124,45 +129,39 @@ func Run(t *testing.T, suite TestingSuite) { | ||||
| 	suite.SetT(t) | ||||
| 	suite.SetS(suite) | ||||
|  | ||||
| 	var suiteSetupDone bool | ||||
|  | ||||
| 	var stats *SuiteInformation | ||||
| 	if _, ok := suite.(WithStats); ok { | ||||
| 		stats = newSuiteInformation() | ||||
| 	} | ||||
|  | ||||
| 	tests := []testing.InternalTest{} | ||||
| 	var tests []test | ||||
| 	methodFinder := reflect.TypeOf(suite) | ||||
| 	suiteName := methodFinder.Elem().Name() | ||||
|  | ||||
| 	for i := 0; i < methodFinder.NumMethod(); i++ { | ||||
| 		method := methodFinder.Method(i) | ||||
|  | ||||
| 		ok, err := methodFilter(method.Name) | ||||
| 	var matchMethodRE *regexp.Regexp | ||||
| 	if *matchMethod != "" { | ||||
| 		var err error | ||||
| 		matchMethodRE, err = regexp.Compile(*matchMethod) | ||||
| 		if err != nil { | ||||
| 			fmt.Fprintf(os.Stderr, "testify: invalid regexp for -m: %s\n", err) | ||||
| 			os.Exit(1) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 		if !ok { | ||||
| 	for i := 0; i < methodFinder.NumMethod(); i++ { | ||||
| 		method := methodFinder.Method(i) | ||||
|  | ||||
| 		if !strings.HasPrefix(method.Name, "Test") { | ||||
| 			continue | ||||
| 		} | ||||
| 		// Apply -testify.m filter | ||||
| 		if matchMethodRE != nil && !matchMethodRE.MatchString(method.Name) { | ||||
| 			continue | ||||
| 		} | ||||
|  | ||||
| 		if !suiteSetupDone { | ||||
| 			if stats != nil { | ||||
| 				stats.Start = time.Now() | ||||
| 			} | ||||
|  | ||||
| 			if setupAllSuite, ok := suite.(SetupAllSuite); ok { | ||||
| 				setupAllSuite.SetupSuite() | ||||
| 			} | ||||
|  | ||||
| 			suiteSetupDone = true | ||||
| 		} | ||||
|  | ||||
| 		test := testing.InternalTest{ | ||||
| 			Name: method.Name, | ||||
| 			F: func(t *testing.T) { | ||||
| 		test := test{ | ||||
| 			name: method.Name, | ||||
| 			run: func(t *testing.T) { | ||||
| 				parentT := suite.T() | ||||
| 				suite.SetT(t) | ||||
| 				defer recoverAndFailOnPanic(t) | ||||
| @@ -171,10 +170,7 @@ func Run(t *testing.T, suite TestingSuite) { | ||||
|  | ||||
| 					r := recover() | ||||
|  | ||||
| 					if stats != nil { | ||||
| 						passed := !t.Failed() && r == nil | ||||
| 						stats.end(method.Name, passed) | ||||
| 					} | ||||
| 					stats.end(method.Name, !t.Failed() && r == nil) | ||||
|  | ||||
| 					if afterTestSuite, ok := suite.(AfterTest); ok { | ||||
| 						afterTestSuite.AfterTest(suiteName, method.Name) | ||||
| @@ -195,59 +191,47 @@ func Run(t *testing.T, suite TestingSuite) { | ||||
| 					beforeTestSuite.BeforeTest(methodFinder.Elem().Name(), method.Name) | ||||
| 				} | ||||
|  | ||||
| 				if stats != nil { | ||||
| 					stats.start(method.Name) | ||||
| 				} | ||||
| 				stats.start(method.Name) | ||||
|  | ||||
| 				method.Func.Call([]reflect.Value{reflect.ValueOf(suite)}) | ||||
| 			}, | ||||
| 		} | ||||
| 		tests = append(tests, test) | ||||
| 	} | ||||
| 	if suiteSetupDone { | ||||
| 		defer func() { | ||||
| 			if tearDownAllSuite, ok := suite.(TearDownAllSuite); ok { | ||||
| 				tearDownAllSuite.TearDownSuite() | ||||
| 			} | ||||
|  | ||||
| 			if suiteWithStats, measureStats := suite.(WithStats); measureStats { | ||||
| 				stats.End = time.Now() | ||||
| 				suiteWithStats.HandleStats(suiteName, stats) | ||||
| 			} | ||||
| 		}() | ||||
| 	if len(tests) == 0 { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	if stats != nil { | ||||
| 		stats.Start = time.Now() | ||||
| 	} | ||||
|  | ||||
| 	if setupAllSuite, ok := suite.(SetupAllSuite); ok { | ||||
| 		setupAllSuite.SetupSuite() | ||||
| 	} | ||||
|  | ||||
| 	defer func() { | ||||
| 		if tearDownAllSuite, ok := suite.(TearDownAllSuite); ok { | ||||
| 			tearDownAllSuite.TearDownSuite() | ||||
| 		} | ||||
|  | ||||
| 		if suiteWithStats, measureStats := suite.(WithStats); measureStats { | ||||
| 			stats.End = time.Now() | ||||
| 			suiteWithStats.HandleStats(suiteName, stats) | ||||
| 		} | ||||
| 	}() | ||||
|  | ||||
| 	runTests(t, tests) | ||||
| } | ||||
|  | ||||
| // Filtering method according to set regular expression | ||||
| // specified command-line argument -m | ||||
| func methodFilter(name string) (bool, error) { | ||||
| 	if ok, _ := regexp.MatchString("^Test", name); !ok { | ||||
| 		return false, nil | ||||
| 	} | ||||
| 	return regexp.MatchString(*matchMethod, name) | ||||
| } | ||||
|  | ||||
| func runTests(t testing.TB, tests []testing.InternalTest) { | ||||
| func runTests(t *testing.T, tests []test) { | ||||
| 	if len(tests) == 0 { | ||||
| 		t.Log("warning: no tests to run") | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	r, ok := t.(runner) | ||||
| 	if !ok { // backwards compatibility with Go 1.6 and below | ||||
| 		if !testing.RunTests(allTestsFilter, tests) { | ||||
| 			t.Fail() | ||||
| 		} | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	for _, test := range tests { | ||||
| 		r.Run(test.Name, test.F) | ||||
| 		t.Run(test.name, test.run) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| type runner interface { | ||||
| 	Run(name string, f func(t *testing.T)) bool | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 anthonyrawlins
					anthonyrawlins