function ComposerPluginsValidator::validate
Validates the allowed Composer plugins, both in active and stage.
File
-
core/
modules/ package_manager/ src/ Validator/ ComposerPluginsValidator.php, line 131
Class
- ComposerPluginsValidator
- Validates the allowed Composer plugins, both in active and stage.
Namespace
Drupal\package_manager\ValidatorCode
public function validate(PreOperationStageEvent $event) : void {
$stage = $event->stage;
// When about to copy the changes from the stage directory to the active
// directory, use the stage directory's composer instead of the active.
// Because composer plugins may be added or removed; the only thing that
// matters is the set of composer plugins that *will* apply — if a composer
// plugin is being removed, that's fine.
$dir = $event instanceof PreApplyEvent ? $stage->getStageDirectory() : $this->pathLocator
->getProjectRoot();
try {
$allowed_plugins = $this->inspector
->getAllowPluginsConfig($dir);
} catch (RuntimeException $exception) {
$event->addErrorFromThrowable($exception, $this->t('Unable to determine Composer <code>allow-plugins</code> setting.'));
return;
}
if ($allowed_plugins === TRUE) {
$event->addError([
$this->t('All composer plugins are allowed because <code>config.allow-plugins</code> is configured to <code>true</code>. This is an unacceptable security risk.'),
]);
return;
}
// TRICKY: additional trusted Composer plugins is listed first, to allow
// site owners who know what they're doing to use unsupported versions of
// supported Composer plugins.
$trusted_plugins = $this->additionalTrustedComposerPlugins + self::SUPPORTED_PLUGINS_THAT_DO_MODIFY + self::SUPPORTED_PLUGINS_THAT_DO_NOT_MODIFY;
assert(is_array($allowed_plugins));
// Only packages with `true` as a value are actually executed by Composer.
$allowed_plugins = array_keys(array_filter($allowed_plugins));
// The keys are normalized package names, and the values are the original,
// non-normalized package names.
$allowed_plugins = array_combine(array_map([
__CLASS__,
'normalizePackageName',
], $allowed_plugins), $allowed_plugins);
$installed_packages = $this->inspector
->getInstalledPackagesList($dir);
// Determine which plugins are both trusted by us, AND allowed by Composer's
// configuration.
$supported_plugins = array_intersect_key($allowed_plugins, $trusted_plugins);
// Create an array whose keys are the names of those plugins, and the values
// are their installed versions.
$supported_plugins_installed_versions = array_combine($supported_plugins, array_map(fn(string $name): ?string => $installed_packages[$name]?->version, $supported_plugins));
// Find the plugins whose installed versions aren't in the supported range.
$unsupported_installed_versions = array_filter($supported_plugins_installed_versions, fn(?string $version, string $name): bool => $version && !Semver::satisfies($version, $trusted_plugins[$name]), ARRAY_FILTER_USE_BOTH);
$untrusted_plugins = array_diff_key($allowed_plugins, $trusted_plugins);
$messages = array_map(fn(string $raw_name) => $this->t('<code>@name</code>', [
'@name' => $raw_name,
]), $untrusted_plugins);
foreach ($unsupported_installed_versions as $name => $installed_version) {
$messages[] = $this->t("<code>@name</code> is supported, but only version <code>@supported_version</code>, found <code>@installed_version</code>.", [
'@name' => $name,
'@supported_version' => $trusted_plugins[$name],
'@installed_version' => $installed_version,
]);
}
if ($messages) {
$summary = $this->formatPlural(count($messages), 'An unsupported Composer plugin was detected.', 'Unsupported Composer plugins were detected.');
$event->addError($messages, $summary);
}
}
Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.