#!/usr/bin/env python3 """Audit issue 62's native UDP inventory-manager boundary.""" from __future__ import annotations from pathlib import Path import re import generate_api_shims ROOT = Path(__file__).resolve().parents[1] SOURCE = ROOT / "crates" / "libremetaverse" / "src" / "inventory_manager.rs" DOC = ROOT / "docs" / "inventory.md" MANAGER_TESTS = ROOT / "tests" / "compat" / "tests" / "inventory_manager_semantics.rs" TASK_TESTS = ROOT / "tests" / "compat" / "tests" / "task_inventory_semantics.rs" STUB_RE = re.compile(r"\b(?:not_implemented|unimplemented_api)\b|\b(?:todo|unimplemented)!\s*\(") REQUIRED_TYPES = { "T:LibreMetaverse.FindObjectByPathReplyEventArgs", "T:LibreMetaverse.FolderUpdatedEventArgs", "T:LibreMetaverse.InventoryManager", "T:LibreMetaverse.InventoryManager.CopyItemsResult", "T:LibreMetaverse.InventoryManager.FolderUpdateResult", "T:LibreMetaverse.InventoryObjectOfferedEventArgs", "T:LibreMetaverse.ItemReceivedEventArgs", "T:LibreMetaverse.SaveAssetToInventoryEventArgs", "T:LibreMetaverse.ScriptRunningReplyEventArgs", "T:LibreMetaverse.TaskInventoryReplyEventArgs", "T:LibreMetaverse.TaskItemReceivedEventArgs", } REQUIRED_MEMBERS = { "E:LibreMetaverse.InventoryManager.FindObjectByPathReply", "E:LibreMetaverse.InventoryManager.FolderUpdated", "E:LibreMetaverse.InventoryManager.InventoryObjectOffered", "E:LibreMetaverse.InventoryManager.ItemReceived", "E:LibreMetaverse.InventoryManager.ScriptRunningReply", "E:LibreMetaverse.InventoryManager.TaskInventoryReply", "E:LibreMetaverse.InventoryManager.TaskItemReceived", "M:LibreMetaverse.InventoryManager.#ctor(LibreMetaverse.GridClient)", "M:LibreMetaverse.InventoryManager.CreateFolder(LibreMetaverse.UUID,System.String,LibreMetaverse.FolderType)", "M:LibreMetaverse.InventoryManager.CreateItemAsync(LibreMetaverse.UUID,System.String,System.String,LibreMetaverse.AssetType,LibreMetaverse.UUID,LibreMetaverse.InventoryType,LibreMetaverse.WearableType,LibreMetaverse.PermissionMask,System.Threading.CancellationToken)", "M:LibreMetaverse.InventoryManager.CreateLinkAsync(LibreMetaverse.UUID,LibreMetaverse.UUID,System.String,System.String,LibreMetaverse.InventoryType,LibreMetaverse.UUID,System.Threading.CancellationToken)", "M:LibreMetaverse.InventoryManager.FetchItemAsync(LibreMetaverse.UUID,LibreMetaverse.UUID,System.Threading.CancellationToken)", "M:LibreMetaverse.InventoryManager.FindObjectByPathAsync(LibreMetaverse.UUID,LibreMetaverse.UUID,System.String,System.Threading.CancellationToken)", "M:LibreMetaverse.InventoryManager.FolderContentsAsync(LibreMetaverse.UUID,LibreMetaverse.UUID,System.Boolean,System.Boolean,LibreMetaverse.InventorySortOrder,System.Threading.CancellationToken,System.Boolean)", "M:LibreMetaverse.InventoryManager.GetTaskInventoryAsync(LibreMetaverse.UUID,System.UInt32,LibreMetaverse.Simulator,System.Threading.CancellationToken)", "M:LibreMetaverse.InventoryManager.GiveFolderAsync(LibreMetaverse.UUID,System.String,LibreMetaverse.UUID,System.Boolean,System.Threading.CancellationToken)", "M:LibreMetaverse.InventoryManager.GiveItem(LibreMetaverse.UUID,System.String,LibreMetaverse.AssetType,LibreMetaverse.UUID,System.Boolean)", "M:LibreMetaverse.InventoryManager.MoveFolders(System.Collections.Generic.Dictionary{LibreMetaverse.UUID,LibreMetaverse.UUID},System.Threading.CancellationToken)", "M:LibreMetaverse.InventoryManager.MoveItemsAsync(System.Collections.Generic.Dictionary{LibreMetaverse.UUID,LibreMetaverse.UUID},System.Threading.CancellationToken)", "M:LibreMetaverse.InventoryManager.RemoveItemsAsync(System.Collections.Generic.IEnumerable{LibreMetaverse.UUID},System.Threading.CancellationToken)", "M:LibreMetaverse.InventoryManager.RequestCopyItemsWithResultAsync(System.Collections.Generic.List{LibreMetaverse.UUID},System.Collections.Generic.List{LibreMetaverse.UUID},System.Collections.Generic.List{System.String},LibreMetaverse.UUID,System.Threading.CancellationToken)", "M:LibreMetaverse.InventoryManager.RequestDeRezToInventory(System.UInt32,LibreMetaverse.DeRezDestination,LibreMetaverse.UUID,LibreMetaverse.UUID)", "M:LibreMetaverse.InventoryManager.RequestFetchInventoryAsync(System.Collections.Generic.Dictionary{LibreMetaverse.UUID,LibreMetaverse.UUID},System.Threading.CancellationToken,System.Action{System.Collections.Generic.List{LibreMetaverse.InventoryItem}})", "M:LibreMetaverse.InventoryManager.RequestRezFromInventory(LibreMetaverse.Simulator,LibreMetaverse.UUID,LibreMetaverse.Quaternion,LibreMetaverse.Vector3,LibreMetaverse.InventoryItem,LibreMetaverse.UUID,LibreMetaverse.UUID,System.Boolean)", "M:LibreMetaverse.InventoryManager.RequestTaskInventory(System.UInt32,LibreMetaverse.Simulator)", "M:LibreMetaverse.InventoryManager.RequestUpdateItems(System.Collections.Generic.List{LibreMetaverse.InventoryItem},LibreMetaverse.UUID)", "M:LibreMetaverse.InventoryManager.UpdateTaskInventory(System.UInt32,LibreMetaverse.InventoryItem,LibreMetaverse.Simulator,System.Boolean)", "M:LibreMetaverse.InventoryManager.WaitForNextInventoryOfferAsync(System.Threading.CancellationToken)", } def require_markers(path: Path, markers: tuple[str, ...]) -> None: source = path.read_text() missing = [marker for marker in markers if marker not in source] if missing: raise SystemExit(f"{path.name}: audit evidence missing: " + ", ".join(missing)) def main() -> None: native_types = ( generate_api_shims.NATIVE_TYPES.keys() | generate_api_shims.NATIVE_DECLARATIONS.keys() ) missing_types = sorted(REQUIRED_TYPES - native_types) if missing_types: raise SystemExit("issue 62 native types missing: " + ", ".join(missing_types)) missing_members = sorted( REQUIRED_MEMBERS - generate_api_shims.NATIVE_MEMBER_BODIES.keys() ) if missing_members: raise SystemExit("issue 62 native members missing: " + ", ".join(missing_members)) update_task = ( "M:LibreMetaverse.InventoryManager.UpdateTaskInventory(System.UInt32," "LibreMetaverse.InventoryItem,LibreMetaverse.Simulator,System.Boolean)" ) if "only_mod_meta.unwrap_or(true)" not in generate_api_shims.NATIVE_MEMBER_BODIES[update_task]: raise SystemExit("UpdateTaskInventory must retain the C# metadata-only default") for update_member in ( "M:LibreMetaverse.InventoryManager.RequestUpdateItem(LibreMetaverse.InventoryItem)", "M:LibreMetaverse.InventoryManager.RequestUpdateItems(System.Collections.Generic.List{LibreMetaverse.InventoryItem})", ): if "UUID::random()?" not in generate_api_shims.NATIVE_MEMBER_BODIES[update_member]: raise SystemExit(f"{update_member} must generate a transaction ID") if STUB_RE.search(SOURCE.read_text()): raise SystemExit("issue 62 owned Rust stubs remain in inventory_manager.rs") require_markers( SOURCE, ( "MAX_TASK_INVENTORY_BYTES", "MAX_PENDING_REQUESTS", "encode_multiple", "pending_created", "pending_fetches", "pending_task_replies", "callbacks are not invoked while an inventory lock is held", "cancelling_one_fetch_waiter_preserves_concurrent_correlation", "fake_bulk_copy_reply_waits_for_every_block", "asset_type_without_folder_type_falls_back_to_inventory_root", "stale_descendents_packet_cannot_mutate_store", "task_xfer_rejects_announced_data_above_bound", ), ) require_markers( DOC, ( "UDP inventory manager", "4,096 pending operations", "16 MiB", "RequestXfer", "No store lock is held across an await", ), ) require_markers( MANAGER_TESTS, ( "inventory_manager_null_throws", "encrypt_decrypt_round_trip", "item_crc_is_deterministic_and_changes_when_fields_change", "create_inventory_item_returns_correct_subclass", ), ) require_markers( TASK_TESTS, ( "cap_available_returns_contents_folder_and_decrypts_shadow_id", "plain_asset_id_parses_without_decryption", "non_success_status_returns_contents_folder_only", "no_capability_does_not_make_http_request", ), ) print( "issue 62 audit: native inventory packet mappings, bounded correlation and Xfer, " "lock-free callback evidence, documentation, and translated compatibility cases are present" ) if __name__ == "__main__": main()