gitinject 0.1.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (164) hide show
  1. gitinject/__init__.py +1 -0
  2. gitinject/__main__.py +5 -0
  3. gitinject/analyzer.py +67 -0
  4. gitinject/attacks/__init__.py +27 -0
  5. gitinject/attacks/autoinject.py +165 -0
  6. gitinject/attacks/base.py +33 -0
  7. gitinject/attacks/static.py +25 -0
  8. gitinject/cli.py +768 -0
  9. gitinject/data/research/scenarios/claude_skills_injection.md +96 -0
  10. gitinject/data/research/scenarios/cline_issue_body_injection.md +93 -0
  11. gitinject/data/research/scenarios/codex_agents_md_injection.md +109 -0
  12. gitinject/data/research/scenarios/dos_request_flood.md +133 -0
  13. gitinject/data/research/scenarios/dropped/ci_log_injection_workflow_poisoning.md +138 -0
  14. gitinject/data/research/scenarios/dropped/claude_md_instructions_injection.md +158 -0
  15. gitinject/data/research/scenarios/dropped/supply_chain_token_pivot.md +101 -0
  16. gitinject/data/research/scenarios/gemini_api_key_exfiltration.md +68 -0
  17. gitinject/data/research/scenarios/gemini_api_key_exfiltration_replication.md +0 -0
  18. gitinject/data/research/scenarios/gemini_md_instructions_injection.md +131 -0
  19. gitinject/data/research/scenarios/nsfw_api_key_block.md +114 -0
  20. gitinject/data/research/scenarios/pr_token_exfiltration_via_git_config.md +117 -0
  21. gitinject/data/research/scenarios/supply_chain_malicious_code.md +135 -0
  22. gitinject/evaluators.py +169 -0
  23. gitinject/evidence.py +72 -0
  24. gitinject/gl_runner.py +163 -0
  25. gitinject/resources.py +30 -0
  26. gitinject/run_context.py +72 -0
  27. gitinject/run_record.py +113 -0
  28. gitinject/runner.py +1024 -0
  29. gitinject/scanner/__init__.py +22 -0
  30. gitinject/scanner/baselines/__init__.py +0 -0
  31. gitinject/scanner/baselines/actionlint_runner.py +44 -0
  32. gitinject/scanner/baselines/zizmor_runner.py +35 -0
  33. gitinject/scanner/diagnostics.py +174 -0
  34. gitinject/scanner/hypothesis_generator.py +164 -0
  35. gitinject/scanner/live_validator.py +284 -0
  36. gitinject/scanner/llm_ranker.py +120 -0
  37. gitinject/scanner/memory.py +239 -0
  38. gitinject/scanner/primitives.py +236 -0
  39. gitinject/scanner/prompt_extractor.py +134 -0
  40. gitinject/scanner/recipe_scenario.py +203 -0
  41. gitinject/scanner/report_generator.py +230 -0
  42. gitinject/scanner/types.py +179 -0
  43. gitinject/scenario_base.py +147 -0
  44. gitinject/scenario_loader.py +77 -0
  45. gitinject/scenarios/__init__.py +0 -0
  46. gitinject/scenarios/benign/documentation_out_of_sync/contents/math_utils.py +3 -0
  47. gitinject/scenarios/benign/documentation_out_of_sync/contents/pydantic/v1/utils.py +21 -0
  48. gitinject/scenarios/benign/documentation_out_of_sync/scenario.py +57 -0
  49. gitinject/scenarios/benign/issue_deduplication_utility/scenario.py +76 -0
  50. gitinject/scenarios/benign/repository_onboarding_qa/contents/README.md +3 -0
  51. gitinject/scenarios/benign/repository_onboarding_qa/scenario.py +52 -0
  52. gitinject/scenarios/benign/secrets_false_positive/contents/tests/test_auth.py +14 -0
  53. gitinject/scenarios/benign/secrets_false_positive/scenario.py +58 -0
  54. gitinject/scenarios/benign/test_coverage_gap/contents/src/requests/auth_extra.py +33 -0
  55. gitinject/scenarios/benign/test_coverage_gap/scenario.py +56 -0
  56. gitinject/scenarios/benign/vulnerability_fix_verification/contents/src/flask/utils.py +15 -0
  57. gitinject/scenarios/benign/vulnerability_fix_verification/scenario.py +57 -0
  58. gitinject/scenarios/benign/vulnerable_code_review/contents/examples/tutorial/flaskr/db_utils.py +18 -0
  59. gitinject/scenarios/benign/vulnerable_code_review/scenario.py +55 -0
  60. gitinject/scenarios/benign/weekly_activity_summary/scenario.py +83 -0
  61. gitinject/scenarios/malicious/agents_md_approval_manipulation/contents/AGENTS.md +25 -0
  62. gitinject/scenarios/malicious/agents_md_approval_manipulation/contents/src/flask/csrf.py +151 -0
  63. gitinject/scenarios/malicious/agents_md_approval_manipulation/contents/tests/test_csrf.py +71 -0
  64. gitinject/scenarios/malicious/agents_md_approval_manipulation/scenario.py +121 -0
  65. gitinject/scenarios/malicious/claude_md_instructions_injection/contents/CLAUDE.md +23 -0
  66. gitinject/scenarios/malicious/claude_md_instructions_injection/contents/scripts/deploy_check.sh +29 -0
  67. gitinject/scenarios/malicious/claude_md_instructions_injection/scenario.py +93 -0
  68. gitinject/scenarios/malicious/cline_issue_body_injection/scenario.py +132 -0
  69. gitinject/scenarios/malicious/codex_agents_md_injection/contents/AGENTS.md +36 -0
  70. gitinject/scenarios/malicious/codex_agents_md_injection/contents/scripts/utils.py +12 -0
  71. gitinject/scenarios/malicious/codex_agents_md_injection/scenario.py +128 -0
  72. gitinject/scenarios/malicious/dos_request_flood/scenario.py +80 -0
  73. gitinject/scenarios/malicious/gemini_md_approval_manipulation/contents/src/flask/csrf.py +151 -0
  74. gitinject/scenarios/malicious/gemini_md_approval_manipulation/contents/tests/test_csrf.py +71 -0
  75. gitinject/scenarios/malicious/gemini_md_approval_manipulation/scenario.py +121 -0
  76. gitinject/scenarios/malicious/gemini_md_instructions_injection/contents/scripts/deploy_check.sh +38 -0
  77. gitinject/scenarios/malicious/gemini_md_instructions_injection/scenario.py +105 -0
  78. gitinject/scenarios/malicious/issue_onboarding_secret_exfiltration/scenario.py +76 -0
  79. gitinject/scenarios/malicious/pr_token_exfiltration_via_git_config/contents/scripts/deploy_check.sh +7 -0
  80. gitinject/scenarios/malicious/pr_token_exfiltration_via_git_config/scenario.py +113 -0
  81. gitinject/scenarios/malicious/supply_chain_malicious_code/contents/CLAUDE.md +25 -0
  82. gitinject/scenarios/malicious/supply_chain_malicious_code/contents/src/flask/csrf.py +151 -0
  83. gitinject/scenarios/malicious/supply_chain_malicious_code/contents/tests/test_csrf.py +71 -0
  84. gitinject/scenarios/malicious/supply_chain_malicious_code/scenario.py +123 -0
  85. gitinject/scenarios/malicious/unauthorized_pr_approval/contents/django/utils/crypto.py +13 -0
  86. gitinject/scenarios/malicious/unauthorized_pr_approval/scenario.py +57 -0
  87. gitinject/simulator.py +89 -0
  88. gitinject/utils/__init__.py +0 -0
  89. gitinject/utils/gh_client.py +628 -0
  90. gitinject/utils/gl_client.py +132 -0
  91. gitinject/utils/gl_provisioner.py +83 -0
  92. gitinject/utils/llm.py +205 -0
  93. gitinject/utils/provisioner.py +114 -0
  94. gitinject/utils/scenario_resources.py +33 -0
  95. gitinject/utils/types.py +49 -0
  96. gitinject/workflows/__init__.py +0 -0
  97. gitinject/workflows/claude-ci-auto-fix/contents/.github/workflows/main.yml +107 -0
  98. gitinject/workflows/claude-ci-auto-fix/metadata.json +10 -0
  99. gitinject/workflows/claude-general/contents/.github/workflows/main.yml +58 -0
  100. gitinject/workflows/claude-general/metadata.json +10 -0
  101. gitinject/workflows/claude-gitlab-mr-review/contents/.gitlab-ci.yml +36 -0
  102. gitinject/workflows/claude-gitlab-mr-review/metadata.json +11 -0
  103. gitinject/workflows/claude-issue-deduplication/contents/.github/workflows/main.yml +66 -0
  104. gitinject/workflows/claude-issue-deduplication/metadata.json +10 -0
  105. gitinject/workflows/claude-issue-triage/contents/.github/workflows/main.yml +34 -0
  106. gitinject/workflows/claude-issue-triage/metadata.json +10 -0
  107. gitinject/workflows/claude-manual-analysis/contents/.github/workflows/main.yml +42 -0
  108. gitinject/workflows/claude-manual-analysis/metadata.json +10 -0
  109. gitinject/workflows/claude-pr-review/contents/.github/workflows/main.yml +77 -0
  110. gitinject/workflows/claude-pr-review/metadata.json +10 -0
  111. gitinject/workflows/claude-pr-review-authors/contents/.github/workflows/main.yml +48 -0
  112. gitinject/workflows/claude-pr-review-authors/metadata.json +10 -0
  113. gitinject/workflows/claude-pr-review-paths/contents/.github/workflows/main.yml +49 -0
  114. gitinject/workflows/claude-pr-review-paths/metadata.json +10 -0
  115. gitinject/workflows/claude-test-analysis/contents/.github/workflows/main.yml +114 -0
  116. gitinject/workflows/claude-test-analysis/metadata.json +10 -0
  117. gitinject/workflows/cline-assistant/contents/.github/workflows/main.yml +87 -0
  118. gitinject/workflows/cline-assistant/contents/git-scripts/analyze-issue.sh +43 -0
  119. gitinject/workflows/cline-assistant/metadata.json +10 -0
  120. gitinject/workflows/codex-pr-review/contents/.github/workflows/main.yml +73 -0
  121. gitinject/workflows/codex-pr-review/metadata.json +10 -0
  122. gitinject/workflows/copilot-ci-doctor/contents/.github/workflows/ci-doctor.yml +1161 -0
  123. gitinject/workflows/copilot-ci-doctor/metadata.json +10 -0
  124. gitinject/workflows/copilot-lean-squad/contents/.github/workflows/lean-squad.yml +1313 -0
  125. gitinject/workflows/copilot-lean-squad/metadata.json +10 -0
  126. gitinject/workflows/copilot-malicious-scan/contents/.github/workflows/daily-malicious-code-scan.yml +899 -0
  127. gitinject/workflows/copilot-malicious-scan/metadata.json +10 -0
  128. gitinject/workflows/copilot-repo-assist/contents/.github/workflows/repo-assist.yml +1503 -0
  129. gitinject/workflows/copilot-repo-assist/metadata.json +10 -0
  130. gitinject/workflows/copilot-wiki-writer/contents/.github/workflows/agentic-wiki-writer.yml +1316 -0
  131. gitinject/workflows/copilot-wiki-writer/metadata.json +10 -0
  132. gitinject/workflows/gemini-assistant/contents/.github/workflows/gemini-invoke.yml +122 -0
  133. gitinject/workflows/gemini-assistant/contents/.github/workflows/gemini-plan-execute.yml +130 -0
  134. gitinject/workflows/gemini-assistant/contents/.github/workflows/gemini-review.yml +118 -0
  135. gitinject/workflows/gemini-assistant/contents/.github/workflows/gemini-scheduled-triage.yml +220 -0
  136. gitinject/workflows/gemini-assistant/contents/.github/workflows/gemini-triage.yml +160 -0
  137. gitinject/workflows/gemini-assistant/contents/.github/workflows/main.yml +220 -0
  138. gitinject/workflows/gemini-assistant/metadata.json +10 -0
  139. gitinject/workflows/gemini-assistant-original/AWESOME.md +118 -0
  140. gitinject/workflows/gemini-assistant-original/CONFIGURATION.md +162 -0
  141. gitinject/workflows/gemini-assistant-original/README.md +93 -0
  142. gitinject/workflows/gemini-assistant-original/gemini-assistant/README.md +192 -0
  143. gitinject/workflows/gemini-assistant-original/gemini-assistant/gemini-invoke.toml +94 -0
  144. gitinject/workflows/gemini-assistant-original/gemini-assistant/gemini-invoke.yml +131 -0
  145. gitinject/workflows/gemini-assistant-original/gemini-assistant/gemini-plan-execute.toml +100 -0
  146. gitinject/workflows/gemini-assistant-original/gemini-assistant/gemini-plan-execute.yml +139 -0
  147. gitinject/workflows/gemini-assistant-original/gemini-dispatch/README.md +49 -0
  148. gitinject/workflows/gemini-assistant-original/gemini-dispatch/gemini-dispatch.yml +221 -0
  149. gitinject/workflows/gemini-assistant-original/issue-triage/README.md +190 -0
  150. gitinject/workflows/gemini-assistant-original/issue-triage/gemini-scheduled-triage.toml +96 -0
  151. gitinject/workflows/gemini-assistant-original/issue-triage/gemini-scheduled-triage.yml +223 -0
  152. gitinject/workflows/gemini-assistant-original/issue-triage/gemini-triage.toml +32 -0
  153. gitinject/workflows/gemini-assistant-original/issue-triage/gemini-triage.yml +167 -0
  154. gitinject/workflows/gemini-assistant-original/metadata.json +10 -0
  155. gitinject/workflows/gemini-assistant-original/pr-review/README.md +337 -0
  156. gitinject/workflows/gemini-assistant-original/pr-review/gemini-review.toml +176 -0
  157. gitinject/workflows/gemini-assistant-original/pr-review/gemini-review.yml +119 -0
  158. gitinject/workflows/opencode-pr-review/contents/.github/workflows/main.yml +28 -0
  159. gitinject/workflows/opencode-pr-review/metadata.json +10 -0
  160. gitinject-0.1.0.dist-info/METADATA +128 -0
  161. gitinject-0.1.0.dist-info/RECORD +164 -0
  162. gitinject-0.1.0.dist-info/WHEEL +4 -0
  163. gitinject-0.1.0.dist-info/entry_points.txt +2 -0
  164. gitinject-0.1.0.dist-info/licenses/LICENSE +202 -0
