laravel / prompts

Beautiful and user-friendly forms for your command-line PHP applications.

Home Page:https://laravel.com/docs/prompts

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Prompts does not check for a TTY

Spice-King opened this issue · comments

Laravel Prompts Version

0.1.6

Laravel Version

10.22.0

PHP Version

8.2.10

Operating System & Version

Linux 6.4.6

Terminal Application

N/A, this is about TTYless enviroments and thus no terminal

Description

Prompts does zero checking if standard input is a tty. Without an interactive tty, which can be caused running commands from cron or in Docker without allocating one, this causes stty here to fail with stty: standard input: Not a tty. Since there is zero checks to see if this was successful or checking that it's on a tty separately, the code always assumes it is on a tty. When this while loop is entered, there are no time out checks to break out of the loop, nor is there a there something to slow it down since fread(STDIN, 1024) here instantly returns zero length string with out a tty (assuming nothing has been piped in there, or has otherwise been drained).

This has the following consequences, assuming that scheduled commands in cron trigger this, 100% CPU thread utilization per instance started and slow memory exhaustion as concurrently running commands pile up.

There are a few ways I can see fixing this, from detecting the lack of a TTY & throwing an exception to end everything, to accepting default options. My assumption is detect and throw is the better one, but I'm happy to be proven wrong.

Steps To Reproduce

  1. Add a command that uses Illuminate\Console\ConfirmableTrait to the scheduler in Laravel, while forgetting to set --force for production
    • Alternatively, upgrade a package you already have a scheduled command for that migrated to using laravel/prompts, and not realize the consequences that change causes.
  2. Wait for schedule to execute the command without a TTY.
    • Alternatively, you can run a command in your shell this way to execute it without a TTY attached: (setsid php artisan activitylog:clean) </dev/null
    • Yes, the parentheses are needed, use of the subshell avoids setsid forking and going into the background, and the /dev/null redirect is to remove keyboard input, like it would be while cron runs.
  3. Profit!

Thanks for reporting, @Spice-King.

I think #63 will indirectly help with this, and #57 (comment) will fill in the gaps.

I will finish implementing #57 and verify it will pass your reproduction steps. My thoughts are that if it can return a configured default value or an empty value that passes any validation, then it will do so. Otherwise, it will throw an exception.