From 38ee91e15d78325dca2ccaf31bee03cb2dd87aa5 Mon Sep 17 00:00:00 2001 From: Jason McCreary Date: Fri, 10 May 2024 13:20:25 -0400 Subject: [PATCH 1/8] Prevent destructive commands from running --- src/Illuminate/Console/Preventable.php | 36 +++++++++++++++++++ .../Console/Migrations/FreshCommand.php | 7 +++- .../Console/Migrations/RefreshCommand.php | 7 +++- .../Console/Migrations/ResetCommand.php | 7 +++- .../Database/Console/WipeCommand.php | 7 +++- .../DatabaseMigrationRefreshCommandTest.php | 21 +++++++++++ .../DatabaseMigrationResetCommandTest.php | 17 +++++++++ 7 files changed, 98 insertions(+), 4 deletions(-) create mode 100644 src/Illuminate/Console/Preventable.php diff --git a/src/Illuminate/Console/Preventable.php b/src/Illuminate/Console/Preventable.php new file mode 100644 index 000000000000..f36fac1abce4 --- /dev/null +++ b/src/Illuminate/Console/Preventable.php @@ -0,0 +1,36 @@ +components->warn('Command has been prevented from running in this environment.'); + + return true; + } +} diff --git a/src/Illuminate/Database/Console/Migrations/FreshCommand.php b/src/Illuminate/Database/Console/Migrations/FreshCommand.php index de43e74f8610..aad3ef463be1 100644 --- a/src/Illuminate/Database/Console/Migrations/FreshCommand.php +++ b/src/Illuminate/Database/Console/Migrations/FreshCommand.php @@ -4,6 +4,7 @@ use Illuminate\Console\Command; use Illuminate\Console\ConfirmableTrait; +use Illuminate\Console\Preventable; use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Database\Events\DatabaseRefreshed; use Illuminate\Database\Migrations\Migrator; @@ -13,7 +14,7 @@ #[AsCommand(name: 'migrate:fresh')] class FreshCommand extends Command { - use ConfirmableTrait; + use ConfirmableTrait, Preventable; /** * The console command name. @@ -56,6 +57,10 @@ public function __construct(Migrator $migrator) */ public function handle() { + if ($this->preventedFromRunning()) { + return 1; + } + if (! $this->confirmToProceed()) { return 1; } diff --git a/src/Illuminate/Database/Console/Migrations/RefreshCommand.php b/src/Illuminate/Database/Console/Migrations/RefreshCommand.php index e348f1923fb3..3011f9b721db 100755 --- a/src/Illuminate/Database/Console/Migrations/RefreshCommand.php +++ b/src/Illuminate/Database/Console/Migrations/RefreshCommand.php @@ -4,6 +4,7 @@ use Illuminate\Console\Command; use Illuminate\Console\ConfirmableTrait; +use Illuminate\Console\Preventable; use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Database\Events\DatabaseRefreshed; use Symfony\Component\Console\Attribute\AsCommand; @@ -12,7 +13,7 @@ #[AsCommand(name: 'migrate:refresh')] class RefreshCommand extends Command { - use ConfirmableTrait; + use ConfirmableTrait, Preventable; /** * The console command name. @@ -35,6 +36,10 @@ class RefreshCommand extends Command */ public function handle() { + if ($this->preventedFromRunning()) { + return 1; + } + if (! $this->confirmToProceed()) { return 1; } diff --git a/src/Illuminate/Database/Console/Migrations/ResetCommand.php b/src/Illuminate/Database/Console/Migrations/ResetCommand.php index dd9f05126e0a..9d2b57a44dbe 100755 --- a/src/Illuminate/Database/Console/Migrations/ResetCommand.php +++ b/src/Illuminate/Database/Console/Migrations/ResetCommand.php @@ -3,6 +3,7 @@ namespace Illuminate\Database\Console\Migrations; use Illuminate\Console\ConfirmableTrait; +use Illuminate\Console\Preventable; use Illuminate\Database\Migrations\Migrator; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Input\InputOption; @@ -10,7 +11,7 @@ #[AsCommand(name: 'migrate:reset')] class ResetCommand extends BaseCommand { - use ConfirmableTrait; + use ConfirmableTrait, Preventable; /** * The console command name. @@ -53,6 +54,10 @@ public function __construct(Migrator $migrator) */ public function handle() { + if ($this->preventedFromRunning()) { + return 1; + } + if (! $this->confirmToProceed()) { return 1; } diff --git a/src/Illuminate/Database/Console/WipeCommand.php b/src/Illuminate/Database/Console/WipeCommand.php index e9c8e956d003..720e96f1c889 100644 --- a/src/Illuminate/Database/Console/WipeCommand.php +++ b/src/Illuminate/Database/Console/WipeCommand.php @@ -4,13 +4,14 @@ use Illuminate\Console\Command; use Illuminate\Console\ConfirmableTrait; +use Illuminate\Console\Preventable; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Input\InputOption; #[AsCommand(name: 'db:wipe')] class WipeCommand extends Command { - use ConfirmableTrait; + use ConfirmableTrait, Preventable; /** * The console command name. @@ -33,6 +34,10 @@ class WipeCommand extends Command */ public function handle() { + if ($this->preventedFromRunning()) { + return 1; + } + if (! $this->confirmToProceed()) { return 1; } diff --git a/tests/Database/DatabaseMigrationRefreshCommandTest.php b/tests/Database/DatabaseMigrationRefreshCommandTest.php index 8502fdfe8450..cda451ecb2e4 100755 --- a/tests/Database/DatabaseMigrationRefreshCommandTest.php +++ b/tests/Database/DatabaseMigrationRefreshCommandTest.php @@ -72,6 +72,27 @@ public function testRefreshCommandCallsCommandsWithStep() $this->runCommand($command, ['--step' => 2]); } + public function testRefreshCommandExitsWhenPrevented() + { + $command = new RefreshCommand; + + $app = new ApplicationDatabaseRefreshStub(['path.database' => __DIR__]); + $dispatcher = $app->instance(Dispatcher::class, $events = m::mock()); + $console = m::mock(ConsoleApplication::class)->makePartial(); + $console->__construct(); + $command->setLaravel($app); + $command->setApplication($console); + + RefreshCommand::preventFromRunning(); + + $code = $this->runCommand($command); + + $this->assertSame(1, $code); + + $console->shouldNotHaveBeenCalled(); + $dispatcher->shouldNotReceive('dispatch'); + } + protected function runCommand($command, $input = []) { return $command->run(new ArrayInput($input), new NullOutput); diff --git a/tests/Database/DatabaseMigrationResetCommandTest.php b/tests/Database/DatabaseMigrationResetCommandTest.php index d69cc8f81dd2..c4864dd268e3 100755 --- a/tests/Database/DatabaseMigrationResetCommandTest.php +++ b/tests/Database/DatabaseMigrationResetCommandTest.php @@ -52,6 +52,23 @@ public function testResetCommandCanBePretended() $this->runCommand($command, ['--pretend' => true, '--database' => 'foo']); } + public function testRefreshCommandExitsWhenPrevented() + { + $command = new ResetCommand($migrator = m::mock(Migrator::class)); + + $app = new ApplicationDatabaseResetStub(['path.database' => __DIR__]); + $app->useDatabasePath(__DIR__); + $command->setLaravel($app); + + ResetCommand::preventFromRunning(); + + $code = $this->runCommand($command); + + $this->assertSame(1, $code); + + $migrator->shouldNotHaveBeenCalled(); + } + protected function runCommand($command, $input = []) { return $command->run(new ArrayInput($input), new NullOutput); From a7fa77322b5f631347052d443f4cc389d4724543 Mon Sep 17 00:00:00 2001 From: Jason McCreary Date: Fri, 10 May 2024 13:40:43 -0400 Subject: [PATCH 2/8] Test cleanup --- tests/Database/DatabaseMigrationRefreshCommandTest.php | 1 + tests/Database/DatabaseMigrationResetCommandTest.php | 1 + 2 files changed, 2 insertions(+) diff --git a/tests/Database/DatabaseMigrationRefreshCommandTest.php b/tests/Database/DatabaseMigrationRefreshCommandTest.php index cda451ecb2e4..8b1fe0a18cbb 100755 --- a/tests/Database/DatabaseMigrationRefreshCommandTest.php +++ b/tests/Database/DatabaseMigrationRefreshCommandTest.php @@ -19,6 +19,7 @@ class DatabaseMigrationRefreshCommandTest extends TestCase { protected function tearDown(): void { + RefreshCommand::preventFromRunning(false); m::close(); } diff --git a/tests/Database/DatabaseMigrationResetCommandTest.php b/tests/Database/DatabaseMigrationResetCommandTest.php index c4864dd268e3..bf453afc43d3 100755 --- a/tests/Database/DatabaseMigrationResetCommandTest.php +++ b/tests/Database/DatabaseMigrationResetCommandTest.php @@ -15,6 +15,7 @@ class DatabaseMigrationResetCommandTest extends TestCase { protected function tearDown(): void { + ResetCommand::preventFromRunning(false); m::close(); } From 0052c89a38c0b210cc209cb9ecb2ea7732d2e154 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 21 May 2024 13:09:36 -0500 Subject: [PATCH 3/8] formatting --- src/Illuminate/Console/Preventable.php | 36 ---------------- src/Illuminate/Console/Prohibitable.php | 43 +++++++++++++++++++ .../Console/Migrations/FreshCommand.php | 11 ++--- .../Console/Migrations/RefreshCommand.php | 11 ++--- .../Console/Migrations/ResetCommand.php | 11 ++--- .../Database/Console/WipeCommand.php | 11 ++--- .../DatabaseMigrationRefreshCommandTest.php | 4 +- .../DatabaseMigrationResetCommandTest.php | 4 +- 8 files changed, 63 insertions(+), 68 deletions(-) delete mode 100644 src/Illuminate/Console/Preventable.php create mode 100644 src/Illuminate/Console/Prohibitable.php diff --git a/src/Illuminate/Console/Preventable.php b/src/Illuminate/Console/Preventable.php deleted file mode 100644 index f36fac1abce4..000000000000 --- a/src/Illuminate/Console/Preventable.php +++ /dev/null @@ -1,36 +0,0 @@ -components->warn('Command has been prevented from running in this environment.'); - - return true; - } -} diff --git a/src/Illuminate/Console/Prohibitable.php b/src/Illuminate/Console/Prohibitable.php new file mode 100644 index 000000000000..ae10183a18bf --- /dev/null +++ b/src/Illuminate/Console/Prohibitable.php @@ -0,0 +1,43 @@ +components->warn('Command is prohibited from running in this environment.'); + } + + return true; + } +} diff --git a/src/Illuminate/Database/Console/Migrations/FreshCommand.php b/src/Illuminate/Database/Console/Migrations/FreshCommand.php index aad3ef463be1..00c8c3559876 100644 --- a/src/Illuminate/Database/Console/Migrations/FreshCommand.php +++ b/src/Illuminate/Database/Console/Migrations/FreshCommand.php @@ -4,7 +4,7 @@ use Illuminate\Console\Command; use Illuminate\Console\ConfirmableTrait; -use Illuminate\Console\Preventable; +use Illuminate\Console\Prohibitable; use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Database\Events\DatabaseRefreshed; use Illuminate\Database\Migrations\Migrator; @@ -14,7 +14,7 @@ #[AsCommand(name: 'migrate:fresh')] class FreshCommand extends Command { - use ConfirmableTrait, Preventable; + use ConfirmableTrait, Prohibitable; /** * The console command name. @@ -57,11 +57,8 @@ public function __construct(Migrator $migrator) */ public function handle() { - if ($this->preventedFromRunning()) { - return 1; - } - - if (! $this->confirmToProceed()) { + if ($this->isProhibited() || + ! $this->confirmToProceed()) { return 1; } diff --git a/src/Illuminate/Database/Console/Migrations/RefreshCommand.php b/src/Illuminate/Database/Console/Migrations/RefreshCommand.php index 3011f9b721db..3fd1083a7524 100755 --- a/src/Illuminate/Database/Console/Migrations/RefreshCommand.php +++ b/src/Illuminate/Database/Console/Migrations/RefreshCommand.php @@ -4,7 +4,7 @@ use Illuminate\Console\Command; use Illuminate\Console\ConfirmableTrait; -use Illuminate\Console\Preventable; +use Illuminate\Console\Prohibitable; use Illuminate\Contracts\Events\Dispatcher; use Illuminate\Database\Events\DatabaseRefreshed; use Symfony\Component\Console\Attribute\AsCommand; @@ -13,7 +13,7 @@ #[AsCommand(name: 'migrate:refresh')] class RefreshCommand extends Command { - use ConfirmableTrait, Preventable; + use ConfirmableTrait, Prohibitable; /** * The console command name. @@ -36,11 +36,8 @@ class RefreshCommand extends Command */ public function handle() { - if ($this->preventedFromRunning()) { - return 1; - } - - if (! $this->confirmToProceed()) { + if ($this->isProhibited() || + ! $this->confirmToProceed()) { return 1; } diff --git a/src/Illuminate/Database/Console/Migrations/ResetCommand.php b/src/Illuminate/Database/Console/Migrations/ResetCommand.php index 9d2b57a44dbe..695da444b1d1 100755 --- a/src/Illuminate/Database/Console/Migrations/ResetCommand.php +++ b/src/Illuminate/Database/Console/Migrations/ResetCommand.php @@ -3,7 +3,7 @@ namespace Illuminate\Database\Console\Migrations; use Illuminate\Console\ConfirmableTrait; -use Illuminate\Console\Preventable; +use Illuminate\Console\Prohibitable; use Illuminate\Database\Migrations\Migrator; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Input\InputOption; @@ -11,7 +11,7 @@ #[AsCommand(name: 'migrate:reset')] class ResetCommand extends BaseCommand { - use ConfirmableTrait, Preventable; + use ConfirmableTrait, Prohibitable; /** * The console command name. @@ -54,11 +54,8 @@ public function __construct(Migrator $migrator) */ public function handle() { - if ($this->preventedFromRunning()) { - return 1; - } - - if (! $this->confirmToProceed()) { + if ($this->isProhibited() || + ! $this->confirmToProceed()) { return 1; } diff --git a/src/Illuminate/Database/Console/WipeCommand.php b/src/Illuminate/Database/Console/WipeCommand.php index 720e96f1c889..3e83c9b9445d 100644 --- a/src/Illuminate/Database/Console/WipeCommand.php +++ b/src/Illuminate/Database/Console/WipeCommand.php @@ -4,14 +4,14 @@ use Illuminate\Console\Command; use Illuminate\Console\ConfirmableTrait; -use Illuminate\Console\Preventable; +use Illuminate\Console\Prohibitable; use Symfony\Component\Console\Attribute\AsCommand; use Symfony\Component\Console\Input\InputOption; #[AsCommand(name: 'db:wipe')] class WipeCommand extends Command { - use ConfirmableTrait, Preventable; + use ConfirmableTrait, Prohibitable; /** * The console command name. @@ -34,11 +34,8 @@ class WipeCommand extends Command */ public function handle() { - if ($this->preventedFromRunning()) { - return 1; - } - - if (! $this->confirmToProceed()) { + if ($this->isProhibited() || + ! $this->confirmToProceed()) { return 1; } diff --git a/tests/Database/DatabaseMigrationRefreshCommandTest.php b/tests/Database/DatabaseMigrationRefreshCommandTest.php index 8b1fe0a18cbb..70a9c2446458 100755 --- a/tests/Database/DatabaseMigrationRefreshCommandTest.php +++ b/tests/Database/DatabaseMigrationRefreshCommandTest.php @@ -19,7 +19,7 @@ class DatabaseMigrationRefreshCommandTest extends TestCase { protected function tearDown(): void { - RefreshCommand::preventFromRunning(false); + RefreshCommand::prohibit(false); m::close(); } @@ -84,7 +84,7 @@ public function testRefreshCommandExitsWhenPrevented() $command->setLaravel($app); $command->setApplication($console); - RefreshCommand::preventFromRunning(); + RefreshCommand::prohibit(); $code = $this->runCommand($command); diff --git a/tests/Database/DatabaseMigrationResetCommandTest.php b/tests/Database/DatabaseMigrationResetCommandTest.php index bf453afc43d3..654d0066b42e 100755 --- a/tests/Database/DatabaseMigrationResetCommandTest.php +++ b/tests/Database/DatabaseMigrationResetCommandTest.php @@ -15,7 +15,7 @@ class DatabaseMigrationResetCommandTest extends TestCase { protected function tearDown(): void { - ResetCommand::preventFromRunning(false); + ResetCommand::prohibit(false); m::close(); } @@ -61,7 +61,7 @@ public function testRefreshCommandExitsWhenPrevented() $app->useDatabasePath(__DIR__); $command->setLaravel($app); - ResetCommand::preventFromRunning(); + ResetCommand::prohibit(); $code = $this->runCommand($command); From 1b60ed913d40b7ae0031c4ca5bbf86f9ff87c0b9 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 21 May 2024 13:12:25 -0500 Subject: [PATCH 4/8] add consolidated method --- src/Illuminate/Support/Facades/DB.php | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/Illuminate/Support/Facades/DB.php b/src/Illuminate/Support/Facades/DB.php index 3418db12ccf8..5cd9ae917987 100644 --- a/src/Illuminate/Support/Facades/DB.php +++ b/src/Illuminate/Support/Facades/DB.php @@ -2,6 +2,11 @@ namespace Illuminate\Support\Facades; +use Illuminate\Database\Console\Migrations\FreshCommand; +use Illuminate\Database\Console\Migrations\RefreshCommand; +use Illuminate\Database\Console\Migrations\ResetCommand; +use Illuminate\Database\Console\WipeCommand; + /** * @method static \Illuminate\Database\Connection connection(string|null $name = null) * @method static \Illuminate\Database\ConnectionInterface connectUsing(string $name, array $config, bool $force = false) @@ -109,6 +114,22 @@ */ class DB extends Facade { + /** + * Indicate if destructive Artisan commands should be prohibited. + * + * @param bool $prohibit + * @return void + */ + public static function prohibitDestructiveCommands(bool $prohibit = true) + { + if ($prohibit) { + FreshCommand::prohibit(); + RefreshCommand::prohibit(); + ResetCommand::prohibit(); + WipeCommand::prohibit(); + } + } + /** * Get the registered name of the component. * From c1edf6f32e429e433941aa187a1f5e2720202355 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 21 May 2024 13:18:53 -0500 Subject: [PATCH 5/8] Update DB.php --- src/Illuminate/Support/Facades/DB.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/Illuminate/Support/Facades/DB.php b/src/Illuminate/Support/Facades/DB.php index 5cd9ae917987..60cd3c5c1ab9 100644 --- a/src/Illuminate/Support/Facades/DB.php +++ b/src/Illuminate/Support/Facades/DB.php @@ -117,6 +117,8 @@ class DB extends Facade /** * Indicate if destructive Artisan commands should be prohibited. * + * Prohibits: db:wipe, migrate:fresh, migrate:refresh, and migrate:reset + * * @param bool $prohibit * @return void */ From cf2f14b92627a34c6462f7699db658ae66ae7537 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 21 May 2024 13:22:11 -0500 Subject: [PATCH 6/8] pass through --- src/Illuminate/Support/Facades/DB.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/Illuminate/Support/Facades/DB.php b/src/Illuminate/Support/Facades/DB.php index 5cd9ae917987..4f1e587b57d9 100644 --- a/src/Illuminate/Support/Facades/DB.php +++ b/src/Illuminate/Support/Facades/DB.php @@ -122,12 +122,10 @@ class DB extends Facade */ public static function prohibitDestructiveCommands(bool $prohibit = true) { - if ($prohibit) { - FreshCommand::prohibit(); - RefreshCommand::prohibit(); - ResetCommand::prohibit(); - WipeCommand::prohibit(); - } + FreshCommand::prohibit($prohibit); + RefreshCommand::prohibit($prohibit); + ResetCommand::prohibit($prohibit); + WipeCommand::prohibit($prohibit); } /** From 0a155cceb8a2332f063cc8d1b16f33e2f85e0e04 Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 21 May 2024 13:23:02 -0500 Subject: [PATCH 7/8] rename param --- src/Illuminate/Console/Prohibitable.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Illuminate/Console/Prohibitable.php b/src/Illuminate/Console/Prohibitable.php index ae10183a18bf..3e46dc80ceb7 100644 --- a/src/Illuminate/Console/Prohibitable.php +++ b/src/Illuminate/Console/Prohibitable.php @@ -14,12 +14,12 @@ trait Prohibitable /** * Indicate whether the command should be prohibited from running. * - * @param bool $prevent + * @param bool $prohibit * @return bool */ - public static function prohibit($prevent = true) + public static function prohibit($prohibit = true) { - static::$prohibitedFromRunning = $prevent; + static::$prohibitedFromRunning = $prohibit; } /** From be07a7db7665d4a1c29b454d1fbb643b7fe11f0c Mon Sep 17 00:00:00 2001 From: Taylor Otwell Date: Tue, 21 May 2024 13:40:37 -0500 Subject: [PATCH 8/8] Update Prohibitable.php --- src/Illuminate/Console/Prohibitable.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Illuminate/Console/Prohibitable.php b/src/Illuminate/Console/Prohibitable.php index 3e46dc80ceb7..d39be8cf94bd 100644 --- a/src/Illuminate/Console/Prohibitable.php +++ b/src/Illuminate/Console/Prohibitable.php @@ -35,7 +35,7 @@ protected function isProhibited(bool $quiet = false) } if (! $quiet) { - $this->components->warn('Command is prohibited from running in this environment.'); + $this->components->warn('This command is prohibited from running in this environment.'); } return true;