Skip to content

CANARY — DO NOT MERGE: verify the review standard fires - #59

Closed
hallelx2 wants to merge 1 commit into
mainfrom
standards/canary
Closed

CANARY — DO NOT MERGE: verify the review standard fires#59
hallelx2 wants to merge 1 commit into
mainfrom
standards/canary

Conversation

@hallelx2

@hallelx2 hallelx2 commented Aug 10, 2026

Copy link
Copy Markdown
Owner

Verification run for the review standard. Every defect below is deliberate — close without merging.

What this tests

Applies the fix from dev-standards@afe6694. The action inputs were hyphenated (jules-api-key) where sanjay3290/jules-pr-reviewer expects underscores (jules_api_key), so every run since 2026-07-09 failed with Input required and not supplied: jules_api_key. Jules has never reviewed anything.

Seeded defects — internal/canary/billing.go

Class Detail
Broken authorization GetInvoice looks up by id with no ownership or tenant scoping — any caller reads any tenant's invoice
Secret in log the billing token is written to a log line
Hardcoded credential a token constant committed in source

Silence from the reviewer here is a failure, not a pass.

Note: an earlier attempt used a Stripe-format key and was correctly blocked by GitHub push protection — that guard works.

Summary by Sourcery

Add an automated Jules security review workflow for pull requests and introduce a canary billing module with deliberate security defects to validate the review standard.

New Features:

  • Add a GitHub Actions workflow that triggers the Jules PR security reviewer on qualifying pull request events when a JULES_API_KEY secret is configured.

Enhancements:

  • Define explicit extra instructions for Jules to perform an adversarial application-security review focused on authorization, multi-tenant leakage, secret handling, injection/SSRF, and crypto issues.

Tests:

  • Add a canary billing module containing intentionally insecure invoice lookup logic, hardcoded credential, and secret logging to verify that security review tooling and standards detect these defects.

Summary by CodeRabbit

  • New Features
    • Added invoice lookup capabilities, including invoice identifiers, ownership details, and billing amounts.
  • Security
    • Added automated security reviews for pull request changes when configured.
    • Reviews run for newly opened, updated, and review-ready changes.

DO NOT MERGE. Applies the jules-review input-name fix and seeds three security
defects: hardcoded credential, broken authorization, secret in log.
@sourcery-ai

sourcery-ai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Reviewer's Guide

Adds an optional GitHub Actions workflow to trigger Jules-based security reviews on PRs and introduces a canary billing module with deliberate security defects to validate that the review standard catches them.

Sequence diagram for Jules security review GitHub Actions workflow

sequenceDiagram
  actor Developer
  participant GitHub
  participant GitHubActions
  participant JulesReviewer

  Developer->>GitHub: open_pull_request / update_pull_request
  GitHub->>GitHubActions: trigger jules-review workflow
  GitHubActions->>GitHubActions: Guard_only_run_when_a_Jules_key_is_configured
  alt JULES_API_KEY present
    GitHubActions->>JulesReviewer: sanjay3290_jules_pr_reviewer with jules_api_key and github_token
    JulesReviewer-->>GitHub: post security review comments
  else JULES_API_KEY missing
    GitHubActions-->>GitHub: log skipping automated Jules review
  end
Loading

Flow diagram for insecure GetInvoice lookup in canary billing module

flowchart TD
  A[GetInvoice id] --> B[log.Printf billing lookup id and billingToken]
  B --> C{iterate invoices}
  C --> D{id matches invoice.ID?}
  D -->|yes| E[return &invoice]
  D -->|no| C
  C -->|no more invoices| F[return nil]
Loading

File-Level Changes

