Skip to content

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

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

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


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


Note

Medium Risk
Changes required CI behavior and branch-protection semantics (skipped checks superseding failures); misconfiguration could leave PRs mergeable on failing body scans until the second check is required. The body gate is security-sensitive but uses fail-closed scanning and trusted-base policy execution.

Overview
Adds server-side scanning for PR/issue/comment/review text via a new Body content policy job, alongside hardening the existing tree gate so required checks cannot be cleared by skipped or cancelled runs.

New body half: public-repo-guard-body.yml runs body-policy.sh on materialized event text (not shell-interpolated), with triggers for PR edited/synchronize, reviews, review comments, issues, and issue comments. Policy runs from a trusted base sparse checkout so a PR cannot ship a no-op scanner; install PRs fall back to the incoming copy with a warning. body-policy.sh mirrors tree leak classes (credentials, infra IDs, internal markers) but uses proximity rules for private repo names so bare cross-references stay allowed. Annotations redact matched content.

Tree workflow changes: Splits from the body job into public-repo-guard.yml only — drops PR edited, moves concurrency to a tree-only cancelling group, bumps actions/checkout to v7.0.1, and runs body-policy.test.sh in CI. Docs and workflow templates now describe a six-file install and require both required check names.

Operational note: Merging this workflow alone does not add branch protection for body edits; repos must also require public-repo-guard / Body content policy.

Reviewed by Cursor Bugbot for commit 351b528. Configure here.

Review in cubic

Note

Add CI body scanning to detect credential and policy violations in PR/issue/comment text

  • Adds body-policy.sh, a new bash scanner that checks PR titles/bodies, issue bodies, comments, and reviews for credential leaks (Stripe keys, GitHub PATs, AWS key IDs, PEM headers, etc.) and infrastructure identifiers using ripgrep with PCRE2.
  • Adds public-repo-guard-body.yml, a new workflow that triggers on PR, review, comment, and issue body events, materializes the relevant text via jq, and runs the body policy script from a trusted checkout.
  • Violations emit grouped CI annotations with redacted matches (no raw secret echoed) and block merge with exit code 1; scanner errors are fail-closed (exit 2).
  • Updates public-repo-guard.yml to exclude edited from tree-scan triggers (body edits now handled separately) and runs body-policy fixture tests as part of the tree job.
  • Behavioral Change: branch protection must now require both public-repo-guard / Tree content policy and public-repo-guard / Body content policy check names to enforce the full guard.

Macroscope summarized e7c8d61.

Review follow-up (dba6c63)

Three hardenings from review:

  • pull_request_review and pull_request_review_comment now trigger the body gate, and .review.body is projected: review summaries and inline diff comments were separate, unscanned surfaces.
  • body-guard executes the policy from the trusted BASE revision, not the PR merge ref, so a PR cannot rewrite the gate that judges it. The one exception is the install PR itself (base has no policy yet), which runs its own copy with a visible warning; that path is unreachable in an installed repo.
  • The body job's concurrency group is gone: a group holds at most one pending run, so rapid edits were silently cancelling queued scans despite cancel-in-progress: false.

The README install instructions now require BOTH check names (Secrets + content policy and Body content policy); the tree check alone is skipped on edited events, so without the second a failing body scan leaves the PR mergeable.

Review follow-up (0e6354e)

The tree scan and the body gate are now two workflow FILES (public-repo-guard.yml and public-repo-guard-body.yml, sharing the public-repo-guard display name so both required check contexts read unchanged). Review found that the single-file shape was itself a bypass: a job disabled by if: still publishes a check run with a non-failing skipped conclusion, and branch protection reads the latest check run per context, so a description edit (or any review comment) let the skipped tree job supersede a FAILING Secrets + content policy result on the same head SHA. With separate files, a body-only event never emits a check run for the tree context. The install bundle is now six files; the README and both templates are updated.

Also from review: the internal-marker prose rule is now case-insensitive ((?i), scoped to that rule alone), since real banners are written as "INTERNAL ONLY" or "Do Not Share"; credential-format rules stay case-exact. Regression fixtures cover both the capitalised banner and a quoted capitalised mention; all 25 pass.

…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: 1603c957-dc97-4e2c-8236-90ebe500d6c1

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_33fb7ca8-2c36-4f2c-a631-a17de748eb5d)

