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:
2026-06-13 10:41:18 -04:00
parent 8f3b5bd7ce
commit 0cfed5bf27
10 changed files with 689 additions and 24 deletions

View File

@@ -0,0 +1,58 @@
<?php
declare(strict_types=1);
namespace ServerManager\Models;
use ServerManager\Core\Database;
class ServerPermission
{
private Database $db;
public function __construct()
{
$this->db = Database::getInstance();
}
public function save(int $serverId, array $permissions): void
{
$this->deleteByServerId($serverId);
foreach ($permissions as $perm) {
if (empty($perm['type']) || !isset($perm['value'])) {
continue;
}
$this->db->insert('server_permissions', [
'server_id' => $serverId,
'permission_type' => $perm['type'],
'permission_value' => $perm['value'],
'description' => $perm['description'] ?? null,
'created_at' => date('Y-m-d H:i:s'),
]);
}
}
public function getByServerId(int $serverId): array
{
return $this->db->fetchAll(
'SELECT * FROM server_permissions WHERE server_id = ? ORDER BY id ASC',
[$serverId]
);
}
public function deleteByServerId(int $serverId): void
{
$this->db->delete('server_permissions', 'server_id = ?', [$serverId]);
}
public static function formatForValidation(array $permissions): array
{
return array_map(fn($p) => [
'type' => $p['permission_type'],
'value' => $p['permission_value'],
'description' => $p['description'] ?? '',
], $permissions);
}
}