Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/shared/sandbox-runtime.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
---
sandbox: sandbox-runtime
---
6 changes: 6 additions & 0 deletions .github/workflows/smoke-srt.lock.yml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion .github/workflows/smoke-srt.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ network:
allowed:
- defaults
- github
sandbox: sandbox-runtime
imports:
- shared/sandbox-runtime.md
tools:
bash:
github:
Expand Down
14 changes: 14 additions & 0 deletions pkg/parser/frontmatter.go
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ type ImportsResult struct {
MergedNetwork string // Merged network configuration from all imports
MergedPermissions string // Merged permissions configuration from all imports
MergedSecretMasking string // Merged secret-masking steps from all imports
MergedSandbox string // Merged sandbox configuration from all imports
ImportedFiles []string // List of imported file paths (for manifest)
AgentFile string // Path to custom agent file (if imported)
}
Expand Down Expand Up @@ -161,6 +162,7 @@ func ProcessImportsFromFrontmatterWithManifest(frontmatter map[string]any, baseD
var networkBuilder strings.Builder
var permissionsBuilder strings.Builder
var secretMaskingBuilder strings.Builder
var sandboxBuilder strings.Builder
var engines []string
var safeOutputs []string
var agentFile string // Track custom agent file
Expand Down Expand Up @@ -384,6 +386,12 @@ func ProcessImportsFromFrontmatterWithManifest(frontmatter map[string]any, baseD
if err == nil && secretMaskingContent != "" && secretMaskingContent != "{}" {
secretMaskingBuilder.WriteString(secretMaskingContent + "\n")
}

// Extract sandbox from imported file
sandboxContent, err := extractSandboxFromContent(string(content))
if err == nil && sandboxContent != "" {
sandboxBuilder.WriteString(sandboxContent + "\n")
}
}

log.Printf("Completed BFS traversal. Processed %d imports in total", len(processedOrder))
Expand All @@ -400,6 +408,7 @@ func ProcessImportsFromFrontmatterWithManifest(frontmatter map[string]any, baseD
MergedNetwork: networkBuilder.String(),
MergedPermissions: permissionsBuilder.String(),
MergedSecretMasking: secretMaskingBuilder.String(),
MergedSandbox: sandboxBuilder.String(),
ImportedFiles: processedOrder,
AgentFile: agentFile,
}, nil
Expand Down Expand Up @@ -729,6 +738,11 @@ func extractSecretMaskingFromContent(content string) (string, error) {
return extractFrontmatterField(content, "secret-masking", "{}")
}

// extractSandboxFromContent extracts sandbox section from frontmatter as JSON string
func extractSandboxFromContent(content string) (string, error) {
return extractFrontmatterField(content, "sandbox", "")
}

// extractFrontmatterField extracts a specific field from frontmatter as JSON string
func extractFrontmatterField(content, fieldName, emptyValue string) (string, error) {
result, err := ExtractFrontmatterFromContent(content)
Expand Down
128 changes: 128 additions & 0 deletions pkg/parser/schemas/included_file_schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -443,6 +443,134 @@
"additionalProperties": false
}
]
},
"sandbox": {
"description": "Sandbox runtime configuration for AI engines. Controls the execution sandbox (AWF or Sandbox Runtime). Only supported for Copilot engine.",
"examples": [
"default",
"sandbox-runtime",
{
"type": "sandbox-runtime",
"config": {
"network": {
"allowedDomains": [
"github.com",
"*.npmjs.org"
],
"allowUnixSockets": [
"/var/run/docker.sock"
]
}
}
}
],
"oneOf": [
{
"type": "string",
"enum": [
"default",
"sandbox-runtime"
],
"description": "Sandbox type: 'default' uses AWF (Agent Workflow Firewall), 'sandbox-runtime' uses Anthropic Sandbox Runtime with auto-generated config"
},
{
"type": "object",
"description": "Custom sandbox runtime configuration",
"properties": {
"type": {
"type": "string",
"enum": [
"default",
"sandbox-runtime"
],
"description": "Sandbox type to use"
},
"config": {
"type": "object",
"description": "Custom Sandbox Runtime configuration (only applies when type is 'sandbox-runtime')",
"properties": {
"network": {
"type": "object",
"properties": {
"allowedDomains": {
"type": "array",
"description": "List of allowed domains (supports wildcards like '*.github.com')",
"items": {
"type": "string"
}
},
"deniedDomains": {
"type": "array",
"description": "List of explicitly denied domains",
"items": {
"type": "string"
}
},
"allowUnixSockets": {
"type": "array",
"description": "List of allowed Unix socket paths (e.g., ['/var/run/docker.sock'])",
"items": {
"type": "string"
}
},
"allowLocalBinding": {
"type": "boolean",
"description": "Allow binding to local ports (default: false)"
}
},
"additionalProperties": false
},
"filesystem": {
"type": "object",
"properties": {
"denyRead": {
"type": "array",
"description": "List of paths to deny read access",
"items": {
"type": "string"
}
},
"allowWrite": {
"type": "array",
"description": "List of paths to allow write access",
"items": {
"type": "string"
}
},
"denyWrite": {
"type": "array",
"description": "List of paths to deny write access",
"items": {
"type": "string"
}
}
},
"additionalProperties": false
},
"ignoreViolations": {
"type": "object",
"description": "Map of command patterns to paths that should ignore violations",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
},
"enableWeakerNestedSandbox": {
"type": "boolean",
"description": "Enable weaker nested sandbox mode (recommended: true for Docker access)"
}
},
"additionalProperties": false
}
},
"required": [
"type"
],
"additionalProperties": false
}
]
}
},
"additionalProperties": false,
Expand Down
11 changes: 11 additions & 0 deletions pkg/workflow/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,17 @@ func (c *Compiler) ParseWorkflowFile(markdownPath string) (*WorkflowData, error)
}
}

