Protect manifest artifacts in RC10 audit
GeoIntel release gates / Compile, test, contracts and builds (push) Canceled after 0s
GeoIntel release gates / Python and npm vulnerability policy (push) Canceled after 0s
GeoIntel release gates / GIS image, SBOM and container scan (push) Canceled after 0s

This commit is contained in:
Codex
2026-07-18 07:15:40 +02:00
parent 6438bd418b
commit bb38d8a6a3
3 changed files with 75 additions and 5 deletions
+34 -3
View File
@@ -165,6 +165,33 @@ def normalize_storage_reference(value: str | None, storage_root: Path) -> Path |
return resolved
def expand_manifest_references(references: set[Path], storage_root: Path) -> set[Path]:
"""Protect files named by referenced, bounded JSON manifests."""
root = storage_root.resolve()
expanded = set(references)
for manifest in list(references):
if manifest.suffix.lower() != ".json" or not manifest.is_file():
continue
try:
if manifest.stat().st_size > 16 * 1024 * 1024:
continue
payload = json.loads(manifest.read_text(encoding="utf-8"))
except (OSError, UnicodeDecodeError, json.JSONDecodeError):
continue
for value in _iter_strings(payload):
normalized = normalize_storage_reference(value, root)
if normalized is None and "://" not in value:
try:
relative = (manifest.parent / value).resolve()
relative.relative_to(root)
except (OSError, ValueError):
continue
normalized = relative
if normalized is not None:
expanded.add(normalized)
return expanded
def _add_row_references(target: set[Path], row: Any, storage_root: Path, direct_fields: Iterable[str]) -> None:
for field in direct_fields:
normalized = normalize_storage_reference(getattr(row, field, None), storage_root)
@@ -327,9 +354,11 @@ def collect_database_state(db: Any, storage_root: Path) -> dict[str, Any]:
def disk_pressure(storage_root: Path) -> dict[str, Any]:
usage = shutil.disk_usage(storage_root)
free_percent = (usage.free / usage.total * 100) if usage.total else 0.0
if usage.free < 10 * 1024**3 or free_percent < 5:
# Absolute headroom governs very large Unraid arrays: a low percentage of
# tens of terabytes can still leave hundreds of GiB safely available.
if usage.free < 10 * 1024**3:
status = "critical"
elif usage.free < 25 * 1024**3 or free_percent < 10:
elif usage.free < 50 * 1024**3 or (free_percent < 2 and usage.free < 250 * 1024**3):
status = "warning"
else:
status = "ok"
@@ -357,7 +386,7 @@ def build_report(
raise RuntimeError(f"Storage root is not a directory: {root}")
records, skipped_symlinks = inventory_storage(root)
database = collect_database_state(db, root)
references: set[Path] = database.pop("references")
references: set[Path] = expand_manifest_references(database.pop("references"), root)
cutoff = utc_now() - timedelta(days=minimum_age_days)
categories: dict[str, dict[str, Any]] = defaultdict(
@@ -376,12 +405,14 @@ def build_report(
for path in references
if path not in existing_paths and not path.is_dir()
)
referenced_directories = tuple(path for path in references if path.is_dir())
candidates = sorted(
(
record
for record in records
if record.cleanup_eligible
and record.path not in references
and not any(record.path.is_relative_to(reference) for reference in referenced_directories)
and record.modified_at <= cutoff
and record.path.name not in IGNORED_FILENAMES
),