Spaces:
Running
Running
File size: 3,938 Bytes
e526aa8 76e192b e526aa8 76e192b e526aa8 76e192b e526aa8 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 | 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
|