// Merge sandbox configuration from imports with top-level sandbox configuration
if importsResult.MergedSandbox != "" && sandboxConfig == nil {
// Parse the merged sandbox JSON
var sandboxData any
if err := json.Unmarshal([]byte(importsResult.MergedSandbox), &sandboxData); err != nil {
return nil, fmt.Errorf("failed to parse merged sandbox configuration: %w", err)
}
// Extract sandbox config from the parsed data
sandboxConfig = c.extractSandboxConfig(map[string]any{"sandbox": sandboxData})
}

// Validate permissions from imports against top-level permissions
// Extract top-level permissions first
topLevelPermissions := c.extractPermissions(result.Frontmatter)
Expand Down
6 changes: 3 additions & 3 deletions pkg/workflow/firewall_default_enablement_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ func TestCopilotFirewallDefaultIntegration(t *testing.T) {
}

// Enable firewall by default
enableFirewallByDefaultForCopilot(engineConfig.ID, networkPerms)
enableFirewallByDefaultForCopilot(engineConfig.ID, networkPerms, nil)

// Verify firewall is enabled
if networkPerms.Firewall == nil {
Expand Down Expand Up @@ -175,7 +175,7 @@ func TestCopilotFirewallDefaultIntegration(t *testing.T) {
}

// Enable firewall by default (should not override explicit config)
enableFirewallByDefaultForCopilot(engineConfig.ID, networkPerms)
enableFirewallByDefaultForCopilot(engineConfig.ID, networkPerms, nil)

// Verify firewall is still disabled
if networkPerms.Firewall.Enabled {
Expand Down Expand Up @@ -231,7 +231,7 @@ func TestCopilotFirewallDefaultIntegration(t *testing.T) {
}

// Enable firewall by default (should not affect non-copilot engines)
enableFirewallByDefaultForCopilot(engineConfig.ID, networkPerms)
enableFirewallByDefaultForCopilot(engineConfig.ID, networkPerms, nil)

// Verify firewall is NOT enabled for claude
if networkPerms.Firewall != nil {
Expand Down