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

Reply via email to