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
22 changes: 22 additions & 0 deletions pkg/workflow/compiler_safe_outputs_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,28 @@ import (
"github.com/github/gh-aw/pkg/logger"
)

// ========================================
// Safe Output Handler Config (New Path)
// ========================================
//
// This file builds the GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG environment variable
// consumed by the safe-outputs handler manager at runtime.
//
// # Dual Config-Generation Architecture
//
// There are two parallel code paths that produce safe-output handler configuration:
//
// 1. generateSafeOutputsConfig() — safe_outputs_config_generation.go
// Output: GH_AW_SAFE_OUTPUTS_CONFIG_PATH (a config.json file on disk)
// Approach: ad-hoc per-handler blocks using generateMax*Config() helpers
//
// 2. addHandlerManagerConfigEnvVar() — THIS FILE
// Output: GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG (an env var)
// Approach: handlerRegistry + fluent handlerConfigBuilder
//
// When adding a new handler field, update BOTH files so the two paths stay in
// sync. See safe_outputs_config_generation.go for the legacy field set.

var compilerSafeOutputsConfigLog = logger.New("workflow:compiler_safe_outputs_config")

// getEffectiveFooterForTemplatable returns the effective footer as a templatable string.
Expand Down
3 changes: 0 additions & 3 deletions pkg/workflow/frontmatter_extraction_metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,9 +142,6 @@ func buildSourceURL(source string) string {
return url
}

// safeUintToInt safely converts uint to int, returning 0 if overflow would occur
func safeUintToInt(u uint) int { return safeUint64ToInt(uint64(u)) }

// extractToolsTimeout extracts the timeout setting from tools
// Returns 0 if not set (engines will use their own defaults)
// Returns error if timeout is explicitly set but invalid (< 1)
Expand Down
29 changes: 26 additions & 3 deletions pkg/workflow/map_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
// Type Conversion:
// - parseIntValue() - Safely parse numeric types to int with truncation warnings
// - safeUint64ToInt() - Convert uint64 to int, returning 0 on overflow
// - safeUintToInt() - Convert uint to int (thin adapter over safeUint64ToInt)
// - ConvertToInt() - Safely convert any value (int/int64/float64/string) to int
// - ConvertToFloat() - Safely convert any value (float64/int/int64/string) to float64
//
Expand All @@ -41,8 +42,16 @@ import (

var mapHelpersLog = logger.New("workflow:map_helpers")

// parseIntValue safely parses various numeric types to int
// This is a common utility used across multiple parsing functions
// parseIntValue safely parses various numeric types to int.
// Returns (value, true) on success, (0, false) on unsupported type or overflow.
//
// Supported input types: int, int64, uint64, float64.
// Strings are NOT supported — use ConvertToInt for string-to-int conversion.
Comment on lines +45 to +49
Copy link

Copilot AI Mar 23, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

parseIntValue’s updated docstring claims it returns (0,false) on overflow, but the implementation doesn’t check overflow for int64 or float64 conversions (both can overflow int on 32-bit targets like wasm, and float64→int is implementation-defined when out of range). Add explicit range checks (and handle NaN/Inf) and return (0,false) on overflow, or adjust the comment to match current behavior.

Copilot uses AI. Check for mistakes.
// On float64 input, truncation is allowed but logged as a warning.
//
// Use parseIntValue when you need explicit success/failure signalling (the bool
// return) and do not need string parsing. Prefer ConvertToInt when a silent
// fallback to 0 is acceptable or when the input may be a string.
func parseIntValue(value any) (int, bool) {
switch v := value.(type) {
case int:
Expand Down Expand Up @@ -77,6 +86,10 @@ func safeUint64ToInt(u uint64) int {
return int(u)
}

// safeUintToInt safely converts uint to int, returning 0 if overflow would occur.
// This is a thin adapter over safeUint64ToInt for callers that hold a uint value.
func safeUintToInt(u uint) int { return safeUint64ToInt(uint64(u)) }

// filterMapKeys creates a new map excluding the specified keys
func filterMapKeys(original map[string]any, excludeKeys ...string) map[string]any {
excludeSet := make(map[string]bool)
Expand Down Expand Up @@ -104,7 +117,17 @@ func sortedMapKeys(m map[string]string) []string {
return keys
}

// ConvertToInt safely converts any to int
// ConvertToInt safely converts any value to int, returning 0 on failure.
// Supported input types: int, int64, float64, string (parsed via strconv.Atoi).
//
// Unlike parseIntValue, ConvertToInt:
// - Accepts string inputs (parsed with strconv.Atoi)
// - Returns 0 silently on failure (no bool return)
// - Does NOT handle uint64 — use parseIntValue for uint64 overflow-safe conversion
//
// Use ConvertToInt when a silent fallback to 0 is acceptable or when the input
// may be a numeric string from YAML/JSON. Prefer parseIntValue when you need
// explicit success/failure signalling or when the input may be uint64.
func ConvertToInt(val any) int {
switch v := val.(type) {
case int:
Expand Down
Loading
Loading