Skip to content

fix(compliance-audit): suppress gh_api stdout on failure to fix false CODEOWNERS positive#212

Open
don-petry wants to merge 62 commits into
mainfrom
claude/issue-208-20260508-1408
Open

fix(compliance-audit): suppress gh_api stdout on failure to fix false CODEOWNERS positive#212
don-petry wants to merge 62 commits into
mainfrom
claude/issue-208-20260508-1408

Conversation

@don-petry
Copy link
Copy Markdown
Contributor

@don-petry don-petry commented May 8, 2026

Summary

  • Fixes a false positive codeowners-org-leads-not-first compliance finding in scripts/compliance-audit.sh
  • The gh_api() retry wrapper was forwarding gh api stdout unconditionally — including the error JSON body emitted on a 404 response
  • Callers like check_codeowners() received concatenated 404 JSON blobs instead of an empty string, making found=true for a missing file and treating the error JSON as CODEOWNERS content
  • Fix: capture output into a variable and only echo it when exit code is 0

The CODEOWNERS file at .github/CODEOWNERS was already correct (* @petry-projects/org-leads); no CODEOWNERS change is needed.

Test plan

  • Re-run the compliance audit against this repo after merge — the codeowners-org-leads-not-first finding should be absent
  • Verify all other gh_api call sites are unaffected (callers that use || echo "" or redirect stdout to /dev/null still work correctly)

Closes #208

Generated with Claude Code

Summary by CodeRabbit

  • Bug Fixes
    • Improved API response handling and error recovery in the compliance audit script to ensure consistent capture and return of results.

Review Change Stack

…se positives

When gh api returns a 404, it outputs the error JSON to stdout (not
stderr). The previous gh_api() forwarded all stdout unconditionally,
causing callers like check_codeowners() to receive concatenated 404 JSON
blobs instead of empty strings. This made found=true for a missing file
and treated the error JSON as CODEOWNERS content, triggering a false
codeowners-org-leads-not-first finding.

Fix: capture output into a variable and only echo it when the exit code
is 0, so failed API calls produce no stdout.

Closes #208

Co-authored-by: Don Petry <don-petry@users.noreply.github.com>
Copilot AI review requested due to automatic review settings May 8, 2026 14:10
@don-petry don-petry requested a review from a team as a code owner May 8, 2026 14:10
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 8, 2026

Warning

Review limit reached

@don-petry, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 59 minutes and 23 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 0d28643d-1993-4295-a15f-1c4723f5b127

📥 Commits

Reviewing files that changed from the base of the PR and between 6976ebb and d7ee727.

📒 Files selected for processing (1)
  • scripts/compliance-audit.sh
📝 Walkthrough

Walkthrough

The PR updates the gh_api retry wrapper in the compliance audit script to properly capture and return GitHub CLI API responses. Instead of checking only the command exit status, the wrapper now stores stdout in a variable and explicitly returns the captured output on success.

Changes

GitHub CLI API Response Handling

Layer / File(s) Summary
gh_api wrapper output capture fix
scripts/compliance-audit.sh
The retry loop assigns gh api "$@" stdout to an output variable, captures the exit code separately, and on success (rc == 0) prints the captured output before returning 0, replacing the prior inline success check. This ensures API responses are properly propagated to callers instead of being lost.

Estimated code review effort

🎯 1 (Trivial) | ⏱️ ~3 minutes

Possibly related PRs

  • petry-projects/.github#221: Updates the same gh_api retry wrapper to return captured stdout correctly, addressing stdout/exit-code handling that a related PR works around.
🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main change: fixing gh_api stdout suppression on failure to resolve a false CODEOWNERS compliance positive.
Linked Issues check ✅ Passed The PR directly addresses issue #208 by fixing the gh_api() wrapper to suppress error output, ensuring failed API calls produce no stdout and preventing 404 JSON from being treated as CODEOWNERS content.
Out of Scope Changes check ✅ Passed All changes are scoped to fixing the gh_api retry wrapper behavior in compliance-audit.sh as required by issue #208; no out-of-scope modifications are present.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch claude/issue-208-20260508-1408

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

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

@don-petry
Copy link
Copy Markdown
Contributor Author

@petry-projects/org-leads — this PR is ready for review and merge. It fixes a false positive in the compliance audit script.

Copy link
Copy Markdown
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the gh_api() retry wrapper in scripts/compliance-audit.sh to prevent gh api stdout (including error JSON bodies from failed requests like 404s) from being forwarded to callers, which previously caused false positives in checks like check_codeowners().

Changes:

  • Capture gh api output inside gh_api() and only emit it when the command succeeds (exit code 0).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines 100 to 106
for i in $(seq 1 $retries); do
if gh api "$@" 2>/dev/null; then
output=$(gh api "$@" 2>/dev/null)
rc=$?
if [ $rc -eq 0 ]; then
echo "$output"
return 0
fi
@don-petry don-petry closed this May 11, 2026
@don-petry don-petry reopened this May 11, 2026
donpetry-bot
donpetry-bot previously approved these changes May 11, 2026
Copy link
Copy Markdown
Contributor

@donpetry-bot donpetry-bot left a comment

Choose a reason for hiding this comment

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

Automated review — APPROVED ✓

