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:
		
							
								
								
									
										2
									
								
								vendor/google.golang.org/protobuf/reflect/protoreflect/proto.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								vendor/google.golang.org/protobuf/reflect/protoreflect/proto.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -161,7 +161,7 @@ const ( | ||||
| // IsValid reports whether the syntax is valid. | ||||
| func (s Syntax) IsValid() bool { | ||||
| 	switch s { | ||||
| 	case Proto2, Proto3: | ||||
| 	case Proto2, Proto3, Editions: | ||||
| 		return true | ||||
| 	default: | ||||
| 		return false | ||||
|   | ||||
							
								
								
									
										21
									
								
								vendor/google.golang.org/protobuf/reflect/protoreflect/source_gen.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										21
									
								
								vendor/google.golang.org/protobuf/reflect/protoreflect/source_gen.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -373,6 +373,8 @@ func (p *SourcePath) appendFieldOptions(b []byte) []byte { | ||||
| 		b = p.appendRepeatedField(b, "edition_defaults", (*SourcePath).appendFieldOptions_EditionDefault) | ||||
| 	case 21: | ||||
| 		b = p.appendSingularField(b, "features", (*SourcePath).appendFeatureSet) | ||||
| 	case 22: | ||||
| 		b = p.appendSingularField(b, "feature_support", (*SourcePath).appendFieldOptions_FeatureSupport) | ||||
| 	case 999: | ||||
| 		b = p.appendRepeatedField(b, "uninterpreted_option", (*SourcePath).appendUninterpretedOption) | ||||
| 	} | ||||
| @@ -483,6 +485,8 @@ func (p *SourcePath) appendEnumValueOptions(b []byte) []byte { | ||||
| 		b = p.appendSingularField(b, "features", (*SourcePath).appendFeatureSet) | ||||
| 	case 3: | ||||
| 		b = p.appendSingularField(b, "debug_redact", nil) | ||||
| 	case 4: | ||||
| 		b = p.appendSingularField(b, "feature_support", (*SourcePath).appendFieldOptions_FeatureSupport) | ||||
| 	case 999: | ||||
| 		b = p.appendRepeatedField(b, "uninterpreted_option", (*SourcePath).appendUninterpretedOption) | ||||
| 	} | ||||
| @@ -519,6 +523,23 @@ func (p *SourcePath) appendFieldOptions_EditionDefault(b []byte) []byte { | ||||
| 	return b | ||||
| } | ||||
|  | ||||
| func (p *SourcePath) appendFieldOptions_FeatureSupport(b []byte) []byte { | ||||
| 	if len(*p) == 0 { | ||||
| 		return b | ||||
| 	} | ||||
| 	switch (*p)[0] { | ||||
| 	case 1: | ||||
| 		b = p.appendSingularField(b, "edition_introduced", nil) | ||||
| 	case 2: | ||||
| 		b = p.appendSingularField(b, "edition_deprecated", nil) | ||||
| 	case 3: | ||||
| 		b = p.appendSingularField(b, "deprecation_warning", nil) | ||||
| 	case 4: | ||||
| 		b = p.appendSingularField(b, "edition_removed", nil) | ||||
| 	} | ||||
| 	return b | ||||
| } | ||||
|  | ||||
| func (p *SourcePath) appendUninterpretedOption_NamePart(b []byte) []byte { | ||||
| 	if len(*p) == 0 { | ||||
| 		return b | ||||
|   | ||||
							
								
								
									
										12
									
								
								vendor/google.golang.org/protobuf/reflect/protoreflect/type.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										12
									
								
								vendor/google.golang.org/protobuf/reflect/protoreflect/type.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -510,7 +510,7 @@ type ExtensionType interface { | ||||
| 	// | ||||
| 	// ValueOf is more extensive than protoreflect.ValueOf for a given field's | ||||
| 	// value as it has more type information available. | ||||
| 	ValueOf(interface{}) Value | ||||
| 	ValueOf(any) Value | ||||
|  | ||||
| 	// InterfaceOf completely unwraps the Value to the underlying Go type. | ||||
| 	// InterfaceOf panics if the input is nil or does not represent the | ||||
| @@ -519,13 +519,13 @@ type ExtensionType interface { | ||||
| 	// | ||||
| 	// InterfaceOf is able to unwrap the Value further than Value.Interface | ||||
| 	// as it has more type information available. | ||||
| 	InterfaceOf(Value) interface{} | ||||
| 	InterfaceOf(Value) any | ||||
|  | ||||
| 	// IsValidValue reports whether the Value is valid to assign to the field. | ||||
| 	IsValidValue(Value) bool | ||||
|  | ||||
| 	// IsValidInterface reports whether the input is valid to assign to the field. | ||||
| 	IsValidInterface(interface{}) bool | ||||
| 	IsValidInterface(any) bool | ||||
| } | ||||
|  | ||||
| // EnumDescriptor describes an enum and | ||||
| @@ -544,6 +544,12 @@ type EnumDescriptor interface { | ||||
| 	// ReservedRanges is a list of reserved ranges of enum numbers. | ||||
| 	ReservedRanges() EnumRanges | ||||
|  | ||||
| 	// IsClosed reports whether this enum uses closed semantics. | ||||
| 	// See https://protobuf.dev/programming-guides/enum/#definitions. | ||||
| 	// Note: the Go protobuf implementation is not spec compliant and treats | ||||
| 	// all enums as open enums. | ||||
| 	IsClosed() bool | ||||
|  | ||||
| 	isEnumDescriptor | ||||
| } | ||||
| type isEnumDescriptor interface{ ProtoType(EnumDescriptor) } | ||||
|   | ||||
							
								
								
									
										14
									
								
								vendor/google.golang.org/protobuf/reflect/protoreflect/value_pure.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								vendor/google.golang.org/protobuf/reflect/protoreflect/value_pure.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -32,11 +32,11 @@ const ( | ||||
| type value struct { | ||||
| 	pragma.DoNotCompare // 0B | ||||
|  | ||||
| 	typ   valueType   // 8B | ||||
| 	num   uint64      // 8B | ||||
| 	str   string      // 16B | ||||
| 	bin   []byte      // 24B | ||||
| 	iface interface{} // 16B | ||||
| 	typ   valueType // 8B | ||||
| 	num   uint64    // 8B | ||||
| 	str   string    // 16B | ||||
| 	bin   []byte    // 24B | ||||
| 	iface any       // 16B | ||||
| } | ||||
|  | ||||
| func valueOfString(v string) Value { | ||||
| @@ -45,7 +45,7 @@ func valueOfString(v string) Value { | ||||
| func valueOfBytes(v []byte) Value { | ||||
| 	return Value{typ: bytesType, bin: v} | ||||
| } | ||||
| func valueOfIface(v interface{}) Value { | ||||
| func valueOfIface(v any) Value { | ||||
| 	return Value{typ: ifaceType, iface: v} | ||||
| } | ||||
|  | ||||
| @@ -55,6 +55,6 @@ func (v Value) getString() string { | ||||
| func (v Value) getBytes() []byte { | ||||
| 	return v.bin | ||||
| } | ||||
| func (v Value) getIface() interface{} { | ||||
| func (v Value) getIface() any { | ||||
| 	return v.iface | ||||
| } | ||||
|   | ||||
							
								
								
									
										14
									
								
								vendor/google.golang.org/protobuf/reflect/protoreflect/value_union.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										14
									
								
								vendor/google.golang.org/protobuf/reflect/protoreflect/value_union.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -69,8 +69,8 @@ import ( | ||||
| // composite Value. Modifying an empty, read-only value panics. | ||||
| type Value value | ||||
|  | ||||
| // The protoreflect API uses a custom Value union type instead of interface{} | ||||
| // to keep the future open for performance optimizations. Using an interface{} | ||||
| // The protoreflect API uses a custom Value union type instead of any | ||||
| // to keep the future open for performance optimizations. Using an any | ||||
| // always incurs an allocation for primitives (e.g., int64) since it needs to | ||||
| // be boxed on the heap (as interfaces can only contain pointers natively). | ||||
| // Instead, we represent the Value union as a flat struct that internally keeps | ||||
| @@ -85,7 +85,7 @@ type Value value | ||||
| // ValueOf returns a Value initialized with the concrete value stored in v. | ||||
| // This panics if the type does not match one of the allowed types in the | ||||
| // Value union. | ||||
| func ValueOf(v interface{}) Value { | ||||
| func ValueOf(v any) Value { | ||||
| 	switch v := v.(type) { | ||||
| 	case nil: | ||||
| 		return Value{} | ||||
| @@ -192,10 +192,10 @@ func (v Value) IsValid() bool { | ||||
| 	return v.typ != nilType | ||||
| } | ||||
|  | ||||
| // Interface returns v as an interface{}. | ||||
| // Interface returns v as an any. | ||||
| // | ||||
| // Invariant: v == ValueOf(v).Interface() | ||||
| func (v Value) Interface() interface{} { | ||||
| func (v Value) Interface() any { | ||||
| 	switch v.typ { | ||||
| 	case nilType: | ||||
| 		return nil | ||||
| @@ -406,8 +406,8 @@ func (k MapKey) IsValid() bool { | ||||
| 	return Value(k).IsValid() | ||||
| } | ||||
|  | ||||
| // Interface returns k as an interface{}. | ||||
| func (k MapKey) Interface() interface{} { | ||||
| // Interface returns k as an any. | ||||
| func (k MapKey) Interface() any { | ||||
| 	return Value(k).Interface() | ||||
| } | ||||
|  | ||||
|   | ||||
							
								
								
									
										6
									
								
								vendor/google.golang.org/protobuf/reflect/protoreflect/value_unsafe_go120.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								vendor/google.golang.org/protobuf/reflect/protoreflect/value_unsafe_go120.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -45,7 +45,7 @@ var ( | ||||
|  | ||||
| // typeOf returns a pointer to the Go type information. | ||||
| // The pointer is comparable and equal if and only if the types are identical. | ||||
| func typeOf(t interface{}) unsafe.Pointer { | ||||
| func typeOf(t any) unsafe.Pointer { | ||||
| 	return (*ifaceHeader)(unsafe.Pointer(&t)).Type | ||||
| } | ||||
|  | ||||
| @@ -80,7 +80,7 @@ func valueOfBytes(v []byte) Value { | ||||
| 	p := (*sliceHeader)(unsafe.Pointer(&v)) | ||||
| 	return Value{typ: bytesType, ptr: p.Data, num: uint64(len(v))} | ||||
| } | ||||
| func valueOfIface(v interface{}) Value { | ||||
| func valueOfIface(v any) Value { | ||||
| 	p := (*ifaceHeader)(unsafe.Pointer(&v)) | ||||
| 	return Value{typ: p.Type, ptr: p.Data} | ||||
| } | ||||
| @@ -93,7 +93,7 @@ func (v Value) getBytes() (x []byte) { | ||||
| 	*(*sliceHeader)(unsafe.Pointer(&x)) = sliceHeader{Data: v.ptr, Len: int(v.num), Cap: int(v.num)} | ||||
| 	return x | ||||
| } | ||||
| func (v Value) getIface() (x interface{}) { | ||||
| func (v Value) getIface() (x any) { | ||||
| 	*(*ifaceHeader)(unsafe.Pointer(&x)) = ifaceHeader{Type: v.typ, Data: v.ptr} | ||||
| 	return x | ||||
| } | ||||
|   | ||||
							
								
								
									
										8
									
								
								vendor/google.golang.org/protobuf/reflect/protoreflect/value_unsafe_go121.go
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
						
						
									
										8
									
								
								vendor/google.golang.org/protobuf/reflect/protoreflect/value_unsafe_go121.go
									
									
									
										generated
									
									
										vendored
									
									
								
							| @@ -15,7 +15,7 @@ import ( | ||||
|  | ||||
| type ( | ||||
| 	ifaceHeader struct { | ||||
| 		_    [0]interface{} // if interfaces have greater alignment than unsafe.Pointer, this will enforce it. | ||||
| 		_    [0]any // if interfaces have greater alignment than unsafe.Pointer, this will enforce it. | ||||
| 		Type unsafe.Pointer | ||||
| 		Data unsafe.Pointer | ||||
| 	} | ||||
| @@ -37,7 +37,7 @@ var ( | ||||
|  | ||||
| // typeOf returns a pointer to the Go type information. | ||||
| // The pointer is comparable and equal if and only if the types are identical. | ||||
| func typeOf(t interface{}) unsafe.Pointer { | ||||
| func typeOf(t any) unsafe.Pointer { | ||||
| 	return (*ifaceHeader)(unsafe.Pointer(&t)).Type | ||||
| } | ||||
|  | ||||
| @@ -70,7 +70,7 @@ func valueOfString(v string) Value { | ||||
| func valueOfBytes(v []byte) Value { | ||||
| 	return Value{typ: bytesType, ptr: unsafe.Pointer(unsafe.SliceData(v)), num: uint64(len(v))} | ||||
| } | ||||
| func valueOfIface(v interface{}) Value { | ||||
| func valueOfIface(v any) Value { | ||||
| 	p := (*ifaceHeader)(unsafe.Pointer(&v)) | ||||
| 	return Value{typ: p.Type, ptr: p.Data} | ||||
| } | ||||
| @@ -81,7 +81,7 @@ func (v Value) getString() string { | ||||
| func (v Value) getBytes() []byte { | ||||
| 	return unsafe.Slice((*byte)(v.ptr), v.num) | ||||
| } | ||||
| func (v Value) getIface() (x interface{}) { | ||||
| func (v Value) getIface() (x any) { | ||||
| 	*(*ifaceHeader)(unsafe.Pointer(&x)) = ifaceHeader{Type: v.typ, Data: v.ptr} | ||||
| 	return x | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 anthonyrawlins
					anthonyrawlins