mkellermann97 f8c12d548e v0.9.4 — Network View, Light Mode, Security Hardening
Features:
- Network View in Corporate Layout sidebar (bridges, SDN, per-node VM mapping)
- Custom bind address for reverse proxy on different host (#212)
- OIDC JWT verification toggle for broken JWKS environments
- Corporate Layout light mode improvements
- Language picker dropdown for Corporate Layout (#236)
- Community plugin: proxmox-ha (#226)
- Spanish translations update (#234)

Fixes:
- Cross-cluster replication storage mapping (#192)
- Site recovery stuck plans + race conditions (#238)
- Container/local disk migration with multiple storages
- Guest agent log spam when QEMU agent disabled (#237)
- BG image upload behind reverse proxy (#210)
- Topology diagram layout stability
- PBS cluster filtering (#142)
- Datastore usage mismatch sidebar vs tab (#201)
- Node shell letter-spacing in Corporate Layout
- Chevron icon rotation in Corporate node cards

Security:
- SQL injection whitelist for cluster field updates
- File upload path traversal + null byte hardening
- Cluster credentials endpoint access control
- Error message leak prevention (14 endpoints)
- Permission template fixes (5 undefined permissions)
2026-03-29 22:17:31 +02:00

60 lines
2.1 KiB
Python

"""
Hello World Plugin - Example plugin for PegaProx
Demonstrates how to build a plugin with routes, auth, and PegaProx API access.
All plugin routes are automatically protected by authentication (plugins.view permission).
Plugins can access PegaProx internals: cluster_managers, get_db(), request, etc.
"""
import logging
from flask import request
from pegaprox.api.plugins import register_plugin_route
from pegaprox.globals import cluster_managers
from pegaprox.core.db import get_db
PLUGIN_NAME = "Hello World"
def _get_status():
"""Example route: returns plugin status + connected cluster count"""
# access cluster managers (same API as core PegaProx)
connected = sum(1 for m in cluster_managers.values() if m.is_connected)
total = len(cluster_managers)
# access request context (user info from auth)
user = getattr(request, 'session', {}).get('user', 'unknown')
return {
'plugin': 'hello_world',
'status': 'running',
'message': 'Hello from the plugin system!',
'authenticated_user': user,
'clusters': {'connected': connected, 'total': total}
}
def _get_info():
"""Example route: returns plugin metadata"""
return {
'name': PLUGIN_NAME,
'version': '1.0.0',
'author': 'PegaProx Team',
'description': 'Example plugin demonstrating the PegaProx plugin API',
'available_routes': ['status', 'info'],
'api_docs': {
'status': 'GET /api/plugins/hello_world/api/status — Plugin status + cluster info',
'info': 'GET /api/plugins/hello_world/api/info — Plugin metadata'
}
}
def register(app):
"""Called by PegaProx when the plugin is enabled.
Use register_plugin_route(plugin_id, path, handler) to add API routes.
All routes are auto-prefixed: /api/plugins/{plugin_id}/api/{path}
Authentication is handled automatically (plugins.view permission required).
"""
register_plugin_route('hello_world', 'status', _get_status)
register_plugin_route('hello_world', 'info', _get_info)
logging.info("[PLUGINS] Hello World plugin registered")