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/proto/decode.go
generated
vendored
2
vendor/google.golang.org/protobuf/proto/decode.go
generated
vendored
@@ -51,6 +51,8 @@ type UnmarshalOptions struct {
|
||||
|
||||
// Unmarshal parses the wire-format message in b and places the result in m.
|
||||
// The provided message must be mutable (e.g., a non-nil pointer to a message).
|
||||
//
|
||||
// See the [UnmarshalOptions] type if you need more control.
|
||||
func Unmarshal(b []byte, m Message) error {
|
||||
_, err := UnmarshalOptions{RecursionLimit: protowire.DefaultRecursionLimit}.unmarshal(b, m.ProtoReflect())
|
||||
return err
|
||||
|
||||
44
vendor/google.golang.org/protobuf/proto/encode.go
generated
vendored
44
vendor/google.golang.org/protobuf/proto/encode.go
generated
vendored
@@ -5,12 +5,17 @@
|
||||
package proto
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"google.golang.org/protobuf/encoding/protowire"
|
||||
"google.golang.org/protobuf/internal/encoding/messageset"
|
||||
"google.golang.org/protobuf/internal/order"
|
||||
"google.golang.org/protobuf/internal/pragma"
|
||||
"google.golang.org/protobuf/reflect/protoreflect"
|
||||
"google.golang.org/protobuf/runtime/protoiface"
|
||||
|
||||
protoerrors "google.golang.org/protobuf/internal/errors"
|
||||
)
|
||||
|
||||
// MarshalOptions configures the marshaler.
|
||||
@@ -70,7 +75,32 @@ type MarshalOptions struct {
|
||||
UseCachedSize bool
|
||||
}
|
||||
|
||||
// flags turns the specified MarshalOptions (user-facing) into
|
||||
// protoiface.MarshalInputFlags (used internally by the marshaler).
|
||||
//
|
||||
// See impl.marshalOptions.Options for the inverse operation.
|
||||
func (o MarshalOptions) flags() protoiface.MarshalInputFlags {
|
||||
var flags protoiface.MarshalInputFlags
|
||||
|
||||
// Note: o.AllowPartial is always forced to true by MarshalOptions.marshal,
|
||||
// which is why it is not a part of MarshalInputFlags.
|
||||
|
||||
if o.Deterministic {
|
||||
flags |= protoiface.MarshalDeterministic
|
||||
}
|
||||
|
||||
if o.UseCachedSize {
|
||||
flags |= protoiface.MarshalUseCachedSize
|
||||
}
|
||||
|
||||
return flags
|
||||
}
|
||||
|
||||
// Marshal returns the wire-format encoding of m.
|
||||
//
|
||||
// This is the most common entry point for encoding a Protobuf message.
|
||||
//
|
||||
// See the [MarshalOptions] type if you need more control.
|
||||
func Marshal(m Message) ([]byte, error) {
|
||||
// Treat nil message interface as an empty message; nothing to output.
|
||||
if m == nil {
|
||||
@@ -116,6 +146,9 @@ func emptyBytesForMessage(m Message) []byte {
|
||||
|
||||
// MarshalAppend appends the wire-format encoding of m to b,
|
||||
// returning the result.
|
||||
//
|
||||
// This is a less common entry point than [Marshal], which is only needed if you
|
||||
// need to supply your own buffers for performance reasons.
|
||||
func (o MarshalOptions) MarshalAppend(b []byte, m Message) ([]byte, error) {
|
||||
// Treat nil message interface as an empty message; nothing to append.
|
||||
if m == nil {
|
||||
@@ -145,12 +178,7 @@ func (o MarshalOptions) marshal(b []byte, m protoreflect.Message) (out protoifac
|
||||
in := protoiface.MarshalInput{
|
||||
Message: m,
|
||||
Buf: b,
|
||||
}
|
||||
if o.Deterministic {
|
||||
in.Flags |= protoiface.MarshalDeterministic
|
||||
}
|
||||
if o.UseCachedSize {
|
||||
in.Flags |= protoiface.MarshalUseCachedSize
|
||||
Flags: o.flags(),
|
||||
}
|
||||
if methods.Size != nil {
|
||||
sout := methods.Size(protoiface.SizeInput{
|
||||
@@ -168,6 +196,10 @@ func (o MarshalOptions) marshal(b []byte, m protoreflect.Message) (out protoifac
|
||||
out.Buf, err = o.marshalMessageSlow(b, m)
|
||||
}
|
||||
if err != nil {
|
||||
var mismatch *protoerrors.SizeMismatchError
|
||||
if errors.As(err, &mismatch) {
|
||||
return out, fmt.Errorf("marshaling %s: %v", string(m.Descriptor().FullName()), err)
|
||||
}
|
||||
return out, err
|
||||
}
|
||||
if allowPartial {
|
||||
|
||||
17
vendor/google.golang.org/protobuf/proto/extension.go
generated
vendored
17
vendor/google.golang.org/protobuf/proto/extension.go
generated
vendored
@@ -11,18 +11,21 @@ import (
|
||||
// HasExtension reports whether an extension field is populated.
|
||||
// It returns false if m is invalid or if xt does not extend m.
|
||||
func HasExtension(m Message, xt protoreflect.ExtensionType) bool {
|
||||
// Treat nil message interface as an empty message; no populated fields.
|
||||
if m == nil {
|
||||
// Treat nil message interface or descriptor as an empty message; no populated
|
||||
// fields.
|
||||
if m == nil || xt == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
// As a special-case, we reports invalid or mismatching descriptors
|
||||
// as always not being populated (since they aren't).
|
||||
if xt == nil || m.ProtoReflect().Descriptor() != xt.TypeDescriptor().ContainingMessage() {
|
||||
mr := m.ProtoReflect()
|
||||
xd := xt.TypeDescriptor()
|
||||
if mr.Descriptor() != xd.ContainingMessage() {
|
||||
return false
|
||||
}
|
||||
|
||||
return m.ProtoReflect().Has(xt.TypeDescriptor())
|
||||
return mr.Has(xd)
|
||||
}
|
||||
|
||||
// ClearExtension clears an extension field such that subsequent
|
||||
@@ -36,7 +39,7 @@ func ClearExtension(m Message, xt protoreflect.ExtensionType) {
|
||||
// If the field is unpopulated, it returns the default value for
|
||||
// scalars and an immutable, empty value for lists or messages.
|
||||
// It panics if xt does not extend m.
|
||||
func GetExtension(m Message, xt protoreflect.ExtensionType) interface{} {
|
||||
func GetExtension(m Message, xt protoreflect.ExtensionType) any {
|
||||
// Treat nil message interface as an empty message; return the default.
|
||||
if m == nil {
|
||||
return xt.InterfaceOf(xt.Zero())
|
||||
@@ -48,7 +51,7 @@ func GetExtension(m Message, xt protoreflect.ExtensionType) interface{} {
|
||||
// SetExtension stores the value of an extension field.
|
||||
// It panics if m is invalid, xt does not extend m, or if type of v
|
||||
// is invalid for the specified extension field.
|
||||
func SetExtension(m Message, xt protoreflect.ExtensionType, v interface{}) {
|
||||
func SetExtension(m Message, xt protoreflect.ExtensionType, v any) {
|
||||
xd := xt.TypeDescriptor()
|
||||
pv := xt.ValueOf(v)
|
||||
|
||||
@@ -75,7 +78,7 @@ func SetExtension(m Message, xt protoreflect.ExtensionType, v interface{}) {
|
||||
// It returns immediately if f returns false.
|
||||
// While iterating, mutating operations may only be performed
|
||||
// on the current extension field.
|
||||
func RangeExtensions(m Message, f func(protoreflect.ExtensionType, interface{}) bool) {
|
||||
func RangeExtensions(m Message, f func(protoreflect.ExtensionType, any) bool) {
|
||||
// Treat nil message interface as an empty message; nothing to range over.
|
||||
if m == nil {
|
||||
return
|
||||
|
||||
7
vendor/google.golang.org/protobuf/proto/messageset.go
generated
vendored
7
vendor/google.golang.org/protobuf/proto/messageset.go
generated
vendored
@@ -47,11 +47,16 @@ func (o MarshalOptions) marshalMessageSet(b []byte, m protoreflect.Message) ([]b
|
||||
func (o MarshalOptions) marshalMessageSetField(b []byte, fd protoreflect.FieldDescriptor, value protoreflect.Value) ([]byte, error) {
|
||||
b = messageset.AppendFieldStart(b, fd.Number())
|
||||
b = protowire.AppendTag(b, messageset.FieldMessage, protowire.BytesType)
|
||||
b = protowire.AppendVarint(b, uint64(o.Size(value.Message().Interface())))
|
||||
calculatedSize := o.Size(value.Message().Interface())
|
||||
b = protowire.AppendVarint(b, uint64(calculatedSize))
|
||||
before := len(b)
|
||||
b, err := o.marshalMessage(b, value.Message())
|
||||
if err != nil {
|
||||
return b, err
|
||||
}
|
||||
if measuredSize := len(b) - before; calculatedSize != measuredSize {
|
||||
return nil, errors.MismatchedSizeCalculation(calculatedSize, measuredSize)
|
||||
}
|
||||
b = messageset.AppendFieldEnd(b)
|
||||
return b, nil
|
||||
}
|
||||
|
||||
2
vendor/google.golang.org/protobuf/proto/size.go
generated
vendored
2
vendor/google.golang.org/protobuf/proto/size.go
generated
vendored
@@ -34,6 +34,7 @@ func (o MarshalOptions) size(m protoreflect.Message) (size int) {
|
||||
if methods != nil && methods.Size != nil {
|
||||
out := methods.Size(protoiface.SizeInput{
|
||||
Message: m,
|
||||
Flags: o.flags(),
|
||||
})
|
||||
return out.Size
|
||||
}
|
||||
@@ -42,6 +43,7 @@ func (o MarshalOptions) size(m protoreflect.Message) (size int) {
|
||||
// This case is mainly used for legacy types with a Marshal method.
|
||||
out, _ := methods.Marshal(protoiface.MarshalInput{
|
||||
Message: m,
|
||||
Flags: o.flags(),
|
||||
})
|
||||
return len(out.Buf)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user