refactor review-plan safety and validation
This commit is contained in:
+70
-20
@@ -108,7 +108,25 @@ class ExecutionEngine:
|
||||
# Execute all operations
|
||||
results = []
|
||||
for i, operation in enumerate(plan.operations):
|
||||
result = self.execute_operation(operation, mode)
|
||||
try:
|
||||
result = self.execute_operation(operation, mode)
|
||||
except Exception as exc: # pragma: no cover - defensive containment
|
||||
error_msg = (
|
||||
f"Unexpected failure during {operation.operation_type}: {exc}"
|
||||
)
|
||||
self.logger.exception(
|
||||
error_msg,
|
||||
extra={
|
||||
"operation_type": "execute",
|
||||
"file_path": f" - {operation.source_path}",
|
||||
},
|
||||
)
|
||||
result = OperationResult(
|
||||
operation=operation,
|
||||
success=False,
|
||||
error_message=error_msg,
|
||||
executed_at=utc_now(),
|
||||
)
|
||||
results.append(result)
|
||||
|
||||
# Update transaction and state logs in execute mode
|
||||
@@ -183,6 +201,53 @@ class ExecutionEngine:
|
||||
|
||||
return results, summary, rollback_log
|
||||
|
||||
def _validate_library_root_boundaries(
|
||||
self,
|
||||
operation: FileOperation,
|
||||
executed_at: datetime,
|
||||
) -> OperationResult | None:
|
||||
"""Reject move/rename operations that escape the configured library root."""
|
||||
if not self.config or operation.operation_type not in ("move", "rename"):
|
||||
return None
|
||||
|
||||
if not is_within_root(operation.source_path, self.config.library_root):
|
||||
error_msg = f"Unsafe source outside library root: {operation.source_path}"
|
||||
log_operation(
|
||||
self.logger,
|
||||
logging.ERROR,
|
||||
error_msg,
|
||||
operation_type="execute",
|
||||
file_path=operation.source_path,
|
||||
)
|
||||
return OperationResult(
|
||||
operation=operation,
|
||||
success=False,
|
||||
error_message=error_msg,
|
||||
executed_at=executed_at,
|
||||
)
|
||||
|
||||
if operation.destination_path and not is_within_root(
|
||||
operation.destination_path, self.config.library_root
|
||||
):
|
||||
error_msg = (
|
||||
f"Unsafe destination outside library root: {operation.destination_path}"
|
||||
)
|
||||
log_operation(
|
||||
self.logger,
|
||||
logging.ERROR,
|
||||
error_msg,
|
||||
operation_type="execute",
|
||||
file_path=operation.source_path,
|
||||
)
|
||||
return OperationResult(
|
||||
operation=operation,
|
||||
success=False,
|
||||
error_message=error_msg,
|
||||
executed_at=executed_at,
|
||||
)
|
||||
|
||||
return None
|
||||
|
||||
def execute_operation(
|
||||
self,
|
||||
operation: FileOperation,
|
||||
@@ -277,6 +342,10 @@ class ExecutionEngine:
|
||||
executed_at=executed_at
|
||||
)
|
||||
|
||||
boundary_error = self._validate_library_root_boundaries(operation, executed_at)
|
||||
if boundary_error is not None:
|
||||
return boundary_error
|
||||
|
||||
# Execute based on mode
|
||||
if mode == "dry-run":
|
||||
return self._simulate_operation(operation, executed_at)
|
||||
@@ -352,25 +421,6 @@ class ExecutionEngine:
|
||||
|
||||
# Create destination directory if needed
|
||||
if operation.destination_path:
|
||||
if self.config and not is_within_root(
|
||||
operation.destination_path, self.config.library_root
|
||||
):
|
||||
error_msg = (
|
||||
f"Unsafe destination outside library root: {operation.destination_path}"
|
||||
)
|
||||
log_operation(
|
||||
self.logger,
|
||||
logging.ERROR,
|
||||
error_msg,
|
||||
operation_type="execute",
|
||||
file_path=operation.source_path
|
||||
)
|
||||
return OperationResult(
|
||||
operation=operation,
|
||||
success=False,
|
||||
error_message=error_msg,
|
||||
executed_at=executed_at
|
||||
)
|
||||
operation.destination_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
# Perform the move/rename operation
|
||||
|
||||
Reference in New Issue
Block a user