Skip to content

Plugin Drupal8

ConfigAnalysis

Check a configuration is set correctly.

Class: Drutiny\Plugin\Drupal8\Audit\ConfigAnalysis
Extends: Drutiny\Audit\AbstractAnalysis
Package: drutiny/plugin-drupal-8

Parameters

Name Type Description Default
collection string The collection the config belongs to. null
expression string The expression language expression to evaluate. null

Tokens

Name Type Description Default
collection string The collection the config belongs to. null
expression string The expression language expression to evaluate. null
config mixed The returned collection config. null
Source
  public function gather(Sandbox $sandbox) {
    $collection = $sandbox->getParameter('collection');

    $config = $sandbox->drush([
      'format' => 'json',
      'include-overridden' => NULL,
      ])->configGet($collection);

    $sandbox->setParameter('config', $config);
  }
  final public function audit(Sandbox $sandbox)
  {
    $this->gather($sandbox);

    $expressionLanguage = new ExpressionLanguage($sandbox);

    $variables  = $sandbox->getParameterTokens();
    $sandbox->logger()->debug(__CLASS__ . ': ' . Yaml::dump($variables));

    $expression = $sandbox->getParameter('not_applicable', 'false');
    $sandbox->logger()->debug(__CLASS__ . ': ' . $expression);
    if (@$expressionLanguage->evaluate($expression, $variables)) {
      return self::NOT_APPLICABLE;
    }

    $expression = $sandbox->getParameter('expression', 'true');
    $sandbox->logger()->info(__CLASS__ . ': ' . $expression);
    return @$expressionLanguage->evaluate($expression, $variables);
  }

ConfigCheck

Check a configuration is set correctly.

Class: Drutiny\Plugin\Drupal8\Audit\ConfigCheck
Extends: Drutiny\Audit\AbstractComparison
Package: drutiny/plugin-drupal-8

This class can remediate failed audits.

Policies

These are the policies that use this class:

Name Title
Drupal-8:JsAggregation Javascript aggregation
Drupal-8:PageCacheExpiry Drupal Page cache expiry is set
Drupal-8:ErrorLevel Hide errors from screen (log only)
Drupal-8:honeypotTimeLimit Honeypot Time Limit
Drupal-8:CssAggregation CSS aggregation is enabled
Drupal-8:UserRegistrationAdminOnly User registration available to administrators only
Drupal-8:Fast404Enabled Core Fast 404 Enabled

Parameters

Name Type Description Default
collection string The collection the config belongs to. null
key string The key the config belongs to. null
value mixed The value to compare against the retrived value. null
comp_type string The type of comparison to conduct. Defaults to equals. See Drutiny\Audit\AbstractComparison null

Tokens

Name Type Description Default
collection string The collection the config belongs to. null
key string The key the config belongs to. null
value mixed The value to compare against the retrived value. null
comp_type string The type of comparison to conduct. Defaults to equals. See Drutiny\Audit\AbstractComparison null
Source
  public function audit(Sandbox $sandbox) {
    $collection = $sandbox->getParameter('collection');
    $key = $sandbox->getParameter('key');
    $value = $sandbox->getParameter('value');

    $config = $sandbox->drush([
      'format' => 'json',
      'include-overridden' => NULL,
      ])->configGet($collection, $key);
    $reading = $config[$collection . ':' . $key];

    $sandbox->setParameter('reading', $reading);

    return $this->compare($reading, $value, $sandbox);
  }

CronHasRun

Cron last run.

Class: Drutiny\Plugin\Drupal8\Audit\CronHasRun
Extends: Drutiny\Audit
Package: drutiny/plugin-drupal-8

Policies

These are the policies that use this class:

Name Title
Drupal-8:CronHasRun Cron last run

Parameters

Name Type Description Default
cron_max_interval integer The maximum interval between null

Tokens

