diff --git a/README.md b/README.md index 1083710..dd612d7 100644 --- a/README.md +++ b/README.md @@ -36,65 +36,44 @@ composer require yokai/safe-command-bundle return [ // ... - Yokai\SafeCommandBundle\YokaiSafeCommandBundle::class => ['all' => true], + Yokai\SafeCommandBundle\YokaiSafeCommandBundle::class => ['prod' => true], ]; ``` +> [!NOTE] +> The bundle is enabled only for `prod` here, but you are free to do whatever you want. + ### Configuration +The bundle comes with some commands disabled by default (from Symfony's standards). + +That "standard" command list can be overridden: +``` +# config/packages/yokai_safe_command.yaml +when@prod: + yokai_safe_command: + standard: [] +``` + +> [!NOTE] +> "standard" disabled commands are viewable via the command: +> ``` +> bin/console config:dump-reference yokai_safe_command +> ``` + +And you can also add your own commands to the list: ``` # config/packages/yokai_safe_command.yaml -yokai_safe_command: - enabled: true - commands: - enabled: true - config: - enabled: true - commands: - - 'config:dump-reference' - doctrine: - enabled: true - commands: - - 'doctrine:database:drop' - - 'doctrine:mapping:convert' - - 'doctrine:mapping:import' - - 'doctrine:schema:drop' - - 'doctrine:schema:validate' - debug: - enabled: true - commands: - - 'debug:config' - - 'debug:container' - - 'debug:event-dispatcher' - - 'debug:router' - - 'debug:swiftmailer' - - 'debug:translation' - - 'debug:twig' - lint: - enabled: true - commands: - - 'lint:twig' - - 'lint:yaml' - server: - enabled: true - commands: - - 'server:run' - - 'server:start' - - 'server:status' - - 'server:stop' - translation: - enabled: true - commands: - - 'translation:update' - misc: - enabled: true - commands: { } - environments: - enabled: false - environments: - - prod +when@prod: + yokai_safe_command: + custom: + - 'vendor:my:dev-command' + - 'app:my:dev-command' ``` +> [!NOTE] +> `standard` and `custom` configs are merged together to create the final list of disabled commands. + ## License diff --git a/config/services.xml b/config/services.xml index 996d771..b3a60b2 100644 --- a/config/services.xml +++ b/config/services.xml @@ -12,12 +12,6 @@ - - %yokai_safe_command.disabled_commands% - - - diff --git a/src/DependencyInjection/Configuration.php b/src/DependencyInjection/Configuration.php index 6a678d1..e98e091 100644 --- a/src/DependencyInjection/Configuration.php +++ b/src/DependencyInjection/Configuration.php @@ -19,23 +19,46 @@ public function getConfigTreeBuilder(): TreeBuilder $root = $tree->getRootNode(); $root - ->canBeDisabled() ->addDefaultsIfNotSet() ->children() - ->arrayNode('commands') - ->canBeDisabled() - ->addDefaultsIfNotSet() - ->children() - ->append($this->createCommandsNode('config')) - ->append($this->createCommandsNode('doctrine')) - ->append($this->createCommandsNode('debug')) - ->append($this->createCommandsNode('lint')) - ->append($this->createCommandsNode('server')) - ->append($this->createCommandsNode('translation')) - ->append($this->createCommandsNode('misc')) - ->end() + ->arrayNode('standard') + ->defaultValue([ + 'config:dump-reference', + 'doctrine:database:drop', + 'doctrine:mapping:convert', + 'doctrine:mapping:import', + 'doctrine:schema:drop', + 'doctrine:schema:validate', + 'debug:autowiring', + 'debug:config', + 'debug:container', + 'debug:dotenv', + 'debug:event-dispatcher', + 'debug:firewall', + 'debug:form', + 'debug:router', + 'debug:serializer', + 'debug:translation', + 'debug:twig', + 'debug:validator', + 'lint:container', + 'lint:twig', + 'lint:xliff', + 'lint:yaml', + 'server:dump', + 'server:log', + 'translation:extract', + 'translation:pull', + 'translation:push', + ]) + ->useAttributeAsKey('name') + ->prototype('scalar')->end() + ->end() + ->arrayNode('custom') + ->defaultValue([]) + ->useAttributeAsKey('name') + ->prototype('scalar')->end() ->end() - ->append($this->createEnvironmentsNode()) ->end() ; diff --git a/src/DependencyInjection/YokaiSafeCommandExtension.php b/src/DependencyInjection/YokaiSafeCommandExtension.php index 750fbbd..ad8ab28 100644 --- a/src/DependencyInjection/YokaiSafeCommandExtension.php +++ b/src/DependencyInjection/YokaiSafeCommandExtension.php @@ -19,62 +19,13 @@ public function load(array $configs, ContainerBuilder $container): void $configuration = $this->getConfiguration($configs, $container); $config = $this->processConfiguration($configuration, $configs); - if (!$config['enabled']) { - return; - } - $loader = new Loader\XmlFileLoader($container, new FileLocator(__DIR__ . '/../../config')); $loader->load('services.xml'); - $this->defineDisabledCommands($config['commands'], $container); - $this->defineAllowedEnvironments($config['environments'], $container); - } - - private function defineDisabledCommands(array $config, ContainerBuilder $container): void - { - if (!$config['enabled']) { - $container->removeDefinition( - 'yokai_safe_command.event_listener.prevent_disabled_command_from_being_used_listener' - ); - - return; - } - - // collect commands over config sections - $commands = []; - foreach ($config as $value) { - if (!\is_array($value)) { - continue; - } - if (!isset($value['enabled']) || !$value['enabled']) { - continue; - } - if (!isset($value['commands'])) { - continue; - } - - $commands = array_merge($commands, $value['commands']); - } - - // format commands - $commands = array_unique($commands); - sort($commands); - - // set disabled commands parameter + $commands = array_unique([ + ...$config['standard'], + ...$config['custom'], + ]); $container->setParameter('yokai_safe_command.disabled_commands', $commands); } - - private function defineAllowedEnvironments(array $config, ContainerBuilder $container): void - { - if (!$config['enabled']) { - $container->removeDefinition( - 'yokai_safe_command.event_listener.prevent_command_from_being_used_with_disabled_environment_listener' - ); - - return; - } - - // set allowed environments parameter - $container->setParameter('yokai_safe_command.allowed_environments', $config['environments']); - } } diff --git a/src/EventListener/PreventCommandFromBeingUsedWithDisabledEnvironmentListener.php b/src/EventListener/PreventCommandFromBeingUsedWithDisabledEnvironmentListener.php deleted file mode 100644 index e2d7746..0000000 --- a/src/EventListener/PreventCommandFromBeingUsedWithDisabledEnvironmentListener.php +++ /dev/null @@ -1,50 +0,0 @@ - - */ - private array $environments, - ) { - } - - public static function getSubscribedEvents(): array - { - return [ - ConsoleEvents::COMMAND => '__invoke', - ]; - } - - public function __invoke(ConsoleCommandEvent $event): void - { - // if there is no "env" option (this should never happen) - if (!$event->getInput()->hasOption('env')) { - return; - } - - $environment = $event->getInput()->getOption('env'); - $output = $event->getOutput(); - - // if the environment is not one of allowed - if (!\in_array($environment, $this->environments, true)) { - // disable command - $event->disableCommand(); - $output->writeln( - sprintf( - 'Running command with "%s" environment is not allowed. Aborting...', - $environment - ) - ); - } - } -} diff --git a/tests/CommandDisabledTest.php b/tests/CommandDisabledTest.php index 8e84b55..d799ba6 100644 --- a/tests/CommandDisabledTest.php +++ b/tests/CommandDisabledTest.php @@ -4,9 +4,11 @@ namespace Yokai\SafeCommandBundle\Tests; +use Symfony\Component\Console\Command\Command; use Symfony\Component\Console\Event\ConsoleCommandEvent; use Symfony\Component\Console\Input\StringInput; use Symfony\Component\Console\Output\BufferedOutput; +use Symfony\Component\Console\Output\NullOutput; final class CommandDisabledTest extends CommandTestCase { @@ -19,6 +21,8 @@ public function disabled_command_should_not_appear_in_list_command_output(): voi $out = $output->fetch(); + self::assertMatchesRegularExpression('/cache:clear/', $out, 'Some commands are still viewable.'); + foreach (self::commands() as [$command]) { self::assertDoesNotMatchRegularExpression( '/' . $command . '/', @@ -51,6 +55,18 @@ public function disabled_command_should_not_run(string $command): void ); } + /** + * @test + */ + public function enabled_command_should_run(): void + { + $application = self::createApplication(); + + $exit = $application->run(new StringInput('cache:clear'), new NullOutput()); + + self::assertSame(Command::SUCCESS, $exit, 'Some commands are still runnable'); + } + public static function commands(): \Generator { yield ['debug:container']; diff --git a/tests/EnvironmentAllowedTest.php b/tests/EnvironmentAllowedTest.php deleted file mode 100644 index 4c43560..0000000 --- a/tests/EnvironmentAllowedTest.php +++ /dev/null @@ -1,34 +0,0 @@ -run(new StringInput('list --env=prod'), $output = new BufferedOutput()); - - self::assertSame( - ConsoleCommandEvent::RETURN_CODE_DISABLED, - $exit, - 'Running command in disallowed environment return disabled return code.' - ); - - self::assertMatchesRegularExpression( - '/Running command with "prod" environment is not allowed. Aborting.../', - $output->fetch(), - 'Running command with disallowed environment should output message to tell it wont run.' - ); - } -} diff --git a/tests/Stubs/YokaiSafeCommandTestKernel.php b/tests/Stubs/YokaiSafeCommandTestKernel.php index c0a5cb3..e2c0ecc 100644 --- a/tests/Stubs/YokaiSafeCommandTestKernel.php +++ b/tests/Stubs/YokaiSafeCommandTestKernel.php @@ -5,12 +5,15 @@ namespace Yokai\SafeCommandBundle\Tests\Stubs; use Psr\Log\NullLogger; -use Symfony\Component\Config\Loader\LoaderInterface; +use Symfony\Bundle\FrameworkBundle\Kernel\MicroKernelTrait; use Symfony\Component\DependencyInjection\ContainerBuilder; +use Symfony\Component\DependencyInjection\Loader\Configurator\ContainerConfigurator; use Symfony\Component\HttpKernel\Kernel; final class YokaiSafeCommandTestKernel extends Kernel { + use MicroKernelTrait; + public function registerBundles(): array { return [ @@ -19,14 +22,17 @@ public function registerBundles(): array ]; } - protected function build(ContainerBuilder $container): void + protected function configureContainer(ContainerConfigurator $container): void { - $container->set('logger', new NullLogger()); + $container->extension('framework', [ + 'secret' => 'ThisIsNotSecret', + 'test' => true, + ]); } - public function registerContainerConfiguration(LoaderInterface $loader): void + protected function build(ContainerBuilder $container): void { - $loader->load(__DIR__ . '/config.yml'); + $container->set('logger', new NullLogger()); } public function getCacheDir(): string diff --git a/tests/Stubs/config.yml b/tests/Stubs/config.yml deleted file mode 100644 index 4b0960f..0000000 --- a/tests/Stubs/config.yml +++ /dev/null @@ -1,9 +0,0 @@ -framework: - test: true - secret: test - -yokai_safe_command: - environments: - enabled: true - environments: - - test