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
6 changes: 6 additions & 0 deletions .github/workflows/smoke-copilot.lock.yml

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

2 changes: 2 additions & 0 deletions pkg/workflow/compiler_safe_outputs_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -618,6 +618,7 @@ var handlerRegistry = map[string]handlerBuilder{
return newHandlerConfigBuilder().
AddTemplatableInt("max", c.Max).
AddStringSlice("allowed", c.Allowed).
AddStringSlice("blocked", c.Blocked).
AddIfNotEmpty("target", c.Target).
AddIfNotEmpty("target-repo", c.TargetRepoSlug).
AddStringSlice("allowed_repos", c.AllowedRepos).
Expand All @@ -632,6 +633,7 @@ var handlerRegistry = map[string]handlerBuilder{
return newHandlerConfigBuilder().
AddTemplatableInt("max", c.Max).
AddStringSlice("allowed", c.Allowed).
AddStringSlice("blocked", c.Blocked).
AddIfNotEmpty("target", c.Target).
AddIfNotEmpty("target-repo", c.TargetRepoSlug).
AddStringSlice("allowed_repos", c.AllowedRepos).
Expand Down
100 changes: 100 additions & 0 deletions pkg/workflow/compiler_safe_outputs_config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1084,3 +1084,103 @@ func TestHandlerConfigUnassignFromUser(t *testing.T) {
}
}
}

// TestHandlerConfigAssignToUserWithBlocked tests that blocked patterns are included in assign_to_user handler config
func TestHandlerConfigAssignToUserWithBlocked(t *testing.T) {
compiler := NewCompiler()

workflowData := &WorkflowData{
Name: "Test Workflow",
SafeOutputs: &SafeOutputsConfig{
AssignToUser: &AssignToUserConfig{
BaseSafeOutputConfig: BaseSafeOutputConfig{
Max: strPtr("1"),
},
SafeOutputTargetConfig: SafeOutputTargetConfig{
Target: "*",
TargetRepoSlug: "microsoft/vscode",
},
Blocked: []string{"copilot", "*[bot]"},
},
},
}

var steps []string
compiler.addHandlerManagerConfigEnvVar(&steps, workflowData)

for _, step := range steps {
if strings.Contains(step, "GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG") {
parts := strings.Split(step, "GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: ")
if len(parts) == 2 {
jsonStr := strings.TrimSpace(parts[1])
jsonStr = strings.Trim(jsonStr, "\"")
jsonStr = strings.ReplaceAll(jsonStr, "\\\"", "\"")

var config map[string]map[string]any
err := json.Unmarshal([]byte(jsonStr), &config)
require.NoError(t, err, "Handler config JSON should be valid")

assignConfig, ok := config["assign_to_user"]
require.True(t, ok, "Should have assign_to_user handler")

blocked, ok := assignConfig["blocked"]
require.True(t, ok, "Should have blocked field")
blockedSlice, ok := blocked.([]any)
require.True(t, ok, "Blocked should be an array")
assert.Len(t, blockedSlice, 2, "Should have 2 blocked patterns")
assert.Equal(t, "copilot", blockedSlice[0], "First blocked pattern should be copilot")
assert.Equal(t, "*[bot]", blockedSlice[1], "Second blocked pattern should be *[bot]")
}
}
}
}

