Browse Source

fix: pin guided import root directory

master
Codex 2 months ago
parent
commit
ce96ff2720
  1. 100
      ingestion/guided_imports.py
  2. 91
      tests/test_guided_import_discovery.py

100
ingestion/guided_imports.py

@ -25,6 +25,15 @@ _PROFILES_BY_SUFFIX = {
".txt": ("OUROCARD_FULL_V1", "OUROCARD_PARTIAL_V1"),
}
_SUPPORTS_SAFE_DIRECTORY_FDS = (
os.name == "posix"
and os.open in os.supports_dir_fd
and os.stat in os.supports_dir_fd
and os.listdir in os.supports_fd
and hasattr(os, "O_DIRECTORY")
and hasattr(os, "O_NOFOLLOW")
)
def _profile_and_sections(path: Path, data: bytes) -> tuple[str | None, tuple[str, ...]]:
for profile in _PROFILES_BY_SUFFIX.get(path.suffix.casefold(), ()):
@ -38,53 +47,90 @@ def _profile_and_sections(path: Path, data: bytes) -> tuple[str | None, tuple[st
return None, ()
def _unreadable(path: Path) -> DiscoveredFile:
return DiscoveredFile(path.name, "", None, (), "UNREADABLE_FILE")
def _unreadable(name: str) -> DiscoveredFile:
return DiscoveredFile(name, "", None, (), "UNREADABLE_FILE")
def _close(descriptor: int | None) -> None:
if descriptor is not None:
try:
os.close(descriptor)
except OSError:
pass
def _open_import_root() -> int | None:
if not _SUPPORTS_SAFE_DIRECTORY_FDS:
return None
try:
root = os.path.normpath(os.fspath(settings.IMPORT_ROOT))
if not os.path.isabs(root):
root = os.path.abspath(root)
path = Path(root)
descriptor = os.open(path.anchor, os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW)
for component in path.parts[1:]:
next_descriptor = os.open(
component,
os.O_RDONLY | os.O_DIRECTORY | os.O_NOFOLLOW,
dir_fd=descriptor,
)
_close(descriptor)
descriptor = next_descriptor
if not stat.S_ISDIR(os.fstat(descriptor).st_mode):
_close(descriptor)
return None
return descriptor
except (OSError, RuntimeError, TypeError, ValueError):
_close(locals().get("descriptor"))
return None
def _read_discovered_file(path: Path, expected: os.stat_result) -> DiscoveredFile:
def _read_discovered_file(name: str, root_descriptor: int, expected: os.stat_result) -> DiscoveredFile:
descriptor = None
try:
flags = os.O_RDONLY | getattr(os, "O_BINARY", 0)
if no_follow := getattr(os, "O_NOFOLLOW", 0):
flags |= no_follow
descriptor = os.open(path, flags)
descriptor = os.open(name, flags, dir_fd=root_descriptor)
opened = os.fstat(descriptor)
if not stat.S_ISREG(opened.st_mode) or not os.path.samestat(expected, opened):
return _unreadable(path)
return _unreadable(name)
with os.fdopen(descriptor, "rb", closefd=False) as stream:
data = stream.read(MAX_BYTES + 1)
except OSError:
return _unreadable(path)
return _unreadable(name)
finally:
if descriptor is not None:
os.close(descriptor)
_close(descriptor)
if len(data) > MAX_BYTES:
return DiscoveredFile(path.name, "", None, (), "INPUT_TOO_LARGE")
return DiscoveredFile(name, "", None, (), "INPUT_TOO_LARGE")
document_hash = sha256(data).hexdigest()
if path.suffix.casefold() not in _PROFILES_BY_SUFFIX:
return DiscoveredFile(path.name, document_hash, None, (), "UNSUPPORTED_FILE")
profile, sections = _profile_and_sections(path, data)
if Path(name).suffix.casefold() not in _PROFILES_BY_SUFFIX:
return DiscoveredFile(name, document_hash, None, (), "UNSUPPORTED_FILE")
profile, sections = _profile_and_sections(Path(name), data)
if profile is None:
return DiscoveredFile(path.name, document_hash, None, (), "UNRECOGNIZED_LAYOUT")
return DiscoveredFile(path.name, document_hash, profile, sections, None)
return DiscoveredFile(name, document_hash, None, (), "UNRECOGNIZED_LAYOUT")
return DiscoveredFile(name, document_hash, profile, sections, None)
def discover_imports() -> tuple[DiscoveredFile, ...]:
"""Return safe metadata for direct regular files under ``IMPORT_ROOT``."""
try:
root = Path(settings.IMPORT_ROOT).resolve()
entries = tuple(root.iterdir())
except (OSError, RuntimeError):
root_descriptor = _open_import_root()
if root_descriptor is None:
return ()
discovered = []
for path in entries:
try:
try:
expected = path.lstat()
if not stat.S_ISREG(expected.st_mode):
continue
entries = os.listdir(root_descriptor)
except OSError:
discovered.append(_unreadable(path))
continue
discovered.append(_read_discovered_file(path, expected))
return tuple(sorted(discovered, key=lambda row: row.name))
return ()
discovered = []
for name in entries:
try:
expected = os.stat(name, dir_fd=root_descriptor, follow_symlinks=False)
except OSError:
discovered.append(_unreadable(name))
continue
if stat.S_ISREG(expected.st_mode):
discovered.append(_read_discovered_file(name, root_descriptor, expected))
return tuple(sorted(discovered, key=lambda row: row.name))
finally:
_close(root_descriptor)

91
tests/test_guided_import_discovery.py

@ -75,7 +75,7 @@ def test_discovery_marks_a_post_listing_symlink_replacement_unreadable(tmp_path,
def replace_then_open(value, flags, *args, **kwargs):
nonlocal replaced
if not replaced and Path(value) == candidate:
if not replaced and (value == candidate.name or Path(value) == candidate):
replaced = True
candidate.unlink()
candidate.symlink_to(replacement)
@ -96,32 +96,87 @@ def test_discovery_marks_a_post_listing_symlink_replacement_unreadable(tmp_path,
def test_discovery_returns_empty_results_when_listing_the_import_root_fails(tmp_path, monkeypatch):
root = tmp_path / "unavailable"
root.mkdir()
original_iterdir = Path.iterdir
bank = HEADER + b"01/02/2026,,SYNTHETIC BANK ROW,,,12.34\n"
(root / "bank.csv").write_bytes(bank)
original_listdir = os.listdir
def delayed_failure(self):
if self == root.resolve():
def entries():
raise OSError("SYNTHETIC LISTING FAILURE")
yield
return entries()
return original_iterdir(self)
def delayed_failure(value):
if isinstance(value, int):
raise OSError("SYNTHETIC LISTING FAILURE")
return original_listdir(value)
monkeypatch.setattr(Path, "iterdir", delayed_failure)
monkeypatch.setattr(guided_imports.os, "listdir", delayed_failure)
with override_settings(IMPORT_ROOT=root):
assert discover_imports() == ()
def test_discovery_returns_empty_results_when_resolving_the_import_root_fails(tmp_path, monkeypatch):
root = tmp_path / "unresolvable"
original_resolve = Path.resolve
def test_discovery_returns_empty_results_when_opening_the_import_root_fails(tmp_path, monkeypatch):
root = tmp_path / "unopenable"
root.mkdir()
(root / "bank.csv").write_bytes(HEADER + b"01/02/2026,,SYNTHETIC BANK ROW,,,12.34\n")
original_open = os.open
def resolution_failure(self, *args, **kwargs):
if self == root:
raise RuntimeError("SYNTHETIC RESOLUTION FAILURE")
return original_resolve(self, *args, **kwargs)
def root_open_failure(value, flags, *args, **kwargs):
if value == os.path.sep:
raise OSError("SYNTHETIC ROOT OPEN FAILURE")
return original_open(value, flags, *args, **kwargs)
monkeypatch.setattr(Path, "resolve", resolution_failure)
monkeypatch.setattr(guided_imports.os, "open", root_open_failure)
with override_settings(IMPORT_ROOT=root):
assert discover_imports() == ()
def test_discovery_keeps_using_the_opened_root_after_the_root_path_is_replaced(tmp_path, monkeypatch):
root = tmp_path / "imports"
outside = tmp_path / "outside"
parked_root = tmp_path / "parked-imports"
root.mkdir()
outside.mkdir()
inside = HEADER + b"01/02/2026,,SYNTHETIC INSIDE ROW,,,12.34\n"
external = HEADER + b"01/02/2026,,SYNTHETIC EXTERNAL ROW,,,98.76\n"
(root / "bank.csv").write_bytes(inside)
(outside / "bank.csv").write_bytes(external)
original_iterdir = Path.iterdir
original_listdir = os.listdir
replaced = False
def replace_root():
nonlocal replaced
if not replaced:
replaced = True
root.rename(parked_root)
root.symlink_to(outside, target_is_directory=True)
def replace_then_iterdir(self):
if self == root.resolve():
replace_root()
return original_iterdir(self)
def replace_then_listdir(value):
if isinstance(value, int):
replace_root()
return original_listdir(value)
monkeypatch.setattr(Path, "iterdir", replace_then_iterdir)
monkeypatch.setattr(guided_imports.os, "listdir", replace_then_listdir)
with override_settings(IMPORT_ROOT=root):
rows = discover_imports()
assert [(row.name, row.document_hash, row.profile, row.code) for row in rows] == [
("bank.csv", sha256(inside).hexdigest(), "BANK_CSV_V1", None),
]
def test_discovery_fails_closed_for_a_symlinked_import_root_parent(tmp_path):
actual_parent = tmp_path / "actual-parent"
root = actual_parent / "imports"
linked_parent = tmp_path / "linked-parent"
root.mkdir(parents=True)
(root / "bank.csv").write_bytes(HEADER + b"01/02/2026,,SYNTHETIC BANK ROW,,,12.34\n")
linked_parent.symlink_to(actual_parent, target_is_directory=True)
with override_settings(IMPORT_ROOT=linked_parent / "imports"):
assert discover_imports() == ()

Loading…
Cancel
Save