Files
MetaCrate/tools/check_milestone_10_issue_78.py
Chili Palmer 05af8d5edf
All checks were successful
CI / required (push) Successful in 5m53s
Consolidate required CI gate (#115)
2026-08-12 23:47:51 +00:00

110 lines
5.1 KiB
Python

#!/usr/bin/env python3
"""Audit issue 78's pure native RLV protocol ownership and evidence 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-rlv" / "src" / "protocol.rs"
GENERATED = ROOT / "crates" / "libremetaverse-rlv" / "src" / "generated.rs"
TESTS = ROOT / "crates" / "libremetaverse-rlv" / "tests" / "protocol_parsing.rs"
COMPAT = ROOT / "tests" / "compat" / "tests" / "rlv_common_semantics.rs"
DOC = ROOT / "crates" / "libremetaverse-rlv" / "README.md"
WORKFLOW = ROOT / ".gitea" / "workflows" / "ci.yml"
STUB_RE = re.compile(r"\b(?:not_implemented|unimplemented_api)\b|\b(?:todo|unimplemented)!\s*\(")
TYPES = {
"T:LibreMetaverse.RLV.RlvCommon": "crate::protocol::RlvCommon",
"T:LibreMetaverse.RLV.RlvRestriction": "crate::protocol::RlvRestriction",
}
MEMBERS = {
"M:LibreMetaverse.RLV.RlvCommon.TryGetAttachmentPointFromItemName(System.String,System.Nullable{LibreMetaverse.RLV.RlvAttachmentPoint}@)",
"M:LibreMetaverse.RLV.RlvRestriction.#ctor(LibreMetaverse.RLV.RlvRestrictionType,System.Guid,System.String,System.Collections.Generic.ICollection{System.Object})",
"M:LibreMetaverse.RLV.RlvRestriction.Equals(System.Object)",
"M:LibreMetaverse.RLV.RlvRestriction.GetHashCode",
"M:LibreMetaverse.RLV.RlvRestriction.ToString",
"P:LibreMetaverse.RLV.RlvRestriction.Args",
"P:LibreMetaverse.RLV.RlvRestriction.Behavior",
"P:LibreMetaverse.RLV.RlvRestriction.IsException",
"P:LibreMetaverse.RLV.RlvRestriction.OriginalBehavior",
"P:LibreMetaverse.RLV.RlvRestriction.Sender",
"P:LibreMetaverse.RLV.RlvRestriction.SenderName",
}
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 generated_type_block(text: str, rust_name: str) -> str:
marker = f"pub use crate::protocol::{rust_name};"
start = text.find(marker)
if start < 0:
raise SystemExit(f"generated declaration for {rust_name} is missing")
next_type = text.find("\n/// 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 78 native declaration is missing for {api_type}")
missing = sorted(MEMBERS - set(generate_api_shims.NATIVE_MEMBER_BODIES))
if missing:
raise SystemExit("issue 78 native members missing: " + ", ".join(missing))
source = SOURCE.read_text()
if STUB_RE.search(source):
raise SystemExit("issue 78 owned Rust stubs remain in protocol.rs")
table = source[source.index("macro_rules! restriction_table") : source.index("macro_rules! make_restriction_lookup")]
if len(re.findall(r'"[^"]+"\s*=>\s*[A-Za-z0-9_]+', table)) != 119:
raise SystemExit("issue 78 restriction table does not contain exactly 119 names")
generated = GENERATED.read_text()
for rust_name in ("RlvCommon", "RlvRestriction"):
if STUB_RE.search(generated_type_block(generated, rust_name)):
raise SystemExit(f"issue 78 owned generated stubs remain for {rust_name}")
require_markers(SOURCE, (
"MAX_RLV_MESSAGE_BYTES", "MAX_RLV_COMMANDS", "pub struct RlvSourceSpan",
"pub enum RlvParseErrorKind", "pub enum RlvDirective", "pub enum RlvAction",
"pub enum RlvQuery", "pub enum RlvValue", "pub fn parse_message",
"parse_restriction_values", "RLV_RESTRICTION_NAMES",
'"root" | "avatar center" => P::AvatarCenter', "native_try_get_attachment_point",
"pub struct RlvRestriction", "real_restriction", "is_exception",
))
require_markers(TESTS, (
"message_preserves_original_casing_options_and_byte_locations",
"query_variants_preserve_filters_separators_paths_and_aliases",
"every_pinned_restriction_name_round_trips_without_normalization",
"every_pinned_restriction_has_at_least_one_typed_valid_option_form",
"deterministic_single_byte_mutations_are_bounded_and_never_panic",
"command_count_and_message_size_are_bounded",
"mapped_restriction_preserves_alias_exception_equality_and_snapshot_args",
))
require_markers(COMPAT, (
"attachment_point_uses_last_known_tag",
"attachment_point_avatar_center",
"attachment_point_root_alias",
"attachment_point_rejects_unknown_tags",
))
require_markers(DOC, (
"side-effect-free", "119 behavior", "56 pinned", "half-open byte span",
"64 KiB", "128 comma-separated", "does not wait", "ubuntu-latest",
))
require_markers(WORKFLOW, ("required-gate",))
print(
"issue 78 audit: bounded pure RLV parsing, typed commands/queries/restrictions, "
"exact aliases, positioned errors, mapped values, mutation evidence, and docs are present"
)
if __name__ == "__main__":
main()