mirror of
https://github.com/philippemerle/KubeDiagrams.git
synced 2026-05-06 09:06:33 +00:00
183 lines
5.2 KiB
Python
183 lines
5.2 KiB
Python
"""Validation of user inputs."""
|
|
import re
|
|
from typing import Optional, Tuple
|
|
from constants import MANIFEST_RE, KIND_RE
|
|
|
|
|
|
class ValidationError(Exception):
|
|
"""Exception error validation."""
|
|
pass
|
|
|
|
|
|
class InputValidator:
|
|
"""Validator for user inputs."""
|
|
|
|
SUPPORTED_FORMATS = ['png', 'jpg', 'jpeg', 'gif', 'svg', 'pdf', 'dot', 'dot_json']
|
|
|
|
# Valid Pattern for url
|
|
HELM_URL_PATTERN = re.compile(
|
|
r'^(https?://|oci://|file://|[a-zA-Z0-9\-_]+/[a-zA-Z0-9\-_]+)'
|
|
)
|
|
|
|
@classmethod
|
|
def validate_manifest(cls, content: str) -> Tuple[bool, Optional[str]]:
|
|
"""
|
|
Validate a Kubernetes manifest content.
|
|
|
|
Args:
|
|
content: Manifest content
|
|
|
|
Returns:
|
|
Tuple[bool, Optional[str]]: (is_valid, error_message)
|
|
"""
|
|
if not content or not content.strip():
|
|
return False, "Manifest content cannot be empty."
|
|
|
|
# Verify minimum length
|
|
if len(content.strip()) < 10:
|
|
return False, "Manifest content is too short."
|
|
|
|
# Verify it looks like a manifest K8s
|
|
if not cls.looks_like_manifest(content):
|
|
return False, "Content does not appear to be a valid Kubernetes manifest (missing apiVersion or kind)."
|
|
|
|
return True, None
|
|
|
|
@classmethod
|
|
def validate_helmfile(cls, content: str) -> Tuple[bool, Optional[str]]:
|
|
"""
|
|
Validate a Helmfile content.
|
|
|
|
Args:
|
|
content: Content of a Helmfile
|
|
|
|
Returns:
|
|
Tuple[bool, Optional[str]]: (is_valid, error_message)
|
|
"""
|
|
if not content or not content.strip():
|
|
return False, "Helmfile content cannot be empty."
|
|
|
|
if len(content.strip()) < 10:
|
|
return False, "Helmfile content is too short."
|
|
|
|
# Verify it looks like a Helmfile
|
|
if not cls.looks_like_helmfile(content):
|
|
return False, "Content does not appear to be a valid Helmfile (missing typical Helmfile keys)."
|
|
|
|
return True, None
|
|
|
|
@classmethod
|
|
def validate_helm_chart_url(cls, url: str) -> Tuple[bool, Optional[str]]:
|
|
"""
|
|
Validate a Helm chart URL.
|
|
|
|
Args:
|
|
url: URL of the Helm chart
|
|
|
|
Returns:
|
|
Tuple[bool, Optional[str]]: (est_valide, message_erreur)
|
|
"""
|
|
if not url or not url.strip():
|
|
return False, "Chart URL cannot be empty."
|
|
|
|
url = url.strip()
|
|
|
|
# Verify the helm url pattern
|
|
if not cls.HELM_URL_PATTERN.match(url):
|
|
return False, "Invalid Helm chart URL format. Must start with http://, https://, oci://, file://, or be a chart reference."
|
|
|
|
return True, None
|
|
|
|
@classmethod
|
|
def validate_output_format(cls, format_str: str) -> Tuple[bool, Optional[str]]:
|
|
"""
|
|
Validate output format.
|
|
|
|
Args:
|
|
format_str: output format
|
|
|
|
Returns:
|
|
Tuple[bool, Optional[str]]: (is_valid, error_message)
|
|
"""
|
|
if not format_str:
|
|
return False, "Output format cannot be empty."
|
|
|
|
format_str = format_str.lower().strip()
|
|
|
|
if format_str not in cls.SUPPORTED_FORMATS:
|
|
return False, f"Unsupported output format '{format_str}'. Supported formats: {', '.join(cls.SUPPORTED_FORMATS)}"
|
|
|
|
return True, None
|
|
|
|
@classmethod
|
|
def validate_extra_args(cls, args: str) -> Tuple[bool, Optional[str]]:
|
|
"""
|
|
Validate extra args.
|
|
|
|
Args:
|
|
args: extra_args
|
|
|
|
Returns:
|
|
Tuple[bool, Optional[str]]: (is_valid, error_message)
|
|
"""
|
|
if not args or not args.strip():
|
|
return True, None # Les args vides sont valides
|
|
|
|
dangerous_chars = [';', '&', '|', '`', '$', '(', ')']
|
|
for char in dangerous_chars:
|
|
if char in args:
|
|
return False, f"Extra args contain dangerous character '{char}'"
|
|
|
|
return True, None
|
|
|
|
@staticmethod
|
|
def looks_like_manifest(text: str) -> bool:
|
|
"""
|
|
Heuristic to detect a Kubernetes manifest.
|
|
|
|
Args:
|
|
text: content that will be checked
|
|
|
|
Returns:
|
|
bool: True if it looks like a manifest
|
|
"""
|
|
if not text:
|
|
return False
|
|
t = text.strip()
|
|
return bool(MANIFEST_RE.search(t) and KIND_RE.search(t))
|
|
|
|
@staticmethod
|
|
def looks_like_helmfile(text: str) -> bool:
|
|
"""
|
|
Heuristic to detect a HelmFile.
|
|
|
|
Args:
|
|
text: Content that will be checked.
|
|
|
|
Returns:
|
|
bool: True if it looks like a Helmfile
|
|
"""
|
|
if not text:
|
|
return False
|
|
t = text.lower()
|
|
helmfile_keys = ["\nreleases:", "\nrepositories:", "\nhelmdefaults:", "\nenvironments:", "\ntemplates:"]
|
|
return any(key in t for key in helmfile_keys)
|
|
|
|
# TODO: Not used yet
|
|
@classmethod
|
|
def sanitize_filename(cls, filename: str) -> str:
|
|
"""
|
|
Clean a filename to make it safe.
|
|
|
|
Args:
|
|
filename: Filename to clean
|
|
|
|
Returns:
|
|
str: Filename cleaned
|
|
"""
|
|
safe_filename = re.sub(r'[^a-zA-Z0-9._-]', '_', filename)
|
|
# Length limit
|
|
if len(safe_filename) > 255:
|
|
safe_filename = safe_filename[:255]
|
|
return safe_filename
|