#!/usr/bin/env python3 """Audit issue 79's native RLV state, inventory, lock, and permission boundary.""" from __future__ import annotations import json import re from pathlib import Path import generate_api_shims ROOT = Path(__file__).resolve().parents[1] SOURCE = ROOT / "crates" / "libremetaverse-rlv" / "src" / "state.rs" GENERATED = ROOT / "crates" / "libremetaverse-rlv" / "src" / "generated.rs" TESTS = ROOT / "crates" / "libremetaverse-rlv" / "tests" / "state_semantics.rs" COMPAT = ROOT / "tests" / "compat" / "tests" / "rlv_inventory_map_semantics.rs" DOC = ROOT / "crates" / "libremetaverse-rlv" / "README.md" WORKFLOW = ROOT / ".gitea" / "workflows" / "rust-workspace.yml" CATALOG = ROOT / "api" / "public-api.json" STUB_RE = re.compile(r"\b(?:not_implemented|unimplemented_api)\b|\b(?:todo|unimplemented)!\s*\(") TYPES = { "T:LibreMetaverse.RLV.CameraRestrictions": "crate::state::CameraRestrictions", "T:LibreMetaverse.RLV.CameraSettings": "crate::state::CameraSettings", "T:LibreMetaverse.RLV.EventArguments.RestrictionUpdatedEventArgs": "crate::state::RestrictionUpdatedEventArgs", "T:LibreMetaverse.RLV.InventoryMap": "crate::state::InventoryMap", "T:LibreMetaverse.RLV.LockedFolderPublic": "crate::state::LockedFolderPublic", "T:LibreMetaverse.RLV.RlvBlacklist": "crate::state::RlvBlacklist", "T:LibreMetaverse.RLV.RlvInventoryItem": "crate::state::RlvInventoryItem", "T:LibreMetaverse.RLV.RlvPermissionsService": "crate::state::RlvPermissionsService", "T:LibreMetaverse.RLV.RlvRestrictionManager": "crate::state::RlvRestrictionManager", "T:LibreMetaverse.RLV.RlvSharedFolder": "crate::state::RlvSharedFolder", } def require_markers(path: Path, markers: tuple[str, ...]) -> None: text = path.read_text() missing = [marker for marker in markers if marker not in text] if missing: raise SystemExit(f"{path.name}: audit evidence missing: " + ", ".join(missing)) def catalog_members() -> set[str]: catalog = json.loads(CATALOG.read_text()) assembly = next( value for value in catalog["assemblies"] if value["identity"]["name"] == "LibreMetaverse.RLV" ) return { member["doc_id"] for api_type in assembly["types"] if api_type["doc_id"] in TYPES for member in api_type["members"] } def generated_type_block(text: str, doc_id: str) -> str: marker = f"/// C# type: `{doc_id}`." start = text.find(marker) if start < 0: raise SystemExit(f"generated declaration is missing for {doc_id}") next_type = text.find("/// C# type:", start + len(marker)) return text[start:] if next_type < 0 else text[start:next_type] def main() -> None: for api_type, declaration in TYPES.items(): if generate_api_shims.NATIVE_DECLARATIONS.get(api_type) != declaration: raise SystemExit(f"issue 79 native declaration is missing for {api_type}") members = catalog_members() missing = sorted(members - set(generate_api_shims.NATIVE_MEMBER_BODIES)) if missing: raise SystemExit("issue 79 native members missing: " + ", ".join(missing)) source = SOURCE.read_text() if STUB_RE.search(source): raise SystemExit("issue 79 owned Rust stubs remain in state.rs") generated = GENERATED.read_text() for api_type in TYPES: if STUB_RE.search(generated_type_block(generated, api_type)): raise SystemExit(f"issue 79 owned generated stubs remain for {api_type}") require_markers(SOURCE, ( "MAX_RLV_INVENTORY_FOLDERS", "MAX_RLV_INVENTORY_ITEMS", "MAX_RLV_RESTRICTIONS", "pub struct InventoryMap", "pub struct RlvRestrictionManager", "pub struct RlvPermissionsService", "pub struct CameraRestrictions", "pub struct LockedFolderPublic", "pub struct RlvBlacklist", "fn build_locked_folders", "fn secure_allowed", "fn rebuild_locked_folders", "fn emit", "state.revision", "Arc