From e633cfa43dfb1d53e4f62521de35cc0e1db61623 Mon Sep 17 00:00:00 2001 From: enyst Date: Wed, 20 May 2026 19:53:09 +0000 Subject: [PATCH 1/2] Remove staging-specific PostHog defaults Co-authored-by: openhands --- .env.sample | 5 ----- .github/workflows/docker.yml | 8 -------- AGENTS.md | 2 +- docker/Dockerfile | 5 ----- package.json | 2 +- src/services/telemetry.ts | 19 +++++++------------ 6 files changed, 9 insertions(+), 32 deletions(-) diff --git a/.env.sample b/.env.sample index a07368204..7ddbf21fa 100644 --- a/.env.sample +++ b/.env.sample @@ -16,11 +16,6 @@ VITE_FRONTEND_PORT="3001" # Port to run the frontend application VITE_USE_TLS="false" # Use HTTPS/WSS for proxied backend connections VITE_INSECURE_SKIP_VERIFY="false" # Skip TLS certificate verification for proxied backend requests -# Deployment environment — controls which PostHog project key is compiled in. -# Set to "production" or "staging" only in real deployment build pipelines. -# Leave unset locally so developers never accidentally send telemetry. -# VITE_APP_ENV="production" - # Mocking / test helpers VITE_MOCK_API="false" # Enable/disable API mocking with MSW diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 6bb8790ec..f1564fd49 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -160,13 +160,6 @@ jobs: echo "tags=$TAGS" >> "$GITHUB_OUTPUT" - # Use production PostHog key only for tagged releases - if [[ "$RELEVANT_REF" == refs/tags/v* ]]; then - echo "vite_app_env=production" >> "$GITHUB_OUTPUT" - else - echo "vite_app_env=" >> "$GITHUB_OUTPUT" - fi - echo "=== Build outputs ===" echo "Short SHA: $SHORT_SHA" echo "Tags: $TAGS" @@ -186,7 +179,6 @@ jobs: AUTOMATION_VERSION=${{ steps.prep.outputs.automation_version }} OPENHANDS_BUILD_GIT_SHA=${{ env.RELEVANT_SHA }} OPENHANDS_BUILD_GIT_REF=${{ env.RELEVANT_REF }} - VITE_APP_ENV=${{ steps.prep.outputs.vite_app_env }} cache-from: type=gha cache-to: type=gha,mode=max provenance: true diff --git a/AGENTS.md b/AGENTS.md index cfd4e688a..dec7b7883 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -445,6 +445,6 @@ return new ConversationClient(getAgentServerClientOptions()).someMethod(...); - CI workflow: a `Read defaults from config/defaults.json` step uses `node -p` to extract values into `$GITHUB_OUTPUT`. - Dockerfile ARG defaults are kept as fallbacks for local `docker build` without the CI workflow; CI always passes `--build-arg` overrides from the JSON. - To bump a version, edit `config/defaults.json` only — the JS scripts, Docker build, and CI workflow all derive their values from it. -- Docker all-in-one image: `.github/workflows/docker.yml` builds and publishes `ghcr.io/openhands/agent-canvas` — a combined image that bundles the agent-server (from `ghcr.io/openhands/agent-server`), the automation server (`openhands-automation` via pip), and the agent-canvas frontend (static build). The Dockerfile lives at `docker/Dockerfile`, the entrypoint at `docker/entrypoint.sh`. The workflow structure mirrors the SDK repo's `server.yml`: a `build-and-push-image` matrix job (2 × arch: amd64 on `ubuntu-24.04`, arm64 on `ubuntu-24.04-arm`) pushes arch-suffixed tags, then `merge-manifests` creates multi-arch manifests via `docker buildx imagetools create`, then `consolidate-build-info` aggregates artifacts, and `update-pr-description` updates the PR body (using `` / `` markers). The workflow triggers on push to main, `v*` tags (releases), PRs, and `workflow_dispatch`. On release tags it also pushes semver tags (e.g. `1.2.3`, `1.2`, `1`, `latest`). Fork PRs are skipped (no GHCR auth). The image exposes port 8000 as a unified entry point: `/api/automation/*` → automation (:18001), `/api/*` → agent-server (:18000), `/*` → static frontend. The Dockerfile accepts a `VITE_APP_ENV` build arg (default empty → staging PostHog key); the CI workflow passes `VITE_APP_ENV=production` only for tagged releases (`refs/tags/v*`), so PR and main-branch images use the staging key while release images use the production key, matching the `build:lib` npm path. The entrypoint auto-generates **both** the session API key and `OH_SECRET_KEY` (persisted to `~/.openhands/agent-canvas/session-api-key.txt` and `secret-key.txt` respectively) when none is provided, so the image runs secure by default. Users can override either via env var (`OH_SECRET_KEY`, `SESSION_API_KEY` / `OH_SESSION_API_KEYS_0`). Unlike `scripts/dev-safe.mjs` (which uses a static default secret key for local dev convenience), the Docker entrypoint never falls back to a known default. +- Docker all-in-one image: `.github/workflows/docker.yml` builds and publishes `ghcr.io/openhands/agent-canvas` — a combined image that bundles the agent-server (from `ghcr.io/openhands/agent-server`), the automation server (`openhands-automation` via pip), and the agent-canvas frontend (static build). The Dockerfile lives at `docker/Dockerfile`, the entrypoint at `docker/entrypoint.sh`. The workflow structure mirrors the SDK repo's `server.yml`: a `build-and-push-image` matrix job (2 × arch: amd64 on `ubuntu-24.04`, arm64 on `ubuntu-24.04-arm`) pushes arch-suffixed tags, then `merge-manifests` creates multi-arch manifests via `docker buildx imagetools create`, then `consolidate-build-info` aggregates artifacts, and `update-pr-description` updates the PR body (using `` / `` markers). The workflow triggers on push to main, `v*` tags (releases), PRs, and `workflow_dispatch`. On release tags it also pushes semver tags (e.g. `1.2.3`, `1.2`, `1`, `latest`). Fork PRs are skipped (no GHCR auth). The image exposes port 8000 as a unified entry point: `/api/automation/*` → automation (:18001), `/api/*` → agent-server (:18000), `/*` → static frontend. The entrypoint auto-generates **both** the session API key and `OH_SECRET_KEY` (persisted to `~/.openhands/agent-canvas/session-api-key.txt` and `secret-key.txt` respectively) when none is provided, so the image runs secure by default. Users can override either via env var (`OH_SECRET_KEY`, `SESSION_API_KEY` / `OH_SESSION_API_KEYS_0`). Unlike `scripts/dev-safe.mjs` (which uses a static default secret key for local dev convenience), the Docker entrypoint never falls back to a known default. - Cloud conversation resume gating: when a cloud conversation is closed from the UI (`pauseCloudSandbox` is called), the conversation's `conversation_url` is NOT cleared -- it still points to the old sandbox host. `WebSocketProviderWrapper` must suppress the URL (pass `null` to `ConversationWebSocketProvider`) while `sandbox_status === "PAUSED"`, otherwise the WebSocket immediately tries the stale URL before the sandbox wakes. Symmetrically, `useActiveConversation`'s refetch interval must fast-poll (3 s) on both `!conversation_url` AND `sandbox_status === "PAUSED"` -- checking only the missing URL would leave the hook on the 30 s interval while the sandbox is resuming. The resume sequence: navigate -> sandbox PAUSED detected -> `resumeCloudSandbox` called (in `conversation.tsx`) -> fast-poll detects RUNNING -> `conversationUrl` unblocked -> WebSocket connects. diff --git a/docker/Dockerfile b/docker/Dockerfile index beb49ef7b..7e3815e18 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -36,11 +36,6 @@ RUN npm ci COPY . . # Build the static frontend. -# VITE_APP_ENV controls the PostHog telemetry key baked into the bundle: -# "production" → prod key (set by CI for tagged releases) -# anything else → staging key (default for PR / main / local builds) -ARG VITE_APP_ENV="" -ENV VITE_APP_ENV=${VITE_APP_ENV} RUN npm run build # ── Stage 1b: Generate shell-sourceable defaults from config/defaults.json ── diff --git a/package.json b/package.json index 657226e91..61c03a768 100644 --- a/package.json +++ b/package.json @@ -94,7 +94,7 @@ "typecheck:staged": "react-router typegen && npx tsc --noEmit --skipLibCheck", "check-translation-completeness": "node scripts/check-translation-completeness.cjs", "build:app": "npm run make-i18n && react-router build", - "build:lib": "npm run make-i18n && react-router typegen && cross-env BUILD_LIB=true VITE_APP_ENV=production vite build && tsc -p tsconfig.lib.json", + "build:lib": "npm run make-i18n && react-router typegen && cross-env BUILD_LIB=true vite build && tsc -p tsconfig.lib.json", "build:docker": "node scripts/docker-build.mjs" }, "lint-staged": { diff --git a/src/services/telemetry.ts b/src/services/telemetry.ts index 3194ae632..ce6cbb3a5 100644 --- a/src/services/telemetry.ts +++ b/src/services/telemetry.ts @@ -32,20 +32,15 @@ const TELEMETRY_CONSENT_KEY = "openhands-telemetry-consent"; const TELEMETRY_FIRST_USE_KEY = "openhands-telemetry-first-use"; const TELEMETRY_SESSION_KEY = "openhands-telemetry-session"; -// PostHog project keys — one per deployment environment, hardcoded so they -// are baked into the static bundle at build time and cannot drift at runtime. -// Replace POSTHOG_STAGING_KEY with a dedicated project key once provisioned. -const POSTHOG_PROD_KEY = "phc_BgzfxKdgsYMLFTmJqt424ZoyVHvKFfrwttLimzdYTKFK"; -const POSTHOG_STAGING_KEY = "phc_kBtz5nKmxVRRQ7HtPwr2QX9eMC5j65zE86QKocVNwb4U"; - -// Always use the staging key unless VITE_APP_ENV is explicitly set to -// "production" at bundle time (hardcoded in build:lib and production CI). -// Library consumers can always override with VITE_POSTHOG_API_KEY. +// OpenHands PostHog project key, hardcoded so it is baked into the static +// bundle at build time and cannot drift at runtime. +const OPENHANDS_POSTHOG_API_KEY = "phc_BgzfxKdgsYMLFTmJqt424ZoyVHvKFfrwttLimzdYTKFK"; + +// Default to the OpenHands PostHog project. Library consumers can always +// override with VITE_POSTHOG_API_KEY. const POSTHOG_API_KEY: string = (import.meta.env.VITE_POSTHOG_API_KEY as string | undefined) || - (import.meta.env.VITE_APP_ENV === "production" - ? POSTHOG_PROD_KEY - : POSTHOG_STAGING_KEY); + OPENHANDS_POSTHOG_API_KEY; // Default to OpenHands' reverse proxy to bypass ad blockers. // The proxy at z.openhands.dev routes to PostHog's US region. From 9a3dee5b6883410e20ed34450194a3bec846ae21 Mon Sep 17 00:00:00 2001 From: enyst Date: Wed, 20 May 2026 20:02:13 +0000 Subject: [PATCH 2/2] Inline default PostHog key Co-authored-by: openhands --- src/services/telemetry.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/services/telemetry.ts b/src/services/telemetry.ts index ce6cbb3a5..560f6a5a5 100644 --- a/src/services/telemetry.ts +++ b/src/services/telemetry.ts @@ -32,15 +32,12 @@ const TELEMETRY_CONSENT_KEY = "openhands-telemetry-consent"; const TELEMETRY_FIRST_USE_KEY = "openhands-telemetry-first-use"; const TELEMETRY_SESSION_KEY = "openhands-telemetry-session"; -// OpenHands PostHog project key, hardcoded so it is baked into the static -// bundle at build time and cannot drift at runtime. -const OPENHANDS_POSTHOG_API_KEY = "phc_BgzfxKdgsYMLFTmJqt424ZoyVHvKFfrwttLimzdYTKFK"; - -// Default to the OpenHands PostHog project. Library consumers can always -// override with VITE_POSTHOG_API_KEY. +// Default to the OpenHands PostHog project key, hardcoded so it is baked into +// the static bundle at build time and cannot drift at runtime. Library +// consumers can always override with VITE_POSTHOG_API_KEY. const POSTHOG_API_KEY: string = (import.meta.env.VITE_POSTHOG_API_KEY as string | undefined) || - OPENHANDS_POSTHOG_API_KEY; + "phc_BgzfxKdgsYMLFTmJqt424ZoyVHvKFfrwttLimzdYTKFK"; // Default to OpenHands' reverse proxy to bypass ad blockers. // The proxy at z.openhands.dev routes to PostHog's US region.