Name Type Description Default
cron_max_interval integer The maximum interval between null
Source
  public function audit(Sandbox $sandbox) {

    try {
      $timestamp = $sandbox->drush(['format' => 'json'])->stateGet('system.cron_last');
    }
    catch (DrushFormatException $e) {
      return FALSE;
    }

    // Check that cron was run in the last day.
    $since = time() - $timestamp;
    $sandbox->setParameter('cron_last', date('Y-m-d H:i:s', $timestamp));

    if ($since > $sandbox->getParameter('cron_max_interval')) {
      return FALSE;
    }

    return TRUE;
  }

CronLast

Check a configuration is set correctly.

Class: Drutiny\Plugin\Drupal8\Audit\CronLast
Extends: Drutiny\Audit
Package: drutiny/plugin-drupal-8

Policies

These are the policies that use this class:

Name Title
Drupal-8:CronLast Cron running regularly
Source
  public function audit(Sandbox $sandbox) {

    try {
      $last = $sandbox->drush([
        'format' => 'json'
        ])->stateGet('system.cron_last');

      if (empty($last)) {
        return FALSE;
      }

      $sandbox->setParameter('cron_last', date('l jS \of F Y h:i:s A', $last));

      $time_diff = time() - $last;
      // Fail if cron hasn't run in the last 24 hours.
      if ($time_diff > 86400) {
        return FALSE;
      }
      return TRUE;
    }
    catch (DrushFormatException $e) {
      return Audit::ERROR;
    }
  }

DuplicateModules

Duplicate modules.

Class: Drutiny\Plugin\Drupal8\Audit\DuplicateModules
Extends: Drutiny\Audit
Package: drutiny/plugin-drupal-8

Policies

These are the policies that use this class:

Name Title
Drupal-8:DuplicateModules No duplicate modules found
Source
  public function audit(Sandbox $sandbox) {
    $config = $sandbox->drush(['format' => 'json'])
      ->status();

    $docroot = $config['root'];

    $command = <<<CMD
find $docroot -name '*.info.yml' -type f |\
grep -Ev '/themes/|/test' |\
grep -oe '[^/]*\.info.yml' | cut -d'.' -f1 | sort |\
uniq -c | sort -nr | awk '{print $2": "$1}'
CMD;

    $output = $sandbox->exec($command);

    if (empty($output)) {
      return TRUE;
    }

    // Ignore modules where there are only 1 of them.
    $module_count = array_filter(Yaml::parse($output), function ($count) {
      return $count > 1;
    });

    $sandbox->setParameter('duplicate_modules', array_keys($module_count));

    return count($module_count) == 0;
  }

ModuleDisabled

Generic module is disabled check.

Class: Drutiny\Plugin\Drupal8\Audit\ModuleDisabled
Extends: Drutiny\Audit
Package: drutiny/plugin-drupal-8

This class can remediate failed audits.

Policies

These are the policies that use this class:

Name Title
Drupal-8:acquiaCASDisabled CAS is not installed
Drupal-8:acquiaDevinciDisabled Devinci is not installed
Drupal-8:acquiaR4032LoginDisabled Redirect 403 to User Login is not installed
Drupal-8:acquiaHTMLPurifierDisabled HTML Purifier is not installed
Drupal-8:acquiaDropzoneJSDisabled Dropzone JS is not installed
Drupal-8:acquiaTCPDFDisabled TCPDF is not installed
Drupal-8:acquiaConfigMgmtDisabled Configuration Management is not installed
Drupal-8:acquiaCFPurgeDisabled CloudFlare Purge is not installed
Drupal-8:acquiaRadioactivityDisabled Radioactivity is not installed
Drupal-8:acquiaOptimizeDBDisabled Optimize DB is not installed
Drupal-8:acquiaShibAuthDisabled Shibboleth Authentication is not installed
Drupal-8:acquiaWURFLDisabled WURFL is not installed
Drupal-8:acquiaSerialDisabled Serial is not installed
Drupal-8:acquiaVarnishModuleDisabled Varnish Module is not installed
Drupal-8:acquiaBoostDisabled Boost is not installed
Drupal-8:acquiaSearch404Disabled Search 404 is not installed
Drupal-8:acquiaApacheSolrFileDisabled Apache Solr File is not installed
Drupal-8:acquiaCiviCRMDisabled CiviCRM is not installed
Drupal-8:acquiaAPCDisabled APC is not installed
Drupal-8:acquiaLinkCheckerDisabled Link Checker is not installed
Drupal-8:acquiaFilefieldSourcesDisabled Filefield Sources is not installed
Drupal-8:acquiaWorkbenchModerationDisabled Workbench Moderation is not installed
Drupal-8:acquiaNodeViewCountDisabled Node view count is not installed
Drupal-8:acquiaAutoSlaveDisabled AutoSlave is not installed
Drupal-8:acquiaDBMaintenanceDisabled DB Maintenance is not installed
Drupal-8:acquiaLDAPDisabled Lightweight Directory Access Protocol (LDAP) is not installed
Acquia:CloudEdgeNoPurge Acquia Cloud Edge Purging Enabled
Drupal-8:StatisticsDisabled Statistics module is not installed
Drupal-8:NoBackupAndMigrate Backup and Migrate is not installed
Drupal-8:roleMemoryLimitDisabled Role Memory Limit is not installed
Drupal-8:memcacheStorageDisabled Memcache Storage is not installed
Drupal-8:DevelDisabled Devel module is not installed
Drupal-8:tbMegaMenuDisabled TB Mega Menu is not installed
Drupal-8:ipGeolocDisabled IP Geolocation is not installed
Drupal-8:h5pDisabled H5P is not installed
Drupal-8:globalFilterDisabled Views Global Filter is not installed
Drupal-8:ViewsUIDisabled Views UI module is not installed
Drupal-8:recaptchaDisabled reCAPTCHA is not installed
Drupal-8:SimpleTestDisabled Simpletest module is not installed
Drupal-8:ConfigDevelDisabled Configuration development module is not installed
Drupal-8:sessionAPIDisabled Session API is not installed
Drupal-8:PhpDisabled PHP module is not installed
Drupal-8:smartIPDisabled Smart IP is not installed
Drupal-8:KintDisabled Kint module is not installed
Drupal-8:DblogDisabled Database logging is not installed
Drupal-8:fbconnectDisabled Facebook Connect is not installed
Drupal-8:textSizeDisabled Text Size is not installed
Drupal-8:fileCacheDisabled File Cache is not installed
Drupal-8:WebprofilerDisabled Webprofiler module is not installed
Drupal-8:supercookieDisabled Super Cookie is not installed
Drupal-8:ShieldDisabled Shield module is not installed
Drupal-8:pageCacheDisabled Page Cache module is not installed
Drupal-8:viewsFilterHarmonizerDisabled Views Filter Harmonizer is not installed
Drupal-8:blockcacheAlterDisabled Block Cache Alter is not installed
Drupal-8:UpdateDisabled Update module is not installed
Drupal-8:sessionCacheDisabled Session Cache API is not installed
Drupal-8:NoAutomatedCron Automated Cron module is not installed

Parameters

Name Type Description Default
module string The module to check is enabled. null

Tokens

Name Type Description Default
module string The module to check is enabled. null
Source
  public function audit(Sandbox $sandbox)
  {

    $module = $sandbox->getParameter('module');

    try {
      $info = $sandbox->drush(['format' => 'json'])->pmList();
    }
    catch (DrushFormatException $e) {
      return strpos($e->getOutput(), $module . ' was not found.') !== FALSE;
    }

    if (!isset($info[$module])) {
      return TRUE;
    }

    $status = strtolower($info[$module]['status']);

    return ($status != 'enabled');
  }

NoExperimentalCore

Generic module is disabled check.

Class: Drutiny\Plugin\Drupal8\Audit\NoExperimentalCore
Extends: Drutiny\Audit
Package: drutiny/plugin-drupal-8

Policies

These are the policies that use this class:

Name Title
Drupal-8:NoExperimental No Experimental Modules in Use
Source
  public function audit(Sandbox $sandbox)
  {

    $info = $sandbox->drush([
      'format' => 'json',
      'status' => 'Enabled',
      'core',
    ])->pmList();

    $info = array_filter($info, function ($package) {
      return strpos('experimental', strtolower($package['package'])) !== FALSE;
    });

    if (empty($info)) {
      return TRUE;
    }

    $sandbox->setParameter('modules', array_values($info));
    return FALSE;
  }

