text: #!/usr/bin/env python3
  
  """ Pydantic verifier for config structure """
  
  from enum import Enum
  from typing import Optional
  from pydantic.dataclasses import dataclass
  from pydantic import conlist  # pylint: disable=no-name-in-module
  
  # TODO: Move from has_key to iterators and "is in"
  
  
  class OSEnum(str, Enum):
      """ List of all supported OS-es """
      LINUX = "linux"
      WINDOWS = "windows"
  
  
  class VMControllerTypeEnum(str, Enum):
      """ List of all supported controlled plugins. This is only done for VM controller plugins !
          I do not expect many new ones. And typos in config can be a waste of time. Let's see if I am right.  """
      VAGRANT = "vagrant"
      RUNNING_VM = "running_vm"
  
  
  @dataclass
  class CalderaConfig:
      """ Configuration for the Caldera server """
      apikey: str
  
      def has_key(self, keyname):
          """ Checks if a key exists
          Required for compatibility with DotMap which is used in Unit tests
          """
          if keyname in self.__dict__.keys():
              return True
          return False
  
  
  @dataclass
  class VMController:
      """ Configuration for the VM controller """
      vm_type: VMControllerTypeEnum
      vagrantfilepath: str
      ip: Optional[str] = ""  # pylint: disable=invalid-name
  
      def has_key(self, keyname):
          """ Checks if a key exists
              Required for compatibility with DotMap which is used in Unit tests
          """
          if keyname in self.__dict__.keys():
              return True
          return False
  
      # def __dict__(self):
      #     return {"vm_type": self.vm_type,
      #             "vagrantfilepath": self.vagrantfilepath,
      #            "ip": self.ip}
  
  
  @dataclass
  class Attacker:
      """ Configuration for a attacker VM """
      name: str
      vm_controller: VMController
      vm_name: str
      nicknames: Optional[list[str]]
      machinepath: str
      os: OSEnum  # pylint: disable=invalid-name
      use_existing_machine: bool = False
      playground: Optional[str] = None
  
      def has_key(self, keyname):
          """ Checks if a key exists
              Required for compatibility with DotMap which is used in Unit tests
          """
          if keyname in self.__dict__.keys():
              return True
          return False
  
      def get(self, keyname, default=None):
          """ Returns the value of a specific key
              Required for compatibility with DotMap which is used in Unit tests
          """
          if self.has_key(keyname):
              return self.__dict__[keyname]
          return default
  
  
  @dataclass
  class Target:
      """ Configuration for a target VM """
      name: str
      vm_controller: VMController
      vm_name: str
      os: OSEnum  # pylint: disable=invalid-name
      paw: str
      group: str
      machinepath: str
      sensors: Optional[list[str]]
      nicknames: Optional[list[str]]
      active: bool = True
      use_existing_machine: bool = False
      playground: Optional[str] = None
      halt_needs_force: Optional[str] = None
      ssh_user: Optional[str] = None
      ssh_password: Optional[str] = None
      ssh_keyfile: Optional[str] = None
      vulnerabilities: list[str] = None
  
      def has_key(self, keyname):
          """ Checks if a key exists
              Required for compatibility with DotMap which is used in Unit tests
          """
          if keyname in self.__dict__.keys():
              return True
          return False
  
      def get(self, keyname, default=None):
          """ Returns the value of a specific key
              Required for compatibility with DotMap which is used in Unit tests
          """
          if self.has_key(keyname):
              return self.__dict__[keyname]
          return default
  
  
  @dataclass
  class AttackConfig:
      """ Generic configuration for attacks """
      caldera_obfuscator: str = "plain-text"
      caldera_jitter: str = "4/8"
      nap_time: int = 5
  
      def has_key(self, keyname):
          """ Checks if a key exists
              Required for compatibility with DotMap which is used in Unit tests
          """
          if keyname in self.__dict__.keys():
              return True
          return False
  
  
  @dataclass
  class AttackList:
      """ A list of attacks to run. Either plugin based or caldera based """
      linux: Optional[list[str]]
      windows: Optional[list[str]]
  
      def has_key(self, keyname):
          """ Checks if a key exists
              Required for compatibility with DotMap which is used in Unit tests
          """
          if keyname in self.__dict__.keys():
              return True
          return False
  
      def get(self, keyname, default=None):
          """ Returns the value of a specific key
              Required for compatibility with DotMap which is used in Unit tests
          """
          if self.has_key(keyname):
              return self.__dict__[keyname]
          return default
  
  
  @dataclass
  class Results:
      """ What to do with the results """
      loot_dir: str
  
      def has_key(self, keyname):
          """ Checks if a key exists
              Required for compatibility with DotMap which is used in Unit tests
          """
          if keyname in self.__dict__.keys():
              return True
          return False
  
  
  @dataclass
  class MainConfig:
      """ Central configuration for PurpleDome """
      caldera: CalderaConfig
      attackers: conlist(Attacker, min_items=1)
      targets: conlist(Target, min_items=1)
      attacks: AttackConfig
      caldera_attacks: AttackList
      plugin_based_attacks: AttackList
      results: Results
  
      # Free form configuration for plugins
      attack_conf: Optional[dict]
      sensor_conf: Optional[dict]
  
      def has_key(self, keyname):
          """ Checks if a key exists
              Required for compatibility with DotMap which is used in Unit tests
          """
          if keyname in self.__dict__.keys():
              return True
          return False
  
  
  # TODO: Check for name duplication
  