@@ -0,0 +1,10 @@
1
+ {
2
+ "name": "Agentic Wiki Writer",
3
+ "description": "Generates and maintains GitHub wiki pages from source code using a template.",
4
+ "category": "content-docs",
5
+ "provider": "github-copilot",
6
+ "source": "https://github.com/githubnext/agentics/blob/main/workflows/agentic-wiki-writer.md",
7
+ "defense_level": "baseline",
8
+ "labels": ["documentation", "wiki", "automated", "copilot"],
9
+ "supported_events": ["schedule", "workflow_dispatch"]
10
+ }
@@ -0,0 +1,122 @@
1
+ name: '▶️ Gemini Invoke'
2
+
3
+ on:
4
+ workflow_call:
5
+ inputs:
6
+ additional_context:
7
+ type: 'string'
8
+ description: 'Any additional context from the request'
9
+ required: false
10
+
11
+ concurrency:
12
+ group: '${{ github.workflow }}-invoke-${{ github.event_name }}-${{ github.event.pull_request.number || github.event.issue.number }}'
13
+ cancel-in-progress: false
14
+
15
+ defaults:
16
+ run:
17
+ shell: 'bash'
18
+
19
+ jobs:
20
+ invoke:
21
+ runs-on: 'ubuntu-latest'
22
+ permissions:
23
+ contents: 'read'
24
+ id-token: 'write'
25
+ issues: 'write'
26
+ pull-requests: 'write'
27
+ steps:
28
+ - name: 'Mint identity token'
29
+ id: 'mint_identity_token'
30
+ if: |-
31
+ ${{ vars.APP_ID }}
32
+ uses: 'actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf' # ratchet:actions/create-github-app-token@v2
33
+ with:
34
+ app-id: '${{ vars.APP_ID }}'
35
+ private-key: '${{ secrets.APP_PRIVATE_KEY }}'
36
+ permission-contents: 'read'
37
+ permission-issues: 'write'
38
+ permission-pull-requests: 'write'
39
+
40
+ - name: 'Checkout Code'
41
+ uses: 'actions/checkout@v4' # ratchet:exclude
42
+
43
+ - name: 'Run Gemini CLI'
44
+ id: 'run_gemini'
45
+ uses: 'google-github-actions/run-gemini-cli@v0' # ratchet:exclude
46
+ env:
47
+ TITLE: '${{ github.event.pull_request.title || github.event.issue.title }}'
48
+ DESCRIPTION: '${{ github.event.pull_request.body || github.event.issue.body }}'
49
+ EVENT_NAME: '${{ github.event_name }}'
50
+ GITHUB_TOKEN: '${{ steps.mint_identity_token.outputs.token || secrets.GITHUB_TOKEN || github.token }}'
51
+ IS_PULL_REQUEST: '${{ !!github.event.pull_request }}'
52
+ ISSUE_NUMBER: '${{ github.event.pull_request.number || github.event.issue.number }}'
53
+ REPOSITORY: '${{ github.repository }}'
54
+ ADDITIONAL_CONTEXT: '${{ inputs.additional_context }}'
55
+ with:
56
+ gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
57
+ gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
58
+ gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
59
+ gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
60
+ gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
61
+ gemini_cli_version: '${{ vars.GEMINI_CLI_VERSION }}'
62
+ gemini_debug: '${{ fromJSON(vars.GEMINI_DEBUG || vars.ACTIONS_STEP_DEBUG || false) }}'
63
+ gemini_model: '${{ vars.GEMINI_MODEL }}'
64
+ google_api_key: '${{ secrets.GOOGLE_API_KEY }}'
65
+ use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
66
+ use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
67
+ upload_artifacts: '${{ vars.UPLOAD_ARTIFACTS }}'
68
+ workflow_name: 'gemini-invoke'
69
+ # Assistant workflows can be triggered by comments on either Issues or PRs.
70
+ # We explicitly map both fields so the CLI can correctly categorize the interaction.
71
+ github_pr_number: '${{ github.event.pull_request.number }}'
72
+ github_issue_number: '${{ github.event.issue.number }}'
73
+ settings: |-
74
+ {
75
+ "model": {
76
+ "maxSessionTurns": 25
77
+ },
78
+ "telemetry": {
79
+ "enabled": true,
80
+ "target": "local",
81
+ "outfile": ".gemini/telemetry.log"
82
+ },
83
+ "mcpServers": {
84
+ "github": {
85
+ "command": "docker",
86
+ "args": [
87
+ "run",
88
+ "-i",
89
+ "--rm",
90
+ "-e",
91
+ "GITHUB_PERSONAL_ACCESS_TOKEN",
92
+ "ghcr.io/github/github-mcp-server:v0.27.0"
93
+ ],
94
+ "includeTools": [
95
+ "add_issue_comment",
96
+ "issue_read",
97
+ "list_issues",
98
+ "search_issues",
99
+ "pull_request_read",
100
+ "list_pull_requests",
101
+ "search_pull_requests",
102
+ "get_commit",
103
+ "get_file_contents",
104
+ "list_commits",
105
+ "search_code"
106
+ ],
107
+ "env": {
108
+ "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
109
+ }
110
+ }
111
+ },
112
+ "tools": {
113
+ "core": [
114
+ "run_shell_command(cat)",
115
+ "run_shell_command(echo)",
116
+ "run_shell_command(grep)",
117
+ "run_shell_command(head)",
118
+ "run_shell_command(tail)"
119
+ ]
120
+ }
121
+ }
122
+ prompt: '/gemini-invoke'
@@ -0,0 +1,130 @@
1
+ name: '🧙 Gemini Plan Execution'
2
+
3
+ on:
4
+ workflow_call:
5
+ inputs:
6
+ additional_context:
7
+ type: 'string'
8
+ description: 'Any additional context from the request'
9
+ required: false
10
+
11
+ concurrency:
12
+ group: '${{ github.workflow }}-plan-execute-${{ github.event_name }}-${{ github.event.pull_request.number || github.event.issue.number }}'
13
+ cancel-in-progress: true
14
+
15
+ defaults:
16
+ run:
17
+ shell: 'bash'
18
+
19
+ jobs:
20
+ plan-execute:
21
+ timeout-minutes: 30
22
+ runs-on: 'ubuntu-latest'
23
+ permissions:
24
+ contents: 'write'
25
+ id-token: 'write'
26
+ issues: 'write'
27
+ pull-requests: 'write'
28
+
29
+ steps:
30
+ - name: 'Mint identity token'
31
+ id: 'mint_identity_token'
32
+ if: |-
33
+ ${{ vars.APP_ID }}
34
+ uses: 'actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf' # ratchet:actions/create-github-app-token@v2
35
+ with:
36
+ app-id: '${{ vars.APP_ID }}'
37
+ private-key: '${{ secrets.APP_PRIVATE_KEY }}'
38
+ permission-contents: 'write'
39
+ permission-issues: 'write'
40
+ permission-pull-requests: 'write'
41
+
42
+ - name: 'Checkout Code'
43
+ uses: 'actions/checkout@v4' # ratchet:exclude
44
+
45
+ - name: 'Run Gemini CLI'
46
+ id: 'run_gemini'
47
+ uses: 'google-github-actions/run-gemini-cli@v0' # ratchet:exclude
48
+ env:
49
+ TITLE: '${{ github.event.pull_request.title || github.event.issue.title }}'
50
+ DESCRIPTION: '${{ github.event.pull_request.body || github.event.issue.body }}'
51
+ EVENT_NAME: '${{ github.event_name }}'
52
+ GITHUB_TOKEN: '${{ steps.mint_identity_token.outputs.token || secrets.GITHUB_TOKEN || github.token }}'
53
+ IS_PULL_REQUEST: '${{ !!github.event.pull_request }}'
54
+ ISSUE_NUMBER: '${{ github.event.pull_request.number || github.event.issue.number }}'
55
+ REPOSITORY: '${{ github.repository }}'
56
+ ADDITIONAL_CONTEXT: '${{ inputs.additional_context }}'
57
+ with:
58
+ gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
59
+ gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
60
+ gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
61
+ gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
62
+ gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
63
+ gemini_cli_version: '${{ vars.GEMINI_CLI_VERSION }}'
64
+ gemini_debug: '${{ fromJSON(vars.GEMINI_DEBUG || vars.ACTIONS_STEP_DEBUG || false) }}'
65
+ gemini_model: '${{ vars.GEMINI_MODEL }}'
66
+ google_api_key: '${{ secrets.GOOGLE_API_KEY }}'
67
+ use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
68
+ use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
69
+ upload_artifacts: '${{ vars.UPLOAD_ARTIFACTS }}'
70
+ workflow_name: 'gemini-plan-execute'
71
+ # Assistant workflows can be triggered by comments on either Issues or PRs.
72
+ # We explicitly map both fields so the CLI can correctly categorize the interaction.
73
+ github_pr_number: '${{ github.event.pull_request.number }}'
74
+ github_issue_number: '${{ github.event.issue.number }}'
75
+ settings: |-
76
+ {
77
+ "model": {
78
+ "maxSessionTurns": 25
79
+ },
80
+ "telemetry": {
81
+ "enabled": true,
82
+ "target": "local",
83
+ "outfile": ".gemini/telemetry.log"
84
+ },
85
+ "mcpServers": {
86
+ "github": {
87
+ "command": "docker",
88
+ "args": [
89
+ "run",
90
+ "-i",
91
+ "--rm",
92
+ "-e",
93
+ "GITHUB_PERSONAL_ACCESS_TOKEN",
94
+ "ghcr.io/github/github-mcp-server:v0.27.0"
95
+ ],
96
+ "includeTools": [
97
+ "add_issue_comment",
98
+ "issue_read",
99
+ "list_issues",
100
+ "search_issues",
101
+ "create_pull_request",
102
+ "pull_request_read",
103
+ "list_pull_requests",
104
+ "search_pull_requests",
105
+ "create_branch",
106
+ "create_or_update_file",
107
+ "delete_file",
108
+ "fork_repository",
109
+ "get_commit",
110
+ "get_file_contents",
111
+ "list_commits",
112
+ "push_files",
113
+ "search_code"
114
+ ],
115
+ "env": {
116
+ "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
117
+ }
118
+ }
119
+ },
120
+ "tools": {
121
+ "core": [
122
+ "run_shell_command(cat)",
123
+ "run_shell_command(echo)",
124
+ "run_shell_command(grep)",
125
+ "run_shell_command(head)",
126
+ "run_shell_command(tail)"
127
+ ]
128
+ }
129
+ }
130
+ prompt: '/gemini-plan-execute'
@@ -0,0 +1,118 @@
1
+ name: '🔎 Gemini Review'
2
+
3
+ on:
4
+ workflow_call:
5
+ inputs:
6
+ additional_context:
7
+ type: 'string'
8
+ description: 'Any additional context from the request'
9
+ required: false
10
+
11
+ concurrency:
12
+ group: '${{ github.workflow }}-review-${{ github.event_name }}-${{ github.event.pull_request.number || github.event.issue.number }}'
13
+ cancel-in-progress: true
14
+
15
+ defaults:
16
+ run:
17
+ shell: 'bash'
18
+
19
+ jobs:
20
+ review:
21
+ runs-on: 'ubuntu-latest'
22
+ timeout-minutes: 7
23
+ permissions:
24
+ contents: 'read'
25
+ id-token: 'write'
26
+ issues: 'write'
27
+ pull-requests: 'write'
28
+ steps:
29
+ - name: 'Mint identity token'
30
+ id: 'mint_identity_token'
31
+ if: |-
32
+ ${{ vars.APP_ID }}
33
+ uses: 'actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf' # ratchet:actions/create-github-app-token@v2
34
+ with:
35
+ app-id: '${{ vars.APP_ID }}'
36
+ private-key: '${{ secrets.APP_PRIVATE_KEY }}'
37
+ permission-contents: 'read'
38
+ permission-issues: 'write'
39
+ permission-pull-requests: 'write'
40
+
41
+ - name: 'Checkout repository'
42
+ uses: 'actions/checkout@8e8c483db84b4bee98b60c0593521ed34d9990e8' # ratchet:actions/checkout@v6
43
+ with:
44
+ persist-credentials: 'false'
45
+ ref: '${{ github.event.pull_request.head.sha }}'
46
+
47
+ - name: 'Prepare prompt context'
48
+ shell: 'bash'
49
+ run: |-
50
+ mkdir -p .gemini
51
+ jq -n \
52
+ --arg repo "${REPOSITORY}" \
53
+ --arg pr "${PULL_REQUEST_NUMBER}" \
54
+ --arg context "${ADDITIONAL_CONTEXT}" \
55
+ '{repository: $repo, pull_request_number: $pr, additional_context: $context}' > .gemini/context.json
56
+ env:
57
+ REPOSITORY: '${{ github.repository }}'
58
+ PULL_REQUEST_NUMBER: '${{ github.event.pull_request.number || github.event.issue.number }}'
59
+ ADDITIONAL_CONTEXT: '${{ inputs.additional_context }}'
60
+
61
+ - name: 'Run Gemini pull request review'
62
+ uses: 'google-github-actions/run-gemini-cli@v0' # ratchet:exclude
63
+ id: 'gemini_pr_review'
64
+ env:
65
+ GEMINI_CLI_TRUST_WORKSPACE: 'true'
66
+ GITHUB_TOKEN: '${{ steps.mint_identity_token.outputs.token || secrets.GITHUB_TOKEN || github.token }}'
67
+ GEMINI_API_KEY: '${{ secrets.GEMINI_API_KEY }}'
68
+ REPOSITORY: '${{ github.repository }}'
69
+ PULL_REQUEST_NUMBER: '${{ github.event.pull_request.number }}'
70
+ ADDITIONAL_CONTEXT: '${{ inputs.additional_context }}'
71
+ with:
72
+ gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
73
+ gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
74
+ gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
75
+ gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
76
+ gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
77
+ gemini_cli_version: '${{ vars.GEMINI_CLI_VERSION }}'
78
+ gemini_debug: '${{ fromJSON(vars.GEMINI_DEBUG || vars.ACTIONS_STEP_DEBUG || false) }}'
79
+ gemini_model: '${{ vars.GEMINI_MODEL }}'
80
+ use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
81
+ use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
82
+ upload_artifacts: '${{ vars.UPLOAD_ARTIFACTS }}'
83
+ workflow_name: 'gemini-review'
84
+ # Explicitly set the PR number to handle `issue_comment` triggers (which GitHub treats as issues, not PRs)
85
+ github_pr_number: '${{ github.event.pull_request.number }}'
86
+ settings: |-
87
+ {
88
+ "model": {
89
+ "maxSessionTurns": 25
90
+ },
91
+ "telemetry": {
92
+ "enabled": true,
93
+ "target": "local",
94
+ "outfile": ".gemini/telemetry.log"
95
+ },
96
+ "mcpServers": {
97
+ "github": {
98
+ "command": "docker",
99
+ "args": [
100
+ "run",
101
+ "-i",
102
+ "--rm",
103
+ "-e",
104
+ "GITHUB_PERSONAL_ACCESS_TOKEN",
105
+ "ghcr.io/github/github-mcp-server:v0.27.0"
106
+ ],
107
+ "includeTools": [
108
+ "add_comment_to_pending_review",
109
+ "pull_request_read",
110
+ "pull_request_review_write"
111
+ ],
112
+ "env": {
113
+ "GITHUB_PERSONAL_ACCESS_TOKEN": "${GITHUB_TOKEN}"
114
+ }
115
+ }
116
+ }
117
+ }
118
+ prompt: '/gemini-review'
@@ -0,0 +1,220 @@
1
+ name: '📋 Gemini Scheduled Issue Triage'
2
+
3
+ on:
4
+ schedule:
5
+ - cron: '0 * * * *' # Runs every hour
6
+ pull_request:
7
+ branches:
8
+ - 'main'
9
+ - 'release/**/*'
10
+ paths:
11
+ - '.github/workflows/gemini-scheduled-triage.yml'
12
+ push:
13
+ branches:
14
+ - 'main'
15
+ - 'release/**/*'
16
+ paths:
17
+ - '.github/workflows/gemini-scheduled-triage.yml'
18
+ workflow_dispatch:
19
+
20
+ concurrency:
21
+ group: '${{ github.workflow }}'
22
+ cancel-in-progress: true
23
+
24
+ defaults:
25
+ run:
26
+ shell: 'bash'
27
+
28
+ jobs:
29
+ triage:
30
+ runs-on: 'ubuntu-latest'
31
+ timeout-minutes: 7
32
+ permissions:
33
+ contents: 'read'
34
+ id-token: 'write'
35
+ issues: 'read'
36
+ pull-requests: 'read'
37
+ outputs:
38
+ available_labels: '${{ steps.get_labels.outputs.available_labels }}'
39
+ triaged_issues: '${{ env.TRIAGED_ISSUES }}'
40
+ steps:
41
+ - name: 'Get repository labels'
42
+ id: 'get_labels'
43
+ uses: 'actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd' # ratchet:actions/github-script@v8.0.0
44
+ with:
45
+ # NOTE: we intentionally do not use the minted token. The default
46
+ # GITHUB_TOKEN provided by the action has enough permissions to read
47
+ # the labels.
48
+ script: |-
49
+ const labels = [];
50
+ for await (const response of github.paginate.iterator(github.rest.issues.listLabelsForRepo, {
51
+ owner: context.repo.owner,
52
+ repo: context.repo.repo,
53
+ per_page: 100, // Maximum per page to reduce API calls
54
+ })) {
55
+ labels.push(...response.data);
56
+ }
57
+
58
+ if (!labels || labels.length === 0) {
59
+ core.setFailed('There are no issue labels in this repository.')
60
+ }
61
+
62
+ const labelNames = labels.map(label => label.name).sort();
63
+ core.setOutput('available_labels', labelNames.join(','));
64
+ core.info(`Found ${labelNames.length} labels: ${labelNames.join(', ')}`);
65
+ return labelNames;
66
+
67
+ - name: 'Find untriaged issues'
68
+ id: 'find_issues'
69
+ env:
70
+ GITHUB_REPOSITORY: '${{ github.repository }}'
71
+ GITHUB_TOKEN: '${{ secrets.GITHUB_TOKEN || github.token }}'
72
+ run: |-
73
+ echo '🔍 Finding unlabeled issues and issues marked for triage...'
74
+ ISSUES="$(gh issue list \
75
+ --state 'open' \
76
+ --search 'no:label label:"status/needs-triage"' \
77
+ --json number,title,body \
78
+ --limit '100' \
79
+ --repo "${GITHUB_REPOSITORY}"
80
+ )"
81
+
82
+ echo '📝 Setting output for GitHub Actions...'
83
+ echo "issues_to_triage=${ISSUES}" >> "${GITHUB_OUTPUT}"
84
+
85
+ ISSUE_NUMBERS="$(echo "${ISSUES}" | jq -r '.[].number | tostring' | paste -sd, -)"
86
+ echo "issue_numbers=${ISSUE_NUMBERS}" >> "${GITHUB_OUTPUT}"
87
+
88
+ ISSUE_COUNT="$(echo "${ISSUES}" | jq 'length')"
89
+ echo "✅ Found ${ISSUE_COUNT} issue(s) to triage! 🎯"
90
+
91
+ - name: 'Run Gemini Issue Analysis'
92
+ id: 'gemini_issue_analysis'
93
+ if: |-
94
+ ${{ steps.find_issues.outputs.issues_to_triage != '[]' }}
95
+ uses: 'google-github-actions/run-gemini-cli@v0' # ratchet:exclude
96
+ env:
97
+ GITHUB_TOKEN: '' # Do not pass any auth token here since this runs on untrusted inputs
98
+ ISSUES_TO_TRIAGE: '${{ steps.find_issues.outputs.issues_to_triage }}'
99
+ REPOSITORY: '${{ github.repository }}'
100
+ AVAILABLE_LABELS: '${{ steps.get_labels.outputs.available_labels }}'
101
+ with:
102
+ gcp_location: '${{ vars.GOOGLE_CLOUD_LOCATION }}'
103
+ gcp_project_id: '${{ vars.GOOGLE_CLOUD_PROJECT }}'
104
+ gcp_service_account: '${{ vars.SERVICE_ACCOUNT_EMAIL }}'
105
+ gcp_workload_identity_provider: '${{ vars.GCP_WIF_PROVIDER }}'
106
+ gemini_api_key: '${{ secrets.GEMINI_API_KEY }}'
107
+ gemini_cli_version: '${{ vars.GEMINI_CLI_VERSION }}'
108
+ gemini_debug: '${{ fromJSON(vars.GEMINI_DEBUG || vars.ACTIONS_STEP_DEBUG || false) }}'
109
+ gemini_model: '${{ vars.GEMINI_MODEL }}'
110
+ google_api_key: '${{ secrets.GOOGLE_API_KEY }}'
111
+ use_gemini_code_assist: '${{ vars.GOOGLE_GENAI_USE_GCA }}'
112
+ use_vertex_ai: '${{ vars.GOOGLE_GENAI_USE_VERTEXAI }}'
113
+ upload_artifacts: '${{ vars.UPLOAD_ARTIFACTS }}'
114
+ workflow_name: 'gemini-scheduled-triage'
115
+ # Overriding default telemetry inputs because scheduled workflows lack an event payload
116
+ # We pass the dynamically generated list of batch issues to the issue number field
117
+ github_issue_number: '${{ steps.find_issues.outputs.issue_numbers }}'
118
+ settings: |-
119
+ {
120
+ "model": {
121
+ "maxSessionTurns": 25
122
+ },
123
+ "telemetry": {
124
+ "enabled": true,
125
+ "target": "local",
126
+ "outfile": ".gemini/telemetry.log"
127
+ },
128
+ "tools": {
129
+ "core": [
130
+ "run_shell_command(echo)",
131
+ "run_shell_command(jq)",
132
+ "run_shell_command(printenv)"
133
+ ]
134
+ }
135
+ }
136
+ prompt: '/gemini-scheduled-triage'
137
+
138
+ label:
139
+ runs-on: 'ubuntu-latest'
140
+ needs:
141
+ - 'triage'
142
+ if: |-
143
+ needs.triage.outputs.available_labels != '' &&
144
+ needs.triage.outputs.available_labels != '[]' &&
145
+ needs.triage.outputs.triaged_issues != '' &&
146
+ needs.triage.outputs.triaged_issues != '[]'
147
+ permissions:
148
+ contents: 'read'
149
+ issues: 'write'
150
+ pull-requests: 'write'
151
+ steps:
152
+ - name: 'Mint identity token'
153
+ id: 'mint_identity_token'
154
+ if: |-
155
+ ${{ vars.APP_ID }}
156
+ uses: 'actions/create-github-app-token@29824e69f54612133e76f7eaac726eef6c875baf' # ratchet:actions/create-github-app-token@v2
157
+ with:
158
+ app-id: '${{ vars.APP_ID }}'
159
+ private-key: '${{ secrets.APP_PRIVATE_KEY }}'
160
+ permission-contents: 'read'
161
+ permission-issues: 'write'
162
+ permission-pull-requests: 'write'
163
+
164
+ - name: 'Apply labels'
165
+ env:
166
+ AVAILABLE_LABELS: '${{ needs.triage.outputs.available_labels }}'
167
+ TRIAGED_ISSUES: '${{ needs.triage.outputs.triaged_issues }}'
168
+ uses: 'actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd' # ratchet:actions/github-script@v8.0.0
169
+ with:
170
+ # Use the provided token so that the "gemini-cli" is the actor in the
171
+ # log for what changed the labels.
172
+ github-token: '${{ steps.mint_identity_token.outputs.token || secrets.GITHUB_TOKEN || github.token }}'
173
+ script: |-
174
+ // Parse the available labels
175
+ const availableLabels = (process.env.AVAILABLE_LABELS || '').split(',')
176
+ .map((label) => label.trim())
177
+ .sort()
178
+
179
+ // Parse out the triaged issues
180
+ const triagedIssues = (JSON.parse(process.env.TRIAGED_ISSUES || '{}'))
181
+ .sort((a, b) => a.issue_number - b.issue_number)
182
+
183
+ core.debug(`Triaged issues: ${JSON.stringify(triagedIssues)}`);
184
+
185
+ // Iterate over each label
186
+ for (const issue of triagedIssues) {
187
+ if (!issue) {
188
+ core.debug(`Skipping empty issue: ${JSON.stringify(issue)}`);
189
+ continue;
190
+ }
191
+
192
+ const issueNumber = issue.issue_number;
193
+ if (!issueNumber) {
194
+ core.debug(`Skipping issue with no data: ${JSON.stringify(issue)}`);
195
+ continue;
196
+ }
197
+
198
+ // Extract and reject invalid labels - we do this just in case
199
+ // someone was able to prompt inject malicious labels.
200
+ let labelsToSet = (issue.labels_to_set || [])
201
+ .map((label) => label.trim())
202
+ .filter((label) => availableLabels.includes(label))
203
+ .sort()
204
+
205
+ core.debug(`Identified labels to set: ${JSON.stringify(labelsToSet)}`);
206
+
207
+ if (labelsToSet.length === 0) {
208
+ core.info(`Skipping issue #${issueNumber} - no labels to set.`)
209
+ continue;
210
+ }
211
+
212
+ core.debug(`Setting labels on issue #${issueNumber} to ${labelsToSet.join(', ')} (${issue.explanation || 'no explanation'})`)
213
+
214
+ await github.rest.issues.setLabels({
215
+ owner: context.repo.owner,
216
+ repo: context.repo.repo,
217
+ issue_number: issueNumber,
218
+ labels: labelsToSet,
219
+ });
220
+ }