main
  1#!/usr/bin/env python3
  2# Quarterly report generator — reference implementation (Q2 2026).
  3#
  4# Reusable structure: CSS reuse from Template.html via /tmp/q2-style.html,
  5# section assembly, adv_rows() with the Credited/Authored vs Triaged split and
  6# the Outcome (state) column.
  7#
  8# PER-QUARTER (must be refreshed each run — do NOT copy values blindly):
  9#   - input paths: /tmp/q<N>-daily-plan.json, /tmp/q<N>-cal.json, /tmp/q<N>-drive.json
 10#   - meetings[] list + total (from calendar analysis, step 2c)
 11#   - notable_docs[] (from Drive, step 2e)
 12#   - VMT_THREADS (from tekton-vmt mu count, step 2g)
 13#   - CFP / Talks card items (org_done + cfp-radar PRs)
 14#   - executive summary prose, hero dates, output filename
 15#
 16# The advisory table (adv_rows + group headers + Outcome badges) and the
 17# stats strip are data-driven and portable across quarters.
 18
 19import json
 20import html
 21from collections import defaultdict
 22
 23d = json.load(open('/tmp/q2-daily-plan.json'))
 24style = open('/tmp/q2-style.html').read()
 25
 26def esc(s): return html.escape(str(s or ''))
 27
 28# ---- counts ----
 29merged = d['github_merged']
 30reviewed = d['github_reviewed']
 31issues = d['github_issues_created']
 32jira = d['jira_completed']
 33adv = d['github_security_advisories']
 34n_repos = len(set(x['repo'] for x in merged+reviewed+issues))
 35
 36# group helper
 37def by_repo(items):
 38    g = defaultdict(list)
 39    for x in items:
 40        g[x['repo']].append(x)
 41    # order by count desc
 42    return sorted(g.items(), key=lambda kv: -len(kv[1]))
 43
 44CORE = {'tektoncd/pipeline','tektoncd/cli','tektoncd/operator','tektoncd/triggers',
 45        'tektoncd/chains','tektoncd/results','tektoncd/pruner','tektoncd/pipelines-as-code'}
 46INFRA = {'tektoncd/plumbing','tektoncd/infra','openshift-pipelines/plumbing','tektoncd/.github','tektoncd/actions'}
 47
 48def group_label(repo):
 49    if repo in CORE:
 50        return ('⚡ Tekton Core', 0)
 51    if repo in INFRA:
 52        return ('🔧 CI / Infrastructure', 1)
 53    if repo.startswith('openshift-pipelines'):
 54        return ('🚀 OpenShift Pipelines', 2)
 55    return ('🌐 Community, Catalog & Website', 3)
 56
 57def pr_rows(items, limit_per_repo=12):
 58    # build grouped table rows
 59    groups = defaultdict(list)
 60    for repo, lst in by_repo(items):
 61        groups[group_label(repo)].append((repo, lst))
 62    out = []
 63    for (glabel, _), repos in sorted(groups.items(), key=lambda kv: kv[0][1]):
 64        out.append(f'<tr class="group-header"><td colspan="3">{esc(glabel)}</td></tr>')
 65        for repo, lst in repos:
 66            links = '<br>'.join(
 67                f'<a class="pr-link" href="{esc(x["url"])}" target="_blank">{esc(x["title"])}</a>'
 68                for x in lst[:limit_per_repo])
 69            more = '' if len(lst) <= limit_per_repo else f'<br><span style="font-size:0.78rem;color:#999">+ {len(lst)-limit_per_repo} more</span>'
 70            out.append(
 71                f'<tr><td><span class="repo-badge">{esc(repo)}</span></td>'
 72                f'<td>{links}{more}</td>'
 73                f'<td style="font-weight:700;color:var(--indigo)">{len(lst)}</td></tr>')
 74    return '\n'.join(out)
 75
 76# ---- Jira epics: keep epics/features prominent, but show all 8 ----
 77def jira_rows():
 78    out=[]
 79    for j in jira:
 80        key=j.get('key')
 81        summ=j.get('summary')
 82        st=j.get('status','Closed')
 83        url=f"https://issues.redhat.com/browse/{key}"
 84        out.append(
 85            f'<tr><td><a href="{esc(url)}" target="_blank" class="key-badge">{esc(key)}</a></td>'
 86            f'<td><strong>{esc(summ)}</strong></td>'
 87            f'<td><span class="status-closed">{esc(st)}</span></td></tr>')
 88    return '\n'.join(out)
 89
 90# ---- issues by theme ----
 91def issue_rows():
 92    return pr_rows(issues, limit_per_repo=10)
 93
 94# ---- advisories ----
 95def adv_rows(items):
 96    out=[]
 97    state_style={'closed':'green','published':'red','draft':'amber','triage':'blue','withdrawn':'purple'}
 98    state_label={'closed':'Closed','published':'Published','draft':'Draft','triage':'In triage','withdrawn':'Withdrawn'}
 99    for a in items:
