@@ -40,16 +40,20 @@ def push_branch(branch_name: str):
4040def detect_drift (local_doc , aws_doc ) -> bool :
4141 local_statements = {json .dumps (s , sort_keys = True ) for s in local_doc .get ("Statement" , [])}
4242 aws_statements = {json .dumps (s , sort_keys = True ) for s in aws_doc .get ("Statement" , [])}
43-
4443 missing_in_local = aws_statements - local_statements
45-
4644 if missing_in_local :
4745 typer .echo ("❌ Drift detected: Local is missing permissions present in AWS." )
4846 return True
49-
5047 typer .echo ("✅ No removal drift detected (local may have extra permissions; that's fine)." )
5148 return False
5249
50+ def close_issue (repo_full_name , token , issue_num , comment ):
51+ gh = Github (token )
52+ repo = gh .get_repo (repo_full_name )
53+ issue = repo .get_issue (number = issue_num )
54+ issue .create_comment (comment )
55+ issue .edit (state = "closed" )
56+
5357@app .command ()
5458def drift (
5559 policy_name : str = typer .Option (..., "--policy-name" , help = "Name of the IAM policy" ),
@@ -84,6 +88,7 @@ def drift(
8488 typer .echo (str (ve ))
8589 raise typer .Exit (1 )
8690 typer .echo (f"✅ AWS policy { policy_arn } updated to include any local additions." )
91+
8792 if not approval_anyway :
8893 typer .echo ("✅ No forced approval requested. Exiting." )
8994 return
@@ -99,11 +104,15 @@ def drift(
99104 raise typer .Exit (1 )
100105
101106 assignees = [a .strip () for a in approvers .split ("," ) if a .strip ()]
102- issue_num , _ = create_approval_issue (repo_full_name , token , policy_name , assignees = assignees )
107+ issue_num , _ = create_approval_issue (
108+ repo_full_name , token , policy_name , assignees = assignees , approval_anyway = approval_anyway
109+ )
103110 issue_url = f"https://github.com/{ repo_full_name } /issues/{ issue_num } "
104111 typer .echo (f"✅ Approval issue created: { issue_url } " )
105112
106- choice = wait_for_sync_choice (repo_full_name , issue_num , token )
113+ choice = wait_for_sync_choice (
114+ repo_full_name , issue_num , token , allowed_approvers = assignees , approval_anyway = approval_anyway
115+ )
107116
108117 if choice == "local->aws" :
109118 merged_doc = merge_policy_documents (local_doc , aws_doc )
@@ -113,6 +122,7 @@ def drift(
113122 typer .echo (str (ve ))
114123 raise typer .Exit (1 )
115124 typer .echo (f"✅ AWS policy { policy_arn } updated with local changes (append-only)." )
125+ close_issue (repo_full_name , token , issue_num , "✅ AWS updated with local changes. Closing issue." )
116126
117127 elif choice == "aws->local" :
118128 _update_local_and_create_pr (aws_doc , policy_file , repo_full_name , policy_name , issue_num , token , "from AWS policy" )
@@ -127,8 +137,18 @@ def drift(
127137 typer .echo (f"✅ AWS policy { policy_arn } updated with superset of local + AWS." )
128138 _update_local_and_create_pr (superset_doc , policy_file , repo_full_name , policy_name , issue_num , token , "with superset of local + AWS" )
129139
140+ elif choice == "approve" :
141+ typer .echo ("✅ Approved without sync action. Closing issue." )
142+ close_issue (repo_full_name , token , issue_num , "✅ Approved without sync action. Closing issue." )
143+
144+ elif choice == "reject" :
145+ typer .echo ("❌ Approval rejected. Closing issue." )
146+ close_issue (repo_full_name , token , issue_num , "❌ Approval rejected. Closing issue." )
147+ raise typer .Exit (1 )
148+
130149 else :
131150 typer .echo ("⏭ No synchronization performed (skip)." )
151+ close_issue (repo_full_name , token , issue_num , "⏭ No sync chosen. Closing issue." )
132152
133153def _update_aws_policy (iam , policy_arn , policy_doc ):
134154 sids = [stmt .get ("Sid" ) for stmt in policy_doc .get ("Statement" , []) if "Sid" in stmt ]
0 commit comments