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: 2 additions & 1 deletion .github/workflows/dependabot-burner.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/security-alert-burndown.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-project.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/test-project-url-default.lock.yml

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

64 changes: 44 additions & 20 deletions pkg/workflow/compiler_safe_outputs_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,8 +93,8 @@ func (b *handlerConfigBuilder) Build() map[string]any {
// handlerBuilder is a function that builds a handler config from SafeOutputsConfig
type handlerBuilder func(*SafeOutputsConfig) map[string]any

// handlerRegistry maps handler names to their builder functions
var handlerRegistry = map[string]handlerBuilder{
// regularHandlerRegistry maps regular (non-project) handler names to their builder functions
var regularHandlerRegistry = map[string]handlerBuilder{
"create_issue": func(cfg *SafeOutputsConfig) map[string]any {
if cfg.CreateIssues == nil {
return nil
Expand Down Expand Up @@ -422,8 +422,11 @@ var handlerRegistry = map[string]handlerBuilder{
AddIfNotEmpty("github-token", c.GitHubToken).
Build()
},
// Note: create_project, update_project and create_project_status_update are handled by the unified handler,
// not the separate project handler manager, so they are included in this registry.
}

// projectHandlerRegistry maps project handler names to their builder functions
// These handlers require GH_AW_PROJECT_GITHUB_TOKEN and are loaded separately
var projectHandlerRegistry = map[string]handlerBuilder{
"create_project": func(cfg *SafeOutputsConfig) map[string]any {
if cfg.CreateProjects == nil {
return nil
Expand Down Expand Up @@ -479,34 +482,55 @@ func (c *Compiler) addHandlerManagerConfigEnvVar(steps *[]string, data *Workflow
}

compilerSafeOutputsConfigLog.Print("Building handler manager configuration for safe-outputs")
config := make(map[string]map[string]any)

// Build configuration for each handler using the registry
for handlerName, builder := range handlerRegistry {
// Build regular handlers config
regularConfig := make(map[string]map[string]any)
for handlerName, builder := range regularHandlerRegistry {
handlerConfig := builder(data.SafeOutputs)
if handlerConfig != nil {
compilerSafeOutputsConfigLog.Printf("Adding regular handler configuration: %s", handlerName)
regularConfig[handlerName] = handlerConfig
}
}

// Build project handlers config
projectConfig := make(map[string]map[string]any)
for handlerName, builder := range projectHandlerRegistry {
handlerConfig := builder(data.SafeOutputs)
// Include handler if:
// 1. It returns a non-nil config (explicitly enabled, even if empty)
// 2. For auto-enabled handlers, include even with empty config
if handlerConfig != nil {
compilerSafeOutputsConfigLog.Printf("Adding %s handler configuration", handlerName)
config[handlerName] = handlerConfig
compilerSafeOutputsConfigLog.Printf("Adding project handler configuration: %s", handlerName)
projectConfig[handlerName] = handlerConfig
}
}

// Only add the env var if there are handlers to configure
if len(config) > 0 {
compilerSafeOutputsConfigLog.Printf("Marshaling handler config with %d handlers", len(config))
configJSON, err := json.Marshal(config)
// Add regular handlers config env var
if len(regularConfig) > 0 {
compilerSafeOutputsConfigLog.Printf("Marshaling regular handler config with %d handlers", len(regularConfig))
configJSON, err := json.Marshal(regularConfig)
if err != nil {
consolidatedSafeOutputsLog.Printf("Failed to marshal handler config: %v", err)
consolidatedSafeOutputsLog.Printf("Failed to marshal regular handler config: %v", err)
return
}
// Escape the JSON for YAML (handle quotes and special chars)
configStr := string(configJSON)
*steps = append(*steps, fmt.Sprintf(" GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: %q\n", configStr))
compilerSafeOutputsConfigLog.Printf("Added handler config env var: size=%d bytes", len(configStr))
compilerSafeOutputsConfigLog.Printf("Added regular handler config env var: size=%d bytes", len(configStr))
} else {
compilerSafeOutputsConfigLog.Print("No regular handlers configured, skipping regular config env var")
}

// Add project handlers config env var
if len(projectConfig) > 0 {
compilerSafeOutputsConfigLog.Printf("Marshaling project handler config with %d handlers", len(projectConfig))
configJSON, err := json.Marshal(projectConfig)
if err != nil {
consolidatedSafeOutputsLog.Printf("Failed to marshal project handler config: %v", err)
return
}
configStr := string(configJSON)
*steps = append(*steps, fmt.Sprintf(" GH_AW_SAFE_OUTPUTS_PROJECT_HANDLER_CONFIG: %q\n", configStr))
compilerSafeOutputsConfigLog.Printf("Added project handler config env var: size=%d bytes", len(configStr))
} else {
compilerSafeOutputsConfigLog.Print("No handlers configured, skipping config env var")
compilerSafeOutputsConfigLog.Print("No project handlers configured, skipping project config env var")
}
}

Expand Down
49 changes: 30 additions & 19 deletions pkg/workflow/create_project_status_update_handler_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ Test workflow

compiledStr := string(compiledContent)

// Find the GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG line
require.Contains(t, compiledStr, "GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG",
"Expected GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG in compiled workflow")
// Project handlers should be in GH_AW_SAFE_OUTPUTS_PROJECT_HANDLER_CONFIG
require.Contains(t, compiledStr, "GH_AW_SAFE_OUTPUTS_PROJECT_HANDLER_CONFIG",
"Expected GH_AW_SAFE_OUTPUTS_PROJECT_HANDLER_CONFIG in compiled workflow")

// Verify create_project_status_update is in the handler config
// Verify create_project_status_update is in the project handler config
require.Contains(t, compiledStr, "create_project_status_update",
"Expected create_project_status_update in handler config")

Expand Down Expand Up @@ -101,11 +101,11 @@ Test workflow

compiledStr := string(compiledContent)

// Find the GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG line
require.Contains(t, compiledStr, "GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG",
"Expected GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG in compiled workflow")
// Project handlers should be in GH_AW_SAFE_OUTPUTS_PROJECT_HANDLER_CONFIG
require.Contains(t, compiledStr, "GH_AW_SAFE_OUTPUTS_PROJECT_HANDLER_CONFIG",
"Expected GH_AW_SAFE_OUTPUTS_PROJECT_HANDLER_CONFIG in compiled workflow")

// Verify create_project_status_update is in the handler config
// Verify create_project_status_update is in the project handler config
require.Contains(t, compiledStr, "create_project_status_update",
"Expected create_project_status_update in handler config")

Expand Down Expand Up @@ -165,8 +165,23 @@ Test workflow

compiledStr := string(compiledContent)

// Extract main handler config JSON
// Extract project handler config JSON
lines := strings.Split(compiledStr, "\n")
var projectConfigJSON string
for _, line := range lines {
if strings.Contains(line, "GH_AW_SAFE_OUTPUTS_PROJECT_HANDLER_CONFIG:") {
parts := strings.SplitN(line, "GH_AW_SAFE_OUTPUTS_PROJECT_HANDLER_CONFIG:", 2)
if len(parts) == 2 {
projectConfigJSON = strings.TrimSpace(parts[1])
projectConfigJSON = strings.Trim(projectConfigJSON, "\"")
projectConfigJSON = strings.ReplaceAll(projectConfigJSON, "\\\"", "\"")
}
}
}

require.NotEmpty(t, projectConfigJSON, "Failed to extract GH_AW_SAFE_OUTPUTS_PROJECT_HANDLER_CONFIG JSON")

// Verify create-issue is in the regular handler config
var mainConfigJSON string
for _, line := range lines {
if strings.Contains(line, "GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG:") {
Expand All @@ -178,20 +193,16 @@ Test workflow
}
}
}

require.NotEmpty(t, mainConfigJSON, "Failed to extract GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG JSON")

// Verify create_issue is in the main handler config
assert.Contains(t, mainConfigJSON, "create_issue",
"Expected create_issue in main handler config")

// Verify create_project_status_update is also in the main handler config
// (as of recent changes, it's handled by the unified handler, not a separate project handler step)
assert.Contains(t, mainConfigJSON, "create_project_status_update",
"Expected create_project_status_update in main handler config")
// Verify create_project_status_update is in the project handler config
assert.Contains(t, projectConfigJSON, "create_project_status_update",
"Expected create_project_status_update in project handler config")

// Verify max value is correct
assert.Contains(t, mainConfigJSON, `"max":2`,
assert.Contains(t, projectConfigJSON, `"max":2`,
"Expected max:2 in create_project_status_update handler config")
}

Expand Down Expand Up @@ -229,7 +240,7 @@ Test workflow

compiledStr := string(compiledContent)

// Verify project URL is in the handler config
require.Contains(t, compiledStr, "GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG", "Expected main handler config")
// Verify project URL is in the project handler config
require.Contains(t, compiledStr, "GH_AW_SAFE_OUTPUTS_PROJECT_HANDLER_CONFIG", "Expected project handler config")
require.Contains(t, compiledStr, "https://github.com/orgs/nonexistent-test-org-67890/projects/88888", "Expected project URL in handler config")
}
13 changes: 6 additions & 7 deletions pkg/workflow/update_project_handler_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,9 @@ Test workflow
require.NoError(t, err, "Failed to read compiled output")

compiledStr := string(compiledContent)
// Note: update-project is now in the main handler config, not the project handler config
require.Contains(t, compiledStr, "GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG", "Expected main handler config env var")
// Project handlers (update_project, create_project, create_project_status_update)
// should be in GH_AW_SAFE_OUTPUTS_PROJECT_HANDLER_CONFIG, not the regular handler config
require.Contains(t, compiledStr, "GH_AW_SAFE_OUTPUTS_PROJECT_HANDLER_CONFIG", "Expected project handler config env var")
require.Contains(t, compiledStr, "update_project", "Expected update_project in handler config")

// field_definitions uses underscore naming in the JSON config passed to JS
Expand Down Expand Up @@ -86,10 +87,8 @@ Test workflow

compiledStr := string(compiledContent)

// Note: Since update-project is no longer in the project handler manager,
// GH_AW_PROJECT_URL is not set when only update-project is configured.
// update-project is now handled by the unified handler, which doesn't set GH_AW_PROJECT_URL.
// The project URL is passed as part of the handler config instead.
require.Contains(t, compiledStr, "GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG", "Expected main handler config")
// Project handlers (update_project, create_project, create_project_status_update)
// should be in GH_AW_SAFE_OUTPUTS_PROJECT_HANDLER_CONFIG
require.Contains(t, compiledStr, "GH_AW_SAFE_OUTPUTS_PROJECT_HANDLER_CONFIG", "Expected project handler config")
require.Contains(t, compiledStr, "https://github.com/orgs/nonexistent-test-org-12345/projects/99999", "Expected project URL in handler config")
}
Loading