| |
| """ |
| utils/security.py |
| Políticas de escrita/leitura do projeto HASHIRU 6.1 centralizadas. |
| |
| APIs: |
| - is_write_path_allowed(path: str | Path) -> bool |
| - assert_write_allowed(path: Path) -> None (lança PermissionError) |
| - project_root() -> Path |
| |
| Regras: |
| - Restringe escrita a diretórios whitelisted. |
| - Bloqueia extensões perigosas e diretórios negados. |
| - Nunca permite escapar da raiz do projeto. |
| """ |
|
|
| from __future__ import annotations |
|
|
| import os |
| from pathlib import Path |
| from typing import Iterable, Union |
|
|
| PathLike = Union[str, Path] |
|
|
| |
| def project_root() -> Path: |
| return Path(__file__).resolve().parents[1] |
|
|
| |
| SELF_MODIFICATION = { |
| "enabled": True, |
| "auto_backup": False, |
| } |
|
|
| SECURITY_POLICY = { |
| "ALLOWED_WRITE_DIRS": [ |
| ".", "tools", "utils", "scripts", "artifacts" |
| ], |
| "DENIED_DIRS": [ |
| ".git", "backups", "__pycache__", "hashiru_6_env", |
| "venv", ".venv", "node_modules", "dist", "build", |
| ], |
| "DENIED_EXTS": [".bat", ".cmd", ".ps1", ".exe", ".dll"], |
| } |
|
|
| def _is_within(parent: Path, child: Path) -> bool: |
| try: |
| child.relative_to(parent) |
| return True |
| except Exception: |
| return False |
|
|
| def _first_path_component(rel_path: Path) -> str: |
| parts = rel_path.parts |
| if not parts: |
| return "." |
| return parts[0] |
|
|
| def is_write_path_allowed(target_path: PathLike) -> bool: |
| root = project_root() |
| abs_target = (root / Path(target_path)).resolve() |
|
|
| |
| if not _is_within(root, abs_target): |
| return False |
|
|
| |
| if abs_target.suffix.lower() in (SECURITY_POLICY.get("DENIED_EXTS") or []): |
| return False |
|
|
| |
| rel = abs_target.relative_to(root) |
| first = _first_path_component(rel) |
| if first in set(SECURITY_POLICY.get("DENIED_DIRS") or []): |
| return False |
|
|
| |
| allowed = set(SECURITY_POLICY.get("ALLOWED_WRITE_DIRS") or []) |
| return first in allowed |
|
|
| def assert_write_allowed(target_path: PathLike) -> None: |
| if not is_write_path_allowed(target_path): |
| raise PermissionError(f"Política de segurança: escrita negada em '{target_path}'.") |
|
|