#!/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)