Add BigQuery backend connection testing - #3874
Conversation
| @spec create_connection_test_table(Backend.t(), String.t(), String.t()) :: | ||
| {:ok, connection_test_table_status()} | {:error, connection_test_error()} | ||
| defp create_connection_test_table(backend, project_id, dataset_id) do | ||
| case Google.BigQuery.create_table( |
There was a problem hiding this comment.
🟡 Severity: MEDIUM
project_id and dataset_id are user-controlled backend fields, but this call uses Logflare’s shared ingest credential to create _logflare_connection_test in that GCP dataset, even without an attached source. A tenant can target another customer’s project where the shared account is authorized, causing cross-tenant table creation and probe writes.
Helpful? Add 👍 / 👎
💡 Fix Suggestion
Suggestion: Add a project/dataset ownership check at the beginning of test_connection/1 (around line 189) to verify that the user-controlled project_id and dataset_id actually belong to the requesting tenant before invoking any GCP API calls with Logflare's shared ingest credentials.
Specifically:
- In
test_connection/1, extractuser_idfrom the%Backend{}struct pattern match. - Fetch the user via
Users.Cache.get(user_id)and add awithclause guard that comparesproject_id(frombackend.config) against the user'sbigquery_project_id(from theUserstruct) and also checksdataset_idagainstuser.bigquery_dataset_id. If the values do not match, return{:error, :invalid_config}(or a dedicated:unauthorizederror atom) before any GCP call is made. - For tenants using Logflare's own shared project (where
user.bigquery_project_idis nil), also guard that the providedproject_idequalsGCPConfig.default_project_id()and thedataset_idmatches the expected user-scoped dataset.
This ensures that the shared ingest credential is never used to probe a GCP project/dataset that the requesting tenant does not own.
Implements O11Y-1947 with a REST-based BigQuery connection test that deterministically selects an attached source—preferring a direct attachment and falling back to a rule source—and inserts one labeled probe event into its existing table.
The probe requires a same-owner source association, performs no dataset or table DDL, and returns source_required before making a BigQuery request when none exists.
REST responses are normalized to atom-only sanitized errors, and the LiveView explains how to satisfy the source prerequisite.
It intentionally does not wait for Storage Write gRPC support.
Tests: the BigQuery adaptor file passes with 35 tests and one property, the backend component file passes with 5 tests, and Dialyzer, formatting, diff checks, and targeted strict Credo pass.