func cleanSecurityGroupRules()

in tool/clean/clean_security_group/clean_security_group.go [241:314]


func cleanSecurityGroupRules(ctx context.Context, client ec2Client, securityGroup types.SecurityGroup) error {
	sgID := *securityGroup.GroupId

	// Get fresh security group data in one call
	describeOutput, err := client.DescribeSecurityGroups(ctx, &ec2.DescribeSecurityGroupsInput{
		GroupIds: []string{sgID},
	})
	if err != nil {
		return fmt.Errorf("describing security group %s: %w", sgID, err)
	}

	if len(describeOutput.SecurityGroups) == 0 {
		return fmt.Errorf("security group %s not found", sgID)
	}

	sg := describeOutput.SecurityGroups[0]

	// Handle both ingress and egress rules concurrently
	var wg sync.WaitGroup
	var ingressErr, egressErr error

	if len(sg.IpPermissions) > 0 {
		if cfg.dryRun {
			log.Printf("🛑 Dry-Run: Would revoke %d ingress rules from security group: %s",
				len(sg.IpPermissions), sgID)
		} else {
			wg.Add(1)
			go func() {
				defer wg.Done()
				_, err := client.RevokeSecurityGroupIngress(ctx, &ec2.RevokeSecurityGroupIngressInput{
					GroupId:       aws.String(sgID),
					IpPermissions: sg.IpPermissions,
				})
				if err != nil {
					ingressErr = fmt.Errorf("revoking ingress rules: %w", err)
				} else {
					log.Printf("✅ Revoked ingress rules from security group: %s", sgID)
				}
			}()
		}
	}

	if len(sg.IpPermissionsEgress) > 0 {
		if cfg.dryRun {
			log.Printf("🛑 Dry-Run: Would revoke %d egress rules from security group: %s",
				len(sg.IpPermissionsEgress), sgID)
		} else {
			wg.Add(1)
			go func() {
				defer wg.Done()
				_, err := client.RevokeSecurityGroupEgress(ctx, &ec2.RevokeSecurityGroupEgressInput{
					GroupId:       aws.String(sgID),
					IpPermissions: sg.IpPermissionsEgress,
				})
				if err != nil {
					egressErr = fmt.Errorf("revoking egress rules: %w", err)
				} else {
					log.Printf("✅ Revoked egress rules from security group: %s", sgID)
				}
			}()
		}
	}

	wg.Wait()

	if ingressErr != nil {
		return ingressErr
	}
	if egressErr != nil {
		return egressErr
	}

	return nil
}