From b3431571dbbac4f18cff83e8fd4c3dfc3e5f6dc3 Mon Sep 17 00:00:00 2001 From: Sparky <1609870+sparkyfen@users.noreply.github.com> Date: Wed, 19 Aug 2026 13:23:31 -0700 Subject: [PATCH] fix(i18n): arrow notation for the analytics token scope (SONA-200) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Connect Cloudflare Analytics dialog named its one permission as 'Zone · Analytics · Read' while the setup CLIs now write every scope in the dashboard's own arrow form. The scope chip and the callout in both locales now read 'Zone → Analytics: Read' (the label itself stays in dashboard English inside the Japanese copy), and the scope-contract test pins the new form. Mock approved in the design project (screens/admin/connect-cloudflare.html). --- messages/en.json | 4 ++-- messages/ja.json | 4 ++-- src/app.d.ts | 2 +- src/lib/server/cf-analytics-scope.test.ts | 8 ++++---- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/messages/en.json b/messages/en.json index 5d88abc4..26118634 100644 --- a/messages/en.json +++ b/messages/en.json @@ -1160,7 +1160,7 @@ "admin_cf_setup_lede": "Your in-app counters miss anything Cloudflare serves from cache. Connect a read-only token and this page gains an edge-traffic panel: cached hits, bandwidth, threats blocked. It's optional, and it never reads any account but yours.", "admin_cf_setup_s1_title": "Create a scoped, read-only token", "admin_cf_setup_s1_text": "In the Cloudflare dashboard, open My Profile, then API Tokens, Create Token, Custom token. Add exactly one permission. Nothing can write:", - "admin_cf_setup_s1_scope": "Zone · Analytics · Read", + "admin_cf_setup_s1_scope": "Zone → Analytics: Read", "admin_cf_setup_s1_zone": "Then set Zone Resources to include your custom domain's zone, or the query returns nothing.", "admin_cf_setup_s2_title": "Store the token, account id and zone id as secrets", "admin_cf_setup_s2_ci": "Fastest path — store all three as GitHub repository secrets. From the fork's directory (so gh reads the repo from your origin remote), run:", @@ -1169,7 +1169,7 @@ "admin_cf_setup_s3_title": "Redeploy to load the secrets", "admin_cf_setup_s3_text": "Cloudflare Pages binds secrets at deploy time. The GitHub Actions path redeploys for you; if you set the secrets by hand, redeploy now. The edge panel then appears next to your in-app metrics — it reads zone analytics, so your custom domain must be connected (a bare pages.dev URL has no zone data).", "admin_cf_setup_callout_strong": "Read-only, and only your account.", - "admin_cf_setup_callout": " Give the token Zone Analytics Read and nothing else, so a leaked token can't change anything. It only ever reads your own zone's numbers, so it never becomes the boundary between two forks.", + "admin_cf_setup_callout": " Give the token Zone → Analytics: Read and nothing else, so a leaked token can't change anything. It only ever reads your own zone's numbers, so it never becomes the boundary between two forks.", "admin_cf_setup_unlocks_label": "Unlocks:", "admin_cf_setup_unlocks": " a Cloudflare edge panel: cached versus origin requests, total bandwidth, threats blocked. Disconnect anytime by deleting the secret; nothing else on this page depends on it.", "admin_settings_supporter_early_eyebrow": "early access", diff --git a/messages/ja.json b/messages/ja.json index 8546affc..3acc284e 100644 --- a/messages/ja.json +++ b/messages/ja.json @@ -1124,7 +1124,7 @@ "admin_cf_setup_lede": "アプリ内カウンターは、Cloudflareがキャッシュから配信したものを計測できません。読み取り専用のトークンを接続すると、このページにエッジトラフィックのパネル(キャッシュヒット、帯域、ブロックした脅威)が追加されます。任意であり、あなた以外のアカウントを読み取ることはありません。", "admin_cf_setup_s1_title": "範囲を限定した読み取り専用トークンを作成する", "admin_cf_setup_s1_text": "Cloudflareダッシュボードで、マイプロフィール → APIトークン → トークンを作成 → カスタムトークン を開きます。権限をちょうど1つだけ追加します。書き込みは一切できません:", - "admin_cf_setup_s1_scope": "Zone · Analytics · Read", + "admin_cf_setup_s1_scope": "Zone → Analytics: Read", "admin_cf_setup_s1_zone": "次に、ゾーンリソースにカスタムドメインのゾーンを含めてください。含めないとクエリは何も返しません。", "admin_cf_setup_s2_title": "トークン・アカウントID・ゾーンIDをシークレットとして保存する", "admin_cf_setup_s2_ci": "最も簡単な方法 — 3つすべてをGitHubのリポジトリシークレットとして保存します。フォークのディレクトリで(ghがoriginリモートからリポジトリを判別します)、次を実行してください:", @@ -1133,7 +1133,7 @@ "admin_cf_setup_s3_title": "再デプロイしてシークレットを読み込む", "admin_cf_setup_s3_text": "Cloudflare Pagesはデプロイ時にシークレットを読み込みます。GitHub Actions経由なら自動的に再デプロイされます。手動で設定した場合は、ここで再デプロイしてください。その後、Cloudflareエッジパネルがアプリ内メトリクスの隣に表示されます。ゾーン分析を読み取るため、カスタムドメインの接続が必要です(素のpages.dev URLにはゾーンデータがありません)。", "admin_cf_setup_callout_strong": "読み取り専用で、あなたのアカウントのみ。", - "admin_cf_setup_callout": " トークンにはZone Analytics Readだけを与え、それ以外は与えないでください。万一漏れても何も変更できません。読み取るのは常に自分のゾーンの数値だけなので、2つのフォークの境界になることはありません。", + "admin_cf_setup_callout": " トークンにはZone → Analytics: Readだけを与え、それ以外は与えないでください。万一漏れても何も変更できません。読み取るのは常に自分のゾーンの数値だけなので、2つのフォークの境界になることはありません。", "admin_cf_setup_unlocks_label": "追加される機能:", "admin_cf_setup_unlocks": " Cloudflareエッジパネル(キャッシュとオリジンのリクエスト、総帯域、ブロックした脅威)。シークレットを削除すればいつでも接続を解除できます。このページの他の機能はこれに依存しません。", "admin_settings_supporter_early_eyebrow": "早期アクセス", diff --git a/src/app.d.ts b/src/app.d.ts index 9c9ccb0e..f83ec198 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -114,7 +114,7 @@ declare global { * Optional Cloudflare edge-analytics enrichment (issue #6, Observability). * All three must be present for the "Cloudflare edge" panel to appear; * absence just hides it. The token needs exactly one scope — - * Zone · Analytics · Read, with Zone Resources scoped to your zone. The + * Zone → Analytics: Read, with Zone Resources scoped to your zone. The * query below is zone-scoped (viewer.zones), so Account Analytics · Read * authenticates but is refused with a `zone.analytics.read` authz error. Set * via `wrangler pages secret put CLOUDFLARE_ANALYTICS_TOKEN` (+ CLOUDFLARE_ACCOUNT_ID, diff --git a/src/lib/server/cf-analytics-scope.test.ts b/src/lib/server/cf-analytics-scope.test.ts index b2ca0433..8c302b5d 100644 --- a/src/lib/server/cf-analytics-scope.test.ts +++ b/src/lib/server/cf-analytics-scope.test.ts @@ -5,7 +5,7 @@ import { fileURLToPath } from 'node:url'; // Guards the bug class where the setup instructions name a Cloudflare permission // that cannot run the query we actually send. getCloudflareEdge() queries // `viewer { zones { httpRequests1dGroups } }` — a ZONE-scoped dataset, which needs -// `Zone · Analytics · Read`. The modal used to say `Account · Account Analytics · +// `Zone → Analytics: Read`. The modal used to say `Account · Account Analytics · // Read`; that token authenticates fine and is then refused: // // Actor '…' does not have permission 'com.cloudflare.api.account.zone.analytics.read' @@ -30,7 +30,7 @@ const settingsPage = read('../../routes/admin/settings/+page.svelte'); const deployWorkflow = read('../../../.github/workflows/deploy.yml'); describe('Cloudflare edge analytics — documented scope matches the query', () => { - it('the query is zone-scoped, which is what makes Zone · Analytics · Read the right permission', () => { + it('the query is zone-scoped, which is what makes Zone → Analytics: Read the right permission', () => { expect(source).toMatch(/viewer\s*\{\s*zones\(/); expect(source).toContain('httpRequests1dGroups'); }); @@ -39,8 +39,8 @@ describe('Cloudflare edge analytics — documented scope matches the query', () ['en', en], ['ja', ja] ])('%s setup copy names the zone permission, never the account one', (_locale, messages) => { - expect(messages.admin_cf_setup_s1_scope).toBe('Zone · Analytics · Read'); - expect(messages.admin_cf_setup_callout).toContain('Zone Analytics Read'); + expect(messages.admin_cf_setup_s1_scope).toBe('Zone → Analytics: Read'); + expect(messages.admin_cf_setup_callout).toContain('Zone → Analytics: Read'); // The account-scoped permission cannot satisfy a zone-scoped query. If this // string reappears anywhere in the setup flow, the instructions are wrong.