-
Notifications
You must be signed in to change notification settings - Fork 381
security: block agents from pushing to default/protected branches in safeoutputs #22776
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
5cd4f54
a2e004e
276cbd4
bc47aff
43b72d4
ee5a0c7
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -210,13 +210,31 @@ func FormatStepWithCommandAndEnv(stepLines []string, command string, env map[str | |||||||||||||
|
|
||||||||||||||
| for _, key := range envKeys { | ||||||||||||||
| value := env[key] | ||||||||||||||
| stepLines = append(stepLines, fmt.Sprintf(" %s: %s", key, value)) | ||||||||||||||
| stepLines = append(stepLines, fmt.Sprintf(" %s: %s", key, yamlStringValue(value))) | ||||||||||||||
| } | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| return stepLines | ||||||||||||||
| } | ||||||||||||||
|
|
||||||||||||||
| // yamlStringValue returns a YAML-safe representation of a string value. | ||||||||||||||
| // If the value starts with a YAML flow indicator ('{' or '[') or other characters | ||||||||||||||
| // that would cause it to be misinterpreted by YAML parsers, it wraps the value | ||||||||||||||
| // in single quotes. Any embedded single quotes are escaped by doubling them (' becomes ”). | ||||||||||||||
|
Comment on lines
+221
to
+223
|
||||||||||||||
| // If the value starts with a YAML flow indicator ('{' or '[') or other characters | |
| // that would cause it to be misinterpreted by YAML parsers, it wraps the value | |
| // in single quotes. Any embedded single quotes are escaped by doubling them (' becomes ”). | |
| // If the value starts with a YAML flow indicator ('{' or '['), it wraps the value | |
| // in single quotes so it is treated as a plain string rather than a flow collection. | |
| // Any embedded single quotes are escaped by doubling them (' becomes ''). |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -513,4 +513,16 @@ func TestGenerateGeminiSettingsStep(t *testing.T) { | |
| assert.Contains(t, content, "write_file", "Should include write_file for edit tool") | ||
| assert.Contains(t, content, "replace", "Should include replace for edit tool") | ||
| }) | ||
|
|
||
| t.Run("GH_AW_GEMINI_BASE_CONFIG env var is single-quoted for valid YAML", func(t *testing.T) { | ||
| workflowData := &WorkflowData{ | ||
| Name: "test-workflow", | ||
| Tools: map[string]any{}, | ||
| } | ||
|
Comment on lines
+517
to
+521
|
||
| step := engine.generateGeminiSettingsStep(workflowData) | ||
| content := strings.Join(step, "\n") | ||
|
|
||
| // The JSON value must be single-quoted so YAML doesn't treat it as an object | ||
| assert.Contains(t, content, "GH_AW_GEMINI_BASE_CONFIG: '", "JSON env var value must be single-quoted for valid YAML") | ||
| }) | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The default-branch protection check is currently fail-open: if repos.get() fails, the code only warns and continues, which can still allow pushes to the repo's default branch when it is not protected (getBranchProtection would return 404). Given the stated security requirement (agents must not push to default branches), this should fail closed or use a non-network fallback source for default_branch (e.g., default_branch from the event payload / PR base repo data) before proceeding.