mirror of
https://github.com/saymrwulf/CertTransparencySearch.git
synced 2026-05-18 21:10:14 +00:00
Tighten monograph pagination and table layout
This commit is contained in:
parent
b171abb5a8
commit
629f0ade57
1 changed files with 319 additions and 228 deletions
|
|
@ -217,6 +217,63 @@ def compact_list_items(value: str, keep: int = 2, limit: int = 96) -> str:
|
|||
return truncate_text(", ".join(parts[:keep]) + f", ... (+{len(parts) - keep} more)", limit)
|
||||
|
||||
|
||||
def compact_family_basis(value: str) -> str:
|
||||
prefixes = {
|
||||
"CN pattern with running-number slot: ": "Numbered family: ",
|
||||
"Same endpoint CN family (exact CN; www. grouped with base name): ": "Exact endpoint family: ",
|
||||
}
|
||||
for prefix, replacement in prefixes.items():
|
||||
if value.startswith(prefix):
|
||||
return value.replace(prefix, replacement, 1)
|
||||
return truncate_text(value, 92)
|
||||
|
||||
|
||||
def latex_table_cell(value: str) -> str:
|
||||
escaped = latex_escape(value)
|
||||
for token in [".", "/", "-", ":", ";", ",", "="]:
|
||||
escaped = escaped.replace(token, token + r"\allowbreak{}")
|
||||
return escaped
|
||||
|
||||
|
||||
def append_longtable(
|
||||
lines: list[str],
|
||||
spec: str,
|
||||
headers: list[str],
|
||||
rows: list[list[str]],
|
||||
*,
|
||||
font: str = "small",
|
||||
tabcolsep: str | None = "3.8pt",
|
||||
) -> None:
|
||||
lines.append(r"\begingroup")
|
||||
if font:
|
||||
lines.append(rf"\{font}")
|
||||
if tabcolsep:
|
||||
lines.append(rf"\setlength{{\tabcolsep}}{{{tabcolsep}}}")
|
||||
lines.append(rf"\begin{{longtable}}{{{spec}}}")
|
||||
header_line = " & ".join(latex_escape(header) for header in headers) + r" \\"
|
||||
lines.extend(
|
||||
[
|
||||
r"\toprule",
|
||||
header_line,
|
||||
r"\midrule",
|
||||
r"\endfirsthead",
|
||||
r"\toprule",
|
||||
header_line,
|
||||
r"\midrule",
|
||||
r"\endhead",
|
||||
r"\midrule",
|
||||
rf"\multicolumn{{{len(headers)}}}{{r}}{{\footnotesize\itshape Continued on next page}} \\",
|
||||
r"\midrule",
|
||||
r"\endfoot",
|
||||
r"\bottomrule",
|
||||
r"\endlastfoot",
|
||||
]
|
||||
)
|
||||
for row in rows:
|
||||
lines.append(" & ".join(latex_table_cell(cell) for cell in row) + r" \\")
|
||||
lines.extend([r"\end{longtable}", r"\endgroup"])
|
||||
|
||||
|
||||
def nonzero_purpose_rows(purpose_rows: list[list[str]]) -> list[list[str]]:
|
||||
return [row for row in purpose_rows if row[1] != "0"]
|
||||
|
||||
|
|
@ -337,7 +394,7 @@ def top_caa_overlap_rows(analysis: ct_caa_analysis.CaaAnalysis, limit: int = 15)
|
|||
row.name,
|
||||
row.zone,
|
||||
", ".join(row.current_covering_families),
|
||||
truncate_text(", ".join(row.current_covering_subject_cns), 72),
|
||||
compact_list_items(", ".join(row.current_covering_subject_cns), keep=2, limit=64),
|
||||
]
|
||||
for row in ordered[:limit]
|
||||
]
|
||||
|
|
@ -631,10 +688,9 @@ def render_markdown(
|
|||
]
|
||||
family_rows = [
|
||||
[
|
||||
row["group_id"],
|
||||
row["basis"],
|
||||
row["certificates"],
|
||||
row["subjects"],
|
||||
compact_family_basis(row["basis"]),
|
||||
str(row["certificates"]),
|
||||
str(row["subjects"]),
|
||||
first_list_item(row["top_stacks"]),
|
||||
]
|
||||
for row in report["group_digest"]
|
||||
|
|
@ -1245,7 +1301,7 @@ def render_markdown(
|
|||
lines.append("")
|
||||
lines.append("This appendix is a compact family map. It is not the place for full per-certificate evidence; that remains in the detailed inventory appendix at the end.")
|
||||
lines.append("")
|
||||
lines.extend(md_table(["ID", "Basis", "Certs", "CNs", "Dominant Stack"], family_rows))
|
||||
lines.extend(md_table(["Family Basis", "Certs", "CNs", "Dominant Stack"], family_rows))
|
||||
lines.append("")
|
||||
lines.append("## Appendix B: Historical Red-Flag Detail")
|
||||
lines.append("")
|
||||
|
|
@ -1573,6 +1629,15 @@ def render_latex(
|
|||
total_certificates = len(report["classifications"])
|
||||
issuer_trust = report["issuer_trust"]
|
||||
issuer_family_rows = build_issuer_family_rows(report)
|
||||
family_rows = [
|
||||
[
|
||||
compact_family_basis(row["basis"]),
|
||||
str(row["certificates"]),
|
||||
str(row["subjects"]),
|
||||
first_list_item(row["top_stacks"]),
|
||||
]
|
||||
for row in report["group_digest"]
|
||||
]
|
||||
dual_items = [item for item in report["classifications"] if item.category == "tls_server_and_client"]
|
||||
dual_issuer_counts = Counter(short_issuer(item.issuer_name) for item in dual_items)
|
||||
server_only_count = purpose_summary.category_counts.get("tls_server_only", 0)
|
||||
|
|
@ -1631,6 +1696,7 @@ def render_latex(
|
|||
r"\usepackage{booktabs}",
|
||||
r"\usepackage{tabularx}",
|
||||
r"\usepackage{longtable}",
|
||||
r"\usepackage{needspace}",
|
||||
r"\usepackage{enumitem}",
|
||||
r"\usepackage{fancyhdr}",
|
||||
r"\usepackage{titlesec}",
|
||||
|
|
@ -2151,17 +2217,14 @@ def render_latex(
|
|||
]
|
||||
)
|
||||
if caa_analysis.multi_family_overlap_names:
|
||||
lines.extend(
|
||||
[
|
||||
r"\begin{longtable}{>{\raggedright\arraybackslash}p{0.29\linewidth} >{\raggedright\arraybackslash}p{0.14\linewidth} >{\raggedright\arraybackslash}p{0.17\linewidth} >{\raggedright\arraybackslash}p{0.28\linewidth}}",
|
||||
r"\toprule",
|
||||
r"DNS Name & Zone & Live CA Families & Covering Subject CNs \\",
|
||||
r"\midrule",
|
||||
]
|
||||
append_longtable(
|
||||
lines,
|
||||
r">{\raggedright\arraybackslash}p{0.27\linewidth} >{\raggedright\arraybackslash}p{0.10\linewidth} >{\raggedright\arraybackslash}p{0.16\linewidth} >{\raggedright\arraybackslash}p{0.33\linewidth}",
|
||||
["DNS Name", "Zone", "Live CA Families", "Covering Subject CNs"],
|
||||
top_caa_overlap_rows(caa_analysis),
|
||||
font="footnotesize",
|
||||
tabcolsep="3.2pt",
|
||||
)
|
||||
for name, zone, families, subjects in top_caa_overlap_rows(caa_analysis):
|
||||
lines.append(rf"{latex_escape(name)} & {latex_escape(zone)} & {latex_escape(families)} & {latex_escape(subjects)} \\")
|
||||
lines.extend([r"\bottomrule", r"\end{longtable}"])
|
||||
else:
|
||||
lines.append(r"No current multi-family overlap names were found.")
|
||||
lines.append(
|
||||
|
|
@ -2169,17 +2232,14 @@ def render_latex(
|
|||
)
|
||||
lines.append(r"\subsection{Current Policy Mismatch}")
|
||||
if caa_analysis.policy_mismatch_names:
|
||||
lines.extend(
|
||||
[
|
||||
r"\begin{longtable}{>{\raggedright\arraybackslash}p{0.27\linewidth} >{\raggedright\arraybackslash}p{0.12\linewidth} >{\raggedright\arraybackslash}p{0.16\linewidth} >{\raggedright\arraybackslash}p{0.18\linewidth} >{\raggedright\arraybackslash}p{0.17\linewidth}}",
|
||||
r"\toprule",
|
||||
r"DNS Name & Zone & Live CA Families & CAA-Allowed Families & CAA Discovery Result \\",
|
||||
r"\midrule",
|
||||
]
|
||||
append_longtable(
|
||||
lines,
|
||||
r">{\raggedright\arraybackslash}p{0.24\linewidth} >{\raggedright\arraybackslash}p{0.10\linewidth} >{\raggedright\arraybackslash}p{0.14\linewidth} >{\raggedright\arraybackslash}p{0.16\linewidth} >{\raggedright\arraybackslash}p{0.20\linewidth}",
|
||||
["DNS Name", "Zone", "Live CA Families", "CAA-Allowed Families", "CAA Discovery Result"],
|
||||
top_caa_mismatch_rows(caa_analysis),
|
||||
font="footnotesize",
|
||||
tabcolsep="3.0pt",
|
||||
)
|
||||
for name, zone, families, allowed, result in top_caa_mismatch_rows(caa_analysis):
|
||||
lines.append(rf"{latex_escape(name)} & {latex_escape(zone)} & {latex_escape(families)} & {latex_escape(allowed)} & {latex_escape(result)} \\")
|
||||
lines.extend([r"\bottomrule", r"\end{longtable}"])
|
||||
else:
|
||||
lines.append(r"No current policy-mismatch names were found.")
|
||||
lines.append(
|
||||
|
|
@ -2210,34 +2270,31 @@ def render_latex(
|
|||
lines.extend(
|
||||
[
|
||||
r"\subsection{Focused Cohort Versus The Rest Of The Estate}",
|
||||
r"\begin{longtable}{>{\raggedright\arraybackslash}p{0.28\linewidth} >{\raggedright\arraybackslash}p{0.18\linewidth} >{\raggedright\arraybackslash}p{0.18\linewidth} >{\raggedright\arraybackslash}p{0.28\linewidth}}",
|
||||
r"\toprule",
|
||||
r"Comparison View & Focused Cohort & Rest Of Current Corpus & Why It Matters \\",
|
||||
r"\midrule",
|
||||
]
|
||||
)
|
||||
for left, focus_value, rest_value, why in focus_comparison:
|
||||
lines.append(
|
||||
rf"{latex_escape(left)} & {latex_escape(focus_value)} & {latex_escape(rest_value)} & {latex_escape(why)} \\"
|
||||
)
|
||||
lines.extend([r"\bottomrule", r"\end{longtable}"])
|
||||
append_longtable(
|
||||
lines,
|
||||
r">{\raggedright\arraybackslash}p{0.27\linewidth} >{\raggedright\arraybackslash}p{0.16\linewidth} >{\raggedright\arraybackslash}p{0.16\linewidth} >{\raggedright\arraybackslash}p{0.31\linewidth}",
|
||||
["Comparison View", "Focused Cohort", "Rest Of Current Corpus", "Why It Matters"],
|
||||
focus_comparison,
|
||||
font="footnotesize",
|
||||
tabcolsep="3.2pt",
|
||||
)
|
||||
lines.extend(
|
||||
[
|
||||
r"\subsection{Three Buckets Inside The Cohort}",
|
||||
r"\begin{longtable}{>{\raggedright\arraybackslash}p{0.16\linewidth} >{\raggedleft\arraybackslash}p{0.07\linewidth} >{\raggedright\arraybackslash}p{0.20\linewidth} >{\raggedright\arraybackslash}p{0.24\linewidth} >{\raggedright\arraybackslash}p{0.25\linewidth}}",
|
||||
r"\toprule",
|
||||
r"Bucket & Count & Representative Names & What It Looks Like & Why This Bucket Exists \\",
|
||||
r"\midrule",
|
||||
]
|
||||
)
|
||||
for bucket, count, names, shape, why in focus_bucket_summary:
|
||||
lines.append(
|
||||
rf"{latex_escape(bucket)} & {latex_escape(count)} & {latex_escape(names)} & {latex_escape(shape)} & {latex_escape(why)} \\"
|
||||
)
|
||||
append_longtable(
|
||||
lines,
|
||||
r">{\raggedright\arraybackslash}p{0.15\linewidth} >{\raggedleft\arraybackslash}p{0.06\linewidth} >{\raggedright\arraybackslash}p{0.19\linewidth} >{\raggedright\arraybackslash}p{0.24\linewidth} >{\raggedright\arraybackslash}p{0.26\linewidth}",
|
||||
["Bucket", "Count", "Representative Names", "What It Looks Like", "Why This Bucket Exists"],
|
||||
focus_bucket_summary,
|
||||
font="footnotesize",
|
||||
tabcolsep="3.0pt",
|
||||
)
|
||||
lines.extend(
|
||||
[
|
||||
r"\bottomrule",
|
||||
r"\end{longtable}",
|
||||
r"This bucket split is the key to making the cohort intelligible. The memorable names are not all from one naming methodology. Most are direct public fronts. A very small number are platform-anchor certificates with matrix SAN design. The rest are historical leftovers, carried aliases, or opaque labels whose original role is no longer cleanly visible in the current corpus.",
|
||||
r"\subsection{Why This Cohort Feels Different}",
|
||||
r"\begin{itemize}[leftmargin=1.4em]",
|
||||
|
|
@ -2254,43 +2311,42 @@ def render_latex(
|
|||
)
|
||||
lines.append(r"\subsection{Cross-Basket Carrying And Migration}")
|
||||
if focus_analysis.transition_rows:
|
||||
lines.extend(
|
||||
append_longtable(
|
||||
lines,
|
||||
r">{\raggedright\arraybackslash}p{0.22\linewidth} >{\raggedright\arraybackslash}p{0.19\linewidth} >{\raggedright\arraybackslash}p{0.11\linewidth} >{\raggedleft\arraybackslash}p{0.09\linewidth} >{\raggedright\arraybackslash}p{0.27\linewidth}",
|
||||
["Subject CN", "Current Basket Status", "Direct / Carried", "Max Overlap Days", "Carrier Subjects"],
|
||||
[
|
||||
r"\begin{longtable}{>{\raggedright\arraybackslash}p{0.23\linewidth} >{\raggedright\arraybackslash}p{0.21\linewidth} >{\raggedright\arraybackslash}p{0.12\linewidth} >{\raggedleft\arraybackslash}p{0.10\linewidth} >{\raggedright\arraybackslash}p{0.24\linewidth}}",
|
||||
r"\toprule",
|
||||
r"Subject CN & Current Basket Status & Direct / Carried & Max Overlap Days & Carrier Subjects \\",
|
||||
r"\midrule",
|
||||
]
|
||||
[
|
||||
detail.subject_cn,
|
||||
detail.basket_status,
|
||||
f"{detail.current_direct_certificates}/{detail.current_non_focus_san_carriers + detail.historical_non_focus_san_carriers}",
|
||||
str(detail.max_direct_to_carrier_overlap_days),
|
||||
truncate_text(detail.carrier_subjects, 48),
|
||||
]
|
||||
for detail in focus_analysis.transition_rows[:10]
|
||||
],
|
||||
font="footnotesize",
|
||||
tabcolsep="3.1pt",
|
||||
)
|
||||
for detail in focus_analysis.transition_rows[:10]:
|
||||
carried_total = detail.current_non_focus_san_carriers + detail.historical_non_focus_san_carriers
|
||||
lines.append(
|
||||
rf"{latex_escape(detail.subject_cn)} & {latex_escape(detail.basket_status)} & {detail.current_direct_certificates}/{carried_total} & {detail.max_direct_to_carrier_overlap_days} & {latex_escape(truncate_text(detail.carrier_subjects, 48))} \\"
|
||||
)
|
||||
lines.extend([r"\bottomrule", r"\end{longtable}"])
|
||||
else:
|
||||
lines.append(r"No focused names were seen as SAN passengers inside non-focused certificates.")
|
||||
lines.append(
|
||||
r"This migration table answers a narrower question than the rest of the chapter. It asks whether these names were gradually absorbed into broader certificates from outside the cohort. The answer is: only in a limited number of cases. Some names do show SAN-passenger behavior or historical carrying, but that is not the dominant explanation for why the cohort feels different. The dominant explanation is the bucket split above: many remembered direct fronts, a few large platform anchors, and a band of legacy residue."
|
||||
)
|
||||
lines.extend(
|
||||
[
|
||||
r"\subsection{Representative Names By Bucket}",
|
||||
r"\begin{longtable}{>{\raggedright\arraybackslash}p{0.15\linewidth} >{\raggedright\arraybackslash}p{0.18\linewidth} >{\raggedright\arraybackslash}p{0.20\linewidth} >{\raggedright\arraybackslash}p{0.10\linewidth} >{\raggedright\arraybackslash}p{0.27\linewidth}}",
|
||||
r"\toprule",
|
||||
r"Bucket & Subject CN & Observed Role & Direct C/H & Why It Helps Explain The Bucket \\",
|
||||
r"\midrule",
|
||||
]
|
||||
lines.append(r"\subsection{Representative Names By Bucket}")
|
||||
append_longtable(
|
||||
lines,
|
||||
r">{\raggedright\arraybackslash}p{0.14\linewidth} >{\raggedright\arraybackslash}p{0.17\linewidth} >{\raggedright\arraybackslash}p{0.18\linewidth} >{\raggedright\arraybackslash}p{0.09\linewidth} >{\raggedright\arraybackslash}p{0.30\linewidth}",
|
||||
["Bucket", "Subject CN", "Observed Role", "Direct C/H", "Why It Helps Explain The Bucket"],
|
||||
focus_representatives,
|
||||
font="footnotesize",
|
||||
tabcolsep="3.0pt",
|
||||
)
|
||||
for row in focus_representatives:
|
||||
lines.append(
|
||||
rf"{latex_escape(row[0])} & {latex_escape(row[1])} & {latex_escape(row[2])} & {latex_escape(row[3])} & {latex_escape(row[4])} \\"
|
||||
)
|
||||
lines.extend([r"\bottomrule", r"\end{longtable}"])
|
||||
lines.append(
|
||||
r"These examples are evidence anchors, not the whole population. The direct-front examples show the remembered public surface. The platform-anchor examples show the rare but important matrix certificates. The ambiguous examples show why the cohort cannot be reduced to a single neat story without losing the migration and legacy residue that made these names memorable in the first place."
|
||||
)
|
||||
|
||||
lines.append(r"\Needspace{12\baselineskip}")
|
||||
lines.append(r"\section{Making The Whole Estate Make Sense}")
|
||||
add_summary(
|
||||
[
|
||||
|
|
@ -2330,20 +2386,20 @@ def render_latex(
|
|||
|
||||
lines.extend(
|
||||
[
|
||||
r"\clearpage",
|
||||
r"\appendix",
|
||||
r"\section{Full Family Catalogue}",
|
||||
r"This appendix is a compact family map. It is not the place for full per-certificate evidence; that remains in the detailed inventory appendix at the end of the monograph.",
|
||||
r"\begin{longtable}{>{\raggedright\arraybackslash}p{0.08\linewidth} >{\raggedright\arraybackslash}p{0.48\linewidth} >{\raggedleft\arraybackslash}p{0.08\linewidth} >{\raggedleft\arraybackslash}p{0.08\linewidth} >{\raggedright\arraybackslash}p{0.18\linewidth}}",
|
||||
r"\toprule",
|
||||
r"ID & Basis & Certs & CNs & Dominant Stack \\",
|
||||
r"\midrule",
|
||||
]
|
||||
)
|
||||
for row in report["group_digest"]:
|
||||
lines.append(
|
||||
rf"{latex_escape(row['group_id'])} & {latex_escape(row['basis'])} & {row['certificates']} & {row['subjects']} & {latex_escape(first_list_item(row['top_stacks']))} \\"
|
||||
)
|
||||
lines.extend([r"\bottomrule", r"\end{longtable}"])
|
||||
append_longtable(
|
||||
lines,
|
||||
r">{\raggedright\arraybackslash}p{0.56\linewidth} >{\raggedleft\arraybackslash}p{0.09\linewidth} >{\raggedleft\arraybackslash}p{0.08\linewidth} >{\raggedright\arraybackslash}p{0.18\linewidth}",
|
||||
["Family Basis", "Certs", "CNs", "Dominant Stack"],
|
||||
family_rows,
|
||||
font="footnotesize",
|
||||
tabcolsep="3.0pt",
|
||||
)
|
||||
|
||||
lines.extend(
|
||||
[
|
||||
|
|
@ -2354,203 +2410,240 @@ def render_latex(
|
|||
]
|
||||
)
|
||||
if assessment.current_red_flag_rows:
|
||||
lines.extend(
|
||||
append_longtable(
|
||||
lines,
|
||||
r">{\raggedright\arraybackslash}p{0.28\linewidth} >{\raggedleft\arraybackslash}p{0.09\linewidth} >{\raggedright\arraybackslash}p{0.24\linewidth} >{\raggedright\arraybackslash}p{0.27\linewidth}",
|
||||
["Subject CN", "Live Certs", "Current Concern", "Supporting Context"],
|
||||
[
|
||||
r"\begin{longtable}{>{\raggedright\arraybackslash}p{0.29\linewidth} >{\raggedleft\arraybackslash}p{0.10\linewidth} >{\raggedright\arraybackslash}p{0.25\linewidth} >{\raggedright\arraybackslash}p{0.26\linewidth}}",
|
||||
r"\toprule",
|
||||
r"Subject CN & Live Certs & Current Concern & Supporting Context \\",
|
||||
r"\midrule",
|
||||
]
|
||||
[
|
||||
row.subject_cn,
|
||||
str(row.current_certificate_count),
|
||||
row.flags,
|
||||
truncate_text(row.notes, 84),
|
||||
]
|
||||
for row in assessment.current_red_flag_rows
|
||||
],
|
||||
font="footnotesize",
|
||||
tabcolsep="3.0pt",
|
||||
)
|
||||
for row in assessment.current_red_flag_rows:
|
||||
lines.append(
|
||||
rf"{latex_escape(row.subject_cn)} & {row.current_certificate_count} & {latex_escape(row.flags)} & {latex_escape(truncate_text(row.notes, 84))} \\"
|
||||
)
|
||||
lines.extend([r"\bottomrule", r"\end{longtable}"])
|
||||
else:
|
||||
lines.append(r"No current red flags were found.")
|
||||
lines.append(r"\subsection{Past Red-Flag Inventory Now Fixed}")
|
||||
if assessment.past_red_flag_rows:
|
||||
lines.extend(
|
||||
append_longtable(
|
||||
lines,
|
||||
r">{\raggedright\arraybackslash}p{0.28\linewidth} >{\raggedleft\arraybackslash}p{0.09\linewidth} >{\raggedright\arraybackslash}p{0.24\linewidth} >{\raggedright\arraybackslash}p{0.27\linewidth}",
|
||||
["Subject CN", "Historic Certs", "Historical Concern", "Supporting Context"],
|
||||
[
|
||||
r"\begin{longtable}{>{\raggedright\arraybackslash}p{0.29\linewidth} >{\raggedleft\arraybackslash}p{0.10\linewidth} >{\raggedright\arraybackslash}p{0.25\linewidth} >{\raggedright\arraybackslash}p{0.26\linewidth}}",
|
||||
r"\toprule",
|
||||
r"Subject CN & Historic Certs & Historical Concern & Supporting Context \\",
|
||||
r"\midrule",
|
||||
]
|
||||
[
|
||||
row.subject_cn,
|
||||
str(row.certificate_count),
|
||||
row.flags,
|
||||
truncate_text(row.notes, 84),
|
||||
]
|
||||
for row in assessment.past_red_flag_rows
|
||||
],
|
||||
font="footnotesize",
|
||||
tabcolsep="3.0pt",
|
||||
)
|
||||
for row in assessment.past_red_flag_rows:
|
||||
lines.append(
|
||||
rf"{latex_escape(row.subject_cn)} & {row.certificate_count} & {latex_escape(row.flags)} & {latex_escape(truncate_text(row.notes, 84))} \\"
|
||||
)
|
||||
lines.extend([r"\bottomrule", r"\end{longtable}"])
|
||||
else:
|
||||
lines.append(r"No past-only red flags were found.")
|
||||
lines.append(r"\subsection{Current Overlap Red Flags}")
|
||||
if assessment.overlap_current_rows:
|
||||
lines.extend(
|
||||
append_longtable(
|
||||
lines,
|
||||
r">{\raggedright\arraybackslash}p{0.21\linewidth} >{\raggedleft\arraybackslash}p{0.10\linewidth} >{\raggedleft\arraybackslash}p{0.08\linewidth} >{\raggedright\arraybackslash}p{0.51\linewidth}",
|
||||
["Subject CN", "Max Overlap Days", "Live Certs", "What The Renewal Family Looks Like"],
|
||||
[
|
||||
r"\begin{longtable}{>{\raggedright\arraybackslash}p{0.22\linewidth} >{\raggedleft\arraybackslash}p{0.11\linewidth} >{\raggedleft\arraybackslash}p{0.09\linewidth} >{\raggedright\arraybackslash}p{0.48\linewidth}}",
|
||||
r"\toprule",
|
||||
r"Subject CN & Max Overlap Days & Live Certs & What The Renewal Family Looks Like \\",
|
||||
r"\midrule",
|
||||
]
|
||||
[
|
||||
row.subject_cn,
|
||||
str(row.max_overlap_days),
|
||||
str(row.current_certificate_count),
|
||||
f"{row.lineage}; {overlap_signal(row.details)}",
|
||||
]
|
||||
for row in assessment.overlap_current_rows
|
||||
],
|
||||
font="footnotesize",
|
||||
tabcolsep="3.0pt",
|
||||
)
|
||||
for row in assessment.overlap_current_rows:
|
||||
lines.append(
|
||||
rf"{latex_escape(row.subject_cn)} & {row.max_overlap_days} & {row.current_certificate_count} & {latex_escape(f'{row.lineage}; {overlap_signal(row.details)}')} \\"
|
||||
)
|
||||
lines.extend([r"\bottomrule", r"\end{longtable}"])
|
||||
else:
|
||||
lines.append(r"No current overlap red flags were found.")
|
||||
lines.append(r"\subsection{Past Overlap Red Flags Now Fixed}")
|
||||
if assessment.overlap_past_rows:
|
||||
lines.extend(
|
||||
append_longtable(
|
||||
lines,
|
||||
r">{\raggedright\arraybackslash}p{0.21\linewidth} >{\raggedleft\arraybackslash}p{0.10\linewidth} >{\raggedleft\arraybackslash}p{0.09\linewidth} >{\raggedright\arraybackslash}p{0.52\linewidth}",
|
||||
["Subject CN", "Max Overlap Days", "Historic Certs", "What The Renewal Family Looks Like"],
|
||||
[
|
||||
r"\begin{longtable}{>{\raggedright\arraybackslash}p{0.22\linewidth} >{\raggedleft\arraybackslash}p{0.11\linewidth} >{\raggedleft\arraybackslash}p{0.10\linewidth} >{\raggedright\arraybackslash}p{0.47\linewidth}}",
|
||||
r"\toprule",
|
||||
r"Subject CN & Max Overlap Days & Historic Certs & What The Renewal Family Looks Like \\",
|
||||
r"\midrule",
|
||||
]
|
||||
[
|
||||
row.subject_cn,
|
||||
str(row.max_overlap_days),
|
||||
str(row.asset_variant_count),
|
||||
f"{row.lineage}; {overlap_signal(row.details)}",
|
||||
]
|
||||
for row in assessment.overlap_past_rows
|
||||
],
|
||||
font="footnotesize",
|
||||
tabcolsep="3.0pt",
|
||||
)
|
||||
for row in assessment.overlap_past_rows:
|
||||
lines.append(
|
||||
rf"{latex_escape(row.subject_cn)} & {row.max_overlap_days} & {row.asset_variant_count} & {latex_escape(f'{row.lineage}; {overlap_signal(row.details)}')} \\"
|
||||
)
|
||||
lines.extend([r"\bottomrule", r"\end{longtable}"])
|
||||
else:
|
||||
lines.append(r"No past overlap red flags were found.")
|
||||
lines.append(r"\subsection{Current Subject-DN Drift}")
|
||||
if assessment.dn_current_rows:
|
||||
lines.extend(
|
||||
append_longtable(
|
||||
lines,
|
||||
r">{\raggedright\arraybackslash}p{0.25\linewidth} >{\raggedleft\arraybackslash}p{0.10\linewidth} >{\raggedleft\arraybackslash}p{0.08\linewidth} >{\raggedright\arraybackslash}p{0.45\linewidth}",
|
||||
["Subject CN", "Distinct Subject DNs", "Live Certs", "Subject DN Samples"],
|
||||
[
|
||||
r"\begin{longtable}{>{\raggedright\arraybackslash}p{0.26\linewidth} >{\raggedleft\arraybackslash}p{0.10\linewidth} >{\raggedleft\arraybackslash}p{0.09\linewidth} >{\raggedright\arraybackslash}p{0.43\linewidth}}",
|
||||
r"\toprule",
|
||||
r"Subject CN & Distinct Subject DNs & Live Certs & Subject DN Samples \\",
|
||||
r"\midrule",
|
||||
]
|
||||
[
|
||||
row.subject_cn,
|
||||
str(row.distinct_value_count),
|
||||
str(row.current_certificate_count),
|
||||
truncate_text(row.details, 92),
|
||||
]
|
||||
for row in assessment.dn_current_rows
|
||||
],
|
||||
font="footnotesize",
|
||||
tabcolsep="3.0pt",
|
||||
)
|
||||
for row in assessment.dn_current_rows:
|
||||
lines.append(
|
||||
rf"{latex_escape(row.subject_cn)} & {row.distinct_value_count} & {row.current_certificate_count} & {latex_escape(truncate_text(row.details, 92))} \\"
|
||||
)
|
||||
lines.extend([r"\bottomrule", r"\end{longtable}"])
|
||||
else:
|
||||
lines.append(r"No current Subject-DN drift was found.")
|
||||
lines.append(r"\subsection{Past Subject-DN Drift Now Fixed}")
|
||||
if assessment.dn_past_rows:
|
||||
lines.extend(
|
||||
append_longtable(
|
||||
lines,
|
||||
r">{\raggedright\arraybackslash}p{0.25\linewidth} >{\raggedleft\arraybackslash}p{0.10\linewidth} >{\raggedleft\arraybackslash}p{0.09\linewidth} >{\raggedright\arraybackslash}p{0.45\linewidth}",
|
||||
["Subject CN", "Distinct Subject DNs", "Historic Certs", "Subject DN Samples"],
|
||||
[
|
||||
r"\begin{longtable}{>{\raggedright\arraybackslash}p{0.26\linewidth} >{\raggedleft\arraybackslash}p{0.10\linewidth} >{\raggedleft\arraybackslash}p{0.11\linewidth} >{\raggedright\arraybackslash}p{0.41\linewidth}}",
|
||||
r"\toprule",
|
||||
r"Subject CN & Distinct Subject DNs & Historic Certs & Subject DN Samples \\",
|
||||
r"\midrule",
|
||||
]
|
||||
[
|
||||
row.subject_cn,
|
||||
str(row.distinct_value_count),
|
||||
str(row.certificate_count),
|
||||
truncate_text(row.details, 92),
|
||||
]
|
||||
for row in assessment.dn_past_rows
|
||||
],
|
||||
font="footnotesize",
|
||||
tabcolsep="3.0pt",
|
||||
)
|
||||
for row in assessment.dn_past_rows:
|
||||
lines.append(
|
||||
rf"{latex_escape(row.subject_cn)} & {row.distinct_value_count} & {row.certificate_count} & {latex_escape(truncate_text(row.details, 92))} \\"
|
||||
)
|
||||
lines.extend([r"\bottomrule", r"\end{longtable}"])
|
||||
else:
|
||||
lines.append(r"No past-only Subject-DN drift was found.")
|
||||
lines.append(r"\subsection{Current CA-Family Drift}")
|
||||
if assessment.vendor_current_rows:
|
||||
lines.extend(
|
||||
append_longtable(
|
||||
lines,
|
||||
r">{\raggedright\arraybackslash}p{0.27\linewidth} >{\raggedleft\arraybackslash}p{0.10\linewidth} >{\raggedleft\arraybackslash}p{0.08\linewidth} >{\raggedright\arraybackslash}p{0.45\linewidth}",
|
||||
["Subject CN", "Distinct CA Families", "Live Certs", "CA Families Seen"],
|
||||
[
|
||||
r"\begin{longtable}{>{\raggedright\arraybackslash}p{0.28\linewidth} >{\raggedleft\arraybackslash}p{0.11\linewidth} >{\raggedleft\arraybackslash}p{0.09\linewidth} >{\raggedright\arraybackslash}p{0.42\linewidth}}",
|
||||
r"\toprule",
|
||||
r"Subject CN & Distinct CA Families & Live Certs & CA Families Seen \\",
|
||||
r"\midrule",
|
||||
]
|
||||
[
|
||||
row.subject_cn,
|
||||
str(row.distinct_value_count),
|
||||
str(row.current_certificate_count),
|
||||
truncate_text(row.details, 92),
|
||||
]
|
||||
for row in assessment.vendor_current_rows
|
||||
],
|
||||
font="footnotesize",
|
||||
tabcolsep="3.0pt",
|
||||
)
|
||||
for row in assessment.vendor_current_rows:
|
||||
lines.append(
|
||||
rf"{latex_escape(row.subject_cn)} & {row.distinct_value_count} & {row.current_certificate_count} & {latex_escape(truncate_text(row.details, 92))} \\"
|
||||
)
|
||||
lines.extend([r"\bottomrule", r"\end{longtable}"])
|
||||
else:
|
||||
lines.append(r"No current CA-family drift was found.")
|
||||
lines.append(r"\subsection{Past CA-Family Drift Now Fixed}")
|
||||
if assessment.vendor_past_rows:
|
||||
lines.extend(
|
||||
append_longtable(
|
||||
lines,
|
||||
r">{\raggedright\arraybackslash}p{0.27\linewidth} >{\raggedleft\arraybackslash}p{0.10\linewidth} >{\raggedleft\arraybackslash}p{0.09\linewidth} >{\raggedright\arraybackslash}p{0.45\linewidth}",
|
||||
["Subject CN", "Distinct CA Families", "Historic Certs", "CA Families Seen"],
|
||||
[
|
||||
r"\begin{longtable}{>{\raggedright\arraybackslash}p{0.28\linewidth} >{\raggedleft\arraybackslash}p{0.11\linewidth} >{\raggedleft\arraybackslash}p{0.11\linewidth} >{\raggedright\arraybackslash}p{0.40\linewidth}}",
|
||||
r"\toprule",
|
||||
r"Subject CN & Distinct CA Families & Historic Certs & CA Families Seen \\",
|
||||
r"\midrule",
|
||||
]
|
||||
[
|
||||
row.subject_cn,
|
||||
str(row.distinct_value_count),
|
||||
str(row.certificate_count),
|
||||
truncate_text(row.details, 92),
|
||||
]
|
||||
for row in assessment.vendor_past_rows
|
||||
],
|
||||
font="footnotesize",
|
||||
tabcolsep="3.0pt",
|
||||
)
|
||||
for row in assessment.vendor_past_rows:
|
||||
lines.append(
|
||||
rf"{latex_escape(row.subject_cn)} & {row.distinct_value_count} & {row.certificate_count} & {latex_escape(truncate_text(row.details, 92))} \\"
|
||||
)
|
||||
lines.extend([r"\bottomrule", r"\end{longtable}"])
|
||||
else:
|
||||
lines.append(r"No past-only CA-family drift was found.")
|
||||
lines.append(r"\subsection{Current SAN Drift}")
|
||||
if assessment.san_current_rows:
|
||||
lines.extend(
|
||||
append_longtable(
|
||||
lines,
|
||||
r">{\raggedright\arraybackslash}p{0.21\linewidth} >{\raggedleft\arraybackslash}p{0.08\linewidth} >{\raggedleft\arraybackslash}p{0.08\linewidth} >{\raggedright\arraybackslash}p{0.18\linewidth} >{\raggedright\arraybackslash}p{0.35\linewidth}",
|
||||
["Subject CN", "Profiles", "Live Certs", "Delta Pattern", "Representative Delta"],
|
||||
[
|
||||
r"\begin{longtable}{>{\raggedright\arraybackslash}p{0.22\linewidth} >{\raggedleft\arraybackslash}p{0.09\linewidth} >{\raggedleft\arraybackslash}p{0.09\linewidth} >{\raggedright\arraybackslash}p{0.18\linewidth} >{\raggedright\arraybackslash}p{0.32\linewidth}}",
|
||||
r"\toprule",
|
||||
r"Subject CN & Profiles & Live Certs & Delta Pattern & Representative Delta \\",
|
||||
r"\midrule",
|
||||
]
|
||||
[
|
||||
row.subject_cn,
|
||||
str(row.distinct_san_profiles),
|
||||
str(row.current_certificate_count),
|
||||
row.delta_pattern,
|
||||
truncate_text(row.representative_delta, 92),
|
||||
]
|
||||
for row in assessment.san_current_rows
|
||||
],
|
||||
font="footnotesize",
|
||||
tabcolsep="3.0pt",
|
||||
)
|
||||
for row in assessment.san_current_rows:
|
||||
lines.append(
|
||||
rf"{latex_escape(row.subject_cn)} & {row.distinct_san_profiles} & {row.current_certificate_count} & {latex_escape(row.delta_pattern)} & {latex_escape(truncate_text(row.representative_delta, 92))} \\"
|
||||
)
|
||||
lines.extend([r"\bottomrule", r"\end{longtable}"])
|
||||
else:
|
||||
lines.append(r"No current SAN drift was found.")
|
||||
lines.append(r"\subsection{Past SAN Drift Now Fixed}")
|
||||
if assessment.san_past_rows:
|
||||
lines.extend(
|
||||
append_longtable(
|
||||
lines,
|
||||
r">{\raggedright\arraybackslash}p{0.21\linewidth} >{\raggedleft\arraybackslash}p{0.08\linewidth} >{\raggedleft\arraybackslash}p{0.09\linewidth} >{\raggedright\arraybackslash}p{0.18\linewidth} >{\raggedright\arraybackslash}p{0.35\linewidth}",
|
||||
["Subject CN", "Profiles", "Historic Certs", "Delta Pattern", "Representative Delta"],
|
||||
[
|
||||
r"\begin{longtable}{>{\raggedright\arraybackslash}p{0.22\linewidth} >{\raggedleft\arraybackslash}p{0.09\linewidth} >{\raggedleft\arraybackslash}p{0.11\linewidth} >{\raggedright\arraybackslash}p{0.18\linewidth} >{\raggedright\arraybackslash}p{0.30\linewidth}}",
|
||||
r"\toprule",
|
||||
r"Subject CN & Profiles & Historic Certs & Delta Pattern & Representative Delta \\",
|
||||
r"\midrule",
|
||||
]
|
||||
[
|
||||
row.subject_cn,
|
||||
str(row.distinct_san_profiles),
|
||||
str(row.certificate_count),
|
||||
row.delta_pattern,
|
||||
truncate_text(row.representative_delta, 92),
|
||||
]
|
||||
for row in assessment.san_past_rows
|
||||
],
|
||||
font="footnotesize",
|
||||
tabcolsep="3.0pt",
|
||||
)
|
||||
for row in assessment.san_past_rows:
|
||||
lines.append(
|
||||
rf"{latex_escape(row.subject_cn)} & {row.distinct_san_profiles} & {row.certificate_count} & {latex_escape(row.delta_pattern)} & {latex_escape(truncate_text(row.representative_delta, 92))} \\"
|
||||
)
|
||||
lines.extend([r"\bottomrule", r"\end{longtable}"])
|
||||
else:
|
||||
lines.append(r"No past-only SAN drift was found.")
|
||||
lines.append(r"\subsection{Historic Start Dates}")
|
||||
lines.extend(
|
||||
append_longtable(
|
||||
lines,
|
||||
r">{\raggedright\arraybackslash}p{0.16\linewidth} >{\raggedleft\arraybackslash}p{0.10\linewidth} >{\raggedright\arraybackslash}p{0.62\linewidth}",
|
||||
["Start Day", "Certificates", "Dominant Driver"],
|
||||
[
|
||||
r"\begin{longtable}{>{\raggedright\arraybackslash}p{0.16\linewidth} >{\raggedleft\arraybackslash}p{0.10\linewidth} >{\raggedright\arraybackslash}p{0.62\linewidth}}",
|
||||
r"\toprule",
|
||||
r"Start Day & Certificates & Dominant Driver \\",
|
||||
r"\midrule",
|
||||
]
|
||||
[
|
||||
row.start_day,
|
||||
str(row.certificate_count),
|
||||
driver_summary(row.top_subjects, row.top_issuers),
|
||||
]
|
||||
for row in assessment.day_rows
|
||||
],
|
||||
font="footnotesize",
|
||||
tabcolsep="3.0pt",
|
||||
)
|
||||
for row in assessment.day_rows:
|
||||
lines.append(
|
||||
rf"{latex_escape(row.start_day)} & {row.certificate_count} & {latex_escape(driver_summary(row.top_subjects, row.top_issuers))} \\"
|
||||
)
|
||||
lines.extend([r"\bottomrule", r"\end{longtable}"])
|
||||
lines.append(r"\subsection{Historic Step Weeks}")
|
||||
if assessment.week_rows:
|
||||
lines.extend(
|
||||
append_longtable(
|
||||
lines,
|
||||
r">{\raggedright\arraybackslash}p{0.16\linewidth} >{\raggedleft\arraybackslash}p{0.09\linewidth} >{\raggedleft\arraybackslash}p{0.13\linewidth} >{\raggedright\arraybackslash}p{0.52\linewidth}",
|
||||
["Week Start", "Certs", "Prior 8-Week Avg", "Dominant Driver"],
|
||||
[
|
||||
r"\begin{longtable}{>{\raggedright\arraybackslash}p{0.16\linewidth} >{\raggedleft\arraybackslash}p{0.09\linewidth} >{\raggedleft\arraybackslash}p{0.13\linewidth} >{\raggedright\arraybackslash}p{0.52\linewidth}}",
|
||||
r"\toprule",
|
||||
r"Week Start & Certs & Prior 8-Week Avg & Dominant Driver \\",
|
||||
r"\midrule",
|
||||
]
|
||||
[
|
||||
row.week_start,
|
||||
str(row.certificate_count),
|
||||
row.prior_eight_week_avg,
|
||||
driver_summary(row.top_subjects, row.top_issuers),
|
||||
]
|
||||
for row in assessment.week_rows
|
||||
],
|
||||
font="footnotesize",
|
||||
tabcolsep="3.0pt",
|
||||
)
|
||||
for row in assessment.week_rows:
|
||||
lines.append(
|
||||
rf"{latex_escape(row.week_start)} & {row.certificate_count} & {latex_escape(row.prior_eight_week_avg)} & {latex_escape(driver_summary(row.top_subjects, row.top_issuers))} \\"
|
||||
)
|
||||
lines.extend([r"\bottomrule", r"\end{longtable}"])
|
||||
else:
|
||||
lines.append(r"No step weeks met the threshold.")
|
||||
|
||||
|
|
@ -2559,29 +2652,27 @@ def render_latex(
|
|||
r"\section{CAA Policy Detail}",
|
||||
r"This appendix keeps the issuance-policy evidence inside the monograph. It answers a narrower question than the DNS appendix: not where a name lands, but which public CA families DNS currently authorizes to issue for that name.",
|
||||
r"\subsection{CAA Discovery Paths}",
|
||||
r"\begin{longtable}{>{\raggedright\arraybackslash}p{0.24\linewidth} >{\raggedleft\arraybackslash}p{0.10\linewidth} >{\raggedright\arraybackslash}p{0.54\linewidth}}",
|
||||
r"\toprule",
|
||||
r"CAA Discovery Result & Names & Meaning \\",
|
||||
r"\midrule",
|
||||
]
|
||||
)
|
||||
for label, count, meaning in caa_source_rows(caa_analysis):
|
||||
lines.append(rf"{latex_escape(label)} & {latex_escape(count)} & {latex_escape(meaning)} \\")
|
||||
lines.extend([r"\bottomrule", r"\end{longtable}"])
|
||||
append_longtable(
|
||||
lines,
|
||||
r">{\raggedright\arraybackslash}p{0.23\linewidth} >{\raggedleft\arraybackslash}p{0.10\linewidth} >{\raggedright\arraybackslash}p{0.55\linewidth}",
|
||||
["CAA Discovery Result", "Names", "Meaning"],
|
||||
caa_source_rows(caa_analysis),
|
||||
font="footnotesize",
|
||||
tabcolsep="3.0pt",
|
||||
)
|
||||
lines.append(r"\subsection{Policy Regimes By Configured Zone}")
|
||||
for zone in caa_analysis.configured_domains:
|
||||
lines.append(rf"\subsubsection{{{latex_escape(zone)}}}")
|
||||
lines.extend(
|
||||
[
|
||||
r"\begin{longtable}{>{\raggedright\arraybackslash}p{0.25\linewidth} >{\raggedleft\arraybackslash}p{0.10\linewidth} >{\raggedright\arraybackslash}p{0.53\linewidth}}",
|
||||
r"\toprule",
|
||||
r"Policy Regime & Names & Plain-Language Meaning \\",
|
||||
r"\midrule",
|
||||
]
|
||||
append_longtable(
|
||||
lines,
|
||||
r">{\raggedright\arraybackslash}p{0.24\linewidth} >{\raggedleft\arraybackslash}p{0.10\linewidth} >{\raggedright\arraybackslash}p{0.56\linewidth}",
|
||||
["Policy Regime", "Names", "Plain-Language Meaning"],
|
||||
caa_zone_rows[zone],
|
||||
font="footnotesize",
|
||||
tabcolsep="3.0pt",
|
||||
)
|
||||
for regime, count, meaning in caa_zone_rows[zone]:
|
||||
lines.append(rf"{latex_escape(regime)} & {latex_escape(count)} & {latex_escape(meaning)} \\")
|
||||
lines.extend([r"\bottomrule", r"\end{longtable}"])
|
||||
lines.append(r"\subsection{Current Multi-Family Overlap}")
|
||||
if caa_analysis.multi_family_overlap_names:
|
||||
lines.extend(
|
||||
|
|
|
|||
Loading…
Reference in a new issue