iTranslated by AI

The content below is an AI-generated translation. This is an experimental feature, and may contain errors. View original article
🌿

Preventing Command Execution in Specific Environments in Laravel

に公開

Introduction

Recently, I came across this post.

https://x.com/MrPunyapal/status/1851638598766149706

It seems that a mechanism to disable command execution in specific environments was added in Laravel 11.9.0.

There was also an article about it.
https://laravel-news.com/prevent-destructive-commands-from-running-in-laravel-11

I decided to look into how it stops execution.

Environment

  • PHP 8.3.13
  • Laravel 11.31.0

Confirmation should already exist in production environments

In production environments (APP_ENV=production), certain commands allow you to choose whether to execute them or not, as shown below.

Since it's a choice, it is still possible to execute them even in production if you allow it.

So, what is the difference?

The fastest way to understand is to look at the pull request that added this mechanism.

https://github.com/laravel/framework/pull/51376

It seems that four commands—db:wipe, migrate:fresh, migrate:refresh, and migrate:reset—can be stopped in production without offering a choice to run them.
To enable this feature, you need to call the prohibitDestructiveCommands method of the DB facade.

DB::prohibitDestructiveCommands($this->app->isProduction());

Passing true as the argument disables these four commands.

Let's try it out

To implement this, you can simply add it to the boot method of the AppServiceProvider.

app/Providers/AppServiceProvider.php
<?php

namespace App\Providers;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        DB::prohibitDestructiveCommands($this->app->isProduction());
    }
}

If you try executing a command with APP_ENV=production after setting this up:

 % php artisan migrate:fresh

   WARN  This command is prohibited from running in this environment.  

It stopped working without even providing a choice.

If you want to disable only one specific command, it seems you can do so as follows:

ResetCommand::preventFromRunning($this->app->isProduction());

Can it be applied to other commands?

It seems that this mechanism can be used in custom commands by including the Prohibitable trait.

app/Console/Commands/SampleCommand.php
<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Illuminate\Console\Prohibitable;

class SampleCommand extends Command
{
    use Prohibitable;

    protected $signature = 'app:sample-command';

    protected $description = 'Command description';

    public function handle()
    {
        if ($this->isProhibited()) {
            echo 'Cannot execute' . PHP_EOL;
            return Command::FAILURE;
        }

        echo 'Executed' . PHP_EOL;

        return Command::SUCCESS;
    }
}

In custom commands, you can determine whether to disable execution by calling the prohibit method. Setting this in the boot method of AppServiceProvider, as we did earlier, should work perfectly.

app/Providers/AppServiceProvider.php
namespace App\Providers;

use App\Console\Commands\SampleCommand;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        SampleCommand::prohibit($this->app->isProduction());
    }
}

Now, let's try running it just as we did before.

  • APP_ENV=local
% php artisan app:sample-command
Executed
  • APP_ENV=production
% php artisan app:sample-command

   WARN  This command is prohibited from running in this environment.  

Cannot execute

It worked. For custom commands, it seems possible to disable execution in environments other than production by changing the evaluation logic.

Summary

It's a feature I happened to come across, but it's great that the framework provides a mechanism to prevent accidents.
While it's unclear if there will actually be opportunities to implement this in custom commands, as the saying goes, "better safe than sorry," it might give you peace of mind to set it up if an opportunity arises.

GitHubで編集を提案

Discussion