From f5a537c77bf2db6f81731a4523ec0a18376d43b4 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Apr 2026 14:16:25 +0000 Subject: [PATCH 1/7] Add contributor avatars above username in leaderboard tables Agent-Logs-Url: https://github.com/NextCommunity/.github/sessions/204ccf11-afe1-4fcc-80b2-68d5ae9a73b1 Co-authored-by: jbampton <418747+jbampton@users.noreply.github.com> --- scripts/leaderboard.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/scripts/leaderboard.py b/scripts/leaderboard.py index ef54f57..aa87550 100644 --- a/scripts/leaderboard.py +++ b/scripts/leaderboard.py @@ -767,8 +767,9 @@ def generate_markdown(contributors, levels_data): commits_display += f" ยท ๐Ÿค {coauthored}" commits_display += f" ยท ๐Ÿ“ฆ {repos_count}" + avatar = f'
' lines.append( - f"| {rank} | [@{login}](https://github.com/{login})" + f"| {rank} | {avatar}[@{login}](https://github.com/{login})" f" | {level} | {rarity_display} | {commits_display}" f" | {prog} | {streak_display}" f" | {badges} | {points_display} |" @@ -812,8 +813,9 @@ def generate_markdown(contributors, levels_data): breakdown_parts.append(f"๐Ÿ“ {other_c}") breakdown = " ยท ".join(breakdown_parts) if breakdown_parts else "โ€”" + avatar = f'
' lines.append( - f"| {i} | [@{login}](https://github.com/{login})" + f"| {i} | {avatar}[@{login}](https://github.com/{login})" f" | {first_date} | {last_date}" f" | {days_active} | {cpd}" f" | {breakdown} | Top {pctile}% |" From 10ab2bf3ca6719acfd273ec54ed25baf4b4679af Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Apr 2026 14:22:58 +0000 Subject: [PATCH 2/7] Use avatars.githubusercontent.com URL to avoid redirect Agent-Logs-Url: https://github.com/NextCommunity/.github/sessions/7dd9fc60-ee05-4510-97b0-a8ff60efb3ae Co-authored-by: jbampton <418747+jbampton@users.noreply.github.com> --- scripts/leaderboard.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/leaderboard.py b/scripts/leaderboard.py index aa87550..d80282c 100644 --- a/scripts/leaderboard.py +++ b/scripts/leaderboard.py @@ -767,7 +767,7 @@ def generate_markdown(contributors, levels_data): commits_display += f" ยท ๐Ÿค {coauthored}" commits_display += f" ยท ๐Ÿ“ฆ {repos_count}" - avatar = f'
' + avatar = f'
' lines.append( f"| {rank} | {avatar}[@{login}](https://github.com/{login})" f" | {level} | {rarity_display} | {commits_display}" @@ -813,7 +813,7 @@ def generate_markdown(contributors, levels_data): breakdown_parts.append(f"๐Ÿ“ {other_c}") breakdown = " ยท ".join(breakdown_parts) if breakdown_parts else "โ€”" - avatar = f'
' + avatar = f'
' lines.append( f"| {i} | {avatar}[@{login}](https://github.com/{login})" f" | {first_date} | {last_date}" From 88b407327f7c8a477b6926554e6bd80d442b28fa Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Apr 2026 14:32:27 +0000 Subject: [PATCH 3/7] Replace mixed HTML/Markdown contributor cells with pure HTML anchor tags Agent-Logs-Url: https://github.com/NextCommunity/.github/sessions/e5a9c6c2-cf01-4bd4-acc7-5545e5855fdd Co-authored-by: jbampton <418747+jbampton@users.noreply.github.com> --- scripts/leaderboard.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/scripts/leaderboard.py b/scripts/leaderboard.py index d80282c..a95b540 100644 --- a/scripts/leaderboard.py +++ b/scripts/leaderboard.py @@ -767,9 +767,13 @@ def generate_markdown(contributors, levels_data): commits_display += f" ยท ๐Ÿค {coauthored}" commits_display += f" ยท ๐Ÿ“ฆ {repos_count}" - avatar = f'
' + contributor_cell = ( + f'' + f'
' + f"@{login}
" + ) lines.append( - f"| {rank} | {avatar}[@{login}](https://github.com/{login})" + f"| {rank} | {contributor_cell}" f" | {level} | {rarity_display} | {commits_display}" f" | {prog} | {streak_display}" f" | {badges} | {points_display} |" @@ -813,9 +817,13 @@ def generate_markdown(contributors, levels_data): breakdown_parts.append(f"๐Ÿ“ {other_c}") breakdown = " ยท ".join(breakdown_parts) if breakdown_parts else "โ€”" - avatar = f'
' + contributor_cell = ( + f'' + f'
' + f"@{login}
" + ) lines.append( - f"| {i} | {avatar}[@{login}](https://github.com/{login})" + f"| {i} | {contributor_cell}" f" | {first_date} | {last_date}" f" | {days_active} | {cpd}" f" | {breakdown} | Top {pctile}% |" From 65248351d8eba4e7e36112f8e04eea9916f07354 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Apr 2026 14:43:02 +0000 Subject: [PATCH 4/7] Add alt attribute, ?s=64 to avatar URLs, and extract _contributor_cell helper Agent-Logs-Url: https://github.com/NextCommunity/.github/sessions/466e64a0-98f9-4911-8d6f-64ee775320b7 Co-authored-by: jbampton <418747+jbampton@users.noreply.github.com> --- scripts/leaderboard.py | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/scripts/leaderboard.py b/scripts/leaderboard.py index a95b540..6cb8b98 100644 --- a/scripts/leaderboard.py +++ b/scripts/leaderboard.py @@ -707,6 +707,16 @@ def build_leaderboard(token=None): return sorted_contributors, had_errors, levels_data +def _contributor_cell(login): + """Return a pure-HTML table cell with avatar and username link.""" + return ( + f'' + f'{login}\'s avatar
' + f"@{login}
" + ) + + def generate_markdown(contributors, levels_data): """Generate a gamified markdown leaderboard from contributor data.""" rank_badges = {1: "๐Ÿฅ‡", 2: "๐Ÿฅˆ", 3: "๐Ÿฅ‰"} @@ -767,11 +777,7 @@ def generate_markdown(contributors, levels_data): commits_display += f" ยท ๐Ÿค {coauthored}" commits_display += f" ยท ๐Ÿ“ฆ {repos_count}" - contributor_cell = ( - f'' - f'
' - f"@{login}
" - ) + contributor_cell = _contributor_cell(login) lines.append( f"| {rank} | {contributor_cell}" f" | {level} | {rarity_display} | {commits_display}" @@ -817,11 +823,7 @@ def generate_markdown(contributors, levels_data): breakdown_parts.append(f"๐Ÿ“ {other_c}") breakdown = " ยท ".join(breakdown_parts) if breakdown_parts else "โ€”" - contributor_cell = ( - f'' - f'
' - f"@{login}
" - ) + contributor_cell = _contributor_cell(login) lines.append( f"| {i} | {contributor_cell}" f" | {first_date} | {last_date}" From ca235122db71396ab1e2a6ba054ec352167cb086 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Apr 2026 15:11:27 +0000 Subject: [PATCH 5/7] Validate, URL-encode, and HTML-escape login in _contributor_cell() Agent-Logs-Url: https://github.com/NextCommunity/.github/sessions/4027e7e9-1711-46a1-be39-aa77e1751a77 Co-authored-by: jbampton <418747+jbampton@users.noreply.github.com> --- scripts/leaderboard.py | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/scripts/leaderboard.py b/scripts/leaderboard.py index 6cb8b98..54e67b6 100644 --- a/scripts/leaderboard.py +++ b/scripts/leaderboard.py @@ -1,9 +1,11 @@ """Fetch contributor stats from all NextCommunity repos and update the leaderboard.""" +import html import os import re import sys import urllib.error +import urllib.parse import urllib.request import json from bisect import bisect_right @@ -16,6 +18,9 @@ LEADERBOARD_START = "" LEADERBOARD_END = "" SITE_REPO_NAME = "NextCommunity.github.io" + +# GitHub usernames: alphanumeric and single hyphens, 1-39 characters. +_GITHUB_LOGIN_RE = re.compile(r"^[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?$") DOTGITHUB_REPO_NAME = ".github" # Self-documenting record for each commit entry collected across all repos. @@ -708,12 +713,20 @@ def build_leaderboard(token=None): def _contributor_cell(login): - """Return a pure-HTML table cell with avatar and username link.""" + """Return a pure-HTML table cell with avatar and username link. + + ``login`` is validated against GitHub's username pattern before use. + Raises ``ValueError`` if the login contains unexpected characters. + """ + if not _GITHUB_LOGIN_RE.match(login): + raise ValueError(f"Invalid GitHub login: {login!r}") + safe_login = urllib.parse.quote(login, safe="") + escaped_login = html.escape(login) return ( - f'' - f'{login}\'s avatar
' - f"@{login}
" + f'' + f'{escaped_login}\'s avatar
' + f"@{escaped_login}
" ) From c945a26bdbae00d582818e2a0a203b71ee18fa70 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Apr 2026 15:49:26 +0000 Subject: [PATCH 6/7] Tighten _GITHUB_LOGIN_RE to reject consecutive hyphens Agent-Logs-Url: https://github.com/NextCommunity/.github/sessions/01d6fd0f-7d87-4442-97a6-a4884d35e36a Co-authored-by: jbampton <418747+jbampton@users.noreply.github.com> --- scripts/leaderboard.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/leaderboard.py b/scripts/leaderboard.py index 54e67b6..9b652cd 100644 --- a/scripts/leaderboard.py +++ b/scripts/leaderboard.py @@ -19,8 +19,8 @@ LEADERBOARD_END = "" SITE_REPO_NAME = "NextCommunity.github.io" -# GitHub usernames: alphanumeric and single hyphens, 1-39 characters. -_GITHUB_LOGIN_RE = re.compile(r"^[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?$") +# GitHub usernames: 1-39 alphanumeric chars, interior single hyphens only (no consecutive hyphens). +_GITHUB_LOGIN_RE = re.compile(r"^(?=.{1,39}$)[A-Za-z0-9]+(?:-[A-Za-z0-9]+)*$") DOTGITHUB_REPO_NAME = ".github" # Self-documenting record for each commit entry collected across all repos. From cf616180a7b9740a57edf91a1c9b6f43666739ac Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Mon, 27 Apr 2026 16:11:57 +0000 Subject: [PATCH 7/7] Handle invalid logins gracefully in _contributor_cell() Agent-Logs-Url: https://github.com/NextCommunity/.github/sessions/54ce91a8-a4b5-4ab0-811e-00db602a7025 Co-authored-by: jbampton <418747+jbampton@users.noreply.github.com> --- scripts/leaderboard.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/scripts/leaderboard.py b/scripts/leaderboard.py index 9b652cd..eddcde4 100644 --- a/scripts/leaderboard.py +++ b/scripts/leaderboard.py @@ -716,10 +716,12 @@ def _contributor_cell(login): """Return a pure-HTML table cell with avatar and username link. ``login`` is validated against GitHub's username pattern before use. - Raises ``ValueError`` if the login contains unexpected characters. + Returns ``None`` and logs a warning if the login contains unexpected + characters, so callers can skip the row rather than crashing. """ if not _GITHUB_LOGIN_RE.match(login): - raise ValueError(f"Invalid GitHub login: {login!r}") + print(f"WARNING: skipping contributor with invalid GitHub login: {login!r}") + return None safe_login = urllib.parse.quote(login, safe="") escaped_login = html.escape(login) return ( @@ -791,6 +793,8 @@ def generate_markdown(contributors, levels_data): commits_display += f" ยท ๐Ÿ“ฆ {repos_count}" contributor_cell = _contributor_cell(login) + if contributor_cell is None: + continue lines.append( f"| {rank} | {contributor_cell}" f" | {level} | {rarity_display} | {commits_display}" @@ -837,6 +841,8 @@ def generate_markdown(contributors, levels_data): breakdown = " ยท ".join(breakdown_parts) if breakdown_parts else "โ€”" contributor_cell = _contributor_cell(login) + if contributor_cell is None: + continue lines.append( f"| {i} | {contributor_cell}" f" | {first_date} | {last_date}"