macroscopeapp[bot]
macroscopeapp Bot previously approved these changes Aug 6, 2026
@macroscopeapp

macroscopeapp Bot commented Aug 6, 2026

Copy link
Copy Markdown

Approvability

Verdict: Needs human review

Unable to check for correctness in e7c8d61. This PR introduces a new security scanning feature with CI workflows that gate PR merges, complex regex-based leak detection, and changes to merge blocking behavior. Security-related new capabilities warrant human review regardless of code ownership.

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

@qodo-code-review

Copy link
Copy Markdown

PR Summary by Qodo

ci: add issue/comment body scanning to public-repo-guard

✨ Enhancement ⚙️ Configuration changes 🧪 Tests 🕐 20-40 Minutes

Grey Divider

AI Description

• Add issue and comment triggers to scan public PR/issue/comment text for leaks.
• Split tree vs body scanning into separate jobs with correct concurrency behavior.
• Introduce body-policy scanner plus fixture tests to prevent noisy false positives.
Diagram

graph TD
  E{{"GitHub events"}} --> W["public-repo-guard workflow"]
  W --> G["Job: Secrets + content policy"] --> T["Repo tree scan"] --> CP["content-policy.sh"]
  G --> FT["Fixture self-test"] --> BPT["tests/body-policy.test.sh"] --> BP["body-policy.sh"]
  W --> BG["Job: Body content policy"] --> EP[("GITHUB_EVENT_PATH")] --> MT["Materialize body.txt"] --> BP

  subgraph Legend
    direction LR
    _ext{{"Event"}} ~~~ _job["Job/Step"] ~~~ _file[("File/Payload")]
  end
Loading
High-Level Assessment

The following are alternative approaches to this PR:

1. GitHub App/webhook body scanner
  • ➕ Can scan all issue/comment edits without Actions minutes
  • ➕ Can post richer feedback and centralize policy updates across repos
  • ➖ Requires operating and securing an external service/app
  • ➖ More complex rollout (installation, permissions, reliability, incident response)
2. Rely on GitHub Advanced Security secret scanning
  • ➕ Native integration and alerting for supported token types
  • ➕ Less custom policy code to maintain
  • ➖ May not cover organization-specific policy (private repo + ops-detail proximity)
  • ➖ Availability/licensing may differ across orgs and repositories
3. Single job with conditional steps (no separate body-guard job)
  • ➕ Fewer jobs to manage; simpler required-check configuration
  • ➖ Hard to get correct concurrency semantics for tree vs body edits
  • ➖ More likely to waste time running heavy tree scans on comment events

Recommendation: Keep the PR’s approach: a dedicated body-guard job with minimal permissions and event-payload extraction, alongside the existing tree scan job. This cleanly separates cost/concurrency requirements, avoids pull_request_target risks for fork PRs, and includes fixture tests to keep the policy deployable (low false-positive rate) while still failing closed on schema/tooling errors.

Files changed (3) +342 / -5

Enhancement (1) +139 / -0
body-policy.shIntroduce fail-closed body content policy scanner +139/-0

Introduce fail-closed body content policy scanner

• Adds a new ripgrep-based scanner for PR/issue/comment text with explicit allowlisting and redacted annotations. Implements blocking rules for credential formats, internal markers (use vs mention), and private-repo-plus-operational-detail proximity using CI-provided private repo names.

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

Tests (1) +108 / -0
body-policy.test.shAdd fixture tests to prevent noisy body-policy regressions +108/-0

Add fixture tests to prevent noisy body-policy regressions

• Adds hermetic fixture tests that assert both blocking and non-blocking cases, including precision tests for legitimate cross-repo references. Verifies that violations never echo matched text into CI output and that the scanner fails closed on missing/invalid input.

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

Other (1) +95 / -5
public-repo-guard.ymlAdd body scanning job and broaden triggers to issues/comments +95/-5

Add body scanning job and broaden triggers to issues/comments

• Extends workflow triggers to include PR edited, issues, and issue_comment events. Splits behavior into a tree-scanning guard job (with per-job concurrency and updated checkout pin) and a new body-guard job that extracts title/body text from the event payload and runs the body policy scanner.

