From 0d768ef75b930434b698dbe5bc3f8e33383eb68e Mon Sep 17 00:00:00 2001 From: Evelyn Chen Date: Thu, 27 Aug 2026 17:11:21 +0000 Subject: [PATCH] Reject hidden PR body content Authored-By: Codex (GPT-5) --- README.md | 3 +- check.sh | 93 ++++++------------------------------------------------- tests/run | 24 +++++++------- 3 files changed, 23 insertions(+), 97 deletions(-) diff --git a/README.md b/README.md index 87f7997..6c4ac09 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,8 @@ The check validates four things for every non-break-glass Agent PR: `Fixes bug-` automation token and the matching navigable `https://agenthub.fritzlab.net/bug-` URL. Every PR has a separate `## Attribution` section containing the canonical `Authored-By` - product/model watermark. + product/model watermark. Agent-authored PR bodies cannot contain HTML + comment delimiters, so required provenance cannot be hidden from readers. 4. **Commit attribution** — every commit in `base-sha..head-sha`, including commits on `chore/` branches, ends with diff --git a/check.sh b/check.sh index 9c82bd8..7298bae 100755 --- a/check.sh +++ b/check.sh @@ -11,90 +11,6 @@ BODY="${PR_BODY:-}" BASE="${BASE_SHA:-}" HEAD="${HEAD_SHA:-}" -# Gitea renders HTML comments as hidden. Validate the visible body so required -# tracking and attribution cannot exist only in comment source. -VISIBLE_BODY=$(printf '%s\n' "${BODY}" | awk ' - { - line=$0 - fence_pos=1 - while (fence_pos <= 3 && substr(line, fence_pos, 1) == " ") fence_pos++ - fence_char=substr(line, fence_pos, 1) - fence_run=0 - if (fence_char == "`" || fence_char == "~") { - while (substr(line, fence_pos + fence_run, 1) == fence_char) fence_run++ - } - if (!in_comment && in_fence) { - print line - if (fence_char == active_fence_char && fence_run >= active_fence_run) in_fence=0 - next - } - fence_info=substr(line, fence_pos + fence_run) - valid_fence_info=(fence_char == "~" || index(fence_info, "`") == 0) - if (!in_comment && fence_run >= 3 && valid_fence_info) { - in_fence=1 - active_fence_char=fence_char - active_fence_run=fence_run - print line - next - } - - visible="" - pos=1 - backslash_run=0 - while (pos <= length(line)) { - if (in_comment) { - rest=substr(line, pos) - comment_end=index(rest, "-->") - if (comment_end == 0) { - pos=length(line) + 1 - break - } - visible=visible " " - pos += comment_end + 2 - in_comment=0 - backslash_run=0 - continue - } - - if (substr(line, pos, 1) == "`" && backslash_run % 2 == 0) { - ticks=1 - while (substr(line, pos + ticks, 1) == "`") ticks++ - close_pos=pos + ticks - found_close=0 - while (close_pos <= length(line)) { - if (substr(line, close_pos - 1, 1) != "`" && - substr(line, close_pos, ticks) == substr(line, pos, ticks) && - substr(line, close_pos + ticks, 1) != "`") { - found_close=1 - break - } - close_pos++ - } - if (found_close) { - visible=visible substr(line, pos, close_pos + ticks - pos) - pos=close_pos + ticks - backslash_run=0 - continue - } - } - - if (substr(line, pos, 4) == "'; then + echo "FAIL[check-naming]: PR body must not contain HTML comment delimiters" + FAILED=1 +fi + # ---- branch form ---- # /bug-/ if echo "${BRANCH}" | grep -qE "^(dev|ux|ops|security|perf|architect|support)/bug-[a-z0-9]+/[a-z0-9][a-z0-9-]*$"; then diff --git a/tests/run b/tests/run index 6e4c456..ddb75cf 100755 --- a/tests/run +++ b/tests/run @@ -140,30 +140,30 @@ check_contract "attribution must be in its own section" \ "$BASE" "$GOOD_HEAD" "## Attribution must contain" check_contract "hidden provenance does not satisfy the visible contract" \ $'' \ - "$BASE" "$GOOD_HEAD" "PR body must contain a non-empty ## Tracking section" + "$BASE" "$GOOD_HEAD" "PR body must not contain HTML comment delimiters" check_contract "comment removal cannot synthesize section headings" \ $'## Tracking\n- Fixes bug-x7k2m9 — https://agenthub.fritzlab.net/bug-x7k2m9\n\n## Attribution\n- Authored-By: Codex (GPT-5) ' \ - "$BASE" "$GOOD_HEAD" "PR body must contain a non-empty ## Tracking section" + "$BASE" "$GOOD_HEAD" "PR body must not contain HTML comment delimiters" check_contract "four-space indented backticks do not expose comments" \ $' ````\n' \ - "$BASE" "$GOOD_HEAD" "PR body must contain a non-empty ## Tracking section" + "$BASE" "$GOOD_HEAD" "PR body must not contain HTML comment delimiters" check_contract "unequal backtick runs do not expose comments" \ $'`' \ - "$BASE" "$GOOD_HEAD" "PR body must contain a non-empty ## Tracking section" + "$BASE" "$GOOD_HEAD" "PR body must not contain HTML comment delimiters" check_contract "invalid backtick fence info does not expose comments" \ $'```html`oops\n' \ - "$BASE" "$GOOD_HEAD" "PR body must contain a non-empty ## Tracking section" + "$BASE" "$GOOD_HEAD" "PR body must not contain HTML comment delimiters" +check_contract "invalid fence closer does not expose comments" \ + $'```html\n```oops\n```\n' \ + "$BASE" "$GOOD_HEAD" "PR body must not contain HTML comment delimiters" check_contract "fences inside comments do not expose provenance" \ $'' \ - "$BASE" "$GOOD_HEAD" "PR body must contain a non-empty ## Tracking section" + "$BASE" "$GOOD_HEAD" "PR body must not contain HTML comment delimiters" check_contract "escaped backticks do not hide a comment opener" \ $'\\`' \ - "$BASE" "$GOOD_HEAD" "PR body must contain a non-empty ## Tracking section" -check_contract_pass "inline code containing comment opener stays visible" \ - $'Use `\n```\n\n## Tracking\n- Fixes bug-x7k2m9 — https://agenthub.fritzlab.net/bug-x7k2m9\n\n## Attribution\n- Authored-By: Codex (GPT-5) ' \ + "$BASE" "$GOOD_HEAD" "PR body must not contain HTML comment delimiters" +check_contract_pass "fenced code without comments remains valid" \ + $'```text\nvisible example\n```\n\n## Tracking\n- Fixes bug-x7k2m9 — https://agenthub.fritzlab.net/bug-x7k2m9\n\n## Attribution\n- Authored-By: Codex (GPT-5) ' \ "$BASE" "$GOOD_HEAD" git -C "${FIXTURES}" commit --allow-empty -q -m "unwatermarked change"