Risk: LOW
Reviewed commit: a191bfcfa6fc014ce4d88ea3ba70860a890233d4
Review mode: triage-approved (single reviewer)

Summary

Single-line CI workflow change pinning petry-projects/.github/.github/workflows/agent-shield-reusable.yml from the mutable @v1 tag to the exact commit SHA 0cb4bba11d7563bf197ad805f12fb8639e4879e4, with the # v1 human-readable comment retained and the with: required-files: AGENTS.md input preserved. Verified via gh api repos/petry-projects/.github/git/refs/tags/v1 that the pinned SHA matches the actual commit currently behind the v1 tag. Conforms to the org action-pinning policy and follows the same pattern as the recently merged #127 (auto-rebase-reusable.yml SHA pin).

Linked issue analysis

Closes #114 — a compliance-audit finding for unpinned-actions-agent-shield.yml flagging that agent-shield.yml had 1 action not pinned to SHA. The PR addresses exactly that line; no other unpinned references remain in this workflow.

Findings

No issues found.

  • SHA pin verified against upstream tag v1 (matches 0cb4bba11d7563bf197ad805f12fb8639e4879e4).
  • Repo-specific with: inputs preserved unchanged.
  • No secrets, permissions, or trigger surface modified.
  • Pre-existing missing trailing newline on the file is unchanged by this PR; out of scope.

CI status

All required checks green: AgentShield, Claude Code, CodeQL (Analyze actions), Dependency audit (ecosystem detect), SonarCloud / SonarCloud Code Analysis (Quality Gate passed, 0 new issues), CodeRabbit. Dependabot auto-merge and ecosystem-specific audit jobs correctly skipped (no matching ecosystems / not a Dependabot PR). CodeRabbit posted a rate-limit notice but its status check reports SUCCESS; gemini-code-assist skipped due to unsupported file type. Mergeable: yes; merge state BLOCKED only on the required human review.


Reviewed automatically by the PR-review agent (single-reviewer mode: opus 4.7). Reply if you need a human review.

@donpetry-bot donpetry-bot enabled auto-merge (squash) May 11, 2026 22:25
@don-petry don-petry closed this May 12, 2026
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
scripts/compliance-audit.sh (1)

545-551: 🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Update comment to reflect the fixed gh_api() wrapper behavior.

The comment explains that the gh_api() retry wrapper should not be used here because it "loops 3 times without suppressing stdout, so the captured output ends up as 3 concatenated error bodies." However, the wrapper now suppresses stdout on failure (lines 115-118), so this explanation is outdated.

The directive to avoid the wrapper is still correct, but for a different reason: this function needs direct access to the error response body to distinguish 403 permission errors from other failures, and the wrapper now suppresses error output on failure.

📝 Suggested comment update
-  # IMPORTANT: Do NOT use the gh_api() retry wrapper here. When gh api gets a
-  # 403 it outputs the error JSON body to stdout before exiting non-zero. The
-  # retry wrapper loops 3 times without suppressing stdout, so the captured
-  # output ends up as 3 concatenated error bodies — indistinguishable from a
-  # real "not-configured" state and causing persistent false-positive findings.
-  # We capture the response body and exit code separately so we can detect a
-  # 403 permission error and skip without filing a spurious finding.
+  # IMPORTANT: Do NOT use the gh_api() retry wrapper here. This function needs
+  # direct access to the error response body to distinguish 403 permission errors
+  # from other failures (404, 500, etc.). The gh_api() wrapper suppresses error
+  # output on failure to prevent false positives elsewhere, but here we must
+  # inspect the error JSON to detect "Resource not accessible by personal access
+  # token" (403) and skip the check rather than filing a spurious finding.
+  # We capture the response body and exit code separately for this purpose.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@scripts/compliance-audit.sh` around lines 545 - 551, Update the block comment
that explains why we must not use the gh_api() retry wrapper: change the
outdated claim that the wrapper "loops 3 times without suppressing stdout" to
the current behavior (the wrapper now suppresses stdout on failure) and instead
state the real reason we avoid it here — the script needs direct access to the
raw HTTP error response body (and exit code) so it can detect a 403 permission
response versus other failures; reference gh_api() in the comment and instruct
readers to call gh directly to capture the response body and exit status
separately.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@scripts/compliance-audit.sh`:
- Around line 545-551: Update the block comment that explains why we must not
use the gh_api() retry wrapper: change the outdated claim that the wrapper
"loops 3 times without suppressing stdout" to the current behavior (the wrapper
now suppresses stdout on failure) and instead state the real reason we avoid it
here — the script needs direct access to the raw HTTP error response body (and
exit code) so it can detect a 403 permission response versus other failures;
reference gh_api() in the comment and instruct readers to call gh directly to
capture the response body and exit status separately.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro

Run ID: 6a448ef2-a7ce-44f7-a366-a5fb886703ab

📥 Commits

Reviewing files that changed from the base of the PR and between 0765a60 and 6976ebb.

📒 Files selected for processing (1)
  • scripts/compliance-audit.sh

@don-petry
Copy link
Copy Markdown
Contributor Author

@dev-lead - please fix this PR

@sonarqubecloud
Copy link
Copy Markdown

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Compliance: codeowners-org-leads-not-first

3 participants