.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 Outdated
Comment thread .github/workflows/public-repo-guard.yml Outdated
Comment thread .github/workflows/public-repo-guard.yml Outdated
Comment on lines +44 to +48
raw="$(rg -nP --no-filename -- "$re" "$FILE" 2>/dev/null)"; rc=$?
if (( rc >= 2 )); then
echo "::error title=public-repo-guard ($name)::ripgrep failed (exit $rc) scanning rule '$name' — failing closed."
exit 2
fi

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

📝 Info: PCRE2 is required and Ubuntu 22.04's ripgrep package does not have it

Every rule uses -P. Verified: the ubuntu-24.04 runner image does not preinstall ripgrep, so this step apt-installs it; the noble ripgrep package (14.1.0) links libpcre2-8-0 and works, but the jammy package (13.0.0-2ubuntu0.1) is built WITHOUT PCRE2 (confirmed locally: rg --pcre2-version reports unavailable). Consequence: any repo that copies this template and pins runs-on: ubuntu-22.04 gets a permanently red, merge-blocking Body content policy check (fail-closed at scripts/public-repo-guard/body-policy.sh:32), and the tree job's new self-test step fails too. The same is true for local runs on 22.04 — the fixture suite reports 25 failures there. The explicit probe message makes this diagnosable, but a note in the workflow header ("requires a PCRE2-enabled ripgrep; ubuntu-22.04's apt package lacks it") would save the next operator the investigation.

Open in Devin Review

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

Comment thread .github/workflows/public-repo-guard.yml Outdated
Comment thread .github/workflows/public-repo-guard.yml Outdated
@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. Fail-open allowlist filter ✓ Resolved 🐞 Bug ⛨ Security
Description
In body-policy.sh the allowlist filtering pipeline ends with || true, so if either ripgrep
filter errors (exit >=2) the rule can be treated as having no matches and pass instead of failing
closed. This breaks the script’s documented contract (exit 2 on scanner error) and can silently miss
body violations.
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 script explicitly documents that scanner errors must fail closed (exit 2) and enforces this for
the primary ripgrep scan, but the later allowlist-filter pipeline masks non-zero exit codes with `||
true`, allowing filter errors to be interpreted as “no matches.”

