From ebac41b6814ade96571e6dca1c061df848cf1bdb Mon Sep 17 00:00:00 2001 From: Garry Tan Date: Thu, 19 Mar 2026 00:31:43 -0700 Subject: [PATCH] feat: wire Supabase credentials and expose tables via Data API MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add supabase/config.sh with project URL and publishable key (safe to commit — RLS restricts to INSERT only). Update telemetry-sync, community-dashboard, and update-check to source the config and include proper auth headers for the Supabase REST API. Co-Authored-By: Claude Opus 4.6 (1M context) --- bin/gstack-community-dashboard | 5 ++++- bin/gstack-telemetry-sync | 11 +++++++++-- bin/gstack-update-check | 14 +++++++++++--- supabase/config.sh | 10 ++++++++++ test/telemetry.test.ts | 17 +++++++++++++++-- 5 files changed, 49 insertions(+), 8 deletions(-) create mode 100644 supabase/config.sh diff --git a/bin/gstack-community-dashboard b/bin/gstack-community-dashboard index ebe89583..c054e0da 100755 --- a/bin/gstack-community-dashboard +++ b/bin/gstack-community-dashboard @@ -12,7 +12,10 @@ set -uo pipefail GSTACK_DIR="${GSTACK_DIR:-$(cd "$(dirname "$0")/.." && pwd)}" -# Supabase connection — will be populated once project is created +# Source Supabase config if not overridden by env +if [ -z "${GSTACK_SUPABASE_URL:-}" ] && [ -f "$GSTACK_DIR/supabase/config.sh" ]; then + . "$GSTACK_DIR/supabase/config.sh" +fi SUPABASE_URL="${GSTACK_SUPABASE_URL:-}" ANON_KEY="${GSTACK_SUPABASE_ANON_KEY:-}" diff --git a/bin/gstack-telemetry-sync b/bin/gstack-telemetry-sync index 0d94005b..87561d6a 100755 --- a/bin/gstack-telemetry-sync +++ b/bin/gstack-telemetry-sync @@ -18,8 +18,12 @@ CURSOR_FILE="$ANALYTICS_DIR/.last-sync-line" RATE_FILE="$ANALYTICS_DIR/.last-sync-time" CONFIG_CMD="$GSTACK_DIR/bin/gstack-config" -# Default endpoint — will be updated once Supabase project is created +# Source Supabase config if not overridden by env +if [ -z "${GSTACK_TELEMETRY_ENDPOINT:-}" ] && [ -f "$GSTACK_DIR/supabase/config.sh" ]; then + . "$GSTACK_DIR/supabase/config.sh" +fi ENDPOINT="${GSTACK_TELEMETRY_ENDPOINT:-}" +ANON_KEY="${GSTACK_SUPABASE_ANON_KEY:-}" # ─── Pre-checks ────────────────────────────────────────────── # No endpoint configured yet → exit silently @@ -98,8 +102,11 @@ BATCH="$BATCH]" # ─── POST to Supabase ──────────────────────────────────────── RESPONSE="$(curl -sf --max-time 10 \ - -X POST "$ENDPOINT" \ + -X POST "${ENDPOINT}/telemetry_events" \ -H "Content-Type: application/json" \ + -H "apikey: ${ANON_KEY}" \ + -H "Authorization: Bearer ${ANON_KEY}" \ + -H "Prefer: return=minimal" \ -d "$BATCH" 2>/dev/null || true)" # ─── Update cursor on success ──────────────────────────────── diff --git a/bin/gstack-update-check b/bin/gstack-update-check index 0341e202..32cdc2db 100755 --- a/bin/gstack-update-check +++ b/bin/gstack-update-check @@ -143,13 +143,21 @@ mkdir -p "$STATE_DIR" # Fire Supabase install ping in background (parallel, non-blocking) # This logs an update check event for community health metrics. # If the endpoint isn't configured or Supabase is down, this is a no-op. +# Source Supabase config for install ping +if [ -z "${GSTACK_TELEMETRY_ENDPOINT:-}" ] && [ -f "$GSTACK_DIR/supabase/config.sh" ]; then + . "$GSTACK_DIR/supabase/config.sh" +fi _SUPA_ENDPOINT="${GSTACK_TELEMETRY_ENDPOINT:-}" -if [ -n "$_SUPA_ENDPOINT" ]; then +_SUPA_KEY="${GSTACK_SUPABASE_ANON_KEY:-}" +if [ -n "$_SUPA_ENDPOINT" ] && [ -n "$_SUPA_KEY" ]; then _OS="$(uname -s | tr '[:upper:]' '[:lower:]')" curl -sf --max-time 5 \ - -X POST "${_SUPA_ENDPOINT%/telemetry-ingest}/update-check" \ + -X POST "${_SUPA_ENDPOINT}/update_checks" \ -H "Content-Type: application/json" \ - -d "{\"version\":\"$LOCAL\",\"os\":\"$_OS\"}" \ + -H "apikey: ${_SUPA_KEY}" \ + -H "Authorization: Bearer ${_SUPA_KEY}" \ + -H "Prefer: return=minimal" \ + -d "{\"gstack_version\":\"$LOCAL\",\"os\":\"$_OS\"}" \ >/dev/null 2>&1 & fi diff --git a/supabase/config.sh b/supabase/config.sh new file mode 100644 index 00000000..b10aef6b --- /dev/null +++ b/supabase/config.sh @@ -0,0 +1,10 @@ +#!/usr/bin/env bash +# Supabase project config for gstack telemetry +# These are PUBLIC keys — safe to commit (like Firebase public config). +# RLS policies restrict what the anon/publishable key can do (INSERT only). + +GSTACK_SUPABASE_URL="https://frugpmstpnojnhfyimgv.supabase.co" +GSTACK_SUPABASE_ANON_KEY="sb_publishable_tR4i6cyMIrYTE3s6OyHGHw_ppx2p6WK" + +# Telemetry ingest endpoint (Data API) +GSTACK_TELEMETRY_ENDPOINT="${GSTACK_SUPABASE_URL}/rest/v1" diff --git a/test/telemetry.test.ts b/test/telemetry.test.ts index ec516b83..4dc79b29 100644 --- a/test/telemetry.test.ts +++ b/test/telemetry.test.ts @@ -257,9 +257,22 @@ describe('gstack-telemetry-sync', () => { }); describe('gstack-community-dashboard', () => { - test('shows unconfigured message when no Supabase URL', () => { - const output = run(`${BIN}/gstack-community-dashboard`); + test('shows unconfigured message when no Supabase config available', () => { + // Use a fake GSTACK_DIR with no supabase/config.sh + const output = run(`${BIN}/gstack-community-dashboard`, { + GSTACK_DIR: tmpDir, + GSTACK_SUPABASE_URL: '', + GSTACK_SUPABASE_ANON_KEY: '', + }); expect(output).toContain('Supabase not configured'); expect(output).toContain('gstack-analytics'); }); + + test('connects to Supabase when config exists', () => { + // Use the real GSTACK_DIR which has supabase/config.sh + const output = run(`${BIN}/gstack-community-dashboard`); + expect(output).toContain('gstack community dashboard'); + // Should not show "not configured" since config.sh exists + expect(output).not.toContain('Supabase not configured'); + }); });