talas-group/09_MODELE_ECONOMIQUE/Subventions/generate_pdf2_evidence.py

271 lines
10 KiB
Python
Raw Normal View History

#!/usr/bin/env python3
"""
Generate PDF 2: Talas Project Evidence (Software + Infrastructure)
For NGI Zero Commons Fund application attachment.
Demonstrates delivery capacity and project maturity.
"""
from fpdf import FPDF
import os
BASE = "/home/senke/Documents/TG__Talas_Group"
OUT = f"{BASE}/09_MODELE_ECONOMIQUE/Subventions/talas-project-evidence.pdf"
FONT_DIR = "/usr/share/fonts/liberation-sans-fonts"
class TalasPDF(FPDF):
def __init__(self):
super().__init__()
self.add_font("Sans", "", f"{FONT_DIR}/LiberationSans-Regular.ttf")
self.add_font("Sans", "B", f"{FONT_DIR}/LiberationSans-Bold.ttf")
self.add_font("Sans", "I", f"{FONT_DIR}/LiberationSans-Italic.ttf")
self.add_font("Sans", "BI", f"{FONT_DIR}/LiberationSans-BoldItalic.ttf")
def header(self):
self.set_font("Sans", "B", 9)
self.set_text_color(100, 100, 100)
self.cell(0, 5, "Talas — NGI Zero Commons Fund Application — Attachment 2", align="R")
self.ln(8)
def footer(self):
self.set_y(-15)
self.set_font("Sans", "I", 8)
self.set_text_color(150, 150, 150)
self.cell(0, 10, f"Page {self.page_no()}/{{nb}}", align="C")
def section_title(self, title):
self.set_font("Sans", "B", 13)
self.set_text_color(30, 30, 30)
self.cell(0, 10, title, new_x="LMARGIN", new_y="NEXT")
self.set_draw_color(60, 60, 60)
self.line(self.l_margin, self.get_y(), self.w - self.r_margin, self.get_y())
self.ln(4)
def sub_title(self, title):
self.set_font("Sans", "B", 11)
self.set_text_color(50, 50, 50)
self.cell(0, 8, title, new_x="LMARGIN", new_y="NEXT")
self.ln(1)
def body_text(self, text):
self.set_font("Sans", "", 10)
self.set_text_color(40, 40, 40)
self.multi_cell(0, 5, text)
self.ln(2)
def metric_row(self, label, value, detail=""):
self.set_font("Sans", "B", 10)
self.set_text_color(40, 40, 40)
self.cell(55, 6, label)
self.set_font("Sans", "", 10)
self.set_text_color(30, 100, 30)
self.cell(35, 6, value)
self.set_text_color(120, 120, 120)
self.set_font("Sans", "I", 9)
self.cell(0, 6, detail, new_x="LMARGIN", new_y="NEXT")
def bullet(self, text, indent=10):
x = self.get_x()
self.set_font("Sans", "", 9)
self.set_text_color(40, 40, 40)
self.cell(indent, 5, "\u2022")
self.multi_cell(self.w - self.r_margin - self.l_margin - indent, 5, text)
self.ln(1)
def main():
pdf = TalasPDF()
pdf.alias_nb_pages()
pdf.set_auto_page_break(auto=True, margin=20)
# =========================================================
# PAGE 1 — Software delivery evidence
# =========================================================
pdf.add_page()
# Title
pdf.set_font("Sans", "B", 20)
pdf.set_text_color(20, 20, 20)
pdf.cell(0, 12, "Talas — Project Maturity Evidence", align="C",
new_x="LMARGIN", new_y="NEXT")
pdf.set_font("Sans", "", 11)
pdf.set_text_color(80, 80, 80)
pdf.cell(0, 7, "Demonstrating delivery capacity — March 2026", align="C",
new_x="LMARGIN", new_y="NEXT")
pdf.ln(4)
pdf.body_text(
"This document demonstrates the applicant's capacity to deliver on the proposed "
"grant milestones. While this grant focuses on open hardware, the Veza software "
"platform and self-hosted infrastructure provide concrete evidence of sustained, "
"high-quality engineering output by a solo developer."
)
# --- Veza Platform ---
pdf.section_title("1. Veza Platform — Software Delivery Metrics")
pdf.sub_title("Development Velocity")
pdf.metric_row("Total commits (90 days):", "974", "~10.8 commits/day")
pdf.metric_row("Total commits (30 days):", "162", "~5.4 commits/day")
pdf.metric_row("Releases shipped:", "38+", "over 5 months")
pdf.metric_row("CI/CD workflows:", "28", "GitHub Actions")
pdf.metric_row("CI cache hit rate:", "80%", "optimised build pipeline")
pdf.ln(3)
pdf.sub_title("Backend (Go)")
pdf.metric_row("API endpoints:", "102", "REST API handlers")
pdf.metric_row("Database migrations:", "147", "PostgreSQL schema versions")
pdf.metric_row("Test pass rate:", "100%", "104 tests")
pdf.metric_row("Code coverage:", "82.3%", "measured by go test -cover")
pdf.metric_row("Go version:", "1.24", "latest stable")
pdf.ln(3)
pdf.sub_title("Stream Server (Rust)")
pdf.bullet("HLS audio transcoding (FFmpeg integration)")
pdf.bullet("WebSocket real-time chat")
pdf.bullet("Symphonia audio codec library for native decoding")
pdf.bullet("Axum + Tokio async runtime")
pdf.ln(2)
pdf.sub_title("Frontend (React/TypeScript)")
pdf.metric_row("Feature modules:", "35", "")
pdf.metric_row("Languages:", "3", "EN / FR / ES")
pdf.metric_row("ESLint status:", "0 errors", "63 acceptable warnings")
pdf.ln(3)
# --- Security ---
pdf.section_title("2. Security Posture")
pdf.body_text(
"Security-first approach informed by the applicant's academic background "
"(Bachelor + Master in Cybersecurity, EPITA & OTERIA)."
)
pdf.sub_title("External Penetration Test (October 2025)")
pdf.metric_row("Findings identified:", "36", "")
pdf.metric_row("Findings remediated:", "36/36", "100% remediation rate")
pdf.metric_row("Static analysis:", "staticcheck", "integrated in CI")
pdf.metric_row("Secret scanning:", "gitleaks", "automated in pipeline")
pdf.metric_row("Dependency audit:", "automated", "CI/CD integration")
pdf.ln(3)
pdf.sub_title("Security Features Implemented")
security_features = [
"JWT RS256 token authentication",
"WebAuthn / passkeys (passwordless login)",
"Two-factor authentication (TOTP)",
"GDPR-compliant data export and deletion",
"Content Security Policy + security headers",
"Coraza WAF with OWASP Core Rule Set",
"Rate limiting and brute-force protection",
]
for feat in security_features:
pdf.bullet(feat)
# =========================================================
# PAGE 2 — Infrastructure + Legal + Summary
# =========================================================
pdf.add_page()
pdf.section_title("3. Self-Hosted Infrastructure")
pdf.body_text(
"The entire Talas/Veza stack runs on self-owned hardware — no cloud vendor "
"dependency. This demonstrates both technical capability and commitment to "
"infrastructure sovereignty."
)
pdf.sub_title("Hardware")
pdf.metric_row("Servers:", "2x Dell R720", "rack-mounted")
pdf.metric_row("RAM:", "768 GB total", "384 GB per server")
pdf.metric_row("CPU:", "64 cores total", "dual Xeon per server")
pdf.metric_row("Network:", "10 GbE", "inter-server link")
pdf.metric_row("Storage:", "16 HDDs per server (32 total)", "ZFS pools, ~100 spare HDDs in reserve")
pdf.metric_row("Monthly cost:", "~135 EUR", "electricity only")
pdf.ln(3)
pdf.sub_title("Automation & Monitoring")
pdf.metric_row("Ansible roles:", "48", "full infrastructure-as-code")
pdf.metric_row("Deployment:", "Blue-green", "zero-downtime via HAProxy")
pdf.metric_row("Monitoring:", "Prometheus + Grafana", "metrics & dashboards")
pdf.metric_row("Logging:", "Loki", "centralised log aggregation")
pdf.metric_row("Security:", "Coraza WAF", "OWASP CRS integration")
pdf.metric_row("VPN:", "WireGuard", "secure management access")
pdf.ln(5)
# --- Legal ---
pdf.section_title("4. Legal & Business Readiness")
pdf.body_text(
"Company formation (French micro-entreprise) is planned. The following legal "
"documentation is already prepared:"
)
legal_items = [
"GDPR compliance documentation (privacy policy, data processing records)",
"Terms of use (CGU) and terms of sale (CGV) — drafted",
"Warranty and return policy — drafted",
"Legal notices (mentions legales) — drafted",
"Trademark registration guide — prepared",
"Foundation structure plan — Purpose Trust model (Patagonia-inspired)",
"Ethical fiscal optimisation strategy — documented",
"Business plan with per-unit cost analysis (76 EUR cost / 120-180 EUR target price)",
]
for item in legal_items:
pdf.bullet(item)
pdf.ln(3)
# --- Licenses ---
pdf.section_title("5. Open Source Licenses")
pdf.set_font("Sans", "B", 10)
pdf.set_fill_color(240, 240, 240)
pdf.cell(60, 7, "Component", border=1, fill=True)
pdf.cell(50, 7, "License", border=1, fill=True)
pdf.cell(60, 7, "Status", border=1, fill=True, new_x="LMARGIN", new_y="NEXT")
pdf.set_font("Sans", "", 10)
licenses = [
("Microphone hardware", "CERN-OHL-W-2.0", "Design complete, publication pending"),
("Veza backend (Go)", "AGPL-3.0", "Production-ready"),
("Veza stream server (Rust)", "AGPL-3.0", "Production-ready"),
("Veza frontend (React)", "AGPL-3.0", "Production-ready"),
("Calibration toolkit", "AGPL-3.0", "Planned (grant Milestone 1)"),
("Documentation", "CC-BY-SA-4.0", "Planned (grant Milestone 2)"),
]
for comp, lic, status in licenses:
pdf.cell(60, 6, comp, border=1)
pdf.cell(50, 6, lic, border=1)
pdf.cell(60, 6, status, border=1, new_x="LMARGIN", new_y="NEXT")
pdf.ln(6)
# --- Summary ---
pdf.section_title("6. Summary")
pdf.body_text(
"This project demonstrates sustained, high-quality delivery by a solo developer "
"with formal cybersecurity training (EPITA + OTERIA). The applicant has shipped "
"38 releases of a production-grade platform, passed an external security audit "
"with 100% remediation, built and manages a self-hosted infrastructure with 48 "
"Ansible roles, and designed a functional microphone prototype with 2 custom PCBs."
)
pdf.body_text(
"The grant request (12,000 EUR) funds a focused, concrete deliverable: "
"transforming the existing microphone prototype into a reproducible open-hardware "
"commons with professional measurements, verified documentation, and independent "
"build validation."
)
# =========================================================
# Output
# =========================================================
pdf.output(OUT)
print(f"PDF generated: {OUT}")
print(f"Pages: {pdf.pages_count}")
if __name__ == "__main__":
main()