From 080cafeb558c69f81f6fa2f6676b526bdfbed8a6 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 9 Sep 2026 12:46:53 +0000 Subject: [PATCH 1/3] ci: block the maintainer's address, leave contributors' alone The previous revision of this branch rejected every address that was not a service account, which would have blocked an outside contributor from signing off with their own email. DCO sign-off is somebody's own attestation, so their address there is their choice rather than a leak. Three rules now, in place of one blocklist of five consumer domains: - A sign-off trailer may carry any address. Signed-off-by, Co-Authored-By, Reported-by, Reviewed-by, Tested-by and Acked-by are all exempt. - Anywhere else in the message an address is rejected, because that is how one actually arrives by accident -- pasted from a log line, a stack trace, or a quoted report. - The maintainer's own personal address is rejected everywhere, including in a sign-off, matched by SHA-256 digest. Writing it into a public workflow file in the clear would publish it far more prominently than the old commits this check exists to stop repeating. Validated before pushing rather than after. Against the last 60 commits of all four repositories there is not one email false positive: dependabot's support@github.com sign-off passes, version-pinned filenames like claude_code@2.1.263.json are not treated as addresses, and every remaining failure is a session identifier this check already caught. Against the full history of chock-catalog the digest rule flags all 17 commits that really do carry that address, and no others. The workflow's own run: block was then executed end to end: a contributor gmail sign-off passes, the maintainer address and a pasted log line both fail, and neither is echoed into the log. Co-Authored-By: Claude Opus 5 Signed-off-by: Claude --- .github/workflows/ci.yml | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3d0dc80..b00b016 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -58,16 +58,15 @@ jobs: env: BASE_SHA: ${{ github.event.pull_request.base.sha }} run: | - # Local paths and session identifiers. local_data='/home/[A-Za-z0-9._-]+/|/Users/[A-Za-z0-9._-]+/|session_[0-9A-Za-z]{12,}|claude\.ai/code/session|/tmp/claude-[0-9]' - # Any address, not a handful of consumer domains: a corporate or self-hosted - # address is somebody's just as much as a gmail one. The last label must look like - # a TLD, so `claude_code@2.1.263.json` and `pkg@1.2.3.tar.gz` are not matches. email='[A-Za-z0-9._%+-]+@[A-Za-z0-9-]+(\.[A-Za-z0-9-]+)*\.[A-Za-z]{2,24}' - # Addresses that identify a service rather than a person. - allowed='@users\.noreply\.github\.com$|^noreply@anthropic\.com$|^support@github\.com$|^noreply@github\.com$' # Suffixes that make a match a file path rather than an address. not_mail='\.(json|ya?ml|md|txt|py|js|ts|tsx|sh|toml|cfg|ini|lock|log|csv|tsv|html?|svg|png|jpe?g|gif|pdf|zip|gz|tar|whl|so|dll|exe)$' + # Addresses that identify a service rather than a person. + service='@users\.noreply\.github\.com$|^noreply@anthropic\.com$|^support@github\.com$|^noreply@github\.com$' + # The maintainer's personal address, as a SHA-256 digest: writing it here in the + # clear would publish it more prominently than the commits this check guards. + blocked_digest='ecda4887099c1a8d73af02994c42938dfb0a1857674f6c3a6403af922360104f' found=0 while read -r sha; do msg=$(git log -1 --format=%B "$sha") @@ -76,10 +75,21 @@ jobs: echo "::error::commit $sha contains a local path or session identifier" found=1 fi - if printf '%s' "$msg" | grep -oiE "$email" | grep -ivE "$not_mail" | grep -qivE "$allowed"; then - echo "::error::commit $sha contains an email address; sign off with your GitHub noreply address" + # A sign-off is somebody's own attestation, so a contributor's address there is + # their choice and stays allowed. Anywhere else an address arrived by accident -- + # pasted from a log, a stack trace, or a quoted report. + body=$(printf '%s' "$msg" | grep -viE '^(Signed-off-by|Co-Authored-By|Reported-by|Reviewed-by|Tested-by|Acked-by):') + if printf '%s' "$body" | grep -oiE "$email" | grep -ivE "$not_mail" | grep -qivE "$service"; then + echo "::error::commit $sha contains an email address outside a sign-off trailer" found=1 fi + while read -r addr; do + [ -n "$addr" ] || continue + if [ "$(printf '%s' "$addr" | tr 'A-Z' 'a-z' | sha256sum | cut -d' ' -f1)" = "$blocked_digest" ]; then + echo "::error::commit $sha contains the maintainer's personal address; sign off with the GitHub noreply address" + found=1 + fi + done <<< "$(printf '%s' "$msg" | grep -oiE "$email")" done < <(git rev-list --no-merges "$BASE_SHA..HEAD") exit "$found" From 9b4ea5c7c3c45317d74ecae3352e7fa04a52ee17 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 9 Sep 2026 12:55:51 +0000 Subject: [PATCH 2/3] docs: point at the visual standard from where it gets broken VISUAL.md is live in the org's .github repository, but GitHub gives no special treatment to that filename -- unlike profile/README.md or the community health files, nothing surfaces it. It sat at a URL that nothing linked to, which for a standard is close to not existing. The person who needs it is editing docs/figures/, so the pointer goes at the top of palette.py, the file they have open. That file is carried byte-identically by four repositories, so one edit reaches all of them. CONTRIBUTING gains a short Figures section for someone browsing rather than editing, which also states the two rules people get wrong: change the shared files at the source rather than in one copy, and never add a per-repo lint or format exclude to work around them. The docstring line stays under 88 characters, so palette.py remains a formatter fixed point -- verified clean under ruff check and ruff format at 88, 100 and 120. Every generated SVG is byte-identical, verified by regenerating and diffing in all four repositories. Co-Authored-By: Claude Opus 5 Signed-off-by: Claude --- CONTRIBUTING.md | 13 +++++++++++++ docs/figures/palette.py | 3 +++ 2 files changed, 16 insertions(+) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index cde1247..b0905c0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -244,6 +244,19 @@ file it lives in, so you can go straight there instead of hunting: and, for efficacy, the run manifest under `efficacy/` — and adding it to that directory's `SUMMARY.md` extends the sample without touching the format itself. +## Figures + +Every figure under `docs/figures/` is generated from this repository's own data by a script here, +shipped as a light and a dark SVG, and regenerated in CI so a stale figure fails the build. If you +are changing one, read the standard first — it explains the palette, why absence is never drawn as +a weak grade, and why colour is never the only carrier of meaning: + +https://github.com/open-coder-ai/.github/blob/main/VISUAL.md + +`docs/figures/palette.py` and `make_family.py` are shared across every open-coder-ai repository and +carried byte-identically. Change them at the source and copy them out; never edit one copy, and +never add a per-repo lint or format exclude to work around them. + ## Code of Conduct Be kind, be curious, assume good faith. The full text is in diff --git a/docs/figures/palette.py b/docs/figures/palette.py index e5ff671..c52b6d1 100644 --- a/docs/figures/palette.py +++ b/docs/figures/palette.py @@ -1,5 +1,8 @@ """The one visual language every open-coder-ai figure is drawn in. +The standard this implements, and the reasoning behind each rule: +https://github.com/open-coder-ai/.github/blob/main/VISUAL.md + Four repositories carry this file byte-identically while configuring `ruff format` at three different line lengths (88, 100 and 120), so no formatted output could satisfy all of them. Every statement here therefore fits on a single line under 88 characters and From 042099a17a89717695aafd877f9b815254d1f8b2 Mon Sep 17 00:00:00 2001 From: Claude Date: Wed, 9 Sep 2026 15:56:58 +0000 Subject: [PATCH 3/3] ci: use POSIX character classes in tr, as shellcheck asks actionlint runs shellcheck over every run: block and failed this branch on SC2018 and SC2019: tr 'A-Z' 'a-z' only folds ASCII, so an address containing an accented or non-Latin character would not be lowercased before hashing. tr '[:upper:]' '[:lower:]' handles those, which is the point of the rule rather than a style preference. The digest is unchanged for an ASCII address -- verified both forms produce the same SHA-256 -- so the maintainer-address rule keeps matching exactly what it matched before. Found because CI ran a check the local verification did not: a YAML parse proves the file is well-formed, not that the shell inside it is sound. shellcheck is available locally and is now run over the extracted block, which reports all four repositories clean; the old form reproduces SC2018 and SC2019 on demand. Co-Authored-By: Claude Opus 5 Signed-off-by: Claude --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b00b016..6a0e10b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -85,7 +85,7 @@ jobs: fi while read -r addr; do [ -n "$addr" ] || continue - if [ "$(printf '%s' "$addr" | tr 'A-Z' 'a-z' | sha256sum | cut -d' ' -f1)" = "$blocked_digest" ]; then + if [ "$(printf '%s' "$addr" | tr '[:upper:]' '[:lower:]' | sha256sum | cut -d' ' -f1)" = "$blocked_digest" ]; then echo "::error::commit $sha contains the maintainer's personal address; sign off with the GitHub noreply address" found=1 fi