Pedro
defining routes, improving graph and other work related to tester node
76e192b
Raw
History Blame Contribute Delete
3.94 kB
from multi_agent_sdlc.runtime.paths import normalise_relative_path
from multi_agent_sdlc.tools.coder.validation import MODULE_PATTERN
from collections.abc import Callable
from packaging.requirements import InvalidRequirement, Requirement
from packaging.utils import canonicalize_name
def validate_application_arguments(
arguments: list[str],
) -> list[str]:
"""Validate arguments passed to an application or module."""
validated: list[str] = []
for argument in arguments:
if not isinstance(argument, str):
raise TypeError("Every application argument must be a string.")
if "\n" in argument or "\r" in argument:
raise PermissionError("Multiline application arguments are not allowed.")
if "\x00" in argument:
raise PermissionError(
"Null bytes are not allowed in application arguments."
)
validated.append(argument)
return validated
def validate_project_relative_path(path: str) -> str:
candidate = normalise_relative_path(path.strip())
return candidate.as_posix()
def validate_file_content(content: str) -> str:
if "\x00" in content:
raise ValueError("File content cannot contain null bytes.")
return content
def create_entry_point_validator(
role: str,
prohibited_entry_points: set[str],
) -> Callable[[str], str]:
def validate_entry_point(entry_point: str) -> str:
cleaned = entry_point.strip()
if not cleaned:
raise ValueError("Entry point cannot be empty.")
if cleaned.casefold() in prohibited_entry_points:
raise ValueError(f"The {role} cannot execute {cleaned}.")
return cleaned
return validate_entry_point
def create_module_name_validator(
role: str,
prohibited_python_modules: set[str],
) -> Callable[[str], str]:
def validate_module_name(module: str) -> str:
cleaned = module.strip()
if not cleaned:
raise ValueError("Module cannot be empty.")
if not MODULE_PATTERN.fullmatch(cleaned):
raise ValueError(f"Invalid Python module name: {cleaned}")
root_module = cleaned.split(".", maxsplit=1)[0].lower()
if root_module in prohibited_python_modules:
raise PermissionError(
f"The {role} cannot execute Python module `{cleaned}`."
)
return cleaned
return validate_module_name
def create_testing_dependency_validator(
role: str,
prohibited_tester_dependencies: set[str],
) -> Callable[[str], str]:
canonical_prohibited_dependencies = set(
canonicalize_name(name) for name in prohibited_tester_dependencies
)
def validate_testing_dependency(
dependency: str,
) -> str:
cleaned = dependency.strip()
if not cleaned:
raise ValueError("Dependency specification cannot be empty.")
if cleaned.startswith("-"):
raise PermissionError(
"Dependency command-line options are not allowed: " f"{cleaned!r}."
)
requirement = parse_dependency(cleaned)
if requirement.url is not None:
raise PermissionError(
"Git, URL, SSH, and local-file dependencies are not "
f"allowed: {cleaned!r}."
)
dependency_name = canonicalize_name(requirement.name)
if dependency_name in canonical_prohibited_dependencies:
raise PermissionError(f"The {role} cannot add dependency {cleaned!r}.")
return cleaned
return validate_testing_dependency
def parse_dependency(
specification: str,
) -> Requirement:
"""Parse a Python dependency specification."""
try:
return Requirement(specification)
except InvalidRequirement as error:
raise ValueError(
f"Invalid dependency specification: {specification!r}."
) from error