64 lines
2.6 KiB
PHP
64 lines
2.6 KiB
PHP
<?php
|
|
|
|
namespace App\Support;
|
|
|
|
/**
|
|
* The one place a guest command that runs Nextcloud's `occ` is built.
|
|
*
|
|
* `docker compose exec` runs as **root** unless it is told otherwise, and the
|
|
* official Nextcloud image will not have it: `console.php` compares the calling
|
|
* uid against the owner of `config/config.php` — www-data — and exits 1 with
|
|
* "Console has to be executed with the user that owns the file config/config.php"
|
|
* before a single command is dispatched. Every occ call in this product was
|
|
* therefore failing on every instance, and the ones that go through
|
|
* CustomerStep::guest() turned that exit code into a retry and then into a failed
|
|
* run for a machine that was otherwise finished.
|
|
*
|
|
* The same default already cost this project days on its OWN container, where
|
|
* `artisan optimize` ran as root and left storage/logs/laravel.log unwritable —
|
|
* see deploy/update.sh's in_app() and tests/Feature/DeploymentRunsAsTheAppUserTest.
|
|
* That lesson was written down for the deployment and not for the guests.
|
|
*
|
|
* It lives here, in one place, because the prefix was pasted into five files and
|
|
* a sixth call site would have got it wrong again. Nothing else in app/ may spell
|
|
* `docker compose exec` out by hand; the test above refuses it.
|
|
*/
|
|
final class NextcloudOcc
|
|
{
|
|
/** Where the compose project sits inside every guest this product builds. */
|
|
public const DIRECTORY = '/opt/nextcloud';
|
|
|
|
/**
|
|
* The account that owns the Nextcloud installation inside the image.
|
|
*
|
|
* Named rather than defaulted: the rule is that somebody chose the user, so
|
|
* a reader can tell a deliberate root from a forgotten one.
|
|
*/
|
|
public const USER = 'www-data';
|
|
|
|
/**
|
|
* A guest shell command that runs `occ <arguments>` as that account.
|
|
*
|
|
* Environment values are passed on the docker invocation itself and handed
|
|
* through with `-e`, because an assignment placed before the `cd` would not
|
|
* survive the `&&` — this is how OC_PASS reaches `user:add
|
|
* --password-from-env` without the password ever appearing in an occ
|
|
* argument (and so in the guest's process list).
|
|
*
|
|
* @param array<string, string> $env
|
|
*/
|
|
public static function command(string $arguments, array $env = []): string
|
|
{
|
|
$assignments = '';
|
|
$forwards = '';
|
|
|
|
foreach ($env as $name => $value) {
|
|
$assignments .= $name.'='.escapeshellarg($value).' ';
|
|
$forwards .= '-e '.$name.' ';
|
|
}
|
|
|
|
return 'cd '.self::DIRECTORY.' && '.$assignments
|
|
.'docker compose exec -T -u '.self::USER.' '.$forwards.'app php occ '.$arguments;
|
|
}
|
|
}
|