From dbd18985786dce38086a1530e2676c52ff38235a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Hidemaru=20Ogoshi=20/=20=E5=A4=A7=E8=B6=8A?= =?UTF-8?q?=E3=83=8B=E3=82=B3=E3=83=A9=E3=82=B9=E7=A7=80=E4=B8=B8?= <40846197+Nicolas0315@users.noreply.github.com> Date: Wed, 30 Sep 2026 05:48:06 +0900 Subject: [PATCH 1/4] ci: validate organization community docs --- .github/workflows/docs.yml | 48 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) create mode 100644 .github/workflows/docs.yml diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..9ef09ed --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,48 @@ +name: Organization docs + +on: + pull_request: + push: + branches: [main] + +permissions: + contents: read + +jobs: + docs: + name: docs + runs-on: ubuntu-latest + timeout-minutes: 5 + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4 + with: + fetch-depth: 0 + persist-credentials: false + - name: Check required public documents + run: | + python3 - <<'PY' + from pathlib import Path + + for name in ("README.md", "SECURITY.md"): + path = Path(name) + if not path.is_file() or not path.read_text().strip(): + raise SystemExit(f"Missing or empty: {name}") + if "./SECURITY.md" not in Path("README.md").read_text(): + raise SystemExit("README.md must link to SECURITY.md") + print("Required public documents are present.") + PY + - name: Check changed lines + env: + EVENT_NAME: ${{ github.event_name }} + BASE_SHA: ${{ github.event.pull_request.base.sha }} + HEAD_SHA: ${{ github.event.pull_request.head.sha }} + BEFORE_SHA: ${{ github.event.before }} + run: | + set -euo pipefail + if [ "$EVENT_NAME" = pull_request ]; then + git diff --check "$BASE_SHA" "$HEAD_SHA" + elif git cat-file -e "${BEFORE_SHA}^{commit}" 2>/dev/null; then + git diff --check "$BEFORE_SHA" HEAD + else + git diff --check HEAD^ HEAD + fi From a0db2a48b1a353099ad4f04120dc3b2970ccc183 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Hidemaru=20Ogoshi=20/=20=E5=A4=A7=E8=B6=8A?= =?UTF-8?q?=E3=83=8B=E3=82=B3=E3=83=A9=E3=82=B9=E7=A7=80=E4=B8=B8?= <40846197+Nicolas0315@users.noreply.github.com> Date: Wed, 30 Sep 2026 13:23:50 +0900 Subject: [PATCH 2/4] fix: validate actual security link and full changed tree --- .github/workflows/docs.yml | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 9ef09ed..bcaf0e7 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -22,13 +22,26 @@ jobs: run: | python3 - <<'PY' from pathlib import Path + import re for name in ("README.md", "SECURITY.md"): path = Path(name) if not path.is_file() or not path.read_text().strip(): raise SystemExit(f"Missing or empty: {name}") - if "./SECURITY.md" not in Path("README.md").read_text(): - raise SystemExit("README.md must link to SECURITY.md") + readme = Path("README.md").read_text() + readme = re.sub(r"", "", readme, flags=re.DOTALL) + visible_lines = [] + fence = None + for line in readme.splitlines(): + marker = line.lstrip()[:3] + if marker in ("```", "~~~"): + fence = None if fence == marker else marker + continue + if fence is None: + visible_lines.append(line) + visible = "\n".join(visible_lines) + if not re.search(r"(?)\s*\)", visible): + raise SystemExit("README.md must contain a Markdown link to SECURITY.md") print("Required public documents are present.") PY - name: Check changed lines @@ -40,9 +53,9 @@ jobs: run: | set -euo pipefail if [ "$EVENT_NAME" = pull_request ]; then - git diff --check "$BASE_SHA" "$HEAD_SHA" + git diff --check "$BASE_SHA...$HEAD_SHA" elif git cat-file -e "${BEFORE_SHA}^{commit}" 2>/dev/null; then git diff --check "$BEFORE_SHA" HEAD else - git diff --check HEAD^ HEAD + git diff --check "$(git hash-object -t tree /dev/null)" HEAD fi From 0c666d967158c7d357e15d7b6bbf492c79087465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Hidemaru=20Ogoshi=20/=20=E5=A4=A7=E8=B6=8A?= =?UTF-8?q?=E3=83=8B=E3=82=B3=E3=83=A9=E3=82=B9=E7=A7=80=E4=B8=B8?= <40846197+Nicolas0315@users.noreply.github.com> Date: Wed, 30 Sep 2026 13:31:42 +0900 Subject: [PATCH 3/4] fix: parse full Markdown fence delimiters --- .github/workflows/docs.yml | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index bcaf0e7..cb876f1 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -33,12 +33,17 @@ jobs: visible_lines = [] fence = None for line in readme.splitlines(): - marker = line.lstrip()[:3] - if marker in ("```", "~~~"): - fence = None if fence == marker else marker + match = re.match(r"^ {0,3}(`{3,}|~{3,})", line) + if fence is not None: + if (match and match.group(1)[0] == fence[0] + and len(match.group(1)) >= fence[1] + and not line[match.end():].strip()): + fence = None continue - if fence is None: - visible_lines.append(line) + if match: + fence = (match.group(1)[0], len(match.group(1))) + continue + visible_lines.append(line) visible = "\n".join(visible_lines) if not re.search(r"(?)\s*\)", visible): raise SystemExit("README.md must contain a Markdown link to SECURITY.md") From 7dcd7bb781aaaa0e7c1f95de64569eb8c1ad53d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicolas=20Hidemaru=20Ogoshi=20/=20=E5=A4=A7=E8=B6=8A?= =?UTF-8?q?=E3=83=8B=E3=82=B3=E3=83=A9=E3=82=B9=E7=A7=80=E4=B8=B8?= <40846197+Nicolas0315@users.noreply.github.com> Date: Wed, 30 Sep 2026 13:38:27 +0900 Subject: [PATCH 4/4] fix: require rendered security link in README table --- .github/workflows/docs.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index cb876f1..471f108 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -44,9 +44,9 @@ jobs: fence = (match.group(1)[0], len(match.group(1))) continue visible_lines.append(line) - visible = "\n".join(visible_lines) - if not re.search(r"(?)\s*\)", visible): - raise SystemExit("README.md must contain a Markdown link to SECURITY.md") + if not any(re.search(r"^\|\s*\[[^\]\n]+\]\(\./SECURITY\.md\)\s*\|", line) + for line in visible_lines): + raise SystemExit("README.md must list a Markdown link to SECURITY.md") print("Required public documents are present.") PY - name: Check changed lines