Skip to content
Snippets Groups Projects
Commit 28113ca0 authored by Lucas Hedding's avatar Lucas Hedding Committed by Lucas Hedding
Browse files

Issue #3094445 by heddn, bdragon: Code scan findings

parent 0bb0cb3c
No related branches found
No related tags found
No related merge requests found
Showing
with 54 additions and 30 deletions
...@@ -31,7 +31,7 @@ function automatic_updates_requirements($phase) { ...@@ -31,7 +31,7 @@ function automatic_updates_requirements($phase) {
]; ];
} }
if ($phase !== 'runtime') { if ($phase !== 'runtime') {
return; return NULL;
} }
$requirements = []; $requirements = [];
......
...@@ -68,6 +68,13 @@ function automatic_updates_page_top(array &$page_top) { ...@@ -68,6 +68,13 @@ function automatic_updates_page_top(array &$page_top) {
* Implements hook_cron(). * Implements hook_cron().
*/ */
function automatic_updates_cron() { function automatic_updates_cron() {
$state = \Drupal::state();
$request_time = \Drupal::time()->getRequestTime();
$last_check = $state->get('automatic_updates.last_check', 0);
// Only allow cron to run once every hour.
if (($request_time - $last_check) < 3600) {
return;
}
// In-place updates won't function for dev releases of Drupal core. // In-place updates won't function for dev releases of Drupal core.
$dev_core = strpos(\Drupal::VERSION, '-dev') !== FALSE; $dev_core = strpos(\Drupal::VERSION, '-dev') !== FALSE;
/** @var \Drupal\Core\Config\ImmutableConfig $config */ /** @var \Drupal\Core\Config\ImmutableConfig $config */
...@@ -104,6 +111,7 @@ function automatic_updates_cron() { ...@@ -104,6 +111,7 @@ function automatic_updates_cron() {
foreach ($checker->getCategories() as $category) { foreach ($checker->getCategories() as $category) {
$checker->run($category); $checker->run($category);
} }
$state->set('automatic_updates.last_check', \Drupal::time()->getCurrentTime());
} }
/** /**
......
...@@ -56,8 +56,8 @@ services: ...@@ -56,8 +56,8 @@ services:
automatic_updates.readonly_checker: automatic_updates.readonly_checker:
class: Drupal\automatic_updates\ReadinessChecker\ReadOnlyFilesystem class: Drupal\automatic_updates\ReadinessChecker\ReadOnlyFilesystem
arguments: arguments:
- '@logger.channel.automatic_updates'
- '@app.root' - '@app.root'
- '@logger.channel.automatic_updates'
- '@file_system' - '@file_system'
tags: tags:
- { name: readiness_checker, priority: 100, category: error } - { name: readiness_checker, priority: 100, category: error }
......
...@@ -51,8 +51,9 @@ class ReadinessCheckerController extends ControllerBase { ...@@ -51,8 +51,9 @@ class ReadinessCheckerController extends ControllerBase {
public function run() { public function run() {
$messages = []; $messages = [];
foreach ($this->checker->getCategories() as $category) { foreach ($this->checker->getCategories() as $category) {
$messages = array_merge($this->checker->run($category), $messages); $messages[] = $this->checker->run($category);
} }
$messages = array_merge(...$messages);
if (empty($messages)) { if (empty($messages)) {
$this->messenger()->addStatus($this->t('No issues found. Your site is completely ready for <a href="@readiness_checks">automatic updates</a>.', ['@readiness_checks' => 'https://www.drupal.org/docs/8/update/automatic-updates#readiness-checks'])); $this->messenger()->addStatus($this->t('No issues found. Your site is completely ready for <a href="@readiness_checks">automatic updates</a>.', ['@readiness_checks' => 'https://www.drupal.org/docs/8/update/automatic-updates#readiness-checks']));
} }
......
...@@ -76,7 +76,7 @@ class SettingsForm extends ConfigFormBase { ...@@ -76,7 +76,7 @@ class SettingsForm extends ConfigFormBase {
$form['psa'] = [ $form['psa'] = [
'#type' => 'details', '#type' => 'details',
'#title' => $this->t('Public serivice announcements'), '#title' => $this->t('Public service announcements'),
'#open' => TRUE, '#open' => TRUE,
]; ];
$form['psa']['description'] = [ $form['psa']['description'] = [
......
...@@ -21,6 +21,7 @@ trait IgnoredPathsTrait { ...@@ -21,6 +21,7 @@ trait IgnoredPathsTrait {
if ($this->getPathMatcher()->matchPath($file_path, $paths)) { if ($this->getPathMatcher()->matchPath($file_path, $paths)) {
return TRUE; return TRUE;
} }
return FALSE;
} }
/** /**
......
...@@ -70,7 +70,7 @@ trait ProjectInfoTrait { ...@@ -70,7 +70,7 @@ trait ProjectInfoTrait {
return $info['version']; return $info['version'];
} }
// Handle experimental modules from core. // Handle experimental modules from core.
if (strpos($info['install path'], "core") === 0) { if (strpos($info['install path'], 'core') === 0) {
return $this->getExtensionList('module')->get('system')->info['version']; return $this->getExtensionList('module')->get('system')->info['version'];
} }
\Drupal::logger('automatic_updates')->error('Version cannot be located for @extension', ['@extension' => $extension_name]); \Drupal::logger('automatic_updates')->error('Version cannot be located for @extension', ['@extension' => $extension_name]);
...@@ -145,6 +145,7 @@ trait ProjectInfoTrait { ...@@ -145,6 +145,7 @@ trait ProjectInfoTrait {
catch (\Throwable $exception) { catch (\Throwable $exception) {
\Drupal::logger('automatic_updates')->error('Composer.json could not be located for @extension', ['@extension' => $extension_name]); \Drupal::logger('automatic_updates')->error('Composer.json could not be located for @extension', ['@extension' => $extension_name]);
} }
return NULL;
} }
} }
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
namespace Drupal\automatic_updates\ReadinessChecker; namespace Drupal\automatic_updates\ReadinessChecker;
use Drupal\Component\FileSystem\FileSystem as FileSystemComponent;
/** /**
* Disk space checker. * Disk space checker.
*/ */
...@@ -52,6 +54,13 @@ class DiskSpace extends Filesystem { ...@@ -52,6 +54,13 @@ class DiskSpace extends Filesystem {
'@space' => static::MINIMUM_DISK_SPACE / static::MEGABYTE_DIVISOR, '@space' => static::MINIMUM_DISK_SPACE / static::MEGABYTE_DIVISOR,
]); ]);
} }
$temp = FileSystemComponent::getOsTemporaryDirectory();
if (disk_free_space($temp) < static::MINIMUM_DISK_SPACE) {
$messages[] = $this->t('Directory "@temp" has insufficient space. There must be at least @space megabytes free.', [
'@temp' => $temp,
'@space' => static::MINIMUM_DISK_SPACE / static::MEGABYTE_DIVISOR,
]);
}
return $messages; return $messages;
} }
......
...@@ -65,9 +65,9 @@ class ModifiedFiles implements ReadinessCheckerInterface { ...@@ -65,9 +65,9 @@ class ModifiedFiles implements ReadinessCheckerInterface {
*/ */
public function __construct(ModifiedFilesInterface $modified_files, ExtensionList $modules, ExtensionList $profiles, ExtensionList $themes) { public function __construct(ModifiedFilesInterface $modified_files, ExtensionList $modules, ExtensionList $profiles, ExtensionList $themes) {
$this->modifiedFiles = $modified_files; $this->modifiedFiles = $modified_files;
$this->modules = $modules; $this->module = $modules;
$this->profiles = $profiles; $this->profile = $profiles;
$this->themes = $themes; $this->theme = $themes;
} }
/** /**
......
...@@ -29,16 +29,16 @@ class ReadOnlyFilesystem extends Filesystem { ...@@ -29,16 +29,16 @@ class ReadOnlyFilesystem extends Filesystem {
/** /**
* ReadOnlyFilesystem constructor. * ReadOnlyFilesystem constructor.
* *
* @param \Psr\Log\LoggerInterface $logger
* The logger.
* @param string $app_root * @param string $app_root
* The app root. * The app root.
* @param \Psr\Log\LoggerInterface $logger
* The logger.
* @param \Drupal\Core\File\FileSystemInterface $file_system * @param \Drupal\Core\File\FileSystemInterface $file_system
* The file system service. * The file system service.
*/ */
public function __construct(LoggerInterface $logger, $app_root, FileSystemInterface $file_system) { public function __construct($app_root, LoggerInterface $logger, FileSystemInterface $file_system) {
parent::__construct($app_root);
$this->logger = $logger; $this->logger = $logger;
$this->rootPath = (string) $app_root;
$this->fileSystem = $file_system; $this->fileSystem = $file_system;
} }
......
...@@ -135,8 +135,8 @@ class AutomaticUpdatesPsa implements AutomaticUpdatesPsaInterface { ...@@ -135,8 +135,8 @@ class AutomaticUpdatesPsa implements AutomaticUpdatesPsaInterface {
} }
try { try {
$json_payload = json_decode($response); $json_payload = json_decode($response, FALSE);
if (!is_null($json_payload)) { if ($json_payload !== NULL) {
foreach ($json_payload as $json) { foreach ($json_payload as $json) {
if ($json->is_psa && ($json->type === 'core' || $this->isValidExtension($json->type, $json->project))) { if ($json->is_psa && ($json->type === 'core' || $this->isValidExtension($json->type, $json->project))) {
$messages[] = $this->message($json->title, $json->link); $messages[] = $this->message($json->title, $json->link);
...@@ -192,15 +192,15 @@ class AutomaticUpdatesPsa implements AutomaticUpdatesPsaInterface { ...@@ -192,15 +192,15 @@ class AutomaticUpdatesPsa implements AutomaticUpdatesPsaInterface {
*/ */
protected function contribParser(array &$messages, $json) { protected function contribParser(array &$messages, $json) {
$extension_version = $this->{$json->type}->getAllAvailableInfo()[$json->project]['version']; $extension_version = $this->{$json->type}->getAllAvailableInfo()[$json->project]['version'];
$json->insecure = array_filter(array_map(function ($version) { $json->insecure = array_filter(array_map(static function ($version) {
$version_array = explode('-', $version, 2); $version_array = explode('-', $version, 2);
if ($version_array && $version_array[0] === \Drupal::CORE_COMPATIBILITY) { if ($version_array && $version_array[0] === \Drupal::CORE_COMPATIBILITY) {
return isset($version_array[1]) ? $version_array[1] : NULL; return isset($version_array[1]) ? $version_array[1] : NULL;
} }
elseif (count($version_array) === 1) { if (count($version_array) === 1) {
return $version_array[0]; return $version_array[0];
} }
elseif (count($version_array) === 2 && $version_array[1] === 'dev') { if (count($version_array) === 2 && $version_array[1] === 'dev') {
return $version; return $version;
} }
}, $json->insecure)); }, $json->insecure));
......
...@@ -120,7 +120,7 @@ class InPlaceUpdate implements UpdateInterface { ...@@ -120,7 +120,7 @@ class InPlaceUpdate implements UpdateInterface {
$this->fileSystem = $file_system; $this->fileSystem = $file_system;
$this->httpClient = $http_client; $this->httpClient = $http_client;
$this->rootPath = (string) $app_root; $this->rootPath = (string) $app_root;
$this->vendorPath = $this->rootPath . DIRECTORY_SEPARATOR . 'vendor'; $this->vendorPath = $this->rootPath . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR;
$project_root = drupal_get_path('module', 'automatic_updates'); $project_root = drupal_get_path('module', 'automatic_updates');
require_once $project_root . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php'; require_once $project_root . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
} }
...@@ -173,7 +173,7 @@ class InPlaceUpdate implements UpdateInterface { ...@@ -173,7 +173,7 @@ class InPlaceUpdate implements UpdateInterface {
protected function getArchive($project_name, $from_version, $to_version) { protected function getArchive($project_name, $from_version, $to_version) {
$quasi_patch = $this->getQuasiPatchFileName($project_name, $from_version, $to_version); $quasi_patch = $this->getQuasiPatchFileName($project_name, $from_version, $to_version);
$url = $this->buildUrl($project_name, $quasi_patch); $url = $this->buildUrl($project_name, $quasi_patch);
$temp_directory = $this->getTempDirectory(); $temp_directory = FileSystem::getOsTemporaryDirectory() . DIRECTORY_SEPARATOR;
$destination = $this->fileSystem->getDestinationFilename($temp_directory . $quasi_patch, FileSystemInterface::EXISTS_REPLACE); $destination = $this->fileSystem->getDestinationFilename($temp_directory . $quasi_patch, FileSystemInterface::EXISTS_REPLACE);
$this->doGetResource($url, $destination); $this->doGetResource($url, $destination);
$csig_file = $quasi_patch . '.csig'; $csig_file = $quasi_patch . '.csig';
...@@ -226,6 +226,7 @@ class InPlaceUpdate implements UpdateInterface { ...@@ -226,6 +226,7 @@ class InPlaceUpdate implements UpdateInterface {
} }
$this->stripFileDirectoryPath($archive_file); $this->stripFileDirectoryPath($archive_file);
} }
unset($archive_file);
if ($intersection = array_intersect($files, $archive_files)) { if ($intersection = array_intersect($files, $archive_files)) {
$this->logger->error('Can not update because %count files are modified: %paths', [ $this->logger->error('Can not update because %count files are modified: %paths', [
'%count' => count($intersection), '%count' => count($intersection),
...@@ -524,7 +525,7 @@ class InPlaceUpdate implements UpdateInterface { ...@@ -524,7 +525,7 @@ class InPlaceUpdate implements UpdateInterface {
* The real path of a file. * The real path of a file.
*/ */
protected function getProjectRealPath($file_path, $project_root) { protected function getProjectRealPath($file_path, $project_root) {
if (substr($file_path, 0, 6) === 'vendor/') { if (strpos($file_path, 'vendor' . DIRECTORY_SEPARATOR) === 0) {
return $this->vendorPath . substr($file_path, 7); return $this->vendorPath . substr($file_path, 7);
} }
return rtrim($project_root, '/\\') . DIRECTORY_SEPARATOR . $file_path; return rtrim($project_root, '/\\') . DIRECTORY_SEPARATOR . $file_path;
...@@ -569,7 +570,7 @@ class InPlaceUpdate implements UpdateInterface { ...@@ -569,7 +570,7 @@ class InPlaceUpdate implements UpdateInterface {
} }
/** /**
* Clear opcode cache on successful update. * Clear Opcode cache on successful update.
*/ */
protected function clearOpcodeCache() { protected function clearOpcodeCache() {
if (function_exists('opcache_reset')) { if (function_exists('opcache_reset')) {
......
...@@ -150,6 +150,9 @@ class Notify implements NotifyInterface { ...@@ -150,6 +150,9 @@ class Notify implements NotifyInterface {
* The email address where the message will be sent. * The email address where the message will be sent.
* @param array $params * @param array $params
* Parameters to build the email. * Parameters to build the email.
*
* @throws \Drupal\Component\Plugin\Exception\InvalidPluginDefinitionException
* @throws \Drupal\Component\Plugin\Exception\PluginNotFoundException
*/ */
protected function doSend($to, array $params) { protected function doSend($to, array $params) {
$users = $this->entityTypeManager->getStorage('user') $users = $this->entityTypeManager->getStorage('user')
......
...@@ -56,14 +56,14 @@ class ModifiedFilesController extends ControllerBase { ...@@ -56,14 +56,14 @@ class ModifiedFilesController extends ControllerBase {
// Special edge case for core. // Special edge case for core.
if ($project_type === 'core') { if ($project_type === 'core') {
$infos = $this->getInfos('module'); $infos = $this->getInfos('module');
$extensions = array_filter($infos, function (array $info) { $extensions = array_filter($infos, static function (array $info) {
return $info['project'] === 'drupal'; return $info['project'] === 'drupal';
}); });
} }
// Filter for the main project. // Filter for the main project.
else { else {
$infos = $this->getInfos($project_type); $infos = $this->getInfos($project_type);
$extensions = array_filter($infos, function (array $info) use ($extension, $project_type) { $extensions = array_filter($infos, static function (array $info) use ($extension, $project_type) {
return $info['install path'] === "{$project_type}s/contrib/$extension"; return $info['install path'] === "{$project_type}s/contrib/$extension";
}); });
} }
......
...@@ -258,7 +258,7 @@ class InPlaceUpdateTest extends QuickStartTestBase { ...@@ -258,7 +258,7 @@ class InPlaceUpdateTest extends QuickStartTestBase {
$this->deletions = []; $this->deletions = [];
$http_client = new Client(); $http_client = new Client();
$filesystem = new SymfonyFilesystem(); $filesystem = new SymfonyFilesystem();
$this->deletionsDestination = DrupalFileSystem::getOsTemporaryDirectory() . DIRECTORY_SEPARATOR . "$project-" . rand(10000, 99999) . microtime(TRUE); $this->deletionsDestination = DrupalFileSystem::getOsTemporaryDirectory() . DIRECTORY_SEPARATOR . "$project-" . mt_rand(10000, 99999) . microtime(TRUE);
$filesystem->mkdir($this->deletionsDestination); $filesystem->mkdir($this->deletionsDestination);
$file_name = "$project-$from_version-to-$to_version.zip"; $file_name = "$project-$from_version-to-$to_version.zip";
$zip_file = $this->deletionsDestination . DIRECTORY_SEPARATOR . $file_name; $zip_file = $this->deletionsDestination . DIRECTORY_SEPARATOR . $file_name;
......
...@@ -39,7 +39,7 @@ class CronFrequencyTest extends KernelTestBase { ...@@ -39,7 +39,7 @@ class CronFrequencyTest extends KernelTestBase {
->set('interval', 21600) ->set('interval', 21600)
->save(); ->save();
$messages = $this->container->get('automatic_updates.cron_frequency')->run(); $messages = $this->container->get('automatic_updates.cron_frequency')->run();
$this->assertEquals('Cron is not set to run frequently enough. <a href="/admin/config/system/cron">Configure it</a> to run at least every 3 hours or disable automated cron and run it via an external scheduling system.', $messages[0]); self::assertEquals('Cron is not set to run frequently enough. <a href="/admin/config/system/cron">Configure it</a> to run at least every 3 hours or disable automated cron and run it via an external scheduling system.', $messages[0]);
} }
} }
...@@ -33,12 +33,12 @@ class DiskSpaceTest extends KernelTestBase { ...@@ -33,12 +33,12 @@ class DiskSpaceTest extends KernelTestBase {
// Out of space. // Out of space.
$disk_space = new TestDiskSpace($this->container->get('app.root')); $disk_space = new TestDiskSpace($this->container->get('app.root'));
$messages = $disk_space->run(); $messages = $disk_space->run();
$this->assertCount(1, $messages); $this->assertCount(2, $messages);
// Out of space not the same logical disk. // Out of space not the same logical disk.
$disk_space = new TestDiskSpaceNonSameDisk($this->container->get('app.root')); $disk_space = new TestDiskSpaceNonSameDisk($this->container->get('app.root'));
$messages = $disk_space->run(); $messages = $disk_space->run();
$this->assertCount(2, $messages); $this->assertCount(3, $messages);
} }
} }
......
...@@ -28,7 +28,7 @@ class OpcodeCacheTest extends KernelTestBase { ...@@ -28,7 +28,7 @@ class OpcodeCacheTest extends KernelTestBase {
$messages = $this->container->get('automatic_updates.opcode_cache')->run(); $messages = $this->container->get('automatic_updates.opcode_cache')->run();
if ($failure) { if ($failure) {
$this->assertNotEmpty($messages); $this->assertNotEmpty($messages);
$this->assertEquals((string) $messages[0], 'Automatic updates cannot run via CLI when opcode file cache is enabled.'); self::assertEquals((string) $messages[0], 'Automatic updates cannot run via CLI when opcode file cache is enabled.');
} }
else { else {
$this->assertEmpty($messages); $this->assertEmpty($messages);
......
...@@ -27,7 +27,7 @@ class PendingDbUpdatesTest extends KernelTestBase { ...@@ -27,7 +27,7 @@ class PendingDbUpdatesTest extends KernelTestBase {
$this->assertEmpty($messages); $this->assertEmpty($messages);
$messages = (new TestPendingDbUpdates())->run(); $messages = (new TestPendingDbUpdates())->run();
$this->assertEquals('There are pending database updates, therefore updates cannot be applied. Please run update.php.', $messages[0]); self::assertEquals('There are pending database updates, therefore updates cannot be applied. Please run update.php.', $messages[0]);
} }
} }
......
...@@ -29,7 +29,7 @@ class PhpSapiTest extends KernelTestBase { ...@@ -29,7 +29,7 @@ class PhpSapiTest extends KernelTestBase {
$this->container->get('state')->set('automatic_updates.php_sapi', 'foo'); $this->container->get('state')->set('automatic_updates.php_sapi', 'foo');
$messages = $this->container->get('automatic_updates.php_sapi')->run(); $messages = $this->container->get('automatic_updates.php_sapi')->run();
$this->assertEquals('PHP changed from running as "foo" to "cli". This can lead to inconsistent and misleading results.', $messages[0]); self::assertEquals('PHP changed from running as "foo" to "cli". This can lead to inconsistent and misleading results.', $messages[0]);
} }
} }
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment