import argparse
import json
import re
import sys
import urllib.parse
from pathlib import Path
START_MARKER = "<!-- START-SCORECARD-BADGES -->"
END_MARKER = "<!-- END-SCORECARD-BADGES -->"
def color_for_rate(rate: float) -> str:
if rate >= 0.95:
return "brightgreen"
if rate >= 0.80:
return "green"
if rate >= 0.60:
return "yellow"
if rate >= 0.40:
return "orange"
return "red"
def badge_url(label: str, value: str, color: str) -> str:
enc_label = urllib.parse.quote(label, safe="")
enc_value = urllib.parse.quote(value, safe="")
return f"https://img.shields.io/badge/{enc_label}-{enc_value}-{color}"
def build_badges(scorecard: dict) -> list[str]:
badges: list[str] = []
for agg in scorecard.get("aggregates", []):
suite = agg.get("suite", "")
fixture = agg.get("fixture", "")
rate = float(agg.get("success_rate", 0.0))
if suite.startswith("_") or fixture.startswith("_"):
continue if suite != "real_waf" and suite != "accuracy" and suite != "solve":
continue
rate_pct = f"{rate * 100:.1f}%"
label = f"{suite}_{fixture}".replace("/", "_").strip("_")
badges.append(
f")})"
)
return badges
def inject_badges(readme: str, badges: list[str]) -> str:
block = "\n".join(badges) if badges else "_(no scorecard rows yet)_"
full_block = f"{START_MARKER}\n{block}\n{END_MARKER}"
if START_MARKER in readme and END_MARKER in readme:
return re.sub(
re.escape(START_MARKER) + r"[\s\S]*?" + re.escape(END_MARKER),
full_block,
readme,
count=1,
)
sep = "\n\n" if not readme.endswith("\n\n") else ""
return readme + sep + "## Scorecard badges\n\n" + full_block + "\n"
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument("--scorecard", required=True, help="Path to scorecard JSON")
parser.add_argument("--readme", default="README.md", help="Path to README")
args = parser.parse_args()
scorecard_path = Path(args.scorecard)
readme_path = Path(args.readme)
if not scorecard_path.is_file():
print(f"scorecard.py: scorecard JSON not found at {scorecard_path}", file=sys.stderr)
return 2
if not readme_path.is_file():
print(f"scorecard.py: README not found at {readme_path}", file=sys.stderr)
return 2
scorecard = json.loads(scorecard_path.read_text())
badges = build_badges(scorecard)
original = readme_path.read_text()
new = inject_badges(original, badges)
if new == original:
print("scorecard.py: no change")
return 0
readme_path.write_text(new)
print(f"scorecard.py: wrote {len(badges)} badge(s) to {readme_path}")
return 0
if __name__ == "__main__":
sys.exit(main())