73 lines
3.0 KiB
Python
Executable File
73 lines
3.0 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
"""Compare baseline and patched adversarial probe exports.
|
|
|
|
This turns an intervention into evidence: a patch is useful only when it
|
|
produces additional target signals or requests without increasing runtime
|
|
errors. It does not claim that a page is bypassed; it reports observable
|
|
changes for the authorized test target.
|
|
"""
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
from collections import Counter
|
|
from pathlib import Path
|
|
|
|
from common import dump_json, load_json
|
|
|
|
|
|
def events(value: dict) -> list[dict]:
|
|
state = value.get("state") if isinstance(value, dict) else {}
|
|
raw = state.get("events", []) if isinstance(state, dict) else []
|
|
return [item for item in raw if isinstance(item, dict)]
|
|
|
|
|
|
def summarize(items: list[dict]) -> dict:
|
|
types = Counter(str(item.get("type", "unknown")) for item in items)
|
|
paths = Counter(str(item.get("path")) for item in items if item.get("path"))
|
|
return {
|
|
"events": len(items),
|
|
"types": dict(sorted(types.items())),
|
|
"paths": dict(sorted(paths.items())),
|
|
"requests": sum(count for name, count in types.items() if name.startswith("network.")),
|
|
"errors": sum(count for name, count in types.items() if "error" in name or "reject" in name),
|
|
"interventions": sum(count for name, count in types.items() if name.startswith("intervention.")),
|
|
}
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(description="Compare JSRA adversarial probe exports.")
|
|
parser.add_argument("--baseline", required=True)
|
|
parser.add_argument("--patched", required=True)
|
|
parser.add_argument("--output", required=True)
|
|
args = parser.parse_args()
|
|
|
|
before = summarize(events(load_json(Path(args.baseline), {})))
|
|
after = summarize(events(load_json(Path(args.patched), {})))
|
|
new_types = sorted(set(after["types"]) - set(before["types"]))
|
|
new_paths = sorted(set(after["paths"]) - set(before["paths"]))
|
|
errors_not_increased = after["errors"] <= before["errors"]
|
|
evidence_increased = after["events"] > before["events"] or after["requests"] > before["requests"]
|
|
result = {
|
|
"baseline": before,
|
|
"patched": after,
|
|
"delta": {
|
|
"events": after["events"] - before["events"],
|
|
"requests": after["requests"] - before["requests"],
|
|
"errors": after["errors"] - before["errors"],
|
|
"new_types": new_types,
|
|
"new_paths": new_paths,
|
|
},
|
|
"verdict": "improved" if evidence_increased and errors_not_increased else "inconclusive",
|
|
"limitations": [
|
|
"This is an observable-difference report, not proof of bypass or protocol success.",
|
|
"A real target request and business success condition still require independent verification.",
|
|
],
|
|
}
|
|
dump_json(Path(args.output), result)
|
|
print(f"[OK] adversarial diff: {args.output} verdict={result['verdict']}")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|