Skip to content
Merged
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
7 changes: 7 additions & 0 deletions pkg/typeutil/lookup.go
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package typeutil

import "github.com/github/gh-aw/pkg/logger"

var lookupLog = logger.New("typeutil:lookup")

// ParseBool extracts a boolean value from a map[string]any by key.
// Returns false if the map is nil, the key is absent, or the value is not a bool.
func ParseBool(m map[string]any, key string) bool {
Expand Down Expand Up @@ -62,19 +66,22 @@ func LookupStringPath(m map[string]any, path ...string) (string, bool) {
for i, key := range path {
value, ok := current[key]
if !ok {
lookupLog.Printf("Path lookup stopped: key %q missing at step %d/%d", key, i, len(path))
return "", false
}

if i == len(path)-1 {
result, ok := value.(string)
if !ok {
lookupLog.Printf("Path lookup failed: final value at key %q is not a string", key)
return "", false
}
return result, true
}

next, ok := value.(map[string]any)
if !ok {
lookupLog.Printf("Path lookup failed: value at key %q is not a nested map (step %d/%d)", key, i, len(path))
return "", false
}
current = next
Expand Down
3 changes: 3 additions & 0 deletions pkg/workflow/dismiss_pull_request_review.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ func (c *Compiler) parseDismissPullRequestReviewConfig(outputMap map[string]any)
configData = value
} else if value, exists := outputMap["dismiss-review"]; exists {
// Backward-compatible alias.
dismissPullRequestReviewLog.Print("Using legacy dismiss-review alias key")
configData = value
} else {
return nil
Expand All @@ -33,6 +34,7 @@ func (c *Compiler) parseDismissPullRequestReviewConfig(outputMap map[string]any)
// Parse target config (target, target-repo, allowed-repos).
targetConfig, isInvalid := ParseTargetConfig(configMap)
if isInvalid {
dismissPullRequestReviewLog.Print("Rejecting dismiss-pull-request-review: invalid target config")
return nil
}
config.SafeOutputTargetConfig = targetConfig
Expand All @@ -41,6 +43,7 @@ func (c *Compiler) parseDismissPullRequestReviewConfig(outputMap map[string]any)
config.SafeOutputFilterConfig = ParseFilterConfig(configMap)
} else {
// If configData is nil or not a map, still set the default max.
dismissPullRequestReviewLog.Print("dismiss-pull-request-review config is not a map; applying default max only")
config.Max = defaultIntStr(10)
}

Expand Down
8 changes: 8 additions & 0 deletions pkg/workflow/enclaves.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,12 @@ import (
"fmt"
"regexp"
"strings"

"github.com/github/gh-aw/pkg/logger"
)

var enclavesLog = logger.New("workflow:enclaves")

const (
enclaveMCPServerName = "awf-enclave"
enclaveMCPUpstreamURL = "http://awf-enclave-mcp:8080/mcp"
Expand Down Expand Up @@ -112,12 +116,15 @@ func validateEnclavesConfig(workflowData *WorkflowData) error {
if !enclavesEnabled(workflowData) {
return nil
}
enclavesLog.Printf("Validating %d enclave config(s)", len(workflowData.Enclaves))
if !isAWFNetworkIsolationEnabled(workflowData) {
enclavesLog.Print("Rejecting enclaves: AWF network isolation is not enabled")
return errors.New("enclaves requires AWF network isolation; set sandbox.agent.sudo: false or use sandbox.agent.runtime: docker-sbx")
}
if workflowData.ParsedTools != nil &&
workflowData.ParsedTools.GitHub != nil &&
workflowData.ParsedTools.GitHub.BoundedQueries != nil {
enclavesLog.Print("Rejecting enclaves: incompatible with tools.github.bounded-queries")
return errors.New("enclaves cannot be combined with tools.github.bounded-queries; remove tools.github.bounded-queries to use enclaves. Example:\n\nenclaves:\n - script:\n repos:\n - repo: org/my-repo\n sensitivity: confidential")
}
seenTypes := make(map[string]struct{}, len(workflowData.Enclaves))
Expand Down Expand Up @@ -219,6 +226,7 @@ func buildAWFEnclavesConfig(config EnclavesConfig) []map[string]any {
}
result = append(result, values)
}
enclavesLog.Printf("Built %d AWF enclave config(s) from %d entries", len(result), len(config))
return result
}

Expand Down
2 changes: 2 additions & 0 deletions pkg/workflow/mcp_renderer_guard.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ func renderGuardPoliciesJSON(yaml *strings.Builder, policies map[string]any, ind
if len(policies) == 0 {
return
}
mcpRendererLog.Printf("Rendering %d guard-policies entries as JSON", len(policies))

// Marshal to JSON with indentation, then re-indent to match the current indent level
jsonBytes, err := json.MarshalIndent(policies, indent, " ")
Expand All @@ -83,6 +84,7 @@ func renderGuardPoliciesToml(yaml *strings.Builder, policies map[string]any, ser
if len(policies) == 0 {
return
}
mcpRendererLog.Printf("Rendering %d guard-policies entries as TOML for server %s", len(policies), serverID)

yaml.WriteString(" \n")
yaml.WriteString(" [mcp_servers." + serverID + ".\"guard-policies\"]\n")
Expand Down
8 changes: 8 additions & 0 deletions pkg/workflow/memory_validation_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@ import (
"fmt"
"math"
"strconv"

"github.com/github/gh-aw/pkg/logger"
)

var memoryValidationLog = logger.New("workflow:memory_validation_config")

const (
defaultMemoryValidationTimeoutMinutes = 1
maxMemoryValidationTimeoutMinutes = 5
Expand All @@ -21,9 +25,11 @@ func parseMemoryValidationConfig(configMap map[string]any, fieldPath string) (*M
raw, ok := configMap["validation"]
if !ok {
if script, ok := configMap["validation-script"].(string); ok {
memoryValidationLog.Printf("Using legacy validation-script field at %s", fieldPath)
return normalizeMemoryValidationConfig(&MemoryValidationConfig{Script: script}, fieldPath)
}
if script, ok := configMap["custom-validation"].(string); ok {
memoryValidationLog.Printf("Using legacy custom-validation field at %s", fieldPath)
return normalizeMemoryValidationConfig(&MemoryValidationConfig{Script: script}, fieldPath)
}
return nil, nil
Expand All @@ -34,6 +40,7 @@ func parseMemoryValidationConfig(configMap map[string]any, fieldPath string) (*M
return normalizeMemoryValidationConfig(&MemoryValidationConfig{Script: value}, fieldPath)
case map[string]any:
if _, exists := value["timeout"]; exists {
memoryValidationLog.Printf("Rejecting deprecated timeout field at %s", fieldPath)
return nil, fmt.Errorf("%s.timeout has been renamed to %s.timeout-minutes. Example:\n%s:\n timeout-minutes: 1", fieldPath, fieldPath, fieldPath)
}
config := &MemoryValidationConfig{}
Expand Down Expand Up @@ -96,6 +103,7 @@ func normalizeMemoryValidationConfig(config *MemoryValidationConfig, fieldPath s
return nil, fmt.Errorf("%s.script must not be empty. Example:\n%s:\n script: \"throw new Error('invalid state')\"", fieldPath, fieldPath)
}
if config.TimeoutMinutes == 0 {
memoryValidationLog.Printf("Applying default timeout of %d minute(s) at %s", defaultMemoryValidationTimeoutMinutes, fieldPath)
config.TimeoutMinutes = defaultMemoryValidationTimeoutMinutes
}
return config, nil
Expand Down
Loading