Some checks failed
Backend Tests / pytest (Python 3.12) (push) Has been cancelled
Deploy to Production / backend-tests (push) Has been cancelled
Deploy to Production / frontend-build (push) Has been cancelled
Frontend Checks / Build & typecheck (push) Has been cancelled
SonarCloud / SonarCloud Analysis (push) Has been cancelled
Deploy to Production / Trigger production update (push) Has been cancelled
Security - Enforce guest ownership and server assignment across Proxmox endpoints (VM/LXC actions, firewall, backups, tasks, bulk operations, deploy, LXC/ISO creation, golden template) and WebSocket channels - Keep the panel's PVE root ticket server-side for consoles; single-use WebSocket tickets instead of the JWT in URLs; re-check access on open WebSocket bridges - Validate identifiers that reach Proxmox API paths and node shell commands; reject backup archives / foreign volumes in create requests - Close privilege escalation in user management, TOTP replay, reset-link poisoning, X-Forwarded-For spoofing, stored XSS (group icons, SVG logos) - SSH host key pinning (TOFU), encrypted 2FA seeds and notification secrets, password changes end other sessions, redact secrets in logs - Quotas count in-flight creations; 2FA failures count toward lockout Fixes - Consoles on non-default API ports, large App Store/script files, interrupted tasks after restart, impersonation lost on token refresh, HTTPExceptions swallowed into 500s, WebSocket client reconnects Performance and process - Fewer DB writes and queries on hot paths, lazy-loaded locales and heavy pages, off-loop blocking work, indexes (migrations 44-46) - Deploy waits for backend tests and frontend build; frontend checks workflow; API bound to loopback without the SSL profile
89 lines
3.0 KiB
Python
89 lines
3.0 KiB
Python
"""sync_vm_cache: upsert from Proxmox, keep ownership, soft-delete vanished guests."""
|
|
from __future__ import annotations
|
|
|
|
from unittest.mock import MagicMock
|
|
|
|
import pytest
|
|
|
|
from app.models import ProxmoxServer, VMInstance
|
|
from app.workers.monitoring_worker import MonitoringWorker
|
|
|
|
|
|
@pytest.fixture
|
|
def server(db_session):
|
|
srv = ProxmoxServer(
|
|
name="pve-sync", hostname="pve-sync.local", ip_address="10.0.0.9", port=8006,
|
|
api_user="root@pam", use_password=True, password="secret", verify_ssl=False,
|
|
is_online=True,
|
|
)
|
|
db_session.add(srv)
|
|
db_session.commit()
|
|
db_session.refresh(srv)
|
|
return srv
|
|
|
|
|
|
def _fake_client(resources):
|
|
client = MagicMock()
|
|
client.is_connected.return_value = True
|
|
client.get_nodes.return_value = [{"node": "pve1"}]
|
|
client.get_cluster_resources.return_value = resources
|
|
client.get_container_interfaces.return_value = []
|
|
return client
|
|
|
|
|
|
def _run_sync(monkeypatch, resources):
|
|
worker = MonitoringWorker()
|
|
client = _fake_client(resources)
|
|
monkeypatch.setattr(worker, "_create_proxmox_client", lambda server: client)
|
|
worker.sync_vm_cache()
|
|
return client
|
|
|
|
|
|
def test_sync_upserts_and_preserves_owner(db_session, server, seed_users, monkeypatch):
|
|
owner = seed_users["user"]
|
|
db_session.add(VMInstance(server_id=server.id, vmid=100, node="pve1", vm_type="qemu",
|
|
name="old-name", status="stopped", owner_id=owner.id))
|
|
db_session.commit()
|
|
|
|
_run_sync(monkeypatch, [
|
|
{"vmid": 100, "type": "qemu", "name": "web", "node": "pve1", "status": "running",
|
|
"maxmem": 2 * 1024 ** 3, "maxdisk": 10 * 1024 ** 3, "maxcpu": 2},
|
|
{"vmid": 200, "type": "lxc", "name": "ct", "node": "pve1", "status": "stopped"},
|
|
])
|
|
|
|
db_session.expire_all()
|
|
rows = {r.vmid: r for r in db_session.query(VMInstance).filter_by(server_id=server.id)}
|
|
assert set(rows) == {100, 200}
|
|
assert rows[100].name == "web" and rows[100].status == "running"
|
|
assert rows[100].owner_id == owner.id
|
|
assert rows[100].memory == 2048
|
|
assert rows[200].vm_type == "lxc"
|
|
|
|
|
|
def test_sync_soft_deletes_vanished_guest(db_session, server, monkeypatch):
|
|
db_session.add(VMInstance(server_id=server.id, vmid=300, node="pve1", vm_type="qemu",
|
|
name="gone", status="running"))
|
|
db_session.commit()
|
|
|
|
_run_sync(monkeypatch, [{"vmid": 301, "type": "qemu", "name": "stays", "node": "pve1",
|
|
"status": "running"}])
|
|
|
|
db_session.expire_all()
|
|
gone = db_session.query(VMInstance).filter_by(server_id=server.id, vmid=300).one()
|
|
assert gone.deleted_at is not None
|
|
|
|
|
|
def test_sync_creates_client_once_per_server(db_session, server, monkeypatch):
|
|
worker = MonitoringWorker()
|
|
client = _fake_client([])
|
|
created = []
|
|
|
|
def _create(srv):
|
|
created.append(srv.id)
|
|
return client
|
|
|
|
monkeypatch.setattr(worker, "_create_proxmox_client", _create)
|
|
worker.sync_vm_cache()
|
|
|
|
assert created == [server.id]
|