Replace existing Egg Reserved_Env_Variables with SERVER_ prefix (#1070)

* Add migration that updates egg->variables->env_variable, egg->startup, egg->servers->startup

* Update `EggImporterService` to replace `EggVariable::RESERVED_ENV_NAMES`

* Use `EggImporterService::parseReservedEnvNames`

* Refactor & Remove `Migration`
This commit is contained in:
MartinOscar 2025-03-15 19:51:10 +01:00 committed by GitHub
parent ea5914f362
commit e04abcbcf9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 48 additions and 12 deletions

View File

@ -192,7 +192,7 @@ class CreateEgg extends CreateRecord
->hintIcon('tabler-code') ->hintIcon('tabler-code')
->hintIconTooltip(fn ($state) => "{{{$state}}}") ->hintIconTooltip(fn ($state) => "{{{$state}}}")
->unique(modifyRuleUsing: fn (Unique $rule, Get $get) => $rule->where('egg_id', $get('../../id')), ignoreRecord: true) ->unique(modifyRuleUsing: fn (Unique $rule, Get $get) => $rule->where('egg_id', $get('../../id')), ignoreRecord: true)
->rules(EggVariable::$validationRules['env_variable']) ->rules(EggVariable::getRulesForField('env_variable'))
->validationMessages([ ->validationMessages([
'unique' => trans('admin/egg.error_unique'), 'unique' => trans('admin/egg.error_unique'),
'required' => trans('admin/egg.error_required'), 'required' => trans('admin/egg.error_required'),

View File

@ -183,7 +183,7 @@ class EditEgg extends EditRecord
->hintIcon('tabler-code') ->hintIcon('tabler-code')
->hintIconTooltip(fn ($state) => "{{{$state}}}") ->hintIconTooltip(fn ($state) => "{{{$state}}}")
->unique(modifyRuleUsing: fn (Unique $rule, Get $get) => $rule->where('egg_id', $get('../../id')), ignoreRecord: true) ->unique(modifyRuleUsing: fn (Unique $rule, Get $get) => $rule->where('egg_id', $get('../../id')), ignoreRecord: true)
->rules(EggVariable::$validationRules['env_variable']) ->rules(EggVariable::getRulesForField('env_variable'))
->validationMessages([ ->validationMessages([
'unique' => trans('admin/egg.error_unique'), 'unique' => trans('admin/egg.error_unique'),
'required' => trans('admin/egg.error_required'), 'required' => trans('admin/egg.error_required'),

View File

@ -33,7 +33,7 @@ use Illuminate\Database\Eloquent\Relations\HasMany;
class EggVariable extends Model implements Validatable class EggVariable extends Model implements Validatable
{ {
use HasFactory; use HasFactory;
use HasValidation; use HasValidation { getRules as getValidationRules; }
/** /**
* The resource name for this model when it is transformed into an * The resource name for this model when it is transformed into an
@ -44,7 +44,7 @@ class EggVariable extends Model implements Validatable
/** /**
* Reserved environment variable names. * Reserved environment variable names.
*/ */
public const RESERVED_ENV_NAMES = 'P_SERVER_UUID,P_SERVER_ALLOCATION_LIMIT,SERVER_MEMORY,SERVER_IP,SERVER_PORT,ENV,HOME,USER,STARTUP,MODIFIED_STARTUP,SERVER_UUID,UUID,INTERNAL_IP,HOSTNAME,TERM,LANG,PWD,TZ,TIMEZONE'; public const RESERVED_ENV_NAMES = ['P_SERVER_UUID', 'P_SERVER_ALLOCATION_LIMIT', 'SERVER_MEMORY', 'SERVER_IP', 'SERVER_PORT', 'ENV', 'HOME', 'USER', 'STARTUP', 'MODIFIED_STARTUP', 'SERVER_UUID', 'UUID', 'INTERNAL_IP', 'HOSTNAME', 'TERM', 'LANG', 'PWD', 'TZ', 'TIMEZONE'];
/** /**
* Fields that are not mass assignable. * Fields that are not mass assignable.
@ -57,7 +57,6 @@ class EggVariable extends Model implements Validatable
'sort' => ['nullable'], 'sort' => ['nullable'],
'name' => ['required', 'string', 'between:1,255'], 'name' => ['required', 'string', 'between:1,255'],
'description' => ['string'], 'description' => ['string'],
'env_variable' => ['required', 'alphaDash', 'between:1,255', 'notIn:' . self::RESERVED_ENV_NAMES],
'default_value' => ['string'], 'default_value' => ['string'],
'user_viewable' => ['boolean'], 'user_viewable' => ['boolean'],
'user_editable' => ['boolean'], 'user_editable' => ['boolean'],
@ -65,6 +64,20 @@ class EggVariable extends Model implements Validatable
'rules.*' => ['string'], 'rules.*' => ['string'],
]; ];
/**
* Implement language verification by overriding Eloquence's gather rules function.
*
* @return array<string|string[]>
*/
public static function getRules(): array
{
$rules = self::getValidationRules();
$rules['env_variable'] = ['required', 'alphaDash', 'between:1,255', 'notIn:' . implode(',', EggVariable::RESERVED_ENV_NAMES)];
return $rules;
}
protected $attributes = [ protected $attributes = [
'user_editable' => 0, 'user_editable' => 0,
'user_viewable' => 0, 'user_viewable' => 0,

View File

@ -122,11 +122,34 @@ class EggImporterService
}; };
// Make sure we only use recent variable format from now on // Make sure we only use recent variable format from now on
$parsed['config']['files'] = str_replace( if (array_get($parsed['config'], 'files')) {
array_keys(self::UPGRADE_VARIABLES), $parsed['config']['files'] = str_replace(
array_values(self::UPGRADE_VARIABLES), array_keys(self::UPGRADE_VARIABLES),
$parsed['config']['files'] ?? '', array_values(self::UPGRADE_VARIABLES),
); $parsed['config']['files'],
);
}
[$forbidden, $allowed] = collect($parsed['variables'])
->map(fn ($variable) => array_merge(
$variable,
['env_variable' => strtoupper($variable['env_variable'])]
))
->partition(fn ($variable) => in_array($variable['env_variable'], EggVariable::RESERVED_ENV_NAMES));
$updatedVariables = $forbidden->map(fn ($variable) => array_merge(
$variable,
['env_variable' => 'SERVER_' . $variable['env_variable']]
));
if ($forbidden->count()) {
$parsed['variables'] = $allowed->merge($updatedVariables)->all();
if (!empty($parsed['startup'])) {
$pattern = '/\b(' . collect($forbidden)->map(fn ($variable) => preg_quote($variable['env_variable']))->join('|') . ')\b/';
$parsed['startup'] = preg_replace($pattern, 'SERVER_$1', $parsed['startup']) ?? $parsed['startup'];
}
}
return $parsed; return $parsed;
} }

View File

@ -42,7 +42,7 @@ class VariableCreationService
*/ */
public function handle(int $egg, array $data): EggVariable public function handle(int $egg, array $data): EggVariable
{ {
if (in_array(strtoupper(array_get($data, 'env_variable')), explode(',', EggVariable::RESERVED_ENV_NAMES))) { if (in_array(strtoupper(array_get($data, 'env_variable')), EggVariable::RESERVED_ENV_NAMES)) {
throw new ReservedVariableNameException(sprintf('Cannot use the protected name %s for this environment variable.', array_get($data, 'env_variable'))); throw new ReservedVariableNameException(sprintf('Cannot use the protected name %s for this environment variable.', array_get($data, 'env_variable')));
} }

View File

@ -45,7 +45,7 @@ class VariableUpdateService
public function handle(EggVariable $variable, array $data): EggVariable public function handle(EggVariable $variable, array $data): EggVariable
{ {
if (!is_null(array_get($data, 'env_variable'))) { if (!is_null(array_get($data, 'env_variable'))) {
if (in_array(strtoupper(array_get($data, 'env_variable')), explode(',', EggVariable::RESERVED_ENV_NAMES))) { if (in_array(strtoupper(array_get($data, 'env_variable')), EggVariable::RESERVED_ENV_NAMES)) {
throw new ReservedVariableNameException(trans('exceptions.service.variables.reserved_name', ['name' => array_get($data, 'env_variable')])); throw new ReservedVariableNameException(trans('exceptions.service.variables.reserved_name', ['name' => array_get($data, 'env_variable')]));
} }