Skip to content

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

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

ci: scan issue and comment bodies — this repo has never scanned one#9
yakimoto wants to merge 6 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.

Extended in review: the last unscanned text surface, and a queueing gap

Review feedback (cubic) identified that diff review comments and review bodies are not issue_comment events, so they were the one public text surface still scanned by nothing. The workflow now also triggers on pull_request_review and pull_request_review_comment; review-comment payloads carry comment so the existing branch covers them, and review submissions scan .review.body (a bare approve scans empty and passes). It also found that the shared concurrency group could drop an intermediate body version, since GitHub queues at most one pending run per group; the group is now keyed on run_id, i.e. never shared. The fixture suite is also now listed as the fifth file of the install bundle, since the guard job runs it.

Refs wave-av/claude-workstation#1747.


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


Note

Cursor Bugbot is generating a summary for commit 944f18b. Configure here.

Note

Scan issue and PR comment/review bodies for credential and policy violations in CI

  • Adds a new body-guard job in public-repo-guard.yml that triggers on issues, issue_comment, pull_request_review, and pull_request_review_comment events, covering event types that were never previously scanned.
  • Introduces body-policy.sh, a ripgrep/PCRE2-based scanner that checks titles, bodies, and comments against rules for credentials (Stripe, Anthropic, GitHub PATs, AWS keys, etc.) and infrastructure identifiers, emitting non-leaking GitHub Actions annotations.
  • Adds body-policy.test.sh, a hermetic fixture test suite that runs inside the existing guard job and fails CI on rule regressions or annotation redaction failures.
  • The scanner fails closed (exit 2) on unrecognized event payloads or missing prerequisites, and supports inline guard:allow <reason> suppressions.
  • Behavioral Change: the guard job no longer runs for PR edited events; that case is now handled by body-guard instead.

Macroscope summarized 2250a51.

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
@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_b1a68da0-c375-4440-a170-684f98768fae)

@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: ae640084-3907-4751-a106-9d077cdbb7d0

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.

@macroscopeapp

macroscopeapp Bot commented Aug 6, 2026

Copy link
Copy Markdown

Approvability

Verdict: Needs human review

Unable to check for correctness in 2250a51. This PR adds new CI security scanning for PR/issue/comment bodies. Open review comments identify a significant security design issue: the body-guard job runs scanner scripts from the PR itself, allowing potential bypass. This security infrastructure change with unresolved concerns warrants 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 with public-repo-guard

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

Grey Divider

AI Description

• Add a dedicated body-guard job to scan PR/issue/comment text on open/edit events.
• Introduce a fail-closed body-policy scanner with allowlists and redacted reporting.
• Add fixture-based self-tests to keep the gate precise and safe to run.
Diagram

graph TD
  W[".github/workflows/public-repo-guard.yml"] --> G["Job: guard (tree scan)"] --> CP["content-policy.sh"]
  G --> T["body-policy.test.sh (fixtures)"] --> BP["body-policy.sh"]
  W --> BG["Job: body-guard (body scan)"] --> M["Materialize title/body via jq"] --> BP
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. Rely on GitHub Advanced Security secret scanning
  • ➕ Native detection, tuned patterns, and first-class UI for remediation
  • ➕ No custom regex maintenance in-repo
  • ➖ May require licensing/enablement; not guaranteed across org/repo scope
  • ➖ Does not cover the same bespoke “content policy” constraints (e.g., private-repo+ops-detail proximity)
2. Inline body checks directly in the workflow YAML
  • ➕ Fewer repo files to vendor/copy across repos
  • ➕ All logic visible in one place for CI reviewers
  • ➖ Harder to test safely without publishing secrets; less maintainable
  • ➖ Regex/allowlist logic becomes brittle and unreadable in YAML

Recommendation: Keep the PR’s approach: a dedicated body-guard job plus a separate, testable body-policy.sh is the most robust option for cross-repo vendoring and for preventing “green check but scanned nothing” failures. The deliberate choices (fail-closed on unknown payload shapes, per-job concurrency, redacted annotations, and fixture-only tests) address the real operational risks better than YAML-inline checks, and are complementary to (not replaced by) any future GitHub-native scanning.

Files changed (3) +342 / -5