// TestHandlerConfigUnassignFromUserWithBlocked tests that blocked patterns are included in unassign_from_user handler config
func TestHandlerConfigUnassignFromUserWithBlocked(t *testing.T) {
compiler := NewCompiler()

workflowData := &WorkflowData{
Name: "Test Workflow",
SafeOutputs: &SafeOutputsConfig{
UnassignFromUser: &UnassignFromUserConfig{
BaseSafeOutputConfig: BaseSafeOutputConfig{
Max: strPtr("2"),
},
SafeOutputTargetConfig: SafeOutputTargetConfig{
Target: "*",
TargetRepoSlug: "microsoft/vscode",
},
Blocked: []string{"copilot", "*[bot]"},
},
},
}

var steps []string
compiler.addHandlerManagerConfigEnvVar(&steps, workflowData)

for _, step := range steps {
if strings.Contains(step, "GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG") {
parts := strings.Split(step, "GH_AW_SAFE_OUTPUTS_HANDLER_CONFIG: ")
if len(parts) == 2 {
jsonStr := strings.TrimSpace(parts[1])
jsonStr = strings.Trim(jsonStr, "\"")
jsonStr = strings.ReplaceAll(jsonStr, "\\\"", "\"")

var config map[string]map[string]any
err := json.Unmarshal([]byte(jsonStr), &config)
require.NoError(t, err, "Handler config JSON should be valid")

unassignConfig, ok := config["unassign_from_user"]
require.True(t, ok, "Should have unassign_from_user handler")

blocked, ok := unassignConfig["blocked"]
require.True(t, ok, "Should have blocked field")
blockedSlice, ok := blocked.([]any)
require.True(t, ok, "Blocked should be an array")
assert.Len(t, blockedSlice, 2, "Should have 2 blocked patterns")
assert.Equal(t, "copilot", blockedSlice[0], "First blocked pattern should be copilot")
assert.Equal(t, "*[bot]", blockedSlice[1], "Second blocked pattern should be *[bot]")
}
}
}
}
3 changes: 3 additions & 0 deletions pkg/workflow/safe_outputs_config_generation.go
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,9 @@ func generateSafeOutputsConfig(data *WorkflowData) string {
if len(data.SafeOutputs.AddLabels.Allowed) > 0 {
additionalFields["allowed"] = data.SafeOutputs.AddLabels.Allowed
}
if len(data.SafeOutputs.AddLabels.Blocked) > 0 {
additionalFields["blocked"] = data.SafeOutputs.AddLabels.Blocked
}
safeOutputsConfig["add_labels"] = generateTargetConfigWithRepos(
data.SafeOutputs.AddLabels.SafeOutputTargetConfig,
data.SafeOutputs.AddLabels.Max,
Expand Down
37 changes: 37 additions & 0 deletions pkg/workflow/safe_outputs_config_generation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,3 +328,40 @@ func TestGenerateCustomJobToolDefinitionJSONSerializable(t *testing.T) {
require.NoError(t, json.Unmarshal(data, &parsed), "JSON should be parseable back")
assert.Equal(t, "deploy", parsed["name"], "name should round-trip through JSON")
}

// TestGenerateSafeOutputsConfigAddLabelsBlocked tests that the blocked field is included
// in config.json for add_labels.
func TestGenerateSafeOutputsConfigAddLabelsBlocked(t *testing.T) {
data := &WorkflowData{
SafeOutputs: &SafeOutputsConfig{
AddLabels: &AddLabelsConfig{
BaseSafeOutputConfig: BaseSafeOutputConfig{Max: strPtr("5")},
SafeOutputTargetConfig: SafeOutputTargetConfig{
Target: "*",
TargetRepoSlug: "microsoft/vscode",
},
Allowed: []string{"bug", "enhancement"},
Blocked: []string{"[*]*", "~spam", "stale", "triage-needed"},
},
},
}

result := generateSafeOutputsConfig(data)
require.NotEmpty(t, result, "Expected non-empty config")

var parsed map[string]any
require.NoError(t, json.Unmarshal([]byte(result), &parsed), "Result must be valid JSON")

addLabelsConfig, ok := parsed["add_labels"].(map[string]any)
require.True(t, ok, "Expected add_labels key in config")

blocked, ok := addLabelsConfig["blocked"]
require.True(t, ok, "Expected blocked field in add_labels config")
blockedSlice, ok := blocked.([]any)
require.True(t, ok, "Blocked should be an array")
assert.Len(t, blockedSlice, 4, "Should have 4 blocked patterns")
assert.Equal(t, "[*]*", blockedSlice[0], "First blocked pattern should match")
assert.Equal(t, "~spam", blockedSlice[1], "Second blocked pattern should match")
assert.Equal(t, "stale", blockedSlice[2], "Third blocked pattern should match")
assert.Equal(t, "triage-needed", blockedSlice[3], "Fourth blocked pattern should match")
}
Loading