# score.py: triage sample-findings.csv with the chapter 6 rubric and print the ranked queue.
# usage: python3 score.py sample-findings.csv
import csv, sys

BASE = {"Critical": 4, "High": 3, "Medium": 2, "Low": 1}
EXPOSURE = {"internet": 2, "internal": 1, "isolated": 0.5}
CRITICALITY = {"crown-jewel": 2, "standard": 1, "dev": 0.5}

# the two judgment calls the formula cannot make for you
FALSE_POSITIVES = {"F007", "F008"}
DUPLICATE_OF = {"F002": "F001"}

def band(score):
    return "P1" if score >= 12 else "P2" if score >= 6 else "P3" if score >= 3 else "P4"

queue = []
for row in csv.DictReader(open(sys.argv[1])):
    if row["id"] in FALSE_POSITIVES or row["id"] in DUPLICATE_OF:
        continue
    score = BASE[row["severity"]] * EXPOSURE[row["exposure"]] * CRITICALITY[row["asset_criticality"]]
    priority = "P1" if row["kev"] == "yes" else band(score)
    queue.append((priority, score, row))

queue.sort(key=lambda q: ({"P1": 0, "P2": 1, "P3": 2, "P4": 3}[q[0]], -q[1], q[2]["id"]))
print(f"{'rank':>4}  {'pri':3} {'score':>5}  {'id':5} {'asset':15} {'title'}")
for n, (p, s, r) in enumerate(queue, 1):
    kev = " (KEV)" if r["kev"] == "yes" else ""
    print(f"{n:>4}  {p:3} {s:>5g}  {r['id']:5} {r['asset']:15} {r['title'][:44]}{kev}")