Enhancement (1) +139 / -0
body-policy.shNew body policy scanner for PR/issue/comment text +139/-0

New body policy scanner for PR/issue/comment text

• Adds a ripgrep-based scanner that reads untrusted text from a file and enforces blocking rules for credential formats, internal identifiers, and “internal-only” markers, with allowlisting for deliberate exceptions and self-referential security discussions. Ensures safe reporting by redacting matched content and failing closed on scanner errors. Optionally adds a proximity-based rule using GUARD_PRIVATE_REPOS to detect private-repo names near operational detail without blocking legitimate cross-references.

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

Tests (1) +108 / -0
body-policy.test.shFixture-only tests for body-policy precision and redaction +108/-0

Fixture-only tests for body-policy precision and redaction

• Introduces a hermetic test harness covering blocking and non-blocking cases, including regressions around quoted markers and legitimate cross-repo references. Verifies that annotations never echo matched text, and validates fail-closed behavior for missing/invalid inputs. Uses constructed fixtures to avoid committing credential-shaped strings.

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

Other (1) +95 / -5
public-repo-guard.ymlAdd body scanning triggers and a dedicated body-guard job +95/-5

Add body scanning triggers and a dedicated body-guard job

• Extends workflow triggers to include issue and comment events and PR edits, and introduces a new body-guard job to scan PR/issue/comment text. Moves concurrency to per-job policies (tree job cancels in-progress; body job does not) and bumps actions/checkout to v7.0.1. Adds a fixture self-test step to ensure body-policy behavior stays precise and safe.

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

@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 6 potential issues.

Open in Devin Review

Comment thread scripts/public-repo-guard/body-policy.sh
Comment thread scripts/public-repo-guard/body-policy.sh
Comment thread .github/workflows/public-repo-guard.yml Outdated

FILE="${1:-}"
[[ -n "$FILE" && -f "$FILE" ]] || { echo "::error::body-policy: usage: body-policy.sh <file>"; exit 2; }
command -v rg >/dev/null 2>&1 || { echo "::error::body-policy: ripgrep (rg) required"; exit 2; }

@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.

🔍 Fixture suite verified end-to-end (all 28 cases pass under a PCRE2 engine)

I executed scripts/public-repo-guard/tests/body-policy.test.sh locally. The system ripgrep here is the Ubuntu 22.04 package (13.0.0-2ubuntu0.1) which is built WITHOUT PCRE2, so every fixture failed with exit 2 via the new preflight at scripts/public-repo-guard/body-policy.sh:31. Re-running with a PCRE2-capable shim, all 28 fixtures pass, including the tricky use-vs-mention lookarounds and the proximity rule in both orders. Two consequences worth noting: (a) the preflight message asserting "the apt/brew packages are" PCRE2-enabled is not true for Ubuntu 22.04's ripgrep 13, so a developer running the suite locally on 22.04 (or a self-hosted 22.04 runner) gets a hard exit 2 for the whole gate; (b) the same dependency already exists in scripts/public-repo-guard/content-policy.sh:52, so if the hosted runner image's ripgrep lacked PCRE2 the pre-existing guard job would already be permanently red — which is good evidence the hosted image is fine. Worth confirming the runner label stays on an image whose apt ripgrep has PCRE2.

Open in Devin Review

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

Comment thread .github/workflows/public-repo-guard.yml
Comment thread scripts/public-repo-guard/body-policy.sh
@qodo-code-review

qodo-code-review Bot commented Aug 6, 2026

Copy link
Copy Markdown

Code Review by Qodo

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

Grey Divider


Action required

1. Body allowlist bypass ✓ Resolved 🐞 Bug ⛨ Security
Description
body-policy.sh globally drops any matching line containing ABOUT_THE_CONTROL keywords before
evaluating violations, so a real credential/identifier can be missed if that same line also mentions
e.g. public-repo-guard or SECURITY.md. This weakens every rule implemented via check() and
enables trivial same-line bypasses (intentional or accidental).
Code

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

+  matches="$(printf '%s' "$raw" \
+    | rg -vN -- 'guard:allow[[:space:]]+[^[:space:]]' \
+    | rg -vNiP -- "$ABOUT_THE_CONTROL" || true)"
+  [[ -z "$matches" ]] && return 0
Evidence
The allowlist regex is defined broadly and then applied as a negative filter to the full set of
matches inside check(), so any violation line containing these tokens is removed before
counting/reporting. Because check() is used for every rule (keys, infra IDs, markers, etc.), the
bypass applies across the entire policy, not just one class of checks.

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

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

### Issue description
`body-policy.sh` applies the `ABOUT_THE_CONTROL` allowlist as a **global line-level suppression filter** for *every* rule’s matches. This can hide genuine violations for credentials/keys/etc. if the same line contains any allowlisted token.

### Issue Context
The intent is to avoid the scanner blocking discussions *about* the guard itself. However, applying this filter to all rules means it can also suppress high-signal secret formats.

### Fix Focus Areas
- scripts/public-repo-guard/body-policy.sh[31-36]
- scripts/public-repo-guard/body-policy.sh[52-69]
- scripts/public-repo-guard/tests/body-policy.test.sh[22-37]

### Suggested fix direction
1. Make the `ABOUT_THE_CONTROL` suppression **rule-scoped**, not global:
  - Either add an argument to `check()` like `allow_about_control=true|false` and only enable it for the specific rules that need it (likely the `internal-marker` / policy-discussion type rules),
  - Or remove the `ABOUT_THE_CONTROL` filter and rely on explicit `guard:allow <reason>` for exemptions.
2. Add/extend a fixture test proving the bug and the fix, e.g. ensure an AWS AKID or `github_pat_...` on a line containing `public-repo-guard` or `SECURITY.md` still **BLOCKS** (exit 1).

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


2. PR can modify scanner 🐞 Bug ⛨ Security
Description
The new body-guard job runs on pull_request events but checks out and executes
scripts/public-repo-guard/body-policy.sh from that checkout, so a PR can change the scanner to
always succeed and bypass PR-body enforcement. This directly undermines the intended “PREVENTS the
merge” behavior for PR body leaks.
Code

.github/workflows/public-repo-guard.yml[R128-131]

+      - 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.
Evidence
The workflow is triggered for pull_request events, and the body-guard job checks out
scripts/public-repo-guard and then executes body-policy.sh from the checked-out working
directory. Because the executed script is taken from the checkout, a PR can alter that script to
change the scan behavior for PR-triggered runs.

.github/workflows/public-repo-guard.yml[28-36]
.github/workflows/public-repo-guard.yml[113-116]
.github/workflows/public-repo-guard.yml[128-134]
.github/workflows/public-repo-guard.yml[160-163]

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

### Issue description
`body-guard` executes `bash scripts/public-repo-guard/body-policy.sh ...` after an `actions/checkout` that does not pin a trusted repository ref for `pull_request` events. That means the PR can change `body-policy.sh` (or related scripts) and effectively disable the scan.

### Issue Context
This job is explicitly intended to gate PR bodies (and detect issue/comment leaks). For issue/comment events, checking out the default branch is fine, but for `pull_request` the scanner code must be trusted (base branch), not PR-controlled.

### Fix Focus Areas
- .github/workflows/public-repo-guard.yml[31-36]
- .github/workflows/public-repo-guard.yml[113-116]
- .github/workflows/public-repo-guard.yml[128-134]
- .github/workflows/public-repo-guard.yml[160-163]

### Suggested fix direction
- In `body-guard`, make the checkout explicitly pull a **trusted ref** for the scanner scripts:
 - Example:
   - uses: actions/checkout@<pin>
     with:
       ref: ${{ github.event.pull_request.base.sha || github.sha }}
       sparse-checkout: scripts/public-repo-guard
       sparse-checkout-cone-mode: false
 - Then continue to run `bash scripts/public-repo-guard/body-policy.sh ...` as before.
- If you later need to scan PR tree content in this job, do a **second checkout** into a different path for the untrusted PR content and run the trusted scanner from the base checkout against that path.

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


Grey Divider

Context used
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 adds security-sensitive CI behavior plus substantial independent workflow, event-payload, regex-scanner, and fixture-test logic, creating multiple easy-to-miss failure and bypass modes.

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

Qodo Logo

Comment thread scripts/public-repo-guard/body-policy.sh Outdated
Comment on lines +128 to +131
- 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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Action required

2. Pr can modify scanner 🐞 Bug ⛨ Security

The new body-guard job runs on pull_request events but checks out and executes
scripts/public-repo-guard/body-policy.sh from that checkout, so a PR can change the scanner to
always succeed and bypass PR-body enforcement. This directly undermines the intended “PREVENTS the
merge” behavior for PR body leaks.
Agent Prompt
### Issue description
`body-guard` executes `bash scripts/public-repo-guard/body-policy.sh ...` after an `actions/checkout` that does not pin a trusted repository ref for `pull_request` events. That means the PR can change `body-policy.sh` (or related scripts) and effectively disable the scan.

### Issue Context
This job is explicitly intended to gate PR bodies (and detect issue/comment leaks). For issue/comment events, checking out the default branch is fine, but for `pull_request` the scanner code must be trusted (base branch), not PR-controlled.

### Fix Focus Areas
- .github/workflows/public-repo-guard.yml[31-36]
- .github/workflows/public-repo-guard.yml[113-116]
- .github/workflows/public-repo-guard.yml[128-134]
- .github/workflows/public-repo-guard.yml[160-163]

### Suggested fix direction
- In `body-guard`, make the checkout explicitly pull a **trusted ref** for the scanner scripts:
  - Example:
    - uses: actions/checkout@<pin>
      with:
        ref: ${{ github.event.pull_request.base.sha || github.sha }}
        sparse-checkout: scripts/public-repo-guard
        sparse-checkout-cone-mode: false
  - Then continue to run `bash scripts/public-repo-guard/body-policy.sh ...` as before.
- If you later need to scan PR tree content in this job, do a **second checkout** into a different path for the untrusted PR content and run the trusted scanner from the base checkout against that path.

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

@qodo-code-review

Copy link
Copy Markdown

Qodo Fixer

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

Grey Divider

