Skip to content

ci: scan issue and comment bodies — this repo has never scanned one - #87

Open
yakimoto wants to merge 10 commits into
mainfrom
ci/1747-public-repo-guard-body-scan
Open

ci: scan issue and comment bodies — this repo has never scanned one#87
yakimoto wants to merge 10 commits into
mainfrom
ci/1747-public-repo-guard-body-scan

Conversation

@yakimoto

@yakimoto yakimoto commented Aug 6, 2026

Copy link
Copy Markdown
Contributor

This repo's public-repo-guard has never scanned a single issue or comment body.

Measured across all 28 public wave-av repos (wave-av/claude-workstation#1747, #1794): two coverage shapes satisfy the one required check name Secrets + content policy.

repos triggers jobs
27 pull_request, push, workflow_dispatch guard
1 + issues, issue_comment + body-guard

This repo is in the 27. All 28 report the same green check — because a required check asserts that something named X passed, never what X examined.

The outlier is wave-moq-edge, and its own comment says why it matters:

edited matters as much as opened: a body can be made to leak long after the PR is first raised, and until this workflow covered it, nothing ever re-scanned.

That gap was not theoretical there: a PR was blocked for naming a private repo in wrangler.toml while the very same name, with more operational detail attached, sat unchallenged in its body.

What lands

Three files — the bundle the workflow's own header names, minus what this repo already has (.gitleaks.toml and content-policy.sh are already vendored, and are checked as prerequisites; a repo missing either is refused rather than half-installed):

.github/workflows/public-repo-guard.yml               replaced (72 -> 163 lines)
scripts/public-repo-guard/body-policy.sh              new, mode 100755
scripts/public-repo-guard/tests/body-policy.test.sh   new, mode 100755

The workflow's header names four files as the install unit but executes a fifthtests/body-policy.test.sh, in its own self-test step. Omitting it installs a workflow that fails on a step nobody read, so the manifest ships it. Modes are preserved via the git trees API; the contents API creates 100644 regardless, which would silently break running these scripts as executables.

Planned by governance/lib/vendor-bundle.mjs (claude-workstation#1850) against a checked-in manifest, not by ad-hoc shell.

One deliberate divergence from the reference, stated rather than silent

The shipped workflow is wave-moq-edge's with actions/checkout bumped from v5.0.1 to v7.0.1 (3d3c42e5aac5ba805825da76410c181273ba90b1), the pin already used by claude-workstation's own gate.

Copying verbatim was checked first and rejected on evidence: of the 18 target repos, 17 carry a byte-identical guard, and wave-realtime-edge already runs v7.0.0 — so a verbatim copy would have downgraded it, and shipped a stale pin to the other 17. A separate PR brings the reference itself up to the same pin.

Honest about what this can and cannot do

On a PR this PREVENTS the merge. On an issue or comment the text is already public the moment it posts, so this is DETECTION: it says go redact, fast. Only a client-side pre-write hook stops that class before publication.

Also inherited from the reference: concurrency moves from workflow-level to per job, because the two jobs want opposite behaviour. A workflow-level group forced one policy on both, and rapid body edits cancelled the tree job repeatedly — every cancelled check-run stays attached to the commit, so the PR reported UNSTABLE while the live runs were green.

The body gate ships with its own fixtures and runs them in CI. Its negative cases are the load-bearing half: a leak gate that blocks legitimate cross-repo references gets switched off, and then it protects nothing.

Refs wave-av/claude-workstation#1747.


Open in Devin Review

Note

Medium Risk
Changes security CI behavior and merge blocking on PR bodies; implementation is defensive (no credential echo, fail-closed scanners), but mis-tuned rules could block legitimate discussion or miss edge cases.

Overview
Extends public-repo-guard so GitHub title/body text is scanned in CI, not only the published tree. A new body-guard job runs on PR, issue, comment, review-comment, and review events (including edited), materializes untrusted text via jq into a file, and runs body-policy.sh with persist-credentials: false and sparse checkout of guard scripts.

The existing guard job now skips PR edited and comment-only events, uses per-job concurrency (tree job can cancel in progress; body job does not), bumps actions/checkout to v7.0.1, verifies ripgrep PCRE2 support, and runs body-policy.test.sh fixtures in CI.

body-policy.sh is a fail-closed companion to content-policy.sh: it blocks credential formats, infra identifiers, internal markers, and private-repo names only when paired with operational detail on the same line (unlike the file gate’s bare private-repo block). Matches are redacted in annotations; prose rules allow discussion of the control itself.

tests/body-policy.test.sh adds hermetic fixtures for block/pass cases and filter fail-closed behavior.

Reviewed by Cursor Bugbot for commit dbb3b63. Configure here.


View with [code]smith
Need help on this PR? Tag @codesmith-bot with what you need. Autofix is enabled.

Note

Scan issue and PR comment bodies for policy violations in the public-repo-guard workflow

  • Adds a new body-guard job to public-repo-guard.yml that materializes event titles, bodies, and comment text into a file and runs body-policy.sh against them, covering issues, PR comments, reviews, and review comments.
  • body-policy.sh is a new script that scans body text with ripgrep (PCRE2) for credential formats, infrastructure identifiers, and private repo operational detail; emits GitHub Actions annotations with line numbers but no matched text; and exits 1 on blocking violations or 2 on scanner errors (fail-closed).
  • Per-line guard:allow <reason> markers opt out of specific rules; prose-scoped rules additionally suppress self-referential discussion of the control itself.
  • body-policy.test.sh provides a fixture-based test suite run as a self-test step in the guard job on every scan.
  • The existing guard job gains ripgrep PCRE2 verification, a new concurrency group keyed by PR number/ref, and actions/checkout is upgraded to v7.0.1 with persist-credentials: false.

Macroscope summarized d87f627.

Review in cubic

…ment body

Measured across all 28 public wave-av repos (claude-workstation#1747, #1794):
TWO coverage shapes satisfy the one required check name `Secrets + content policy`.

  27 repos  triggers: pull_request, push, workflow_dispatch      jobs: guard
   1 repo   triggers: + issues, issue_comment                    jobs: + body-guard

This repo is in the 27. All 28 report the same green check.

The outlier is wave-moq-edge, and its own comment says why it matters:

  "`edited` matters as much as `opened`: a body can be made to leak long after the
   PR is first raised, and until this workflow covered it, nothing ever re-scanned."

A PR/issue/comment BODY is exactly as world-readable as the tree, and until now it
was scanned by nothing server-side. That gap was not theoretical on wave-moq-edge: a
PR was blocked for naming a private repo in wrangler.toml while the very same name,
with more operational detail attached, sat unchallenged in its body.

WHAT LANDS HERE — the bundle the workflow's own header names, minus what this repo
already has (.gitleaks.toml and content-policy.sh are already vendored):

  .github/workflows/public-repo-guard.yml          replaced (73 -> 163 lines)
  scripts/public-repo-guard/body-policy.sh         new, mode 100755
  scripts/public-repo-guard/tests/body-policy.test.sh  new, mode 100755

Copied from wave-moq-edge, which has run this shape in production. Modes preserved
via the git trees API — the contents API would have created both scripts 100644.

HONEST ABOUT WHAT IT CAN DO. On a PR this PREVENTS the merge. On an issue or comment
the text is already public the moment it posts, so this is DETECTION: it says go
redact, fast. Only a client-side pre-write hook stops that class before publication.

Also inherited from the reference: concurrency moves from workflow-level to PER JOB,
because the two jobs want opposite behaviour. A workflow-level group forced one
policy on both, and rapid body edits cancelled the tree job repeatedly — every
cancelled check-run stays attached to the commit, so the PR reported UNSTABLE while
the live runs were green.

The body gate ships with its own fixtures and runs them in CI. Its NEGATIVE cases are
the load-bearing half: a leak gate that blocks legitimate cross-repo references gets
switched off, and then it protects nothing.

Refs wave-av/claude-workstation#1747.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@yakimoto yakimoto added the rr:skip-coderabbit RF.P1 reviewer routing (#1039) label Aug 6, 2026
@coderabbitai

coderabbitai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are limited based on label configuration.

🚫 Excluded labels (none allowed) (1)
  • rr:skip-coderabbit

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: f3707d7c-3e59-44b1-8651-6edc5b303f93

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Comment @coderabbitai help to get the list of available commands.

@cursor

cursor Bot commented Aug 6, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_a69bf77d-fdb9-448c-8bb2-13ba80c8a653)

@cubic-dev-ai

cubic-dev-ai Bot commented Aug 6, 2026

Copy link
Copy Markdown

Running ultrareview automatically — Running ultrareview automatically — this adds a new fail-closed secret/body scanner and reworks CI gating/concurrency; a subtle regex or workflow bug could block every PR or miss credential leaks on the whole public surface, so it needs a deeper pass.. I'll post findings when complete.

@macroscopeapp

macroscopeapp Bot commented Aug 6, 2026

Copy link
Copy Markdown

Approvability

Verdict: Needs human review

Unable to check for correctness in d87f627. Introduces substantial new CI security scanning infrastructure (new workflow job, 400+ lines of new scripts) that will run on every PR, issue, and comment. While well-designed with comprehensive tests, new security-adjacent capabilities of this scope warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

ci: scan PR/issue/comment bodies in public-repo-guard

✨ Enhancement ⚙️ Configuration changes 🧪 Tests 🕐 40+ Minutes

Grey Divider

AI Description

• Add body scanning for PR titles/bodies, issues, and issue comments (including edits).
• Split tree vs body scanning into separate jobs with event-aware concurrency.
• Introduce body-policy scanner script with fixture tests and fail-closed semantics.
Diagram

graph TD
  E{{"GitHub events"}} --> W["public-repo-guard.yml"]
  W --> G["job: guard (tree)"] --> T["gitleaks + content-policy.sh"] --> S["self-test: body-policy.test.sh"]
  W --> B["job: body-guard"] --> M["materialize body.txt"] --> P["body-policy.sh"]
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Extract as a reusable workflow + composite action
  • ➕ Avoids copy/paste drift across many repos and simplifies upgrades/pin bumps
  • ➕ Centralizes policy logic and test execution, improving consistency
  • ➖ Requires careful governance because reusable workflows can widen trust boundaries
  • ➖ Versioning/rollout across repos becomes a dependency management problem
2. Single job with conditional steps (no separate body job)
  • ➕ Less workflow surface area (one job) and fewer concurrency knobs
  • ➖ Hard to get correct concurrency behavior for both tree and body scans
  • ➖ Risk of wasting compute (tree scan on comment events) or skipping needed scans
3. Rely on GitHub-native secret scanning only
  • ➕ Reduces custom regex/policy maintenance and leverages platform alerts
  • ➖ Does not cover organization-specific content policy and repo-name/ops-detail proximity logic
  • ➖ Coverage and enforcement behavior differ for PR bodies/issues/comments

Recommendation: Keep the PR’s split-job design: it cleanly separates tree scanning from body scanning, enables different concurrency semantics, and avoids security pitfalls (stays on pull_request, materializes untrusted text to a file, and redacts matches). If maintenance across many repos becomes painful, consider a reusable workflow/composite action next—while preserving the same trust model and fail-closed behavior.

Files changed (3) +342 / -5

Enhancement (1) +139 / -0
body-policy.shIntroduce body content policy scanner with redacted reporting +139/-0

Introduce body content policy scanner with redacted reporting

• Adds a new scanner for PR/issue/comment text that detects credential-like patterns and sensitive internal identifiers while minimizing false positives. Implements allowlisting ('guard:allow' and an “about the control” allowlist), redacts matched text from annotations, and fails closed on scanner errors or unexpected input shape.

scripts/public-repo-guard/body-policy.sh

Tests (1) +108 / -0
body-policy.test.shAdd fixture tests for body-policy rules and fail-closed behavior +108/-0

Add fixture tests for body-policy rules and fail-closed behavior

• Adds hermetic fixture tests that validate both blocking detections and deployability-critical non-blocking cases (e.g., bare private-repo cross-references). Also verifies that violations do not echo matched text into CI output and that missing/invalid inputs return a fail-closed exit code.

scripts/public-repo-guard/tests/body-policy.test.sh

Other (1) +95 / -5
public-repo-guard.ymlAdd body-guard job and expand triggers to body edits +95/-5

Add body-guard job and expand triggers to body edits

• Extends workflow triggers to include PR/issue/comment body events (including edits) and adds a dedicated body-guard job. Moves concurrency to job-level to avoid tree-scan cancellations from rapid body edits, bumps actions/checkout pin to v7.0.1, and adds a self-test step for the body policy fixtures.

.github/workflows/public-repo-guard.yml

@qodo-code-review

qodo-code-review Bot commented Aug 6, 2026

Copy link
Copy Markdown

Code Review by Qodo

🐞 Bugs (0) 📘 Rule violations (0) 📜 Skill insights (0)

Grey Divider


Action required

1. Allowlist bypasses body scan ✓ Resolved 🐞 Bug ⛨ Security
Description
In body-policy.sh, every rule’s matches (including credential-format BLOCK rules) are filtered
through ABOUT_THE_CONTROL, so a real secret on the same line as e.g. “public-repo-guard” or
“SECURITY.md” is silently excluded and won’t block. This enables a trivial same-line bypass that can
let credential-shaped leaks through the new body scanner.
Code

scripts/public-repo-guard/body-policy.sh[R53-55]

+  matches="$(printf '%s' "$raw" \
+    | rg -vN -- 'guard:allow[[:space:]]+[^[:space:]]' \
+    | rg -vNiP -- "$ABOUT_THE_CONTROL" || true)"
Evidence
ABOUT_THE_CONTROL is defined as a broad regex and then used to filter out matching lines inside the
generic check() function, meaning it affects all subsequent BLOCK rules including credential
patterns.

scripts/public-repo-guard/body-policy.sh[31-36]
scripts/public-repo-guard/body-policy.sh[53-56]
scripts/public-repo-guard/body-policy.sh[71-79]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
`scripts/public-repo-guard/body-policy.sh` applies the `ABOUT_THE_CONTROL` allowlist inside the generic `check()` function, so it suppresses matches for **all** rules (including credential-format rules like AWS keys and private keys). This creates a same-line bypass: a violating line that also mentions an allowlisted term is dropped and does not increment `VIOLATIONS`.

## Issue Context
The allowlist is intended to prevent self-referential false positives for prose/policy discussion, but applying it indiscriminately weakens the scanner for high-severity patterns that should never be suppressed automatically.

## Fix Focus Areas
- scripts/public-repo-guard/body-policy.sh[31-36]
- scripts/public-repo-guard/body-policy.sh[37-69]
- scripts/public-repo-guard/body-policy.sh[71-86]

## Suggested fix approach
- Add a parameter/flag to `check()` (or create a second helper) to control whether `ABOUT_THE_CONTROL` filtering is applied.
- Apply `ABOUT_THE_CONTROL` filtering only to the rules that are inherently “policy prose” (e.g., `internal-marker`) rather than to credential/identifier rules.
- Keep `guard:allow <reason>` as the explicit, visible escape hatch for exceptional cases.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools



Remediation recommended

2. Review comments not scanned ✓ Resolved 🐞 Bug ≡ Correctness
Description
The workflow only triggers/scans PR bodies, issues, and issue comments; it does not run on
pull_request_review_comment, so inline code review comment bodies are never scanned. Leaks posted in
those review comments will bypass this workflow entirely.
Code

.github/workflows/public-repo-guard.yml[115]

+    if: github.event_name == 'pull_request' || github.event_name == 'issues' || github.event_name == 'issue_comment'
Evidence
The workflow’s event subscriptions and the body-guard job condition omit
pull_request_review_comment, so inline review comments cannot trigger the scan.

.github/workflows/public-repo-guard.yml[28-36]
.github/workflows/public-repo-guard.yml[113-116]

Agent prompt
The issue below was found during a code review. Follow the provided context and guidance below and implement a solution

## Issue description
The body scanning job (`body-guard`) is only triggered for `pull_request`, `issues`, and `issue_comment`. GitHub inline PR review comments use the `pull_request_review_comment` event, which is currently not subscribed, so those comments are not scanned.

## Issue Context
This PR’s intent is to scan “issue and comment bodies”; inline review comments are also world-readable text and are a common place to paste operational details.

## Fix Focus Areas
- .github/workflows/public-repo-guard.yml[28-36]
- .github/workflows/public-repo-guard.yml[113-116]
- .github/workflows/public-repo-guard.yml[142-157]

## Suggested fix approach
- Add `pull_request_review_comment` to the `on:` section with `types: [created, edited]`.
- Update `body-guard`’s `if:` condition to include `github.event_name == 'pull_request_review_comment'`.
- Confirm the jq extraction covers the payload shape (it likely does via `.comment.body`); if needed, add/adjust fields so the comment body is always included.

ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools


Grey Divider

Context used
✅ Compliance rules (platform): 2 rules
Review mode: ⚖️ Balanced: Downgraded extended -> standard: change is below the extended eligibility bar (hunks 5/18, lines 347/200; both must reach the floor). Router rationale: This security-sensitive CI change adds substantial workflow, shell-scanning, event-handling, regex, and test logic across multiple independent edit sites, making redundant review materially useful for subtle bypasses or regressions.

To customize comments, go to the Qodo configuration screen, or learn more in the docs.

Qodo Logo

qodo-code-review[bot]

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

@qodo-code-review

Copy link
Copy Markdown

Qodo Fixer

🍒 Ready to be cherry-picked — ✅ Merged (0) · ☑ Fixed (1)

Grey Divider

🔗 Fix PR: #88

This fix PR was closed automatically. Its branch is preserved so you can cherry pick the changes into the original PR.

Prompt for coding agent

This is an automated fix prepared on a separate branch (#88). It is NOT applied to this PR.
To use it: review Fix PR #88 (https://github.com/wave-av/mcp-server/pull/88), evaluate each change critically against your local context, and cherry-pick the changes that are correct into this branch. Do not accept them blindly.
Process — 1 fixed
  • ☑ Fixed: Allowlist bypasses body scan

yakimoto and others added 2 commits August 6, 2026 17:29
… comments

Two review findings:

1. ABOUT_THE_CONTROL was applied inside check() for every rule, so a
   credential-format hit on a line that also named the gate (or SECURITY.md)
   was silently dropped — a same-line bypass. The allowlist is now opt-in
   per rule via a 'prose' tag; only internal-marker and private-repo-ops
   consult it. guard:allow remains the universal, visible escape hatch.

2. pull_request_review_comment was never subscribed, so inline review
   comment bodies were never scanned. Added the trigger, extended
   body-guard's condition, and moved comment.id first in the concurrency
   key: review-comment payloads carry the pull_request object, so keying
   on PR number would fold every review comment into one group.

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
…nstall; probe rg for PCRE2

Three review findings:

1. The leading (?i) on private-repo-ops bled into OPS_DETAIL, turning its
   deliberate SCREAMING_CASE requirement into a match on everyday lowercase
   words (docs/setup_key.md, process.env.api_token) — blocking exactly the
   bare cross-references the rule promises to leave alone. (?i:...) now
   wraps the repo-name alternation alone.

2. The install header said 'copy all four files' but the guard job runs a
   fifth (tests/body-policy.test.sh); a repo installed per the docs would
   fail on every run. The header now lists five.

3. Every rule uses rg -P, and not every distro builds ripgrep with PCRE2
   (Ubuntu jammy's apt package does not). Both install steps now probe -P
   support up front so a runner-image change fails with a named cause
   instead of an opaque scanner error blocking every PR.

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
cubic-dev-ai[bot]

This comment was marked as resolved.

A review's summary body (the text submitted with an approval or
changes-requested) is a fourth world-readable surface, distinct from both
issue_comment and pull_request_review_comment. Subscribe to submitted/edited,
extract .review.body in the materialize step, and key concurrency on
review.id ahead of the PR number so two rapid reviews cannot fold into one
group.

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 5 new potential issues.

Open in Devin Review

Comment thread scripts/public-repo-guard/body-policy.sh Outdated
Comment thread scripts/public-repo-guard/body-policy.sh Outdated
Comment thread scripts/public-repo-guard/body-policy.sh
Comment thread .github/workflows/public-repo-guard.yml Outdated
Comment on lines +67 to +70
if: >-
(github.event_name == 'pull_request' && github.event.action != 'edited')
|| github.event_name == 'push'
|| github.event_name == 'workflow_dispatch'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Tree job is now skipped on PR body edits — confirm branch protection treats that as passing

Adding edited to the pull_request types means every body edit produces a run in which the required-looking check Secrets + content policy is skipped by the job-level if. GitHub treats a job skipped by if as a created check-run with conclusion skipped, which branch protection counts as satisfied, so this should be fine — but it is worth a one-time confirmation on this repo's protection settings, since the tree scan is the gate the org relies on.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

…scan only the object the event touched; surface an unconfigured private-repo rule

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
devin-ai-integration[bot]

This comment was marked as resolved.

…xtures

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 3 new potential issues.

Open in Devin Review

Comment thread scripts/public-repo-guard/body-policy.sh
Comment on lines +139 to +142
# So a bare mention stays silent. What fires is a private repo name within ~140
# characters of INTERNAL OPERATIONAL DETAIL — a SCREAMING_CASE credential NAME, a
# secret-binding verb, a service binding, or a secret COUNT. That is the topology
# of what is wired to what, and it is the shape that actually leaked.

@devin-ai-integration devin-ai-integration Bot Aug 6, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Proximity rule is line-scoped, so a leak split across two lines is not detected

rg matches per line and [^\n]{0,140} further pins both halves to the same line, so a body that names a private repo on one line and the credential/binding detail on the next (a very common markdown bullet-list shape) will not fire. The comment says "within ~140 characters", which reads as character distance rather than same-line-only; worth documenting or moving to a multiline scan if bullet lists are a realistic leak shape.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread .github/workflows/public-repo-guard.yml
…me-then-detail order

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 2 new potential issues.

Open in Devin Review

Comment on lines +130 to +151
body-guard:
name: Body content policy
if: >-
github.event_name == 'pull_request'
|| github.event_name == 'issues'
|| github.event_name == 'issue_comment'
|| github.event_name == 'pull_request_review_comment'
|| github.event_name == 'pull_request_review'
concurrency:
# Keyed on the specific comment / review / PR / issue rather than github.ref,
# because issue events all report the default branch and a ref-keyed group
# would let two comments cancel each other, leaving one unscanned. The
# comment and review ids must come BEFORE the PR number: review-comment and
# review payloads carry the pull_request object too, and keying those on the
# PR number would fold every comment on a PR into one group.
#
# cancel-in-progress is deliberately FALSE. Every version of a body deserves a
# verdict, the job is seconds long, and a cancelled check-run lingers on the
# commit and makes an otherwise-green PR look broken.
group: public-repo-guard-body-${{ github.event.comment.id || github.event.review.id || github.event.pull_request.number || github.event.issue.number || github.ref }}
cancel-in-progress: false
runs-on: ubuntu-latest

@devin-ai-integration devin-ai-integration Bot Aug 6, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 Comment/issue-triggered runs attach their check to the default branch, not the PR

issues, issue_comment, pull_request_review_comment and pull_request_review runs execute in the context of the default branch and their check-runs attach to the default branch head, not the PR head. Two consequences worth confirming against branch protection: (1) a leak in a PR comment or review body will NOT block that PR's merge (the header comment acknowledges this is detection-only), and (2) a failing body-guard run for a comment will surface as a red run on the default branch's commit, which can be mistaken for a broken main. Also note these events always use the default branch's copy of body-policy.sh, so changes to the gate only take effect for comments after merge.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread scripts/public-repo-guard/body-policy.sh
Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
devin-ai-integration[bot]

This comment was marked as resolved.

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
@cursor

cursor Bot commented Aug 6, 2026

Copy link
Copy Markdown

Bugbot couldn't run - usage limit reached

Bugbot is counted against Cursor usage for this user or team, and this run hit a usage or spend limit.

A user or team admin can review and increase usage limits in the Cursor dashboard.

(requestId: serverGenReqId_5ddc1058-e529-40ca-9740-00f8ea33d801)

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 4 new potential issues.

Open in Devin Review

Comment thread scripts/public-repo-guard/body-policy.sh Outdated
Comment thread scripts/public-repo-guard/tests/body-policy.test.sh
Comment on lines +134 to +141
body-guard:
name: Body content policy
if: >-
github.event_name == 'pull_request'
|| github.event_name == 'issues'
|| github.event_name == 'issue_comment'
|| github.event_name == 'pull_request_review_comment'
|| github.event_name == 'pull_request_review'

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔍 The new body check runs under a new check-run name, so it blocks nothing until branch protection is updated

The PR description states "On a PR this PREVENTS the merge." That is only true if Body content policy is added to the branch's required status checks. The PR's own evidence table says the single required check name today is Secrets + content policy, which is the guard job's name (.github/workflows/public-repo-guard.yml:63). body-guard ships with a distinct name (:135), so out of the box a body leak on a PR produces a red-but-not-required check and merge is still permitted.

Second, related point: guard is now skipped on pull_request edited (:67-70). A body edit therefore produces a fresh Secrets + content policy check run with conclusion skipped on the same head SHA. GitHub treats a skipped required check as passing, so this should be benign, but it is worth confirming against this org's branch-protection settings before relying on the required check to mean the tree was actually scanned for that SHA.

Both are configuration follow-ups outside the diff, not defects in the code.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Comment thread .github/workflows/public-repo-guard.yml
…fixtures

The body profile's internal-ip rule matched the documentation form of the
range itself (100.64.0.0/10), so any security discussion naming the range
— including quotes of the gate's own comments — blocked with no escape
short of guard:allow. The tree gate never hits this because it excludes the
guard's own directory; body text has no such exclusion. Exempt the two
range-talk shapes (all-zero host portion and CIDR-suffixed subnets) while a
concrete host like 100.71.4.19 still blocks, with fixtures for all three.

The fixture suite also now probes for PCRE2 support up front, mirroring the
workflow's install step: on a PCRE2-less rg every fixture degraded to the
scanner's fail-closed exit 2, producing dozens of opaque 'want exit 1,
got 2' failures indistinguishable from a broken gate.

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 1 new potential issue.

Open in Devin Review

Comment on lines +157 to +166
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
# Only the gate's own scripts are needed — no reason to pay for the whole
# tree on every comment.
sparse-checkout: scripts/public-repo-guard
sparse-checkout-cone-mode: false
# This job runs repo-checked-out scripts over attacker-controlled body
# text; nothing here pushes or calls the API, so the token must not
# linger in .git/config for those scripts to find.
persist-credentials: false

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟨 Body-leak gate can be neutralized by the pull request it is scanning

The body gate checks out the repository at the pull request's merge ref and then executes scripts/public-repo-guard/body-policy.sh from that checkout (.github/workflows/public-repo-guard.yml:157-166 and .github/workflows/public-repo-guard.yml:213). Because the script executed is the PR's own copy, a pull request (including one from a fork) that edits body-policy.sh — e.g. weakening a rule or making it exit 0 unconditionally — is scanned by its own modified gate, so the leak check for that PR's title/body becomes advisory rather than authoritative. The same structural property already applies to the pre-existing tree gate (content-policy.sh), so this PR extends rather than introduces the pattern. No token or secret exposure is involved: permissions: contents: read, pull_request (not pull_request_target) is used, and persist-credentials: false is set, which are all correct choices.

Open in Devin Review

Was this helpful? React with 👍 or 👎 to provide feedback.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the gate's deliberate trust model, shared with the pre-existing tree gate and ruled on in prior passes: on pull_request events the workflow file itself is equally PR-editable, so pinning the script to base adds no boundary. The comment itself notes the pattern is pre-existing and all token-safety choices (contents: read, pull_request, persist-credentials: false) are correct.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

rr:skip-coderabbit RF.P1 reviewer routing (#1039)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant