feat(google-analytics): add allowedPropertyIds to restrict property access#481
feat(google-analytics): add allowedPropertyIds to restrict property access#481igoramf wants to merge 5 commits into
Conversation
…property access Adds a new `allowedPropertyIds` field to the StateSchema that, when configured, restricts all tools to only operate on the listed GA4 properties. get-account-summaries filters out accounts/properties not in the allowlist, and resolveProperty enforces the restriction on every other tool call. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
1 issue found across 3 files
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
…countIds Account-level restriction is simpler to configure (one ID per customer) and automatically includes all properties under the account, including new ones added in the future. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
1 issue found across 3 files (changes from recent commits).
Reply with feedback, questions, or to request a fix.
Re-trigger cubic
resolveProperty is now async and, when allowedAccountIds is configured, fetches the property's parent account from the GA4 Admin API to verify it belongs to an allowed account. All tools updated to await the result. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…filtering The extra getProperty() call in resolveProperty was unnecessary — the LLM only discovers property IDs via get-account-summaries, which already filters by allowedAccountIds. Reverts resolveProperty to a simple sync function. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…yIds Restrict access at the property level instead of account level. - StateSchema: allowedAccountIds → allowedPropertyIds (numeric IDs accepted) - env.ts: getAllowedPropertyIds normalizes "123" → "properties/123"; resolveProperty validates against allowlist synchronously - accounts.ts: filters properties within each account summary, hides accounts with no allowed properties Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
There was a problem hiding this comment.
1 issue found across 3 files (changes from recent commits).
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="google-analytics/server/lib/env.ts">
<violation number="1" location="google-analytics/server/lib/env.ts:14">
P2: `normalizePropertyId` lacks validation for blank or malformed entries, which makes allowlist enforcement brittle and can cause accidental total lockout. The codebase already has a strict `normalizeProperty` function in `ga-client.ts` that validates property IDs and throws on malformed input; `normalizePropertyId` should align with that behavior.
For example, an allowlist entry of `" "` normalizes to `""`, and `"abc"` passes through unchanged. Because any non-empty allowlist array activates enforcement, a misconfigured list with only invalid entries silently denies all valid properties. Defensive validation (e.g., filtering out or rejecting invalid/blank entries during normalization) would prevent this operational failure mode.</violation>
</file>
Tip: Review your code locally with the cubic CLI to iterate faster.
Re-trigger cubic
| }; | ||
|
|
||
| // Normalizes "1234567" → "properties/1234567"; already-prefixed IDs pass through. | ||
| function normalizePropertyId(id: string): string { |
There was a problem hiding this comment.
P2: normalizePropertyId lacks validation for blank or malformed entries, which makes allowlist enforcement brittle and can cause accidental total lockout. The codebase already has a strict normalizeProperty function in ga-client.ts that validates property IDs and throws on malformed input; normalizePropertyId should align with that behavior.
For example, an allowlist entry of " " normalizes to "", and "abc" passes through unchanged. Because any non-empty allowlist array activates enforcement, a misconfigured list with only invalid entries silently denies all valid properties. Defensive validation (e.g., filtering out or rejecting invalid/blank entries during normalization) would prevent this operational failure mode.
Prompt for AI agents
Check if this issue is valid — if so, understand the root cause and fix it. At google-analytics/server/lib/env.ts, line 14:
<comment>`normalizePropertyId` lacks validation for blank or malformed entries, which makes allowlist enforcement brittle and can cause accidental total lockout. The codebase already has a strict `normalizeProperty` function in `ga-client.ts` that validates property IDs and throws on malformed input; `normalizePropertyId` should align with that behavior.
For example, an allowlist entry of `" "` normalizes to `""`, and `"abc"` passes through unchanged. Because any non-empty allowlist array activates enforcement, a misconfigured list with only invalid entries silently denies all valid properties. Defensive validation (e.g., filtering out or rejecting invalid/blank entries during normalization) would prevent this operational failure mode.</comment>
<file context>
@@ -10,20 +10,20 @@ export const getGoogleAccessToken = (env: Env): string => {
-// Normalizes "1234567" → "accounts/1234567"; already-prefixed IDs pass through.
-function normalizeAccountId(id: string): string {
+// Normalizes "1234567" → "properties/1234567"; already-prefixed IDs pass through.
+function normalizePropertyId(id: string): string {
const clean = String(id).trim();
- return /^\d+$/.test(clean) ? `accounts/${clean}` : clean;
</file context>
Summary
allowedPropertyIdsfield to the Google Analytics MCPStateSchemaget-account-summariesfilters accounts/properties not in the allowlistresolvePropertyenforces the restriction on every other tool call (run-report,run-funnel-report,run-realtime-report,get-property-details, etc.)allowedPropertyIdsempty preserves current behavior (all properties accessible)How it works
Configure
allowedPropertyIdsin the Mesh UI for a GA installation:Any tool call targeting a property outside this list will return an error.
get-account-summarieswill only show accounts that have at least one allowed property.Test plan
allowedPropertyIds— all accounts visible, all properties accessible (no regression)allowedPropertyIds: ["properties/258313733"]—get-account-summariesreturns only FARM GA4 accountrun-reportwith an unlisted property — receives errorProperty "..." is not allowedrun-reportwith an allowed property — works normally🤖 Generated with Claude Code
Summary by cubic
Add an optional GA4 property allowlist to the Google Analytics integration. When
allowedPropertyIdsis set, tools only discover and operate on those properties; leaving it empty keeps current behavior.New Features
allowedPropertyIdstoStateSchema; accepts1234567orproperties/1234567and normalizes IDs.get-account-summariesshows only allowed properties and hides accounts without any.resolvePropertynormalizes IDs and rejects any property not in the allowlist (sync).Migration
allowedPropertyIdsin the Mesh UI, e.g. ["properties/258313733", "123456"].Written for commit a44901c. Summary will update on new commits.