🔗 Fix PR: #10

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 (#10). It is NOT applied to this PR.
To use it: review Fix PR #10 (https://github.com/wave-av/crest-console/pull/10), 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: Body allowlist bypass

…e comment on comment events

Three review findings, each with a regression fixture:

- The about-the-control allowlist filtered every rule's output, so a line
  mentioning SECURITY.md exempted a live AWS key on the same line. It now
  applies only to the narrative rules (internal-marker, private-repo-ops);
  credential/infra rules keep guard:allow as their only exemption.
- A leading (?i) on the private-repo-ops pattern spilled into OPS_DETAIL,
  blocking ordinary lowercase prose like 'api_key' near a repo name. The
  flag is now scoped to the repo names via (?i:...).
- issue_comment payloads carry the parent issue body, so one bad issue body
  failed every future comment on the thread. Comment events now scan only
  the comment; the parent got its own verdict from opened/edited runs.

Also preflights rg --pcre2-version with a diagnosis, so a ripgrep build
without PCRE2 fails with 'install a PCRE2-enabled build' instead of a
per-rule 'ripgrep failed (exit 2)' on every fixture.

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

This comment was marked as resolved.

… invented ones

The fixture file is public and exempt from both tree scanners
(content-policy.sh excludes the directory, .gitleaks.toml allowlists it),
so pinning real private repo names published exactly the class of
information the gate exists to block. The tests inject their own
GUARD_PRIVATE_REPOS, so invented names exercise the same code paths.

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

This comment was marked as resolved.

devin-ai-integration[bot]

This comment was marked as resolved.

yakimoto and others added 2 commits August 6, 2026 17:46
…eued body scan

Three review findings on the body gate:

- pull_request_review and pull_request_review_comment were the one public
  text surface nothing scanned: diff review comments are not issue_comment
  events. Review-comment payloads carry .comment so the existing branch
  covers them; review submissions get their own .review.body branch, which
  must precede the pull_request fallback or the PR body would be re-scanned
  under the review's check name.

- The shared concurrency group could drop an intermediate body version:
  GitHub keeps at most one pending run per group, so a burst of edits let a
  queued version go unscanned. The group is now keyed on run_id, i.e. never
  shared.

- The install list said four files but the guard job runs the fixture
  suite, so a repo installed without it goes red; it now names all five.

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

Underscore is a word character, so in WAVE_API_TOKEN the only \b sits
before the W, where [A-Z][A-Z0-9]* cannot reach the required _TOKEN — the
\b-anchored OPS_DETAIL silently missed every multi-underscore credential
name when it appeared AFTER the repo name (the detail-then-name order had
no anchor and worked). Drop the \b so both orders match mid-token, with a
regression fixture for the previously-missed order.

Also make the 'talking about the control' fixture actually exercise the
about-the-control allowlist: the body now names a configured repo next to
SECRET_TOKEN, so the test fails if the allowlist is deleted or its rule
scoping breaks.

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>

@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 +140 to +195
- 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

- name: Install ripgrep
run: command -v rg >/dev/null || (sudo apt-get update -qq && sudo apt-get install -y -qq ripgrep)

# The body is read straight out of the event payload FILE and written to
# another file. It is never interpolated into a run: block and never placed
# in an environment variable, so shell metacharacters in a hostile PR body
# have nothing to act on. jq is preinstalled on the GitHub-hosted images.
- name: Materialize the untrusted title/body to a file
run: |
set -euo pipefail
mkdir -p "$RUNNER_TEMP/bodyscan"
# An UNRECOGNIZED payload shape must fail, never quietly scan nothing and
# report a pass. If the event schema ever moves, this job must go red
# rather than become a green rubber stamp over an unscanned body.
if [ "$(jq -r 'has("pull_request") or has("issue") or has("comment")' "$GITHUB_EVENT_PATH")" != "true" ]; then
echo "::error title=public-repo-guard (body-guard)::Event payload contains no pull_request/issue/comment object — refusing to report a pass on an unscanned body."
exit 1
fi
# On a comment event the payload also carries the parent issue/PR title
# and body. Re-scanning those here would make ONE bad issue body fail
# every future comment on the thread, however clean — so a comment run
# scans only the comment (this covers issue_comment AND diff review
# comments: pull_request_review_comment payloads carry `comment` too).
# The parent body already got its own verdict from the issues/
# pull_request opened+edited runs.
if [ "$(jq -r 'has("comment")' "$GITHUB_EVENT_PATH")" = "true" ]; then
jq -r '.comment.body // empty' \
"$GITHUB_EVENT_PATH" > "$RUNNER_TEMP/bodyscan/body.txt"
# A review SUBMISSION scans only the review body (often empty for a bare
# approve — an empty scan is a pass, not an error). Its inline diff
# comments each arrive as their own pull_request_review_comment event.
# This branch must come before the pull_request fallback: the review
# payload carries `pull_request` too, and falling through would re-scan
# the PR body under the review's check name instead of the review.
elif [ "$(jq -r 'has("review")' "$GITHUB_EVENT_PATH")" = "true" ]; then
jq -r '.review.body // empty' \
"$GITHUB_EVENT_PATH" > "$RUNNER_TEMP/bodyscan/body.txt"
else
jq -r '[.pull_request.title, .pull_request.body,
.issue.title, .issue.body]
| map(select(. != null)) | join("\n")' \
"$GITHUB_EVENT_PATH" > "$RUNNER_TEMP/bodyscan/body.txt"
fi
echo "scanning $(wc -l < "$RUNNER_TEMP/bodyscan/body.txt") line(s) of body text"

- name: body policy (PR / issue / comment text)
env:
GUARD_PRIVATE_REPOS: ${{ vars.GUARD_PRIVATE_REPOS }}
run: bash scripts/public-repo-guard/body-policy.sh "$RUNNER_TEMP/bodyscan/body.txt"

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 gate runs the gate script from the untrusted PR branch, so a fork PR can neuter its own scan

On pull_request events the new body-guard job checks out the PR's own code (actions/checkout at .github/workflows/public-repo-guard.yml:140) and then executes scripts/public-repo-guard/body-policy.sh from that checkout (.github/workflows/public-repo-guard.yml:195). A contributor (including a fork) can include a commit that edits body-policy.sh to exit 0 unconditionally, so the body leak gate reports a pass on the very PR that disables it. The same pattern already exists for the pre-existing guard job's content-policy.sh step, so this extends an existing weakness rather than introducing a new class.

Open in Devin Review

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

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