Commit 406a607a authored by Adam G-H's avatar Adam G-H
Browse files

Issue #3253647 by phenaproxima, tedbow: Validate some Composer settings

parent 3f3e11c9
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -48,6 +48,12 @@ services:
      - '@package_manager.validator.composer_executable'
    tags:
      - { name: event_subscriber }
  automatic_updates.validator.composer_settings:
    class: Drupal\automatic_updates\Validator\PackageManagerReadinessCheck
    arguments:
      - '@package_manager.validator.composer_settings'
    tags:
      - { name: event_subscriber }
  automatic_updates.disk_space_validator:
    class: Drupal\automatic_updates\Validator\PackageManagerReadinessCheck
    arguments:
+6 −0
Original line number Diff line number Diff line
@@ -118,6 +118,12 @@ services:
      - '@string_translation'
    tags:
      - { name: event_subscriber }
  package_manager.validator.composer_settings:
    class: Drupal\package_manager\EventSubscriber\ComposerSettingsValidator
    arguments:
      - '@string_translation'
    tags:
      - { name: event_subscriber }
  package_manager.excluded_paths_subscriber:
    class: Drupal\package_manager\EventSubscriber\ExcludedPathsSubscriber
    arguments:
+10 −0
Original line number Diff line number Diff line
@@ -37,6 +37,16 @@ class ComposerUtility {
    $this->composer = $composer;
  }

  /**
   * Returns the underlying Composer instance.
   *
   * @return \Composer\Composer
   *   The Composer instance.
   */
  public function getComposer(): Composer {
    return $this->composer;
  }

  /**
   * Creates a utility object using the files in a given directory.
   *
+54 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\package_manager\EventSubscriber;

use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\Core\StringTranslation\TranslationInterface;
use Drupal\package_manager\Event\PreCreateEvent;
use Drupal\package_manager\Event\PreOperationStageEvent;

/**
 * Validates certain Composer settings.
 */
class ComposerSettingsValidator implements PreOperationStageValidatorInterface {

  use StringTranslationTrait;

  /**
   * Constructs a ComposerSettingsValidator object.
   *
   * @param \Drupal\Core\StringTranslation\TranslationInterface $translation
   *   The string translation service.
   */
  public function __construct(TranslationInterface $translation) {
    $this->setStringTranslation($translation);
  }

  /**
   * {@inheritdoc}
   */
  public function validateStagePreOperation(PreOperationStageEvent $event): void {
    $config = $event->getStage()
      ->getActiveComposer()
      ->getComposer()
      ->getConfig();

    if ($config->get('secure-http') !== TRUE) {
      $event->addError([
        $this->t('HTTPS must be enabled for Composer downloads. See <a href=":url">the Composer documentation</a> for more information.', [
          ':url' => 'https://getcomposer.org/doc/06-config.md#secure-http',
        ]),
      ]);
    }
  }

  /**
   * {@inheritdoc}
   */
  public static function getSubscribedEvents() {
    return [
      PreCreateEvent::class => 'validateStagePreOperation',
    ];
  }

}
+100 −0
Original line number Diff line number Diff line
<?php

namespace Drupal\Tests\package_manager\Kernel;

use Drupal\Component\Serialization\Json;
use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\package_manager\Exception\StageValidationException;
use Drupal\package_manager\PathLocator;
use Drupal\package_manager\ValidationResult;
use org\bovigo\vfs\vfsStream;

/**
 * @covers \Drupal\package_manager\EventSubscriber\ComposerSettingsValidator
 *
 * @group package_manager
 */
class ComposerSettingsValidatorTest extends PackageManagerKernelTestBase {

  /**
   * {@inheritdoc}
   */
  protected function disableValidators(ContainerBuilder $container): void {
    parent::disableValidators($container);

    // Disable the disk space validator, since it tries to inspect the file
    // system in ways that vfsStream doesn't support, like calling stat() and
    // disk_free_space().
    $container->removeDefinition('package_manager.validator.disk_space');

    // Disable the lock file validator, since the mock file system we create in
    // this test doesn't have any lock files to validate.
    $container->removeDefinition('package_manager.validator.lock_file');
  }

  /**
   * Data provider for ::testSecureHttpValidation().
   *
   * @return array[]
   *   Sets of arguments to pass to the test method.
   */
  public function providerSecureHttpValidation(): array {
    $error = ValidationResult::createError([
      'HTTPS must be enabled for Composer downloads. See <a href="https://getcomposer.org/doc/06-config.md#secure-http">the Composer documentation</a> for more information.',
    ]);

    return [
      'disabled' => [
        Json::encode([
          'config' => [
            'secure-http' => FALSE,
          ],
        ]),
        [$error],
      ],
      'explicitly enabled' => [
        Json::encode([
          'config' => [
            'secure-http' => TRUE,
          ],
        ]),
        [],
      ],
      'implicitly enabled' => [
        '{}',
        [],
      ],
    ];
  }

  /**
   * Tests that Composer's secure-http setting is validated.
   *
   * @param string $contents
   *   The contents of the composer.json file.
   * @param \Drupal\package_manager\ValidationResult[] $expected_results
   *   The expected validation results, if any.
   *
   * @dataProvider providerSecureHttpValidation
   */
  public function testSecureHttpValidation(string $contents, array $expected_results): void {
    $file = vfsStream::newFile('composer.json')->setContent($contents);
    $this->vfsRoot->addChild($file);

    $active_dir = $this->vfsRoot->url();
    $locator = $this->prophesize(PathLocator::class);
    $locator->getActiveDirectory()->willReturn($active_dir);
    $locator->getProjectRoot()->willReturn($active_dir);
    $locator->getVendorDirectory()->willReturn($active_dir);
    $this->container->set('package_manager.path_locator', $locator->reveal());

    try {
      $this->createStage()->create();
      $this->assertSame([], $expected_results);
    }
    catch (StageValidationException $e) {
      $this->assertValidationResultsEqual($expected_results, $e->getResults());
    }
  }

}
Loading