100        ghsa=a.get('ghsa_id')
101        cve=a.get('cve_id')
102        sev=a.get('severity')
103        summ=a.get('summary')
104        url=a.get('url') or (f"https://github.com/advisories/{ghsa}" if ghsa else '#')
105        st=a.get('state') or ''
106        cve_badge=f'<span class="cve-badge">{esc(cve)}</span>' if cve else ''
107        sevtag={'critical':'red','high':'red','medium':'amber','low':'blue'}.get(sev,'blue')
108        sttag=state_style.get(st,'blue')
109        stlabel=state_label.get(st,st or '-')
110        out.append(
111            f'<tr><td><a class="pr-link" href="{esc(url)}" target="_blank">{esc(ghsa)}</a>{cve_badge}</td>'
112            f'<td>{esc(summ)}</td>'
113            f'<td><span class="repo-badge">{esc(a.get("repo"))}</span></td>'
114            f'<td><span class="tag {sevtag}">{esc(sev or "-")}</span></td>'
115            f'<td><span class="tag {sttag}">{esc(stlabel)}</span></td></tr>')
116    return '\n'.join(out)
117
118adv_credited=[a for a in adv if a.get('role') in ('author','credited')]
119adv_triaged=[a for a in adv if a.get('role')=='triaged']
120VMT_THREADS=13
121
122# ---- meetings (from calendar analysis, hardcoded top series) ----
123meetings = [
124    ("Pipelines Core Weekly", 13), ("Pipelines weekly Architecture Decision Review (ADR)", 13),
125    ("OpenShift Pipelines Performance Sync", 13), ("Pipelines as Code Internal Weekly", 13),
126    ("Leading Forward Metrics Initiative Sync", 13), ("Pipelines Multicluster: Sync with Konflux", 13),
127    ("Vincent / Vibhav syncup", 13), ("[Weekly] OpenShift Pipelines Program Call", 12),
128    ("PM / Engineering Managers Weekly Sync", 12), ("1:1s (Vincent, Eyal:Vincent)", 22),
129    ("Konflux Program Meeting", 10), ("Backlog Refinement OpenShift Pipelines", 10),
130    ("Stakeholder Meeting", 13), ("OpenShift Pipelines Sprint Demo", 7),
131    ("Konflux Internal Architecture Call", 5), ("The 2026 Goals: Bi-Weekly Sync", 5),
132]
133def meeting_items():
134    return '\n'.join(
135        f'<li><span class="meeting-dot"></span><div><div class="meeting-title">{esc(name)}</div>'
136        f'<div class="meeting-meta">{n} sessions in Q2</div></div></li>'
137        for name,n in meetings)
138
139# ---- drive docs ----
140drive = json.load(open('/tmp/q2-drive.json'))
141dfiles = drive.get('files') or drive.get('items') or []
142notable_docs = [
143    "Design: Post-Quantum Crypto for Sigstore (Public)",
144    "The Autonomous Workflow: Introduce Agentic Workflows on Tekton",
145    "OpenShift Policy - Enabling Github Commit Signing Verification",
146    "Konflux dependencies risk for 100x scale",
147    "Notes - Plan to bring results in parity with Kubearchive",
148    "Working Agreement | OpenShift Pipelines Team",
149    "Pipelines weekly Architecture Decision Review (ADR) — Notes",
150    "Weekly updates report to the team",
151    "RH Operator Portfolio Alignment Call",
152    "Applied AI Architecture Call",
153]
154def doc_items():
155    return '\n'.join(
156        f'<li><span class="meeting-dot" style="background:var(--teal)"></span><div><div class="meeting-title">{esc(n)}</div></div></li>'
157        for n in notable_docs)
158
159# ---- assemble ----
160H = []
161H.append(f'''<!DOCTYPE html>
162<html lang="en"><head><meta charset="UTF-8">
163<meta name="viewport" content="width=device-width, initial-scale=1.0">
164<title>Q2 2026 Achievements — Vincent Demeester</title>
165{style}</head><body>
166<div class="hero"><div class="hero-inner">
167  <span class="hero-badge">Quarterly Achievements</span>
168  <h1>Q2 2026 <span>· Apr 1 – Jun 30</span></h1>
169  <div class="hero-sub">Vincent Demeester · Senior Principal Software Engineer · R&amp;D Secure Flow</div>
170  <div class="hero-meta">
171    <div class="hero-meta-item"><span class="icon">👤</span> Vincent Demeester</div>
172    <div class="hero-meta-item"><span class="icon">🏢</span> Red Hat · OpenShift Pipelines</div>
173    <div class="hero-meta-item"><span class="icon">👔</span> Manager: Eyal Edri</div>
174  </div>
175</div></div>
176
177<div class="stats-strip"><div class="stats-inner">
178  <div class="stat-item"><div class="stat-num">{len(jira)}</div><div class="stat-label">Jira Issues Closed</div></div>
179  <div class="stat-item"><div class="stat-num">{len(merged)}</div><div class="stat-label">PRs Merged</div></div>
180  <div class="stat-item"><div class="stat-num">{len(reviewed)}</div><div class="stat-label">PRs Reviewed</div></div>
181  <div class="stat-item"><div class="stat-num">{len(issues)}</div><div class="stat-label">Issues Filed</div></div>
182  <div class="stat-item"><div class="stat-num">{len(adv_credited)}</div><div class="stat-label">CVEs Credited</div></div>
183  <div class="stat-item"><div class="stat-num">{len(adv)}</div><div class="stat-label">Advisories Triaged</div></div>
184  <div class="stat-item"><div class="stat-num">267</div><div class="stat-label">Meetings</div></div>
185</div></div>
186
187<main class="main">
188
189  <div class="card">
190    <div class="card-header"><div class="card-icon indigo">📋</div>
191      <div><div class="card-title">Executive Summary</div><div class="card-subtitle">Q2 2026 · Apr 1 – Jun 30</div></div></div>
192    <div class="card-body" style="padding: 20px 24px; line-height: 1.75; font-size: 0.93rem;">
193      <p style="margin-bottom:12px;">Vincent Demeester sustained an exceptionally high output in Q2 2026, merging <strong>{len(merged)} pull requests</strong> and reviewing <strong>{len(reviewed)} more</strong> across <strong>{n_repos} repositories</strong> in the tektoncd and openshift-pipelines orgs, while closing <strong>{len(jira)} Jira issues</strong> spanning epics, performance bugs, and governance automation.</p>
194      <p style="margin-bottom:12px;">He led significant <strong>security and reliability work</strong> as a member of the Tekton VMT, reviewing and triaging <strong>{len(adv)} security advisories</strong> ({len(adv_credited)} crediting him as author/reporter) plus <strong>{VMT_THREADS} tekton-vmt report threads</strong> — including authoring a Git resolver token-leak (<a href="https://github.com/advisories/GHSA-wjxp-xrpv-xpff" target="_blank" style="color:var(--indigo)">CVE-2026-40161</a>) and an unauthenticated core-interceptors secret-exfiltration vulnerability (<a href="https://github.com/advisories/GHSA-gfmw-q9x8-xcrp" target="_blank" style="color:var(--indigo)">CVE-2026-54456</a>) — plus a fix for thousands of redundant PipelineRun reconciliations (<a href="https://issues.redhat.com/browse/SRVKP-9988" target="_blank" class="key-badge">SRVKP-9988</a>) and an API rate-limit failure in 1.17 (<a href="https://issues.redhat.com/browse/SRVKP-7037" target="_blank" class="key-badge">SRVKP-7037</a>).</p>
195      <p style="margin-bottom:12px;">The bulk of authored work landed in <strong>tektoncd/pipeline</strong> (47 PRs) and the CI/infrastructure repos <strong>tektoncd/plumbing</strong> (23) and <strong>tektoncd/operator</strong> (11), keeping release tracks, dogfooding clusters, and dependency automation healthy. Review load was dominated by <strong>tektoncd/pipeline</strong> (216 reviews) and <strong>tektoncd/operator</strong> (60), reflecting his role as a primary maintainer and reviewer across the core projects.</p>
196      <p>On the community and governance front, Vincent automated branch protection for the openshift-pipelines GitHub org (<a href="https://issues.redhat.com/browse/SRVKP-11412" target="_blank" class="key-badge">SRVKP-11412</a>), updated the official CNCF maintainers list (<a href="https://issues.redhat.com/browse/SRVKP-11033" target="_blank" class="key-badge">SRVKP-11033</a>), and refreshed OWNERS/maintainers across tektoncd repositories (<a href="https://issues.redhat.com/browse/SRVKP-11026" target="_blank" class="key-badge">SRVKP-11026</a>). He filed <strong>{len(issues)} issues</strong> to plan and track future work, and engaged across <strong>267 meetings spanning 64 recurring series</strong> as a technical lead and cross-team coordinator.</p>
197    </div>
198  </div>
199
200  <div class="card">
201    <div class="card-header"><div class="card-icon indigo">🎯</div>
202      <div><div class="card-title">Jira — Issues Closed <span class="count-pill">{len(jira)}</span></div><div class="card-subtitle">Q2 2026 · SRVKP (resolved in period)</div></div></div>
203    <div class="section-summary">Resolved <strong>{len(jira)} tracked issues</strong> in Q2, including two security epics, two high-impact performance/reliability bugs (redundant reconciliation and API rate-limiting), and three governance-automation items covering branch protection, CNCF maintainer lists, and cross-repo OWNERS updates.</div>
204    <div class="card-body"><table>
205      <thead><tr><th>Key</th><th>Summary</th><th>Status</th></tr></thead>
206      <tbody>{jira_rows()}</tbody></table></div>
207  </div>
208
209  <div class="card">
210    <div class="card-header"><div class="card-icon blue">⚙️</div>
211      <div><div class="card-title">GitHub — Pull Requests Authored &amp; Merged <span class="count-pill">{len(merged)}</span></div><div class="card-subtitle">Grouped by repository · Apr–Jun 2026</div></div></div>
212    <div class="section-summary">Merged <strong>{len(merged)} PRs across {len(set(x["repo"] for x in merged))} repositories</strong>. Highest volume in <strong>tektoncd/pipeline</strong> (47) covering features, fixes, security hardening, and release cherry-picks, followed by CI/infra work in <strong>tektoncd/plumbing</strong> (23) and <strong>tektoncd/operator</strong> (11), with additional contributions to infra, catalog, community, and website.</div>
213    <div class="card-body"><table>
214      <thead><tr><th>Repository</th><th>Contributions</th><th>Count</th></tr></thead>
215      <tbody>{pr_rows(merged)}</tbody></table></div>
216  </div>
217
218  <div class="card">
219    <div class="card-header"><div class="card-icon green">👁️</div>
220      <div><div class="card-title">GitHub — Pull Requests Reviewed <span class="count-pill">{len(reviewed)}</span></div><div class="card-subtitle">Grouped by repository · Apr–Jun 2026</div></div></div>
221    <div class="section-summary">Reviewed <strong>{len(reviewed)} pull requests</strong> authored by others, dominated by <strong>tektoncd/pipeline</strong> (216) and <strong>tektoncd/operator</strong> (60), with substantial review load in <strong>tektoncd/plumbing</strong> (72) and <strong>tektoncd/cli</strong> (26) — reflecting maintainer-level ownership across the core Tekton projects and dependency-update pipelines.</div>
222    <div class="card-body"><table>
223      <thead><tr><th>Repository</th><th>Sample Reviewed PRs</th><th>Count</th></tr></thead>
224      <tbody>{pr_rows(reviewed, limit_per_repo=8)}</tbody></table></div>
225  </div>
226
227  <div class="card">
228    <div class="card-header"><div class="card-icon amber">📝</div>
229      <div><div class="card-title">GitHub — Issues Filed <span class="count-pill">{len(issues)}</span></div><div class="card-subtitle">Grouped by repository · Apr–Jun 2026</div></div></div>
230    <div class="section-summary">Filed <strong>{len(issues)} issues</strong> to plan and track work across the tektoncd org, concentrated in <strong>tektoncd/pipeline</strong> (32), <strong>tektoncd/cli</strong> (14), and <strong>tektoncd/plumbing</strong> (12) — spanning bug reports, security follow-ups, feature proposals, and CI/infra tasks.</div>
231    <div class="card-body"><table>
232      <thead><tr><th>Repository</th><th>Sample Issues</th><th>Count</th></tr></thead>
233      <tbody>{issue_rows()}</tbody></table></div>
234  </div>
235
236  <div class="card">
237    <div class="card-header"><div class="card-icon red">🔒</div>
238      <div><div class="card-title">GitHub — Security Advisories <span class="count-pill">{len(adv)}</span></div><div class="card-subtitle">VMT review queue · {len(adv_credited)} credited/authored + {len(adv_triaged)} triaged · Apr–Jun 2026</div></div></div>
239    <div class="section-summary">As a member of the <strong>Tekton Vulnerability Management Team (VMT)</strong>, reviewed and triaged <strong>{len(adv)} security advisories</strong> across pipeline, triggers, chains, and pipelines-as-code, of which <strong>{len(adv_credited)} credited Vincent as author or reporter</strong>. This includes coordinating a Git-resolver token-leak (CVE-2026-40161, authored), a Git-resolver RCE via argument injection (CVE-2026-40938), and an unauthenticated core-interceptors secret-exfiltration vulnerability (CVE-2026-54456, authored). Alongside the GitHub advisories, Vincent processed <strong>{VMT_THREADS} distinct security report threads</strong> on the tekton-vmt mailing list — the bulk of triage/review work that is not formally credited on the published advisories. Of the {len(adv_triaged)} triaged advisories, {sum(1 for a in adv_triaged if a.get("state")=="closed")} were closed (rejected, duplicate, or resolved), {sum(1 for a in adv_triaged if a.get("state")=="published")} published, and {sum(1 for a in adv_triaged if a.get("state") in ("draft","triage"))} remain in draft/triage.</div>
240    <div class="card-body">
241      <table>
242        <thead><tr><th>Advisory</th><th>Summary</th><th>Repo</th><th>Severity</th><th>Outcome</th></tr></thead>
243        <tbody>
244          <tr class="group-header"><td colspan="5">⭐ Credited / Authored ({len(adv_credited)})</td></tr>
245          {adv_rows(adv_credited)}
246          <tr class="group-header"><td colspan="5">🛡 Triaged — VMT review queue ({len(adv_triaged)})</td></tr>
247          {adv_rows(adv_triaged)}
248        </tbody>
249      </table>
250    </div>
251  </div>
252
253  <div class="card">
254    <div class="card-header"><div class="card-icon amber">🎤</div>
255      <div><div class="card-title">Talks, CFPs &amp; Community Visibility</div><div class="card-subtitle">Conference submissions, blogs &amp; presentations · Apr–Jun 2026</div></div></div>
256    <div class="section-summary">Drove external visibility for OpenShift Pipelines: submitted a CFP to <strong>Open Source Summit EU</strong>, prepared <strong>KubeCon NA 2026 CFP abstracts</strong> and a reframed CVE talk abstract ("When the LLMs Come Knocking") via the <strong>cfp-radar</strong> tracker, authored a Red Hat blog entry on the CNCF transition, and prepared the Konflux Architecture Review presentation.</div>
257    <div class="card-body"><ul class="meeting-list">
258      <li><span class="meeting-dot" style="background:var(--amber)"></span><div><div class="meeting-title">CFP — Open Source Summit EU</div><div class="meeting-meta">Submitted · deadline 2026-06-22</div></div></li>
259      <li><span class="meeting-dot" style="background:var(--amber)"></span><div><div class="meeting-title"><a class="pr-link" href="https://github.com/openshift-pipelines/cfp-radar/pull/2" target="_blank">KubeCon NA 2026 CFP abstracts</a></div><div class="meeting-meta">cfp-radar #2 · merged 2026-04-13</div></div></li>
260      <li><span class="meeting-dot" style="background:var(--amber)"></span><div><div class="meeting-title"><a class="pr-link" href="https://github.com/openshift-pipelines/cfp-radar/pull/3" target="_blank">CVE talk abstract — "When the LLMs Come Knocking"</a></div><div class="meeting-meta">cfp-radar #3 · merged 2026-06-04</div></div></li>
261      <li><span class="meeting-dot" style="background:var(--amber)"></span><div><div class="meeting-title">Red Hat Blog entry — Tekton joining the CNCF</div><div class="meeting-meta">Authored</div></div></li>
262      <li><span class="meeting-dot" style="background:var(--amber)"></span><div><div class="meeting-title">Konflux Architecture Review presentation</div><div class="meeting-meta">Prepared · May 25</div></div></li>
263    </ul></div>
264  </div>
265
266  <div class="card">
267    <div class="card-header"><div class="card-icon indigo">🤝</div>
268      <div><div class="card-title">Meeting &amp; Cross-Team Engagement <span class="count-pill">267</span></div><div class="card-subtitle">Google Calendar · 64 recurring series · Apr–Jun 2026</div></div></div>
269    <div class="section-summary">Attended <strong>267 work meetings across 64 recurring series</strong>, leading core-team syncs (Pipelines Core Weekly, ADR calls, Performance Sync), driving cross-team initiatives (Konflux multicluster, Leading Forward metrics), and maintaining program-level and 1:1 cadences.</div>
270    <div class="card-body"><ul class="meeting-list">{meeting_items()}</ul></div>
271  </div>
272
273  <div class="card">
274    <div class="card-header"><div class="card-icon teal">📄</div>
275      <div><div class="card-title">Documents &amp; Design Work <span class="count-pill">{len(dfiles)}</span></div><div class="card-subtitle">Google Drive · authored / co-authored · Apr–Jun 2026</div></div></div>
276    <div class="section-summary">Authored and contributed to <strong>{len(dfiles)} documents</strong>, including design work on post-quantum crypto for Sigstore, agentic workflows on Tekton, commit-signing verification policy, and Konflux scale/risk analysis.</div>
277    <div class="card-body"><ul class="meeting-list">{doc_items()}</ul></div>
278  </div>
279
280  <div class="card">
281    <div class="card-header"><div class="card-icon purple">🏷️</div>
282      <div><div class="card-title">Areas of Focus</div></div></div>
283    <div class="tags">
284      <span class="tag red">Security &amp; CVEs</span>
285      <span class="tag blue">Tekton Pipelines Core</span>
286      <span class="tag green">Code Review &amp; Maintainership</span>
287      <span class="tag amber">CI / Infrastructure</span>
288      <span class="tag indigo">Performance &amp; Reliability</span>
289      <span class="tag teal">Release Management</span>
290      <span class="tag purple">Governance &amp; CNCF</span>
291      <span class="tag blue">Konflux Integration</span>
292      <span class="tag green">Multicluster</span>
293      <span class="tag amber">Agentic Workflows</span>
294    </div>
295  </div>
296
297</main>
298
299<div class="footer">
300  Generated by pi · Data sources: daily-plan (Jira SRVKP · GitHub vdemeester, tektoncd + openshift-pipelines), Google Calendar, Google Drive, GitHub Security Advisories (VMT), tekton-vmt mailing list, cfp-radar · Period: Apr 1 – Jun 30, 2026 · GitLab &amp; Slack not queried
301</div>
302
303</body></html>''')
304
305open('/home/vdemeest/desktop/downloads/q2-2026-achievements-vincent-demeester.html','w').write('\n'.join(H))
306print("written", sum(len(x) for x in H), "chars")