Change Details Files
Introduce a GitHub Actions workflow that conditionally invokes the Jules security review action on pull requests when a Jules API key secret is configured.
  • Define a jules-review workflow triggered on pull request events (opened, synchronize, ready_for_review).
  • Add a guard step that checks for the JULES_API_KEY secret and short-circuits the workflow when absent, emitting an informational log message.
  • Integrate the sanjay3290/jules-pr-reviewer GitHub Action with correctly named inputs for the Jules API key and GitHub token.
  • Provide extra security-focused review instructions directing Jules to hunt for authorization, tenant leakage, secret handling, injection/SSRF, and crypto issues, citing file:line and fixes.
.github/workflows/jules-review.yml
Add a canary billing module with intentionally insecure invoice retrieval logic and embedded secrets to test that reviewers flag the seeded defects.
  • Define a hardcoded billing token constant representing a credential stored directly in source code.
  • Implement an Invoice type and an in-memory invoices slice with sample data.
  • Provide a GetInvoice function that retrieves invoices solely by ID without any ownership or tenant scoping, enabling cross-tenant data access.
  • Log the billing token alongside lookup operations, exposing a secret in application logs.
internal/canary/billing.go

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@coderabbitai

coderabbitai Bot commented Aug 10, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

Jules security review

Layer / File(s) Summary
Jules review workflow
.github/workflows/jules-review.yml
The workflow runs on selected pull request events. It requires JULES_API_KEY, grants repository and pull request permissions, and invokes a pinned Jules security-review action.

Canary billing lookup

Layer / File(s) Summary
Invoice model and lookup
internal/canary/billing.go
The package adds Invoice, seeded in-memory invoices, a billing credential, and GetInvoice. The lookup logs the credential and does not apply ownership or tenant checks.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Possibly related PRs

Suggested labels: dev-standards

🚥 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 clearly identifies this as a canary security-review test and states that it must not be merged.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
🛠️ Fix failing CI checks 💡
  • Create stacked PR
  • Commit on current branch
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch standards/canary

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.

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

Hey - I've found 3 issues, and left some high level feedback:

  • internal/canary/billing.go exposes a hardcoded credential in billingToken; replace this with a runtime-provided secret (e.g., env var or secret manager) and avoid committing tokens to source control.
  • GetInvoice currently returns invoices solely by ID with no ownership or tenant scoping; ensure authorization is enforced so callers can only access invoices belonging to their own tenant/owner.
  • The log.Printf in GetInvoice includes the billingToken in logs; remove secret values from log output and, if needed, log only non-sensitive identifiers.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- internal/canary/billing.go exposes a hardcoded credential in `billingToken`; replace this with a runtime-provided secret (e.g., env var or secret manager) and avoid committing tokens to source control.
- GetInvoice currently returns invoices solely by ID with no ownership or tenant scoping; ensure authorization is enforced so callers can only access invoices belonging to their own tenant/owner.
- The `log.Printf` in GetInvoice includes the `billingToken` in logs; remove secret values from log output and, if needed, log only non-sensitive identifiers.

## Individual Comments