PurgePluginExists

Check a purge plugin exists.

Class: Drutiny\Plugin\Drupal8\Audit\PurgePluginExists
Extends: Drutiny\Audit
Package: drutiny/plugin-drupal-8

Policies

These are the policies that use this class:

Name Title
Acquia:PurgePlugin Acquia Purge Plugin Exists

Parameters

Name Type Description Default
plugin string The plugins to check exists null

Tokens

Name Type Description Default
plugin string The plugins to check exists null
Source
  public function audit(Sandbox $sandbox) {
    $plugin_name = $sandbox->getParameter('plugin');

    try {
      $config = $sandbox->drush([
        'format' => 'json',
        'include-overridden' => NULL,
        ])->configGet('purge.plugins');
      $plugins = $config['purgers'];

      foreach ($plugins as $plugin) {
        if ($plugin['plugin_id'] == $plugin_name) {
          return TRUE;
        }
      }
    }
    catch (\Drutiny\Driver\DrushFormatException $e) {
      $sandbox->setParameter('exception', $e->getMessage());
    }

    return FALSE;
  }

PurgePluginNotExists

Check a purge plugin exists.

Class: Drutiny\Plugin\Drupal8\Audit\PurgePluginNotExists
Extends: Drutiny\Plugin\Drupal8\Audit\PurgePluginExists
Package: drutiny/plugin-drupal-8

Source
  public function audit(Sandbox $sandbox) {
    return !parent::audit($sandbox);
  }

SettingCompare

Check a configuration is set correctly.

Class: Drutiny\Plugin\Drupal8\Audit\SettingCompare
Extends: Drutiny\Audit\AbstractComparison
Package: drutiny/plugin-drupal-8

Policies

These are the policies that use this class:

Name Title
Drupal-8:MemcachedExtension Memcache extension set
Drupal-8:DefaultCacheMemcache Memcache set as default cache backend

Parameters

Name Type Description Default
key string The settings key to evauate null
value string The value of the key you want to compare against. null
conditional_expression string The expression language to evaludate. See https://symfony.com/doc/current/components/expression_language/syntax.html 'true'

Tokens

Name Type Description Default
key string The settings key to evauate null
value string The value of the key you want to compare against. null
reading mixed The value retrieve from the key in the Drupal site. null
conditional_expression string The expression language to evaludate. See https://symfony.com/doc/current/components/expression_language/syntax.html 'true'
Source
  public function audit(Sandbox $sandbox) {
    $key = $sandbox->getParameter('key');
    $value = $sandbox->getParameter('value');

    $settings = $sandbox->drush()->evaluate(function () {
      return \Drupal\Core\Site\Settings::getAll();
    });

    if (!is_array($settings)){
      throw new \Exception("Settings retrieved were not in a known format. Expected Array.");
    }

    $keys = explode('.', $key);

    while ($k = array_shift($keys)) {
      if (!isset($settings[$k])) {
        $sandbox->logger()->info("Could not find '$k' value in $key. No such setting exists.");
        return FALSE;
      }
      $settings = $settings[$k];
    }

    $reading = $settings;

    $sandbox->setParameter('reading', $reading);

    return $this->compare($reading, $value, $sandbox);
  }

UntrustedRoles

User #1

Class: Drutiny\Plugin\Drupal8\Audit\UntrustedRoles
Extends: Drutiny\Audit
Package: drutiny/plugin-drupal-8

Policies

These are the policies that use this class:

Name Title
Drupal-8:UntrustedRoles Untrusted Roles with administrative permissions
Source
  public function audit(Sandbox $sandbox) {
    $rows = $sandbox->drush()->evaluate(function ($roles) {
      // Load all of Drupal's permissions so that we have access to the
      // "restrict access" property.
      $all_permissions = \Drupal::service('user.permissions')->getPermissions();

      $rows = [];
      foreach ($roles as $role) {
        $untrusted_permissions = [];

        // Get all permissions assigned to the untrusted role.
        $roleObj = \Drupal\user\Entity\Role::load($role);
        $permissions = $roleObj->getPermissions();

        // Check each permission assigned to the untrusted role and determine if
        // it is administrative.
        // Administrative permissions will either have the "restrict access"
        // property set, or the permission name contains the string "administer".
        foreach ($permissions as $permission) {
          if (isset($all_permissions[$permission]['restrict access']) ||
            strstr($permission, 'administer') !== FALSE ) {
              $untrusted_permissions[] = $all_permissions[$permission]['title'];
          }
        }

        if (!empty($untrusted_permissions)) {
          $rows[] = [
            'role' => $role,
            'permissions' => implode(', ', $untrusted_permissions),
          ];
        }
      }
      return $rows;
    }, [
      'roles' => $sandbox->getParameter('untrusted_roles', ['anonymous', 'authenticated'])
    ]);

    $sandbox->setParameter('rows', $rows);

    return empty($rows) ? AUDIT::SUCCESS : AUDIT::FAIL;
  }

UnusedModules

Cron last run.

Class: Drutiny\Plugin\Drupal8\Audit\UnusedModules
Extends: Drutiny\Audit
Package: drutiny/plugin-drupal-8

Policies

These are the policies that use this class:

Name Title
Drupal-8:UnusedModules Unused modules in the codebase
Source
  public function audit(Sandbox $sandbox) {

    try {
      $list = $sandbox->drush(['format' => 'json'])->pmInfo();
    }
    catch (DrushFormatException $e) {
      return FALSE;
    }

    $installed_paths = [];
    $disabled = [];
    foreach ($list as $project => $info) {

      if (strpos($info['package'], 'Core') !== FALSE) {
        continue;
      }
      if ($info['type'] == 'theme') {
        continue;
      }
      if ($info['status'] == 'enabled') {
        $installed_paths[] = $info['path'];
        continue;
      }
      $disabled[$project] = $info;
    }

    $unused = [];
    foreach ($disabled as $project => $info) {
      foreach ($installed_paths as $path) {
        if (strpos($info['path'], $path) !== FALSE) {
          continue 2;
        }
      }
      $unused[] = $info['title'];
    }

    $sandbox->setParameter('unused_modules', $unused);

    return !count($unused);
  }

User1

User #1

Class: Drutiny\Plugin\Drupal8\Audit\User1
Extends: Drutiny\Audit
Package: drutiny/plugin-drupal-8

This class can remediate failed audits.

Policies

These are the policies that use this class:

Name Title
Drupal-8:User1LockDown Administrator login is locked down (uid:1)

Parameters

Name Type Description Default
email The email the user account should be. null
blacklist List of usernames that are not acceptable. null
status Whether the account should be enabled or disabled. null

Tokens

Name Type Description Default
email The email the user account should be. null
blacklist List of usernames that are not acceptable. null
status Whether the account should be enabled or disabled. null
Source
  public function audit(Sandbox $sandbox) {
    // Get the details for user #1.
    $user = $sandbox->drush(['format' => 'json'])
                    ->userInformation(1);

    $user = (object) array_pop($user);

    $errors = [];
    $fixups = [];

    // Username.
    $pattern = $sandbox->getParameter('blacklist');
    if (preg_match("#${pattern}#i", $user->name)) {
      $errors[] = "Username '$user->name' is too easy to guess.";
    }
    $sandbox->setParameter('username', $user->name);

    // Email address.
    $email = $sandbox->getParameter('email');

    if (!empty($email) && ($email !== $user->mail)) {
      $errors[] = "Email address '$user->mail' is not set correctly.";
    }

    // Status.
    $status = (bool) $sandbox->getParameter('status');
    if ($status !== (bool) $user->status) {
      $errors[] = 'Status is not set correctly. Should be ' . ($user->status ? 'active' : 'inactive') . '.';
    }

    $sandbox->setParameter('errors', $errors);
    return empty($errors) ? TRUE : Audit::WARNING;
  }