Skip to content

fix: BigQuery finops UX — surface bq_region, actionable errors, warehouse_add warning#756

Open
anandgupta42 wants to merge 1 commit intomainfrom
fix/bq-finops-region-visibility
Open

fix: BigQuery finops UX — surface bq_region, actionable errors, warehouse_add warning#756
anandgupta42 wants to merge 1 commit intomainfrom
fix/bq-finops-region-visibility

Conversation

@anandgupta42
Copy link
Copy Markdown
Contributor

@anandgupta42 anandgupta42 commented Apr 25, 2026

What does this PR do?

Surfaces bq_region in every BigQuery finops tool response, adds two helpers in bq-utils.ts (augmentBqError for region-related errors, isBqPermissionError for the TABLE_STORAGE 403 pattern), and warns in warehouse_add when a BigQuery connection is registered without a location field (or with a whitespace-only value). Builds on the v0.6.1 multi-region work in #739; addresses the four UX/visibility items naturally clustered out of the seven follow-ups in #754.

Type of change

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

Issue for this PR

Closes #755 (focused sub-issue split out of the broader #754 follow-up tracker — three behavioural items remain in #754).

How did you verify your code works?

  • 30 unit + integration tests in the new packages/opencode/test/altimate/finops-bq-visibility.test.ts covering: augmentBqError positive/negative paths (canonical INFORMATION_SCHEMA refs, Not found: Dataset region-..., region-based routing, multi-region-aware, bare region-, idempotency, non-string inputs), isBqPermissionError positive/negative paths (Permission denied, accessDenied, bigquery.resourceAdmin, IAM permission, canonical 403, numeric-prefix 4031/40322/port-4030 false-positives), warehouse_add warning across BigQuery / Snowflake / explicit-location / empty-string / whitespace-only / null cases, and getQueryHistory end-to-end bq_region surfacing on success and error paths.
  • Full altimate + skill test suite: 3236 pass / 491 skipped (env-gated) / 0 fail.
  • Marker guard (strict): clean — no upstream-shared files touched.
  • Typecheck (bun turbo typecheck): 5/5 packages green.
  • Multi-model code review via /consensus:code-review with 8 external models (GPT 5.4, Gemini 3.1 Pro, Kimi K2.5, MiniMax M2.7, GLM-5, Qwen 3.6 Plus, DeepSeek V3.2, MiMo-V2-Pro) plus Claude. 7/8 converged round 1; convergence corrected three accuracy issues from the initial draft (retracted accessdenied redundancy claim, fixed dead-code citation, dropped unverified-alias claims) — see commit body for details.

Checklist

  • My code follows the style guidelines of this project
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

🤖 Generated with Claude Code


Summary by cubic

Shows the BigQuery region in all finops responses and makes region/permission errors actionable. Also warns on warehouse_add when a BigQuery connection has no location to avoid silent US fallback.

  • New Features
    • Adds bq_region (sanitized) to all BigQuery finops results on success and error paths (query-history, credit-analyzer, expensive-queries, warehouse-advisor, unused-resources, role-access).
    • Introduces augmentBqError to append a clear region hint to region-related BigQuery errors, and isBqPermissionError to detect INFORMATION_SCHEMA.TABLE_STORAGE 403s with guidance on bigquery.resourceAdmin.
    • Updates warehouse_add to warn when adding a BigQuery connection without a location (including whitespace-only).

Written for commit 1ca5618. Summary will update on new commits.

Summary by CodeRabbit

  • New Features

    • BigQuery operations now track and display the region used for queries in results.
    • Enhanced error messages for region-related issues with actionable guidance.
    • Added permission error detection for BigQuery operations.
  • Bug Fixes

    • Improved error handling and messaging for BigQuery-related failures.
  • Documentation

    • Added warning when configuring BigQuery connections without an explicit region setting.
  • Tests

    • Added comprehensive test coverage for BigQuery error handling and region tracking.

…ouse_add warning

Partial resolution of #754, focused on the four BigQuery UX/visibility items
that naturally cluster. Three behavioural deferrals (#5 throw-on-invalid,
#6 options-object refactor, #7 e2e silent-skip) remain open in #754.

## Changes

1. `bq_region` surfaced in every BigQuery finops tool response.
   `QueryHistoryResult`, `CreditAnalysisResult`, `ExpensiveQueriesResult`,
   `WarehouseAdvisorResult`, `UnusedResourcesResult`, and `RoleGrantsResult`
   gain an optional `bq_region?: string` field. All five finops modules
   compute `sanitisedBqRegion = sanitizeBqRegion(bqRegion)` once at entry
   and thread it through success and error returns. Non-BigQuery warehouses
   omit the field. Lets the agent (and humans inspecting tool output) see
   which region was actually queried after the silent `us` fallback shipped
   in v0.6.1 (#739).

2. `augmentBqError(error, region)` helper in `bq-utils.ts`.
   Appends a region hint to BigQuery errors that look region-related,
   anchored to `region-<x>.INFORMATION_SCHEMA` references and "Not found"
   lines so unrelated text (`region-based routing`, `multi-region-aware`)
   does not trigger. Idempotent — safe under nested catch wrapping.
   Wired into all five finops `catch` blocks.

3. `isBqPermissionError(error)` helper in `bq-utils.ts`.
   Detects the `INFORMATION_SCHEMA.TABLE_STORAGE` 403 pattern that
   `finops_unused_resources` hits routinely on project-scoped service
   accounts. Word-boundary `\b403\b` check so `4031`, `40322`, `port 4030`
   do not false-positive. `unused-resources.ts` produces an actionable
   message naming `bigquery.resourceAdmin` (org-level requirement) when
   this fires.

4. `warehouse_add` non-fatal warning when a BigQuery connection is
   registered without a `location` field. Catches whitespace-only values
   too — `sanitizeBqRegion` trims at query time and falls back to "us",
   so `location: "  "` would otherwise pass a truthy-only guard but
   silently query the wrong region.

## Review notes

Reviewed via `/consensus:code-review` with eight external models
(GPT 5.4, Gemini 3.1 Pro, Kimi K2.5, MiniMax M2.7, GLM-5, Qwen 3.6 Plus,
DeepSeek V3.2, MiMo-V2-Pro) plus Claude. 7 of 8 converged in round 1;
Qwen's CLI did not return in time. Convergence corrected three accuracy
issues from the initial draft:

- Original draft claimed `includes("accessdenied")` was redundant after
  `.toLowerCase()`. MiniMax retracted this on second look — Google's
  BigQuery SDKs emit `AccessDenied` (camelCase), which lowercases to
  `accessdenied` (no space) and would not be caught by the
  `access denied` substring check. Both checks are kept.
- Original draft attributed dead `?? "us"` to two locations. Verified by
  grep — only `unused-resources.ts:212` had it. Single fix applied.
- Original draft listed several BigQuery `location` aliases
  (`Location`, `projectLocation`, `locationId`) as "auto-normalized" but
  `BIGQUERY_ALIASES` in `packages/drivers/src/normalize.ts` does not
  include any `location` alias. The check on `args.config.location` is
  correct for current aliases. The remaining real concern (whitespace
  trim) was downgraded and addressed.

## Tests

8 new tests in `finops-bq-visibility.test.ts` for the convergence-driven
guards: `region-based routing`, `multi-region-aware`, bare `region-`,
canonical INFORMATION_SCHEMA shapes, numeric-prefix `403` negative cases,
canonical 403 surfaces, whitespace-only and null `location` warnings.
30/30 in this file pass; full altimate + skill suite 3236/3236.

Verified:
- `bun turbo typecheck`: 5/5 green
- `bun run script/upstream/analyze.ts --markers --base main --strict`: clean
- 3236 pass / 491 skipped (env-gated) / 0 fail across altimate + skill

Closes #755

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

Claude Code Review

This repository is configured for manual code reviews. Comment @claude review to trigger a review and subscribe this PR to future pushes, or @claude review once for a one-time review.

Tip: disable this comment in your organization's Code Review settings.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 25, 2026

📝 Walkthrough

Walkthrough

This PR adds BigQuery-specific error diagnostics and region visibility across finops tools. It introduces two utility functions for analyzing region-related errors and detecting permission failures, propagates the queried bq_region to all finops API responses, adds a user warning for missing connection locations, and includes comprehensive test coverage.

Changes

Cohort / File(s) Summary
BigQuery Utility Functions
packages/opencode/src/altimate/native/finops/bq-utils.ts
Adds augmentBqError() to append region hints to region-related BigQuery errors (INFORMATION_SCHEMA/dataset-not-found patterns) and isBqPermissionError() to detect permission/403 failures with word-boundary checks.
FinOps Modules
packages/opencode/src/altimate/native/finops/credit-analyzer.ts, query-history.ts, role-access.ts, unused-resources.ts, warehouse-advisor.ts
Sanitize BigQuery regions, propagate bq_region to success/failure response payloads, and use augmentBqError() for improved error messages. Unused-resources also detects permission errors via isBqPermissionError().
Type Definitions
packages/opencode/src/altimate/native/types.ts
Adds optional bq_region?: string field to six FinOps result interfaces (QueryHistoryResult, CreditAnalysisResult, ExpensiveQueriesResult, WarehouseAdvisorResult, UnusedResourcesResult, RoleGrantsResult).
Warehouse Configuration
packages/opencode/src/altimate/tools/warehouse-add.ts
Appends a non-fatal warning when BigQuery connection is added without a location field, instructing users to re-add with explicit region.
Test Coverage
packages/opencode/test/altimate/finops-bq-visibility.test.ts
Comprehensive test suite validating augmentBqError() idempotency and region-error detection, isBqPermissionError() pattern matching with word-boundary logic, warehouse-add warning behavior, and bq_region propagation across finops success/failure paths.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related issues

Possibly related PRs

Suggested labels

contributor, needs-review:blocked

Poem

🐰 A rabbit's whisper through the logs,

Region hints now glow through fog,

Where TABLE_STORAGE once denied,

Now resourceAdmin stands with pride!

Errors dance with cleaner words,

FinOps sings like never heard! ✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The PR description is comprehensive and well-structured, but does not include the required 'PINEAPPLE' marker at the top as mandated by the template for AI-generated contributions. Add 'PINEAPPLE' at the very top of the PR description before any other content, as required by the template for AI-generated contributions.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly and specifically describes the main change: surfacing bq_region, adding actionable errors, and including a warehouse_add warning for BigQuery finops UX improvements.
Linked Issues check ✅ Passed All four objectives from #755 are met: bq_region is surfaced across all finops tools, augmentBqError and isBqPermissionError are implemented with proper idempotency and pattern matching, and warehouse_add warns on missing location.
Out of Scope Changes check ✅ Passed All changes are scoped to the four objectives from #755; no extraneous modifications appear outside the defined scope regarding bq_region surfacing, error helpers, or warehouse_add warning.
Docstring Coverage ✅ Passed Docstring coverage is 80.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 docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/bq-finops-region-visibility

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.

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.

🧹 Nitpick comments (2)
packages/opencode/src/altimate/native/finops/unused-resources.ts (1)

196-213: Minor: drop the non-null assertion on sanitisedBqRegion.

Inside the whType === "bigquery" branch, sanitisedBqRegion is guaranteed to be a string by construction (line 155). Rather than relying on a ! assertion, narrow it locally so the type system enforces the invariant:

♻️ Suggested narrowing
     } else if (whType === "bigquery") {
+      const region = sanitisedBqRegion ?? "us"
       try {
         const sql = interpolateBqRegion(BIGQUERY_UNUSED_TABLES_SQL, bqRegion)
         const result = await connector.execute(sql, limit, [days, limit])
         unusedTables = rowsToRecords(result)
       } catch (e) {
         // TABLE_STORAGE is an org-level view. Most project-scoped service
         // accounts lack bigquery.resourceAdmin at the org and hit 403 here —
         // point them at the specific permission rather than a raw SQL error.
         if (isBqPermissionError(e)) {
           errors.push(
             `Could not query unused tables: BigQuery returned a permission error for INFORMATION_SCHEMA.TABLE_STORAGE. ` +
               `This view is org-level and requires bigquery.resourceAdmin (or equivalent) at the organisation. ` +
               `Project-scoped service accounts typically can't read it. Raw error: ${e}`,
           )
         } else {
-          errors.push(`Could not query unused tables: ${augmentBqError(e, sanitisedBqRegion!)}`)
+          errors.push(`Could not query unused tables: ${augmentBqError(e, region)}`)
         }
       }
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/opencode/src/altimate/native/finops/unused-resources.ts` around
lines 196 - 213, Remove the non-null assertion on sanitisedBqRegion in the
bigquery error branch: since sanitisedBqRegion is already guaranteed to be a
string earlier, narrow it locally (e.g., const region = sanitisedBqRegion)
inside the whType === "bigquery" branch and pass that region variable to
augmentBqError(e, region) instead of augmentBqError(e, sanitisedBqRegion!);
update the error push that uses augmentBqError accordingly so no "!" is needed.
packages/opencode/test/altimate/finops-bq-visibility.test.ts (1)

1-419: LGTM — well-scoped coverage of the four UX/visibility items.

The test file does a careful job exercising each item from #755:

  • augmentBqError: regex tightening tests (lines 81–107) explicitly lock in the post-convergence anchoring (region-<x>.INFORMATION_SCHEMA and Not found: shapes only) and idempotency (lines 56–63) — these will catch any future regression where the regex relaxes to plain region-<word>.
  • isBqPermissionError: the \b403\b word-boundary tests (lines 170–185) and the documented String(403) → "403" coercion (lines 191–194) clearly capture the contract.
  • warehouse_add: positive/negative coverage for empty, whitespace, null, present, and non-BQ types (lines 239–352); useful that the whitespace case is asserted explicitly with the convergence rationale inline.
  • getQueryHistory: the success/error/sanitisation/non-BQ/unknown-warehouse matrix (lines 370–418) pins down the response invariant cleanly, and Registry.reset() in both beforeEach/afterEach keeps the suite isolated.

A few small, optional observations (none blocking):

  • Lines 229–232: mock.restore() already restores every active spyOn, so dispatcherSpy?.mockRestore() in the same afterEach is redundant. Harmless, but you could drop the explicit call (and the module-level let dispatcherSpy) and just rely on mock.restore().
  • Lines 220–237: ALTIMATE_TELEMETRY_DISABLED is only deleted in afterAll for this describe. Per-test cleanup (mirroring the getQueryHistory block at lines 365–368) would make the suite slightly more hermetic if a test in this block ever throws before reaching afterAll.
  • Line 399: expect(result.bq_region).toBe("usdroptablex") is a very tight coupling to the current sanitiser implementation (lower-case + strip non-[a-z0-9]). If you ever switch the sanitiser to keep hyphens or use a different replacement char, this test will break for reasons unrelated to the security property under test. The two not.toContain assertions on the next lines already capture the security invariant; consider keeping those as the primary contract and treating the exact-match as documentation only.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/opencode/test/altimate/finops-bq-visibility.test.ts` around lines 1
- 419, Remove the redundant module-level dispatcherSpy and its explicit
dispatcherSpy?.mockRestore() calls in the warehouse_add suite and rely solely on
mock.restore(); in practice delete the let dispatcherSpy declaration and any
spyRestore lines (references: dispatcherSpy, mock.restore()). Ensure
ALTIMATE_TELEMETRY_DISABLED is cleaned up per-test by moving the env deletion
into the warehouse_add afterEach (references:
process.env.ALTIMATE_TELEMETRY_DISABLED, beforeEach/afterEach in the
"warehouse_add" describe). Relax the brittle exact-match assertion in the
getQueryHistory sanitisation test (reference:
expect(result.bq_region).toBe("usdroptablex")) so it only asserts the security
contract (e.g., no backticks/semicolons and normalized alphanumeric output)
rather than a specific sanitized string.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/opencode/src/altimate/native/finops/unused-resources.ts`:
- Around line 196-213: Remove the non-null assertion on sanitisedBqRegion in the
bigquery error branch: since sanitisedBqRegion is already guaranteed to be a
string earlier, narrow it locally (e.g., const region = sanitisedBqRegion)
inside the whType === "bigquery" branch and pass that region variable to
augmentBqError(e, region) instead of augmentBqError(e, sanitisedBqRegion!);
update the error push that uses augmentBqError accordingly so no "!" is needed.

In `@packages/opencode/test/altimate/finops-bq-visibility.test.ts`:
- Around line 1-419: Remove the redundant module-level dispatcherSpy and its
explicit dispatcherSpy?.mockRestore() calls in the warehouse_add suite and rely
solely on mock.restore(); in practice delete the let dispatcherSpy declaration
and any spyRestore lines (references: dispatcherSpy, mock.restore()). Ensure
ALTIMATE_TELEMETRY_DISABLED is cleaned up per-test by moving the env deletion
into the warehouse_add afterEach (references:
process.env.ALTIMATE_TELEMETRY_DISABLED, beforeEach/afterEach in the
"warehouse_add" describe). Relax the brittle exact-match assertion in the
getQueryHistory sanitisation test (reference:
expect(result.bq_region).toBe("usdroptablex")) so it only asserts the security
contract (e.g., no backticks/semicolons and normalized alphanumeric output)
rather than a specific sanitized string.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 7ceccd2e-be94-4ccf-9950-9bc1d527fb86

📥 Commits

Reviewing files that changed from the base of the PR and between 941c8ca and 1ca5618.

📒 Files selected for processing (9)
  • packages/opencode/src/altimate/native/finops/bq-utils.ts
  • packages/opencode/src/altimate/native/finops/credit-analyzer.ts
  • packages/opencode/src/altimate/native/finops/query-history.ts
  • packages/opencode/src/altimate/native/finops/role-access.ts
  • packages/opencode/src/altimate/native/finops/unused-resources.ts
  • packages/opencode/src/altimate/native/finops/warehouse-advisor.ts
  • packages/opencode/src/altimate/native/types.ts
  • packages/opencode/src/altimate/tools/warehouse-add.ts
  • packages/opencode/test/altimate/finops-bq-visibility.test.ts

Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot left a comment

Choose a reason for hiding this comment

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

1 issue found across 9 files

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="packages/opencode/src/altimate/native/finops/bq-utils.ts">

<violation number="1" location="packages/opencode/src/altimate/native/finops/bq-utils.ts:111">
P2: `isBqPermissionError` is too broad: matching any `403` can misclassify non-permission BigQuery errors as permission issues.</violation>
</file>

Reply with feedback, questions, or to request a fix. Tag @cubic-dev-ai to re-run a review.

msg.includes("accessdenied") ||
msg.includes("bigquery.resourceadmin") ||
msg.includes("iam permission") ||
/\b403\b/.test(msg)
Copy link
Copy Markdown

@cubic-dev-ai cubic-dev-ai Bot Apr 25, 2026

Choose a reason for hiding this comment

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

P2: isBqPermissionError is too broad: matching any 403 can misclassify non-permission BigQuery errors as permission issues.

Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At packages/opencode/src/altimate/native/finops/bq-utils.ts, line 111:

<comment>`isBqPermissionError` is too broad: matching any `403` can misclassify non-permission BigQuery errors as permission issues.</comment>

<file context>
@@ -55,3 +55,59 @@ export function interpolateBqRegion(sqlTemplate: string, bqRegion?: unknown): st
+    msg.includes("accessdenied") ||
+    msg.includes("bigquery.resourceadmin") ||
+    msg.includes("iam permission") ||
+    /\b403\b/.test(msg)
+  )
+}
</file context>
Fix with Cubic

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.

BigQuery finops: surface bq_region + actionable error messages + warehouse_add warning

1 participant