### Comment 1
<location path="internal/canary/billing.go" line_range="7-8" />
<code_context>
+
+// CANARY — deliberate defects to verify the review standard fires. DO NOT MERGE.
+
+// hardcoded credential
+const billingToken = "b7f3d91e4c2a8056f1d3e7a94c0b2856d4f9a1e3"
+
+type Invoice struct {
</code_context>
<issue_to_address>
**🚨 issue (security):** Avoid hardcoded secrets in source; use a secret manager or configuration instead.

Even for canary code, realistic-looking tokens can be picked up by scanners or copied into real code. For production, load credentials from environment variables or a secret store, and keep canaries using clearly fake, non-credential-like values.
</issue_to_address>

### Comment 2
<location path="internal/canary/billing.go" line_range="21" />
<code_context>
+// GetInvoice looks up by id with no ownership or tenant scoping — any caller can
+// read any tenant's invoice.
+func GetInvoice(id string) *Invoice {
+	log.Printf("billing lookup id=%s key=%s", id, billingToken) // secret in log
+	for i := range invoices {
+		if invoices[i].ID == id {
</code_context>
<issue_to_address>
**🚨 issue (security):** Do not log secret material; logs are often less protected than primary storage.

Logging `billingToken` exposes sensitive data to anyone with log or aggregation access. Even in canary code, avoid printing secrets; prefer redacted values (e.g., invoice ID only or a token hash) instead.
</issue_to_address>

### Comment 3
<location path="internal/canary/billing.go" line_range="18-20" />
<code_context>
+
+var invoices = []Invoice{{ID: "in_1", OwnerID: "u_1", Amount: 4200}}
+
+// GetInvoice looks up by id with no ownership or tenant scoping — any caller can
+// read any tenant's invoice.
+func GetInvoice(id string) *Invoice {
+	log.Printf("billing lookup id=%s key=%s", id, billingToken) // secret in log
+	for i := range invoices {
</code_context>
<issue_to_address>
**🚨 issue (security):** Missing authorization/tenant scoping on invoice lookup enables cross-tenant data exposure.

`GetInvoice` only filters by invoice ID and never checks that the caller is the owner or belongs to the correct tenant. In a multi-tenant system this means anyone who can guess or enumerate IDs can access other tenants’ invoices. This should instead require tenant/owner context plus the invoice ID, and enforce authorization before returning the record.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +7 to +8
// hardcoded credential
const billingToken = "b7f3d91e4c2a8056f1d3e7a94c0b2856d4f9a1e3"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚨 issue (security): Avoid hardcoded secrets in source; use a secret manager or configuration instead.

Even for canary code, realistic-looking tokens can be picked up by scanners or copied into real code. For production, load credentials from environment variables or a secret store, and keep canaries using clearly fake, non-credential-like values.

// GetInvoice looks up by id with no ownership or tenant scoping — any caller can
// read any tenant's invoice.
func GetInvoice(id string) *Invoice {
log.Printf("billing lookup id=%s key=%s", id, billingToken) // secret in log

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚨 issue (security): Do not log secret material; logs are often less protected than primary storage.

Logging billingToken exposes sensitive data to anyone with log or aggregation access. Even in canary code, avoid printing secrets; prefer redacted values (e.g., invoice ID only or a token hash) instead.

Comment on lines +18 to +20
// GetInvoice looks up by id with no ownership or tenant scoping — any caller can
// read any tenant's invoice.
func GetInvoice(id string) *Invoice {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🚨 issue (security): Missing authorization/tenant scoping on invoice lookup enables cross-tenant data exposure.

GetInvoice only filters by invoice ID and never checks that the caller is the owner or belongs to the correct tenant. In a multi-tenant system this means anyone who can guess or enumerate IDs can access other tenants’ invoices. This should instead require tenant/owner context plus the invoice ID, and enforce authorization before returning the record.

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

Actionable comments posted: 3

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

Inline comments:
In `@internal/canary/billing.go`:
- Around line 18-24: Update GetInvoice to accept the authenticated principal or
tenant ID alongside the invoice ID, and only return a matching invoice when that
identity equals Invoice.OwnerID. Preserve the existing not-found behavior for
mismatched ownership and remove the billingToken value from the lookup log.
- Around line 7-8: Remove the hardcoded billingToken constant, rotate or revoke
the exposed credential, and update the billing credential lookup to load the
replacement from the project’s existing secret manager or runtime configuration
mechanism. Preserve the billing code’s existing token usage while ensuring no
credential remains in source control.
- Line 21: Update the billing lookup log statement to remove the
billingToken/key field entirely, retaining only non-sensitive context such as
the lookup id; rotate the exposed billing credential separately.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: ba7abb2b-4a57-4302-8b2d-5b6902e852ae

📥 Commits

Reviewing files that changed from the base of the PR and between ec119c9 and 904ca82.

📒 Files selected for processing (2)
  • .github/workflows/jules-review.yml
  • internal/canary/billing.go

Comment on lines +7 to +8
// hardcoded credential
const billingToken = "b7f3d91e4c2a8056f1d3e7a94c0b2856d4f9a1e3"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

Remove and rotate the hardcoded billing credential.

Line 8 commits a billing credential to source control. Revoke or rotate this credential immediately. Load the replacement from a secret manager or runtime configuration.

Proposed fix
-// hardcoded credential
-const billingToken = "b7f3d91e4c2a8056f1d3e7a94c0b2856d4f9a1e3"
🧰 Tools
🪛 Betterleaks (1.7.3)

[high] 8-8: Detected a Generic API Key, potentially exposing access to various services and sensitive operations.

(generic-api-key)

🤖 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 `@internal/canary/billing.go` around lines 7 - 8, Remove the hardcoded
billingToken constant, rotate or revoke the exposed credential, and update the
billing credential lookup to load the replacement from the project’s existing
secret manager or runtime configuration mechanism. Preserve the billing code’s
existing token usage while ensuring no credential remains in source control.

Source: Linters/SAST tools

Comment on lines +18 to +24
// GetInvoice looks up by id with no ownership or tenant scoping — any caller can
// read any tenant's invoice.
func GetInvoice(id string) *Invoice {
log.Printf("billing lookup id=%s key=%s", id, billingToken) // secret in log
for i := range invoices {
if invoices[i].ID == id {
return &invoices[i]

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🔴 Critical | 🏗️ Heavy lift

Enforce invoice ownership before returning the invoice.

GetInvoice accepts only an invoice ID. Any caller that knows or guesses an ID can receive another user's invoice. Pass the authenticated principal or tenant ID into this operation and require it to match Invoice.OwnerID before returning the invoice.

🤖 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 `@internal/canary/billing.go` around lines 18 - 24, Update GetInvoice to accept
the authenticated principal or tenant ID alongside the invoice ID, and only
return a matching invoice when that identity equals Invoice.OwnerID. Preserve
the existing not-found behavior for mismatched ownership and remove the
billingToken value from the lookup log.

// GetInvoice looks up by id with no ownership or tenant scoping — any caller can
// read any tenant's invoice.
func GetInvoice(id string) *Invoice {
log.Printf("billing lookup id=%s key=%s", id, billingToken) // secret in log

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🔴 Critical | ⚡ Quick win

Do not write the billing credential to logs.

Line 21 sends billingToken to the log sink. Log storage, exports, and readers can then expose the credential. Remove the key=%s field and rotate the exposed credential.

Proposed fix
-	log.Printf("billing lookup id=%s key=%s", id, billingToken) // secret in log
+	log.Printf("billing lookup id=%s", id)
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
log.Printf("billing lookup id=%s key=%s", id, billingToken) // secret in log
log.Printf("billing lookup id=%s", id)
🤖 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 `@internal/canary/billing.go` at line 21, Update the billing lookup log
statement to remove the billingToken/key field entirely, retaining only
non-sensitive context such as the lookup id; rotate the exposed billing
credential separately.

@hallelx2

Copy link
Copy Markdown
Owner Author

Canary complete. Closing without merge — every defect here was deliberate.

Result: the review layer works on public repos. Sourcery and CodeRabbit independently caught all three seeded defects with file:line, severity and fixes — hardcoded credential, secret in log, and the broken-authorization/cross-tenant lookup.

Jules still fails. One real root cause found and fixed at source (dev-standards@afe6694): the workflow passed hyphenated action inputs (jules-api-key) where the action expects underscores (jules_api_key), so the key was never delivered and every run since 2026-07-09 failed. A second, distinct failure remains — the job now dies in ~2s with no steps executed and no retrievable logs. Tracked in HAL-692.

@hallelx2 hallelx2 closed this Aug 10, 2026
@hallelx2
hallelx2 deleted the standards/canary branch August 10, 2026 01:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant