142 lines
5.0 KiB
Python
Executable File
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)
|