This is an automated email from the ASF dual-hosted git repository. imbajin pushed a commit to branch feat/oink-community-content in repository https://gitbox.apache.org/repos/asf/hugegraph-doc.git
commit d50bc28e85835e9325ff6b0e9ac789156a9e22bd Author: dark <[email protected]> AuthorDate: Fri Sep 4 19:09:33 2026 +0800 docs(community): document reviewed identity mapping - require human-reviewed GitHub login and numeric user ID pairs\n- document maintainer refresh and offline validation commands\n- convert GitHub avatar responses to stripped 128px WebP\n- retain content-addressed same-origin avatar storage --- scripts/community_roster.md | 24 ++++++++++++++++++++++++ scripts/community_roster.py | 20 +++++++++++++++++++- 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/scripts/community_roster.md b/scripts/community_roster.md new file mode 100644 index 000000000..aedf4da70 --- /dev/null +++ b/scripts/community_roster.md @@ -0,0 +1,24 @@ +# Community roster data + +`roster.json` is the checked-in, visitor-facing snapshot of current Apache +HugeGraph PMC members and Committers. It is generated from the three ASF public +sources recorded in the file: + +```bash +python3 scripts/community_roster.py refresh +python3 scripts/community_roster.py validate --warn-after-days 90 +``` + +`refresh` is a maintainer-run operation. It finishes all source, role, mapping, +and avatar checks before atomically replacing the last-good roster. It never +pushes or opens a pull request. + +`github-map.json` is deliberately maintained by human review. A mapping must +record both the exact GitHub login and the account's numeric GitHub user ID. +Do not derive mappings from a person's name, email address, employer, or commit +history. Leave an ASF ID unmapped until a maintainer has confirmed the account. + +Mapped avatars are downloaded during refresh, converted with `cwebp` when +needed, stripped of metadata, checked as 128 by 128 WebP, and stored under a +SHA-256 content-addressed filename. Unmapped members render initials and link +to the ASF phonebook without requiring JavaScript. diff --git a/scripts/community_roster.py b/scripts/community_roster.py index 817d35adb..8c8e61a91 100644 --- a/scripts/community_roster.py +++ b/scripts/community_roster.py @@ -139,7 +139,25 @@ def _avatar_bytes(user_id: int) -> bytes: headers={"Accept": "image/webp", "User-Agent": "apache-hugegraph-doc-community-roster/1"}, ) with urllib.request.urlopen(request, timeout=30) as response: - raw = _strip_webp_metadata(response.read()) + raw = response.read() + try: + raw = _strip_webp_metadata(raw) + except RosterError: + converter = shutil.which("cwebp") + if not converter: + raise RosterError("mapped avatars require cwebp when GitHub does not return WebP") + with tempfile.TemporaryDirectory(prefix="hugegraph-avatar-") as work: + source = pathlib.Path(work) / "source" + target = pathlib.Path(work) / "avatar.webp" + source.write_bytes(raw) + result = subprocess.run( + [converter, "-quiet", "-resize", "128", "128", "-metadata", "none", str(source), "-o", str(target)], + text=True, + capture_output=True, + ) + if result.returncode: + raise RosterError(f"cwebp failed for numeric GitHub user ID {user_id}: {result.stderr.strip()}") + raw = _strip_webp_metadata(target.read_bytes()) if _webp_dimensions(raw) != (128, 128): raise RosterError(f"GitHub avatar for numeric user ID {user_id} is not 128x128 WebP") return raw
