import asyncio
import aiohttp
import os
from datetime import datetime
# 环境变量
GITHUB_REPOSITORY = os.getenv("GITHUB_REPOSITORY")
SONAR_TOKEN = os.getenv("SONAR_TOKEN")
DEVIN_API_KEY = os.getenv("DEVIN_API_KEY")
SONAR_ORG = os.getenv("SONAR_ORG")
SONAR_PROJECT_KEY = os.getenv("SONAR_PROJECT_KEY")
DEVIN_API_BASE = "https://api.devin.ai/v1"
async def get_sonarcloud_issues():
"""从 SonarCloud 获取未解决的漏洞。"""
url = "https://sonarcloud.io/api/issues/search"
headers = {"Authorization": f"Bearer {SONAR_TOKEN}"}
params = {
"organization": SONAR_ORG,
"projectKeys": SONAR_PROJECT_KEY,
"types": "VULNERABILITY",
"statuses": "OPEN"
}
async with aiohttp.ClientSession() as session:
async with session.get(url, headers=headers, params=params) as response:
if response.status != 200:
print(f"获取 SonarCloud 问题时出错:{await response.text()}")
return []
result = await response.json()
print(f"发现 {len(result.get('issues', []))} 个问题")
return result.get('issues', [])
async def delegate_task_to_devin(issue):
"""将修复、提交和推送的完整任务委托给 Devin AI。"""
async with aiohttp.ClientSession() as session:
headers = {"Authorization": f"Bearer {DEVIN_API_KEY}"}
prompt = f"""
修复 {GITHUB_REPOSITORY} 中的以下漏洞:{issue['message']},位于文件 {issue['component']}。
1. 创建名为 'devin/{issue['key']}-fix-vulnerability' 的新分支。
2. 实施修复。
3. 编写详细的提交消息说明更改内容:
- 问题键:{issue['key']}
- 组件:{issue['component']}
- 由 Devin AI 于 {datetime.now().isoformat()} 修复
- 包含 'Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>'。
4. 将分支推送到远程仓库。
5. 创建包含修复说明的拉取请求。
"""
data = {"prompt": prompt, "idempotent": True}
async with session.post(f"{DEVIN_API_BASE}/sessions", json=data, headers=headers) as response:
if response.status != 200:
print(f"委托任务给 Devin 时出错:{await response.text()}")
return None
result = await response.json()
print(f"已创建 Devin 会话:{result}")
return result
async def monitor_devin_session(session_id):
"""监控 Devin 的进度直至任务完成。"""
async with aiohttp.ClientSession() as session:
headers = {"Authorization": f"Bearer {DEVIN_API_KEY}"}
while True:
async with session.get(f"{DEVIN_API_BASE}/sessions/{session_id}", headers=headers) as response:
if response.status != 200:
print(f"监控 Devin 会话时出错:{await response.text()}")
return None
result = await response.json()
status = result.get("status_enum")
if status in ["completed", "stopped"]:
print(f"Devin 已完成任务:{result}")
return result
elif status == "blocked":
print("Devin 遇到问题,请手动检查。")
return None
await asyncio.sleep(5)
async def main():
try:
issues = await get_sonarcloud_issues()
for issue in issues:
print(f"正在处理问题:{issue['key']}")
# 将任务委托给 Devin AI
session_data = await delegate_task_to_devin(issue)
if session_data:
session_id = session_data["session_id"]
# 监控 Devin 的进度
await monitor_devin_session(session_id)
except Exception as e:
print(f"发生错误:{str(e)}")
raise
if __name__ == "__main__":
asyncio.run(main())