fix: verify raw source bytes and bound reads after file changes

This commit is contained in:
emil28092005
2026-09-16 04:02:10 +03:00
parent ba24db2be5
commit 1ac263b678
4 changed files with 42 additions and 6 deletions
+3 -3
View File
@@ -12,7 +12,7 @@ from typing import TYPE_CHECKING
import numpy as np
from micro_scout.symbols import Symbol, build_edges, parse_source, source_paths
from micro_scout.symbols import Symbol, build_edges, parse_source, read_source, source_paths
from micro_scout.text import digest
if TYPE_CHECKING:
@@ -68,8 +68,8 @@ def build_index(
for path in source_paths(root):
relative = path.relative_to(root).as_posix()
try:
text = path.read_text(encoding="utf-8")
except (UnicodeError, OSError) as exc:
text = read_source(path)
except (ValueError, OSError) as exc:
warnings.append({"path": relative, "reason": type(exc).__name__})
continue
files[relative] = digest(text)
+2 -2
View File
@@ -13,7 +13,7 @@ import numpy as np
from micro_scout.index import Index
from micro_scout.lexical import BM25, reciprocal_rank_fusion, top_indices
from micro_scout.symbols import EXTENSIONS, Symbol
from micro_scout.symbols import EXTENSIONS, Symbol, read_source
from micro_scout.text import digest
if TYPE_CHECKING:
@@ -55,7 +55,7 @@ class Scout:
)
):
raise ValueError("Source path escapes repository or uses a symlink")
text = path.read_text(encoding="utf-8")
text = read_source(path)
except (OSError, UnicodeError) as exc:
raise StaleReferenceError(
f"Source unavailable: {symbol.path}; rebuild index"
+11 -1
View File
@@ -44,6 +44,16 @@ EXCLUDED = {
".mypy_cache",
".pytest_cache",
}
MAX_FILE_BYTES = 1_000_000
def read_source(path: Path, max_bytes: int = MAX_FILE_BYTES) -> str:
"""Read bounded UTF-8 without newline translation, so SHA-256 matches file bytes."""
with path.open("rb") as stream:
raw = stream.read(max_bytes + 1)
if len(raw) > max_bytes:
raise ValueError("Source exceeds the file-size limit")
return raw.decode("utf-8")
@dataclass(frozen=True)
@@ -71,7 +81,7 @@ class Symbol:
return asdict(self)
def source_paths(root: Path, max_file_bytes: int = 1_000_000) -> list[Path]:
def source_paths(root: Path, max_file_bytes: int = MAX_FILE_BYTES) -> list[Path]:
"""Honor gitignore when available; never traverse symlinks or hidden trees."""
root = root.resolve(strict=True)
if not root.is_dir():