Files
srx-ai-automation-docs/scripts/orchestrator/gitea/close_pr_with_feedback.py

142 lines
5.0 KiB
Python
Executable File

#!/usr/bin/env python3
"""
Close PR with Feedback - Reject a PR and help AI learn
"""
import sys
import json
import yaml
import requests
from datetime import datetime
from typing import List
sys.path.append('/home/netops/orchestrator')
from gitea_integration import GiteaIntegration
from pr_feedback import PRFeedbackSystem
def close_pr_with_feedback(pr_number: int, reason: str, issues: List[str]):
"""Close a PR and record feedback for AI learning"""
# Load config
with open('/home/netops/orchestrator/config.yaml', 'r') as f:
config = yaml.safe_load(f)
# Initialize systems
gitea = GiteaIntegration(config['gitea'])
feedback_system = PRFeedbackSystem()
print(f"\n🚫 Closing PR #{pr_number} with feedback...")
# First, add a comment to the PR explaining why it's being closed
comment = f"""## 🤖 AI Configuration Review - Rejected
**Reason**: {reason}
**Issues Found**:
{chr(10).join(f'- {issue}' for issue in issues)}
This feedback has been recorded to improve future AI suggestions. The AI will learn from these issues and avoid them in future configurations.
### Specific Problems:
- **Security**: The any/any/any permit rule is too permissive
- **Best Practice**: Source addresses should be specific, not 'any'
- **Risk**: This configuration could expose the network to threats
The AI will generate better suggestions next time based on this feedback.
"""
# Post comment to PR (using Gitea API)
api_url = f"{config['gitea']['url']}/api/v1/repos/{config['gitea']['repo']}/issues/{pr_number}/comments"
headers = {
'Authorization': f"token {config['gitea']['token']}",
'Content-Type': 'application/json'
}
comment_data = {"body": comment}
try:
response = requests.post(api_url, json=comment_data, headers=headers)
if response.status_code in [200, 201]:
print("✅ Added feedback comment to PR")
else:
print(f"⚠️ Could not add comment: {response.status_code}")
except Exception as e:
print(f"⚠️ Error adding comment: {e}")
# Record feedback for AI learning
feedback_details = {
'reason': reason,
'specific_issues': '\n'.join(issues),
'configuration_issues': [
{'type': 'security_permissive', 'description': 'Rules too permissive (any/any/any)'},
{'type': 'security_missing', 'description': 'Missing source address restrictions'}
]
}
feedback_system.record_pr_feedback(pr_number, 'rejected', feedback_details)
# Update orchestrator state
state_file = '/var/lib/orchestrator/state.json'
try:
with open(state_file, 'r') as f:
state = json.load(f)
state['pending_pr'] = None
state['last_pr_status'] = 'rejected'
state['last_pr_rejected'] = datetime.now().isoformat()
with open(state_file, 'w') as f:
json.dump(state, f, indent=2)
print("✅ Updated orchestrator state")
except Exception as e:
print(f"⚠️ Could not update state: {e}")
# Show AI learning summary
patterns = feedback_system.analyze_feedback_patterns()
print(f"\n📊 AI Learning Summary:")
print(f"Total feedback entries: {patterns['total_prs']}")
print(f"Rejected PRs: {patterns['rejected']}")
print(f"Security concerns: {patterns['security_concerns']}")
print("\n✅ PR closed with feedback. The AI will learn from this!")
print("\nNext time the AI generates a configuration, it will:")
print("- Avoid any/any/any permit rules")
print("- Use specific source addresses")
print("- Follow security best practices")
print("\n⚠️ IMPORTANT: Now manually close the PR in Gitea!")
print(f"Go to: {config['gitea']['url']}/{config['gitea']['repo']}/pulls/{pr_number}")
print("Click the 'Close Pull Request' button")
# Quick reject function for current PR
def reject_current_pr():
"""Reject PR #2 with specific feedback"""
close_pr_with_feedback(
pr_number=2,
reason="Security policy too permissive - any/any/any permit rule is dangerous",
issues=[
"ALLOW-ESTABLISHED policy permits all traffic from trust to untrust",
"Source address should not be 'any' - use specific networks",
"Application should not be 'any' - specify required services only",
"This configuration could expose internal network to threats"
]
)
if __name__ == "__main__":
if len(sys.argv) > 1 and sys.argv[1] == "--current":
# Reject the current PR #2
reject_current_pr()
else:
# Interactive mode
pr_num = input("Enter PR number to reject: ")
reason = input("Reason for rejection: ")
issues = []
print("Enter specific issues (empty line to finish):")
while True:
issue = input("- ")
if not issue:
break
issues.append(issue)
close_pr_with_feedback(int(pr_num), reason, issues)