feat: telemetry data integrity — source tagging, UUID fingerprint, duration guards

- Add source field (live/test/dev) to telemetry pipeline: --source flag in
  gstack-telemetry-log, GSTACK_TELEMETRY_SOURCE env fallback, pass-through
  in telemetry-sync, source=eq.live filter on all dashboard queries
- Replace SHA-256 installation_id with UUID install_fingerprint for all tiers
  (not just community). Expand-contract migration: ADD new column + trigger
  to copy installation_id, preserving backward compat with old clients
- Fix duration bug: persist _TEL_START to file via $PPID (stable across bash
  blocks), cap durations at 86400s, reject negative values
- Ungate update-check pings from telemetry=off — sends only version + OS +
  random UUID. Generate .install-id in update-check for telemetry=off users
- Migration 003: source columns, install_fingerprint, duration CHECK
  constraint, indexes, recreated views with source filter, growth funnel
  (first-seen based), materialized views for daily installs + version adoption
- E2E test isolation: session-runner sets GSTACK_TELEMETRY_SOURCE=test
- 8 new telemetry tests (source field, duration caps, fingerprint persistence)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
Garry Tan
2026-03-23 15:48:25 -07:00
parent b437b531b7
commit 6bd6d5ba0f
8 changed files with 269 additions and 50 deletions
+19 -4
View File
@@ -167,9 +167,24 @@ if [ -z "${GSTACK_TELEMETRY_ENDPOINT:-}" ] && [ -f "$GSTACK_DIR/supabase/config.
fi
_SUPA_ENDPOINT="${GSTACK_TELEMETRY_ENDPOINT:-}"
_SUPA_KEY="${GSTACK_SUPABASE_ANON_KEY:-}"
# Respect telemetry opt-out — don't ping Supabase if user set telemetry: off
_TEL_TIER="$("$GSTACK_DIR/bin/gstack-config" get telemetry 2>/dev/null || true)"
if [ -n "$_SUPA_ENDPOINT" ] && [ -n "$_SUPA_KEY" ] && [ "${_TEL_TIER:-off}" != "off" ]; then
# Generate/read install fingerprint (runs for ALL tiers including off)
_FP=""
_FP_FILE="$STATE_DIR/.install-id"
if [ -f "$_FP_FILE" ]; then
_FP="$(cat "$_FP_FILE" 2>/dev/null | tr -d '[:space:]')"
fi
if [ -z "$_FP" ]; then
_FP="$(uuidgen 2>/dev/null || cat /proc/sys/kernel/random/uuid 2>/dev/null || python3 -c 'import uuid; print(uuid.uuid4())' 2>/dev/null || echo "")"
_FP="$(echo "$_FP" | tr '[:upper:]' '[:lower:]')"
if [ -n "$_FP" ]; then
mkdir -p "$STATE_DIR"
echo "$_FP" > "$_FP_FILE"
fi
fi
# Update-check pings always fire (ungated from telemetry tier).
# This sends only: version, OS, and a random UUID. No usage data.
# Equivalent to what GitHub sees in HTTP access logs for VERSION.
if [ -n "$_SUPA_ENDPOINT" ] && [ -n "$_SUPA_KEY" ]; then
_OS="$(uname -s | tr '[:upper:]' '[:lower:]')"
curl -sf --max-time 5 \
-X POST "${_SUPA_ENDPOINT}/update_checks" \
@@ -177,7 +192,7 @@ if [ -n "$_SUPA_ENDPOINT" ] && [ -n "$_SUPA_KEY" ] && [ "${_TEL_TIER:-off}" != "
-H "apikey: ${_SUPA_KEY}" \
-H "Authorization: Bearer ${_SUPA_KEY}" \
-H "Prefer: return=minimal" \
-d "{\"gstack_version\":\"$LOCAL\",\"os\":\"$_OS\"}" \
-d "{\"gstack_version\":\"$LOCAL\",\"os\":\"$_OS\",\"install_fingerprint\":\"${_FP}\"}" \
>/dev/null 2>&1 &
fi