feat: validate required SSH permissions before creating server
- New server_permissions table (migration 007) stores required SSH permissions per server - PermissionValidator service connects via SSH and validates each permission before save - ServerPermission model for CRUD on server_permissions table - Web flow: create/edit forms include dynamic permission rows with quick-add presets - API flow: serverAdd/serverUpdate accept permissions array, return 400 on failure - Show view displays required permissions on server detail page - Form input preserved on validation failure (credentials excluded) - AGENTS.md updated with new conventions
This commit is contained in:
@@ -7,10 +7,12 @@ namespace ServerManager\Controllers;
|
||||
use ServerManager\Core\App;
|
||||
use ServerManager\Core\Session;
|
||||
use ServerManager\Models\Server;
|
||||
use ServerManager\Models\ServerPermission;
|
||||
use ServerManager\Models\User;
|
||||
use ServerManager\Services\MonitoringService;
|
||||
use ServerManager\Services\SSHService;
|
||||
use ServerManager\Services\AuditService;
|
||||
use ServerManager\Services\PermissionValidator;
|
||||
use ServerManager\Models\CommandHistory;
|
||||
use ServerManager\Core\Validator;
|
||||
|
||||
@@ -143,9 +145,43 @@ class ApiController
|
||||
$this->view->json(['error' => $validator->getFirstError()], 400);
|
||||
}
|
||||
|
||||
$permissions = $this->extractPermissionsFromInput($input);
|
||||
|
||||
if (!empty($permissions)) {
|
||||
$serverConfig = [
|
||||
'ip_address' => $input['ip_address'],
|
||||
'ssh_port' => (int) $input['ssh_port'],
|
||||
'ssh_user' => $input['ssh_user'],
|
||||
'ssh_password' => $input['ssh_password'] ?? null,
|
||||
'ssh_key' => $input['ssh_key'] ?? null,
|
||||
];
|
||||
|
||||
$permValidator = new PermissionValidator();
|
||||
$permResult = $permValidator->validate($serverConfig, $permissions);
|
||||
|
||||
if (!$permResult['passed']) {
|
||||
$failedPermissions = array_filter($permResult['results'], fn($r) => !$r['passed']);
|
||||
$errors = [];
|
||||
foreach ($failedPermissions as $fp) {
|
||||
$label = $fp['description'] ?: ($fp['type'] . ': ' . $fp['value']);
|
||||
$errors[] = $label . ' — ' . $fp['message'];
|
||||
}
|
||||
|
||||
$this->view->json([
|
||||
'error' => 'Permission validation failed',
|
||||
'permission_errors' => $errors,
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
|
||||
$serverModel = new Server();
|
||||
$id = $serverModel->create($input);
|
||||
|
||||
if (!empty($permissions)) {
|
||||
$permModel = new ServerPermission();
|
||||
$permModel->save($id, $permissions);
|
||||
}
|
||||
|
||||
$this->view->json([
|
||||
'success' => true,
|
||||
'message' => 'Server created successfully.',
|
||||
@@ -170,14 +206,70 @@ class ApiController
|
||||
$this->view->json(['error' => 'Forbidden'], 403);
|
||||
}
|
||||
|
||||
$permissions = $this->extractPermissionsFromInput($input);
|
||||
|
||||
if (!empty($permissions)) {
|
||||
$serverConfig = [
|
||||
'ip_address' => $input['ip_address'] ?? $server['ip_address'],
|
||||
'ssh_port' => (int) ($input['ssh_port'] ?? $server['ssh_port']),
|
||||
'ssh_user' => $input['ssh_user'] ?? $server['ssh_user'],
|
||||
'ssh_password' => $input['ssh_password'] ?? $server['ssh_password'],
|
||||
'ssh_key' => $input['ssh_key'] ?? $server['ssh_key'],
|
||||
];
|
||||
|
||||
$permValidator = new PermissionValidator();
|
||||
$permResult = $permValidator->validate($serverConfig, $permissions);
|
||||
|
||||
if (!$permResult['passed']) {
|
||||
$failedPermissions = array_filter($permResult['results'], fn($r) => !$r['passed']);
|
||||
$errors = [];
|
||||
foreach ($failedPermissions as $fp) {
|
||||
$label = $fp['description'] ?: ($fp['type'] . ': ' . $fp['value']);
|
||||
$errors[] = $label . ' — ' . $fp['message'];
|
||||
}
|
||||
|
||||
$this->view->json([
|
||||
'error' => 'Permission validation failed',
|
||||
'permission_errors' => $errors,
|
||||
], 400);
|
||||
}
|
||||
}
|
||||
|
||||
$serverModel->update($id, $input);
|
||||
|
||||
if (!empty($permissions)) {
|
||||
$permModel = new ServerPermission();
|
||||
$permModel->save($id, $permissions);
|
||||
}
|
||||
|
||||
$this->view->json([
|
||||
'success' => true,
|
||||
'message' => 'Server updated successfully.',
|
||||
]);
|
||||
}
|
||||
|
||||
private function extractPermissionsFromInput(array $input): array
|
||||
{
|
||||
$permissions = $input['permissions'] ?? [];
|
||||
|
||||
if (!is_array($permissions)) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$filtered = [];
|
||||
foreach ($permissions as $perm) {
|
||||
if (!empty($perm['type']) && isset($perm['value']) && $perm['value'] !== '') {
|
||||
$filtered[] = [
|
||||
'type' => $perm['type'],
|
||||
'value' => trim($perm['value']),
|
||||
'description' => trim($perm['description'] ?? ''),
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
return $filtered;
|
||||
}
|
||||
|
||||
public function serverDelete(int $id): void
|
||||
{
|
||||
$user = $this->authenticateRequest();
|
||||
|
||||
Reference in New Issue
Block a user