58 lines
2.8 KiB
Python
58 lines
2.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Compare shipped native CLI, Rust library and Python example on authored fixtures."""
|
|
|
|
import argparse
|
|
import hashlib
|
|
import json
|
|
import subprocess
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
|
|
def run(command):
|
|
result = subprocess.run(command, check=True, capture_output=True, text=True, timeout=60)
|
|
return json.loads(result.stdout)
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser(description=__doc__)
|
|
parser.add_argument("--binary", type=Path, required=True)
|
|
parser.add_argument("--rust-example", type=Path, required=True)
|
|
parser.add_argument("--fixture", type=Path, required=True)
|
|
args = parser.parse_args()
|
|
example = Path(__file__).resolve().parents[1] / "examples" / "lookup.py"
|
|
generation = args.fixture / "candidate"
|
|
# This local test generated the fixture itself. Production pins come from
|
|
# an authenticated publisher, as explained in the consumer documentation.
|
|
pin = hashlib.sha256((generation / "COMPLETE.json").read_bytes()).hexdigest()
|
|
for query in ("FB", "Atlas", "Café Atlas", "$(echo unsafe); `id`"):
|
|
shared = ["--generation", str(generation), "--pin", pin, "--query", query]
|
|
cli = run([str(args.binary), "lookup", *shared, "--limit", "100"])
|
|
rust = run([str(args.rust_example), *shared])
|
|
python = run([sys.executable, str(example), "--binary", str(args.binary), *shared])
|
|
if cli != rust or cli != python:
|
|
raise ValueError(f"consumer output differs for {query!r}")
|
|
if not cli["attribution"]:
|
|
raise ValueError("consumer lost attribution")
|
|
if query == "FB":
|
|
candidate = cli["candidates"][0]
|
|
if candidate["canonical_name"] != "Facebook" or not candidate["provenance"]:
|
|
raise ValueError("name/provenance contract mismatch")
|
|
if candidate["web_property"]["domain"]["registrable_domain"] != "facebook.com":
|
|
raise ValueError("domain contract mismatch")
|
|
if query == "Atlas":
|
|
urls = {candidate["url"] for candidate in cli["candidates"]}
|
|
if urls != {"https://atlas.example.com/", "https://atlas.example.co.uk/",
|
|
"https://atlas.example.de/"}:
|
|
raise ValueError("regional properties were lost")
|
|
bad = ["--generation", str(generation), "--pin", "0" * 64, "--query", "FB"]
|
|
for command in ([str(args.binary), "lookup", *bad], [str(args.rust_example), *bad],
|
|
[sys.executable, str(example), "--binary", str(args.binary), *bad]):
|
|
result = subprocess.run(command, capture_output=True, timeout=60)
|
|
if result.returncode == 0:
|
|
raise ValueError("consumer accepted an untrusted generation")
|
|
print("Native CLI, Rust and Python consumer parity passed, including trust failures.")
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|