From ed8965b92b5354a58e7fbcac076d49f44f102a94 Mon Sep 17 00:00:00 2001 From: Saeed Vaziry <61919774+saeedvaziry@users.noreply.github.com> Date: Sat, 27 Jul 2024 17:43:46 +0200 Subject: [PATCH] Fix .env updates for double quotations (#259) --- app/Actions/Site/UpdateEnv.php | 4 +++ app/Exceptions/SSHUploadFailed.php | 8 +++++ app/Facades/SSH.php | 2 ++ .../Controllers/ApplicationController.php | 10 ++++-- app/SSH/OS/OS.php | 35 +++++++++++++++---- app/SSH/OS/scripts/edit-file.sh | 3 -- app/Support/Testing/SSHFake.php | 27 ++++++++++++++ tests/Feature/ApplicationTest.php | 4 +-- 8 files changed, 79 insertions(+), 14 deletions(-) create mode 100755 app/Exceptions/SSHUploadFailed.php delete mode 100644 app/SSH/OS/scripts/edit-file.sh diff --git a/app/Actions/Site/UpdateEnv.php b/app/Actions/Site/UpdateEnv.php index ed8c078..c221e4d 100644 --- a/app/Actions/Site/UpdateEnv.php +++ b/app/Actions/Site/UpdateEnv.php @@ -2,10 +2,14 @@ namespace App\Actions\Site; +use App\Exceptions\SSHUploadFailed; use App\Models\Site; class UpdateEnv { + /** + * @throws SSHUploadFailed + */ public function update(Site $site, array $input): void { $site->server->os()->editFile( diff --git a/app/Exceptions/SSHUploadFailed.php b/app/Exceptions/SSHUploadFailed.php new file mode 100755 index 0000000..c2e6794 --- /dev/null +++ b/app/Exceptions/SSHUploadFailed.php @@ -0,0 +1,8 @@ +authorize('manage', $server); - app(UpdateEnv::class)->update($site, $request->input()); - - Toast::success('Env updated!'); + try { + app(UpdateEnv::class)->update($site, $request->input()); + Toast::success('Env updated!'); + } catch (SSHUploadFailed) { + Toast::error('Failed to update .env file!'); + } return back(); } diff --git a/app/SSH/OS/OS.php b/app/SSH/OS/OS.php index 1b34622..8d02583 100644 --- a/app/SSH/OS/OS.php +++ b/app/SSH/OS/OS.php @@ -2,9 +2,14 @@ namespace App\SSH\OS; +use App\Exceptions\SSHUploadFailed; use App\Models\Server; use App\Models\ServerLog; use App\SSH\HasScripts; +use Illuminate\Filesystem\FilesystemAdapter; +use Illuminate\Support\Facades\Storage; +use Illuminate\Support\Str; +use Throwable; class OS { @@ -109,14 +114,25 @@ public function reboot(): void ); } + /** + * @throws SSHUploadFailed + */ public function editFile(string $path, ?string $content = null): void { - $this->server->ssh()->exec( - $this->getScript('edit-file.sh', [ - 'path' => $path, - 'content' => $content ?? '', - ]), - ); + $tmpName = Str::random(10).strtotime('now'); + try { + /** @var FilesystemAdapter $storageDisk */ + $storageDisk = Storage::disk('local'); + $storageDisk->put($tmpName, $content); + $this->server->ssh()->upload( + $storageDisk->path($tmpName), + $path + ); + } catch (Throwable) { + throw new SSHUploadFailed(); + } finally { + $this->deleteTempFile($tmpName); + } } public function readFile(string $path): string @@ -200,4 +216,11 @@ public function resourceInfo(): array 'disk_free' => str($info)->after('disk_free:')->before(PHP_EOL)->toString(), ]; } + + private function deleteTempFile(string $name): void + { + if (Storage::disk('local')->exists($name)) { + Storage::disk('local')->delete($name); + } + } } diff --git a/app/SSH/OS/scripts/edit-file.sh b/app/SSH/OS/scripts/edit-file.sh deleted file mode 100644 index 67e5def..0000000 --- a/app/SSH/OS/scripts/edit-file.sh +++ /dev/null @@ -1,3 +0,0 @@ -if ! echo "__content__" | tee __path__; then - echo 'VITO_SSH_ERROR' && exit 1 -fi diff --git a/app/Support/Testing/SSHFake.php b/app/Support/Testing/SSHFake.php index 2cecde9..2551462 100644 --- a/app/Support/Testing/SSHFake.php +++ b/app/Support/Testing/SSHFake.php @@ -17,6 +17,12 @@ class SSHFake extends SSH protected bool $connectionWillFail = false; + protected string $uploadedLocalPath; + + protected string $uploadedRemotePath; + + protected string $uploadedContent; + public function __construct(?string $output = null) { $this->output = $output; @@ -63,6 +69,9 @@ public function exec(string $command, string $log = '', ?int $siteId = null, ?bo public function upload(string $local, string $remote): void { + $this->uploadedLocalPath = $local; + $this->uploadedRemotePath = $remote; + $this->uploadedContent = file_get_contents($local); $this->log = null; } @@ -105,4 +114,22 @@ public function assertExecutedContains(string $command): void } Assert::assertTrue(true, $executed); } + + public function assertFileUploaded(string $toPath, ?string $content = null): void + { + if (! $this->uploadedLocalPath || ! $this->uploadedRemotePath) { + Assert::fail('File is not uploaded'); + } + + Assert::assertEquals($toPath, $this->uploadedRemotePath); + + if ($content) { + Assert::assertEquals($content, $this->uploadedContent); + } + } + + public function getUploadedLocalPath(): string + { + return $this->uploadedLocalPath; + } } diff --git a/tests/Feature/ApplicationTest.php b/tests/Feature/ApplicationTest.php index b1e120a..4cf62c4 100644 --- a/tests/Feature/ApplicationTest.php +++ b/tests/Feature/ApplicationTest.php @@ -179,10 +179,10 @@ public function test_update_env_file(): void 'server' => $this->server, 'site' => $this->site, ]), [ - 'env' => 'APP_ENV=production', + 'env' => 'APP_ENV="production"', ])->assertSessionDoesntHaveErrors(); - SSH::assertExecutedContains('echo "APP_ENV=production" | tee /home/vito/'.$this->site->domain.'/.env'); + SSH::assertFileUploaded('/home/vito/'.$this->site->domain.'/.env', 'APP_ENV="production"'); } public function test_git_hook_deployment(): void