scripts/public-repo-guard/body-policy.sh[18-48]
scripts/public-repo-guard/body-policy.sh[53-56]

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` claims to fail closed on scanner errors (exit 2), and it correctly enforces that for the primary `rg` scan. However, the subsequent allowlist filtering uses a pipeline ending in `|| true`, which masks *all* non-zero exit codes—including real ripgrep errors (>=2). This can turn a filter error into an empty `matches` result and report a false “OK”.

### Issue Context
- ripgrep exit codes: 0=match, 1=no match, >=2=error.
- We should allow exit code 1 in the filtering stage (meaning “nothing left after filtering”), but must fail closed on exit >=2.

### Fix Focus Areas
- scripts/public-repo-guard/body-policy.sh[41-56]

### What to change
- Remove the unconditional `|| true` masking.
- Capture and validate exit codes for each filtering stage:
 - Accept 0/1 as non-error.
 - If any filter returns >=2, emit an `::error::...` message and `exit 2`.
- (Optional) avoid relying on `-N` if not needed; the input already contains line numbers from the initial `rg -nP` scan.

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



Remediation recommended

2. Control allowlist hides secrets ✓ Resolved 🐞 Bug ⛨ Security
Description
ABOUT_THE_CONTROL is applied as a line-level exemption inside check() for every rule, including
credential-format rules, so any credential-shaped leak on a line mentioning e.g.
public-repo-guard/SECURITY.md is filtered out and not reported. This creates a bypass that can
miss real secrets in security discussions.
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
check(). Because credential-format rules are also implemented via check BLOCK ..., any
credential hit on an allowlisted line is removed before reporting.

scripts/public-repo-guard/body-policy.sh[31-35]
scripts/public-repo-guard/body-policy.sh[53-55]
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
`ABOUT_THE_CONTROL` is meant to prevent self-referential false positives, but it is currently applied to *all* rules. That means high-value detections (Stripe keys, GitHub PATs, private keys, etc.) are also suppressed if the same line contains a control-related term.

### Issue Context
The exemption is implemented as a negative filter (`rg -v ... "$ABOUT_THE_CONTROL"`) on the matched lines, so it removes entire lines—even if those lines contain real credential patterns.

### Fix Focus Areas
- scripts/public-repo-guard/body-policy.sh[31-35]
- scripts/public-repo-guard/body-policy.sh[53-55]
- scripts/public-repo-guard/body-policy.sh[71-79]

### What to change
- Split rule evaluation into at least two paths:
 1) **Credential-format rules**: only honor explicit `guard:allow ...` (and do not apply `ABOUT_THE_CONTROL`).
 2) **Prose/content rules** where self-reference is expected: apply `ABOUT_THE_CONTROL` in addition to `guard:allow`.
- Add a fixture test that ensures a credential-shaped token is still blocked even if the same line mentions `public-repo-guard`/`SECURITY.md`.

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


Grey Divider

Context used
✅ Compliance rules (platform): 7 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 independent workflow, shell-scanning, event-payload, concurrency, and policy/test logic, creating multiple plausible easy-to-miss defects across code paths.

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.

@qodo-code-review

Copy link
Copy Markdown

Qodo Fixer

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

Grey Divider

🔗 Fix PR: #29

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 (#29). It is NOT applied to this PR.
To use it: review Fix PR #29 (https://github.com/wave-av/.github/pull/29), 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: Fail-open allowlist filter

… sync template

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

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

@cubic-dev-ai cubic-dev-ai 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.

2 issues found and verified against the latest diff

Confidence score: 2/5

  • In .github/workflows/public-repo-guard.yml, a failed body scan may not actually gate merges unless Body content policy is explicitly required, and title/body-only edits can bypass the existing required tree check; this creates a concrete policy-enforcement gap on public PRs — add Body content policy to required status checks and ensure it runs on metadata-only edits.
  • In .github/workflows/public-repo-guard.yml, installing ripgrep via apt means the runner may get a build without PCRE2, while body-policy.sh rules depend on that feature; scans can silently misbehave or fail inconsistently across environments — pin a known-good ripgrep version (or verify PCRE2 support at runtime) before running policy checks.
Prompt for AI agents (unresolved issues)

Check if these issues are valid — if so, understand the root cause of each and fix them. If appropriate, use sub-agents to investigate and fix each issue separately.


<file name=".github/workflows/public-repo-guard.yml">

<violation number="1" location=".github/workflows/public-repo-guard.yml:114">
P1: A failing body scan will not block a PR unless `Body content policy` is added to the repository's required status checks; on body/title edits the existing required tree check is skipped and can remain green. Configure this new check as required, or make the existing required gate depend on it, to enforce the stated PR-blocking behavior.</violation>

<violation number="2" location=".github/workflows/public-repo-guard.yml:135">
P2: The workflow installs ripgrep via `apt-get install -y -qq ripgrep`, which pulls whatever version the runner image's distro package provides with no guarantee of PCRE2 support. Since every rule in body-policy.sh relies on `rg -nP` (PCRE2 regex), a non-PCRE2 build of ripgrep causes every rule to error out with 'PCRE2 is not available in this build of ripgrep', which check() treats as a scanner error (exit 2) — failing the job on every body scan with an opaque message. Consider asserting PCRE2 support explicitly (e.g. `rg -P --version`) before running the checks so failures are diagnosable.</violation>
</file>

Tip: instead of fixing issues one by one fix them all with cubic

Re-trigger cubic

Comment thread .github/workflows/public-repo-guard.yml Outdated
# detection — it tells us to go redact, fast. Only the client-side pre-write hook
# can stop that class before publication.
body-guard:
name: Body content policy

@cubic-dev-ai cubic-dev-ai 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.

P1: A failing body scan will not block a PR unless Body content policy is added to the repository's required status checks; on body/title edits the existing required tree check is skipped and can remain green. Configure this new check as required, or make the existing required gate depend on it, to enforce the stated PR-blocking behavior.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/public-repo-guard.yml, line 114:

<comment>A failing body scan will not block a PR unless `Body content policy` is added to the repository's required status checks; on body/title edits the existing required tree check is skipped and can remain green. Configure this new check as required, or make the existing required gate depend on it, to enforce the stated PR-blocking behavior.</comment>

<file context>
@@ -71,3 +92,72 @@ jobs:
+  # detection — it tells us to go redact, fast. Only the client-side pre-write hook
+  # can stop that class before publication.
+  body-guard:
+    name: Body content policy
+    if: github.event_name == 'pull_request' || github.event_name == 'issues' || github.event_name == 'issue_comment'
+    concurrency:
</file context>
Fix with cubic

Comment thread .github/workflows/public-repo-guard.yml Outdated
Comment thread .github/workflows/public-repo-guard.yml Outdated
Comment thread .github/workflows/public-repo-guard.yml Outdated
Comment thread .github/workflows/public-repo-guard.yml Outdated
sparse-checkout: scripts/public-repo-guard
sparse-checkout-cone-mode: false

- name: Install ripgrep

@cubic-dev-ai cubic-dev-ai 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.

P2: The workflow installs ripgrep via apt-get install -y -qq ripgrep, which pulls whatever version the runner image's distro package provides with no guarantee of PCRE2 support. Since every rule in body-policy.sh relies on rg -nP (PCRE2 regex), a non-PCRE2 build of ripgrep causes every rule to error out with 'PCRE2 is not available in this build of ripgrep', which check() treats as a scanner error (exit 2) — failing the job on every body scan with an opaque message. Consider asserting PCRE2 support explicitly (e.g. rg -P --version) before running the checks so failures are diagnosable.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At .github/workflows/public-repo-guard.yml, line 135:

<comment>The workflow installs ripgrep via `apt-get install -y -qq ripgrep`, which pulls whatever version the runner image's distro package provides with no guarantee of PCRE2 support. Since every rule in body-policy.sh relies on `rg -nP` (PCRE2 regex), a non-PCRE2 build of ripgrep causes every rule to error out with 'PCRE2 is not available in this build of ripgrep', which check() treats as a scanner error (exit 2) — failing the job on every body scan with an opaque message. Consider asserting PCRE2 support explicitly (e.g. `rg -P --version`) before running the checks so failures are diagnosable.</comment>

<file context>
@@ -71,3 +92,72 @@ jobs:
+          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)
+
</file context>
Fix with cubic

devin-ai-integration[bot]

This comment was marked as resolved.

yakimoto and others added 2 commits August 6, 2026 17:49
…ing concurrency

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

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

This comment was marked as resolved.

…b superseded a failing required check

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 +46 to +49
issues:
types: [opened, edited]
issue_comment:
types: [created, edited]

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

🔍 Body verdicts from issue/comment/review events never land on the PR head SHA

Only pull_request events (opened/edited/reopened/synchronize) produce a check run against the PR head commit. For issue_comment and issues, GITHUB_SHA is the default-branch head, and for pull_request_review/pull_request_review_comment it is the PR merge commit — so a FAILING body scan from those events is invisible to branch protection and, for issue/issue_comment, attaches a red public-repo-guard / Body content policy check run to the head of main. The header at .github/workflows/public-repo-guard-body.yml:24-27 frames comment/issue coverage as detection-only, which is consistent, but the side effect of reddening the default-branch commit status (and any tooling that reads it, e.g. release gating or merge queues) is worth confirming is acceptable.

Open in Devin Review

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

Comment thread .github/workflows/public-repo-guard-body.yml
…he alarm, not a bug

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

This comment was marked as resolved.

…job policy provenance

The fixture file pinned three real-looking private repo names into the one
path neither gate scans (content-policy.sh excludes scripts/public-repo-guard/
and .gitleaks.toml allowlists it), against body-policy.sh's own 'names are NOT
hardcoded' rule. The test names are now clearly fictitious and the file says
why.

The tree job's use of the PR's own content-policy.sh is now documented as
deliberate: on pull_request events the workflow definition itself runs from
the PR merge ref, so pinning the script to base removes no attacker
capability, and the tree gate must scan and self-test the policy version the
tree ships so script and fixtures can change together.

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_71827916-8955-42aa-9570-2cc1d98d88bf)

devin-ai-integration[bot]

This comment was marked as resolved.

With [A-Z0-9]* the class excluded _, so for a multi-segment name like
WAVE_VIEWPORT_LEASE_SECRET only the trailing LEASE_SECRET could match,
and its start sits right after a _ (a word character) — the \b prepended
in the name-then-detail alternative was unsatisfiable, silently passing
that order. The detail-then-name order has no leading \b, which is why
the existing fixtures stayed green.

Adds a regression fixture for the forward order, plus a fixture pinning
the deliberate about-exempt behaviour of the proximity rule (a line that
names the gate is dropped even when it carries the leak shape), which
was previously untested.

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

This comment was marked as resolved.

…hat reddens docs paths gets switched off

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

This comment was marked as resolved.

…a line-scoped rule

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 +199 to +202
# The proximity gap: any character INSIDE a paragraph. A newline is allowed
# only when not followed by another (possibly whitespace-padded) blank line,
# so hard wraps and bullets stay in scope while a paragraph break resets it.
_GAP='(?:[^\n]|\n(?![ \t]*\n)){0,140}?'

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔴 Legitimate pull-request descriptions get blocked because Windows-style line endings defeat the paragraph boundary

The gap between a private repo name and operational detail is allowed to cross a blank line whenever the blank line uses Windows-style endings (\n(?![ \t]*\n) at scripts/public-repo-guard/body-policy.sh:202), so ordinary descriptions that mention a private repo in one paragraph and a credential name in the next are wrongly reported as leaks.
Impact: Authors of perfectly clean pull requests see a red required check they cannot fix, and the gate quickly loses credibility.

CR characters make the paragraph-break lookahead fail

GitHub delivers PR/issue/comment bodies in the event payload with CRLF line endings, and jq -r writes them out verbatim (.github/workflows/public-repo-guard-body.yml:134-140). The gap regex allows a newline only when it is not followed by another (whitespace-padded) newline, but [ \t] does not include \r. For a real paragraph break \r\n\r\n, the lookahead sees \r\n after the first \n, does not match, so the negative lookahead succeeds and the newline is consumed as gap — proximity is never reset.

Reproduced locally with rg 14.1.1: the exact fixture from scripts/public-repo-guard/tests/body-policy.test.sh:101-104 (expected exit 0) exits 1 when written with CRLF. The fixtures only use LF, so CI never catches it.

Fix options: allow \r in the lookahead padding, or strip CRs when materializing the body in the workflow (and add a CRLF fixture).

Suggested change
# The proximity gap: any character INSIDE a paragraph. A newline is allowed
# only when not followed by another (possibly whitespace-padded) blank line,
# so hard wraps and bullets stay in scope while a paragraph break resets it.
_GAP='(?:[^\n]|\n(?![ \t]*\n)){0,140}?'
# The proximity gap: any character INSIDE a paragraph. A newline is allowed
# only when not followed by another (possibly whitespace-padded) blank line,
# so hard wraps and bullets stay in scope while a paragraph break resets it.
# `\r` is part of the padding class: GitHub bodies arrive CRLF-terminated.
_GAP='(?:[^\n]|\n(?![ \t\r]*\n)){0,140}?'
Open in Devin Review

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

Comment on lines +49 to +59
**Install + enforce:** copy the six files the workflow's header lists —
`public-repo-guard.yml` AND `public-repo-guard-body.yml` into
`.github/workflows/`, plus `.gitleaks.toml`,
`scripts/public-repo-guard/content-policy.sh`,
`scripts/public-repo-guard/body-policy.sh`, and
`scripts/public-repo-guard/tests/body-policy.test.sh` — then add BOTH check
names, `public-repo-guard / Secrets + content policy` and
`public-repo-guard / Body content policy`, to the branch's required status
checks. The tree check alone does not gate body edits: those only trigger the
body workflow, so without the second required check a failing body scan leaves
the PR mergeable.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 Changelog not updated for a user-facing change

The repository's agent contract requires the Unreleased section of CHANGELOG.md to be updated with user-facing changes, but this PR adds a new required merge gate and installation instructions without any changelog entry (workflow-templates/README.md:49-68).
Impact: Consumers of the org templates get a new mandatory check with no changelog record of it.

Rule source

AGENTS.md — Conventions: "Update CHANGELOG.md (Unreleased) with user-facing changes." The PR adds public-repo-guard-body.yml, body-policy.sh and changes the install/enforce instructions, which are user-facing for every repo installing the gate.

Open in Devin Review

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

…AGENTS.md requires

Co-authored-by: Codesmith <codesmith-bot@users.noreply.github.com>
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