From ee40880f395a7398cee02e776afcdd4ef8f4e694 Mon Sep 17 00:00:00 2001 From: Hongming Wang Date: Mon, 20 Apr 2026 12:51:22 -0700 Subject: [PATCH] fix(ci): bake api.moleculesai.app into tenant canvas bundle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Canvas's browser-side code (auth.ts, api.ts, billing.ts) all call fetch(PLATFORM_URL + /cp/*). PLATFORM_URL comes from NEXT_PUBLIC_PLATFORM_URL at build time; with the build arg unset, it falls back to http://localhost:8080 in the compiled bundle. That means on a tenant like hongmingwang.moleculesai.app, the user's browser actually tried to fetch http://localhost:8080/cp/ auth/me — which resolves to the USER'S OWN machine, not the tenant. Login redirect loops 404. Every tenant canvas has been unable to complete a fresh login on this path; existing sessions only worked because the cookie was already set domain-wide. Fix: pass NEXT_PUBLIC_PLATFORM_URL=https://api.moleculesai.app as a build arg in the tenant-image workflow. CP already allows CORS from *.moleculesai.app + credentials, and the session cookie is scoped to .moleculesai.app so tenant subdomains inherit it. Verified in prod by rebuilding canvas locally with the flag and hot-patching the hongmingwang instance via SSM. Baked chunks now contain api.moleculesai.app; browser auth redirects resolve cleanly to the CP. Self-hosted users override by rebuilding with their own URL — same pattern molecule-app uses with NEXT_PUBLIC_CP_ORIGIN. Co-Authored-By: Claude Opus 4.7 (1M context) --- .../workflows/publish-workspace-server-image.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.github/workflows/publish-workspace-server-image.yml b/.github/workflows/publish-workspace-server-image.yml index 5f7d6bd4..c72d6c8e 100644 --- a/.github/workflows/publish-workspace-server-image.yml +++ b/.github/workflows/publish-workspace-server-image.yml @@ -111,6 +111,21 @@ jobs: ${{ env.TENANT_IMAGE_NAME }}:staging-${{ steps.tags.outputs.sha }} cache-from: type=gha cache-to: type=gha,mode=max + # Bake the SaaS control-plane URL into the canvas bundle. + # Canvas's browser-side code uses PLATFORM_URL for every + # /cp/* call (auth, orgs, billing, terms). Leaving this empty + # made PLATFORM_URL fall back to http://localhost:8080 in the + # built bundle — which fails from the user's browser because + # localhost resolves to their own machine, not the tenant + # instance. Baking the CP origin here fixes browser-side auth + # for every tenant. + # + # Self-hosted / private-label deployments override this by + # rebuilding the image with a different NEXT_PUBLIC_PLATFORM_URL + # build-arg (e.g. https://api.their-domain.com). Same pattern + # molecule-app uses with NEXT_PUBLIC_CP_ORIGIN. + build-args: | + NEXT_PUBLIC_PLATFORM_URL=https://api.moleculesai.app labels: | org.opencontainers.image.source=https://github.com/${{ github.repository }} org.opencontainers.image.revision=${{ github.sha }}