text: __all__ = ["IAMRolesOverprivilegedRule", "IAMRoleWildcardActionOnPolicyRule"]
  
  from typing import Dict, Optional
  
  from pycfmodel.model.cf_model import CFModel
  from pycfmodel.model.resources.iam_managed_policy import IAMManagedPolicy
  from pycfmodel.model.resources.iam_role import IAMRole
  
  from cfripper.config.regex import REGEX_IS_STAR, REGEX_WILDCARD_POLICY_ACTION
  from cfripper.model.enums import RuleGranularity
  from cfripper.model.result import Result
  from cfripper.rules.base_rules import Rule
  
  
  class IAMRolesOverprivilegedRule(Rule):
      """
      Rule that checks for wildcards in resources for a set of actions and restricts managed policies.
  
      Filters context:
      | Parameter               | Type                             | Description                                                    |
      |:-----------------------:|:--------------------------------:|:--------------------------------------------------------------:|
      |`config`                 | str                              | `config` variable available inside the rule                    |
      |`extras`                 | str                              | `extras` variable available inside the rule                    |
      |`logical_id`             | str                              | ID used in Cloudformation to refer the resource being analysed |
      |`resource`               | `IAMRole`                        | Resource that is being addressed                               |
      |`statement`              | `Optional[Statement]`            | Statement being checked found in the Resource                  |
      |`action`                 | `Optional[str]`                  | Action containing insecure permission with forbidden prefix    |
      """
  
      GRANULARITY = RuleGranularity.RESOURCE
  
      def invoke(self, cfmodel: CFModel, extras: Optional[Dict] = None) -> Result:
          result = Result()
          for logical_id, resource in cfmodel.Resources.items():
              if isinstance(resource, IAMRole):
                  self.check_managed_policies(result, logical_id, resource, extras)
                  self.check_inline_policies(result, logical_id, resource, extras)
          return result
  
      def check_managed_policies(self, result: Result, logical_id: str, role: IAMRole, extras: Optional[Dict] = None):
          """Run the managed policies against a blacklist."""
          if not role.Properties.ManagedPolicyArns:
              return
  
          for managed_policy_arn in role.Properties.ManagedPolicyArns:
              if managed_policy_arn in self._config.forbidden_managed_policy_arns:
                  self.add_failure_to_result(
                      result,
                      f"Role {logical_id} has forbidden Managed Policy {managed_policy_arn}",
                      resource_ids={logical_id},
                      context={
                          "config": self._config,
                          "extras": extras,
                          "logical_id": logical_id,
                          "resource": role,
                          "statement": None,
                          "action": None,
                      },
                  )
  
      def check_inline_policies(self, result: Result, logical_id: str, role: IAMRole, extras: Optional[Dict] = None):
          """Check conditional and non-conditional inline policies."""
          if not role.Properties.Policies:
              return
  
          for policy in role.Properties.Policies:
              for statement in policy.PolicyDocument.statements_with(REGEX_IS_STAR):
                  if statement.Effect and statement.Effect == "Allow":
                      for action in statement.get_action_list():
                          for prefix in self._config.forbidden_resource_star_action_prefixes:
                              if action.startswith(prefix):
                                  self.add_failure_to_result(
                                      result,
                                      f"Role '{logical_id}' contains an insecure permission '{action}' in policy "
                                      f"'{policy.PolicyName}'",
                                      resource_ids={logical_id},
                                      context={
                                          "config": self._config,
                                          "extras": extras,
                                          "logical_id": logical_id,
                                          "resource": role,
                                          "statement": statement,
                                          "action": action,
                                      },
                                  )
  
  
  class IAMRoleWildcardActionOnPolicyRule(Rule):
      """
      Checks for use of wildcard characters in all IAM Role policies (including `AssumeRolePolicyDocument`)
      and [AWS Managed Policies](https://docs.aws.amazon.com/IAM/latest/UserGuide/access_policies_managed-vs-inline.html).
  
      Filters context:
          | Parameter           | Type                               | Description                                                    |
          |:-------------------:|:----------------------------------:|:--------------------------------------------------------------:|
          |`config`             | str                                | `config` variable available inside the rule                    |
          |`extras`             | str                                | `extras` variable available inside the rule                    |
          |`logical_id`         | str                                | ID used in Cloudformation to refer the resource being analysed |
          |`resource`           | `Union[IAMRole, IAMManagedPolicy]` | Resource that is being addressed                               |
      """
  
      GRANULARITY = RuleGranularity.RESOURCE
      REASON = "IAM role {} should not allow a `*` action on its {}"
  
      def invoke(self, cfmodel: CFModel, extras: Optional[Dict] = None) -> Result:
          result = Result()
          for logical_id, resource in cfmodel.Resources.items():
              if isinstance(resource, IAMRole):
                  # check AssumeRolePolicyDocument.
                  if resource.Properties.AssumeRolePolicyDocument.allowed_actions_with(REGEX_WILDCARD_POLICY_ACTION):
                      self.add_failure_to_result(
                          result,
                          self.REASON.format(logical_id, "AssumeRolePolicy"),
                          resource_ids={logical_id},
                          context={
                              "config": self._config,
                              "extras": extras,
                              "logical_id": logical_id,
                              "resource": resource,
                          },
                      )
  
                  # check other policies of the IAM role.
                  if resource.Properties.Policies:
                      for policy in resource.Properties.Policies:
                          if policy.PolicyDocument.allowed_actions_with(REGEX_WILDCARD_POLICY_ACTION):
                              self.add_failure_to_result(
                                  result,
                                  self.REASON.format(logical_id, f"{policy.PolicyName} policy"),
                                  resource_ids={logical_id},
                                  context={
                                      "config": self._config,
                                      "extras": extras,
                                      "logical_id": logical_id,
                                      "resource": resource,
                                  },
                              )
  
              # check AWS::IAM::ManagedPolicy.
              elif isinstance(resource, IAMManagedPolicy) and resource.Properties.PolicyDocument.allowed_actions_with(
                  REGEX_WILDCARD_POLICY_ACTION
              ):
                  self.add_failure_to_result(
                      result,
                      self.REASON.format(logical_id, "AWS::IAM::ManagedPolicy"),
                      resource_ids={logical_id},
                      context={"config": self._config, "extras": extras, "logical_id": logical_id, "resource": resource},
                  )
          return result
  