Skip to content

ci: deploy studio.geolibre.app on every push to main - #1842

Merged
giswqs merged 4 commits into
mainfrom
feat/studio-deploy
Aug 11, 2026
Merged

ci: deploy studio.geolibre.app on every push to main#1842
giswqs merged 4 commits into
mainfrom
feat/studio-deploy

Conversation

@giswqs

@giswqs giswqs commented Aug 11, 2026

Copy link
Copy Markdown
Member

Summary

  • add .github/workflows/studio-deploy.yml, which builds this app with the Clerk sign-in gate on and publishes it to https://studio.geolibre.app on every push to main (plus manual dispatch with a ref, for rollback)
  • add https://studio.geolibre.app to the AI proxy's ALLOWED_ORIGINS

Why the site is not deployed with actions/deploy-pages

The gated instance is hosted from a separate private repo, opengeos/studio.geolibre.app, which holds only the built site. actions/deploy-pages deploys the Pages site of the repository it runs in, so it cannot publish there from here. The workflow force-pushes the build as a single orphan commit to that repo's gh-pages branch instead, which keeps the hosting repo at the size of one build (~200 MB) rather than accumulating one commit per merge.

The workflow lives in this repo so the deployment is versioned alongside the code it ships.

Before this can run

Two secrets on this repository:

Secret Purpose
VITE_GEOLIBRE_CLERK_PUBLISHABLE_KEY Turns the gate on. Public by design; a secret only to keep rotation in one place.
STUDIO_DEPLOY_TOKEN Fine-grained PAT with Contents: write on opengeos/studio.geolibre.app.

And, outside this repo: the CNAME studio → opengeos.github.io DNS record (DNS only — a proxied record blocks GitHub's certificate provisioning), and the studio.geolibre.app domain plus its Frontend API records in the Clerk Dashboard.

The ungated-publish guard

A missing or misspelled key builds cleanly and would publish an open instance, so the run fails unless the configured key is in the bundle.

It matches the key's value, not its pk_test_/pk_live_ prefix. @clerk/shared/dist/keys.mjs ships those prefixes as literals in its own key validation, and they land in the ClerkGate chunk whether or not a key is configured — a prefix check passes on an ungated build. Verified both ways locally: the configured key matches, an unconfigured one does not.

Scope

This deployment is static, so relative to the Docker image it has no /sidecar, no same-origin /ai proxy, and no CSP (Pages cannot set response headers). The Clerk gate controls rendering, not data — the AI Worker is protected only by its Origin allowlist, which a non-browser client can set freely. Cloudflare Access service tokens on the Worker route would be the fix if the API spend matters.

Validation

  • pre-commit run --files on both changed files (includes the full npm build)
  • built with a dummy key and confirmed it reaches dist/assets; confirmed a non-matching key fails the guard
  • opengeos/studio.geolibre.app created, gh-pages seeded with a placeholder + .nojekyll, Pages enabled on that branch with the custom domain

Summary by CodeRabbit

  • New Features
    • Added automated deployment of the gated desktop app to the Studio site after updates to the main branch or a manual release.
    • Enabled the deployed Studio app to make supported requests through the AI proxy.
    • Added deployment checks to help ensure published builds are complete and correctly configured.
    • Improved release handling so deployments are serialized and published consistently.

studio.geolibre.app is the Clerk-gated instance of this app, hosted from the
separate private repo opengeos/studio.geolibre.app. That repo only holds the
built site, so this cannot use actions/deploy-pages (which deploys the Pages
site of the repository it runs in) — the build is force-pushed as a single
orphan commit to its gh-pages branch instead, keeping that repo the size of
one build rather than one commit per merge.

The workflow lives here so the deployment is versioned with the code it
ships. It needs two secrets: VITE_GEOLIBRE_CLERK_PUBLISHABLE_KEY (the gate)
and STUDIO_DEPLOY_TOKEN (write access to the hosting repo).

A missing key builds cleanly and would publish an *ungated* instance, so the
run fails unless the configured key is actually in the bundle. The check
matches the key's value rather than its pk_test_/pk_live_ prefix: @clerk/shared
ships those prefixes as literals in its own validation, so a prefix check
passes even with no key configured.

Also add https://studio.geolibre.app to the AI proxy's ALLOWED_ORIGINS.
GitHub Pages cannot proxy, so unlike the Docker image the assistant and the
disaster-news lookup call the Worker cross-origin and 401 without it.
Copilot AI lite review requested due to automatic review settings August 11, 2026 01:56

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@coderabbitai

coderabbitai Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: b2078178-a4c5-42a6-9aa5-482ab16ed9a4

📥 Commits

Reviewing files that changed from the base of the PR and between e492206 and f54b71f.

📒 Files selected for processing (2)
  • workers/ai-proxy/worker-configuration.d.ts
  • workers/ai-proxy/wrangler.jsonc

📝 Walkthrough

Walkthrough

The change adds an automated workflow that builds and publishes geolibre-desktop to studio.geolibre.app. It validates the Clerk key, prepares GitHub Pages metadata, enforces a size limit, and configures the AI proxy for the hosted origin.

Changes

Studio deployment

Layer / File(s) Summary
Deployment triggers and application build
.github/workflows/studio-deploy.yml
The workflow runs on main pushes or manual dispatch. It restricts publishing to the canonical repository, configures concurrency, installs dependencies, and builds geolibre-desktop with service settings.
Bundle validation and Pages preparation
.github/workflows/studio-deploy.yml
The workflow checks that the Clerk key exists in the generated bundle. It creates .nojekyll and CNAME, reports build size, and rejects sites larger than 900 MB.
Publication and proxy access
.github/workflows/studio-deploy.yml, workers/ai-proxy/wrangler.jsonc, workers/ai-proxy/worker-configuration.d.ts
The workflow force-pushes the build to the hosting repository as an orphan gh-pages commit. The AI proxy requires the configured secrets and allows requests from https://studio.geolibre.app.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant GitHubActions
  participant GeolibreDesktop
  participant Clerk
  participant StudioHosting
  participant AIProxy
  GitHubActions->>GeolibreDesktop: install dependencies and build configured application
  GeolibreDesktop->>Clerk: embed Clerk publishable key
  GitHubActions->>GitHubActions: verify key and prepare Pages metadata
  GitHubActions->>StudioHosting: force-push orphan gh-pages build
  StudioHosting->>AIProxy: send requests with Studio origin
  AIProxy-->>StudioHosting: allow hosted origin
Loading

Possibly related PRs

  • opengeos/GeoLibre#1841: Introduces the Clerk-gated hosted desktop app that this workflow builds and deploys.

Poem

A rabbit watches builds run bright,
Clerk’s key appears in the bundle right.
Pages receives the orphaned site,
The proxy permits Studio’s request.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly describes the workflow that deploys studio.geolibre.app on pushes to main.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/studio-deploy

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint install failed: dependency version conflict. Check your lock file or package.json.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

🔍 Cloudflare PR preview

Item Value
Site https://a01a3b42.geolibre-preview.pages.dev
Demo app https://a01a3b42.geolibre-preview.pages.dev/demo/
Commit e492206

@github-actions

github-actions Bot commented Aug 11, 2026

Copy link
Copy Markdown
Contributor

🔍 GitHub Pages PR preview

Item Value
Site Deploy failed. See the job log.
Demo app Unavailable
Commit e492206

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/studio-deploy.yml:
- Line 43: In the checkout/deployment flow around the ref input and the
deployment messages near lines 134 and 141, capture the checked-out commit with
git rev-parse HEAD before git init, then reuse that recorded SHA in both
deployment messages instead of GITHUB_SHA so they report the actual built ref.
🪄 Autofix

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: d510f205-668b-4d1b-842e-793137bfae5a

📥 Commits

Reviewing files that changed from the base of the PR and between bd90773 and dfb858a.

📒 Files selected for processing (2)
  • .github/workflows/studio-deploy.yml
  • workers/ai-proxy/wrangler.jsonc

Comment thread .github/workflows/studio-deploy.yml
@github-actions

Copy link
Copy Markdown
Contributor

Code review

Bugs: None found. The inputs.ref || github.sha fallback, the concurrency group scoping, and the -e-driven step failures (grep guard, size guard) all behave as intended when traced against GitHub Actions semantics.

Security: None found. The Clerk-gate verification step correctly matches the exact secret value (not just its public prefix) using grep -F, matching the stated threat model in @clerk/shared. The job is correctly restricted to opengeos/GeoLibre so forks can't exfiltrate STUDIO_DEPLOY_TOKEN or VITE_GEOLIBRE_CLERK_PUBLISHABLE_KEY. Top-level permissions: contents: read is least-privilege since publishing uses a separate fine-grained PAT, not GITHUB_TOKEN. The ai-proxy ALLOWED_ORIGINS addition is an exact-match string added to a Set-based origin check (workers/ai-proxy/src/index.ts), consistent with the existing entries. (Confidence: high)

Performance: None found. The size guard (900 MB threshold vs. GitHub Pages' 1 GB hard limit) and the single-orphan-commit force-push strategy both match their stated rationale in the comments.

Quality:

  • Verified the Clerk key ends up in JS bundled under dist/assets/ (not inlined into index.html), which is what the grep guard relies on — confirmed via ClerkGate.tsx/clerk-auth.ts usage, so the guard is sound. (Confidence: high)
  • Minor, non-blocking observation: unlike pages.yml, this workflow has no environment: block, so every push to main auto-deploys to the gated production instance with no manual approval gate, even though it holds a repo-write PAT to a separate repository. This may be an intentional tradeoff given the existing guard rails (branch restriction, key-in-bundle check); flagging only as a possible hardening option, not a defect. (Confidence: low)

CLAUDE.md: No violations — this PR only touches .github/workflows/ and workers/ai-proxy/wrangler.jsonc, neither of which is covered by the repo's documented conventions (Whitebox catalog, i18n, CSP allowlist, etc.), and it doesn't touch any of those mirrored constants.

Overall this is a well-documented, carefully reasoned workflow addition; I cross-checked its claims against docs/getting-started.md, vite.config.ts, clerk-auth.ts, and the AI proxy source, and found no discrepancies worth blocking on.

The instance is invite-only (Clerk sign-up mode "Restricted") by default,
where a waitlist form would collect requests nobody can approve. Drive it
from the repository variable GEOLIBRE_CLERK_WAITLIST instead of hardcoding
it on: unset expands to "", which the app already reads as unset, so the
waitlist can be turned on later from Settings → Variables without a code
change.
Comment thread .github/workflows/studio-deploy.yml
@github-actions

Copy link
Copy Markdown
Contributor

Code review

Bugs

  • .github/workflows/studio-deploy.yml:145 — The deploy commit message always uses $GITHUB_SHA, but for workflow_dispatch that env var reflects the branch selected in the "Run workflow" dropdown, not the ref input used to actually build/check out the site (line 49). During the manual rollback flow the PR description explicitly calls out, the published gh-pages commit message will misreport which commit was deployed. Confidence: medium (only affects workflow_dispatch with a non-default ref).

Security

  • None found. The Clerk-key gate check uses grep -F -- to avoid the key value being interpreted as a regex/flag, the deploy PAT is a separately-scoped fine-grained token (not the default GITHUB_TOKEN), and secret values are masked by Actions in logs even when embedded in the push URL.

Performance

  • None found; the size guard and single orphan-commit force-push strategy are reasonable given the ~200 MB build.

Quality

  • The workflow is well-commented and mirrors conventions from pages.yml (env var handling, secrets/vars fallback pattern, node/npm setup). No notable issues.

CLAUDE.md

  • The ALLOWED_ORIGINS change in workers/ai-proxy/wrangler.jsonc correctly adds https://studio.geolibre.app, consistent with the PR's stated scope. No CLAUDE.md guidance (Tauri CSP hosts, WASM catalog, i18n, etc.) applies to either changed file.

- Label the deployment with the commit that was actually built. On
  workflow_dispatch, $GITHUB_SHA is the SHA of the ref chosen in the "Run
  workflow" dropdown, not the `ref` input, so a manual rollback pushed a
  gh-pages commit citing main's tip while serving older content — misleading
  for anyone auditing what is live. Capture `git rev-parse HEAD` after
  checkout (the input may be a branch or tag name, not a SHA) and use it in
  the commit message and the summary line.
- Set persist-credentials: false on the checkout (zizmor "artipacked"). No
  step uses the checkout's token: npm ci fetches from the registry and the
  publish step carries its own credentials.
Comment thread workers/ai-proxy/wrangler.jsonc
@github-actions

Copy link
Copy Markdown
Contributor

Code review

Bugs: None found. Traced through the workflow's env/fallback logic end-to-end — inputs.ref || github.sha resolution, the Clerk gate value-match guard (grep -F), the readDeploymentEnvValue/window.__GEOLIBRE_DEPLOYMENT_ENV__ precedence for a static (non-Docker) deployment, GEOLIBRE_APP_BASE defaulting to root, and the dist/assets path — all check out against the actual source (clerk-auth.ts, deployment-env.ts, vite.config.ts, provider.ts). No logic errors or edge cases found.

Security: None found. persist-credentials: false on checkout is correct since the publish step carries its own PAT; permissions: contents: read is appropriately scoped; the job is gated to opengeos/GeoLibre so forks can't burn secrets; the Clerk-key grep uses -F (fixed-string) and fails closed if the key or dist/assets is missing; the new https://studio.geolibre.app origin is added correctly to the AI proxy's exact-match ALLOWED_ORIGINS set.

Performance: None found. The orphan-commit force-push strategy and the 900 MB pre-push size guard (with ~200 MB actual builds) are reasonable.

Quality:

  • Low/medium confidence: workers/ai-proxy/worker-configuration.d.ts is a generated file (wrangler types) whose ALLOWED_ORIGINS literal type mirrors wrangler.jsonc. This PR updates the source value but doesn't regenerate the type file, leaving it stale. No CI job type-checks against it today, so practical impact is essentially nil — flagged inline as a minor nit.
  • Very low confidence: the job has no timeout-minutes, so a stalled git push (network stall) could hang up to the 6-hour default and block the studio-deploy concurrency group for later runs. Not worth blocking on given how rare this is.

CLAUDE.md: No violations. New workflow follows the existing pages.yml conventions (action versions, env-var patterns, secret naming); wrangler.jsonc change is a scoped one-line addition consistent with the AI proxy's existing config shape.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
.github/workflows/studio-deploy.yml (2)

45-50: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Pin the Node.js version used for deployment.

The repository declares only node >=22 and has no Node.js version file. node-version: lts/* selects a moving runtime. Use a fixed compatible version or add a shared version file to keep rollback builds reproducible.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/studio-deploy.yml around lines 45 - 50, Replace the moving
node-version value in the “Set up Node.js” workflow step with a fixed Node.js
version compatible with the repository’s node >=22 requirement, or configure it
to read from a shared committed version file. Keep the existing npm cache
settings unchanged.

43-56: 🔒 Security & Privacy | 🔴 Critical | 🏗️ Heavy lift

Restrict the manual deployment ref before exposing the deployment token.

inputs.ref can select untrusted code. That code can create .git/hooks/pre-commit or .git/hooks/pre-push during npm ci or the build. The current publish step runs both hooks with STUDIO_DEPLOY_TOKEN set, which exposes the token.

Validate the selected commit against protected refs before npm ci. Remove apps/geolibre-desktop/dist/.git before git init. Disable hooks for both git commit and git push. Expose STUDIO_DEPLOY_TOKEN only on the hook-disabled push command.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In @.github/workflows/studio-deploy.yml around lines 43 - 56, Update the
deployment workflow to validate the selected ref from inputs.ref against
protected refs before running npm ci. Remove apps/geolibre-desktop/dist/.git
before git init, and disable hooks for both git commit and git push. Restrict
STUDIO_DEPLOY_TOKEN to the hook-disabled git push command only.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In @.github/workflows/studio-deploy.yml:
- Around line 45-50: Replace the moving node-version value in the “Set up
Node.js” workflow step with a fixed Node.js version compatible with the
repository’s node >=22 requirement, or configure it to read from a shared
committed version file. Keep the existing npm cache settings unchanged.
- Around line 43-56: Update the deployment workflow to validate the selected ref
from inputs.ref against protected refs before running npm ci. Remove
apps/geolibre-desktop/dist/.git before git init, and disable hooks for both git
commit and git push. Restrict STUDIO_DEPLOY_TOKEN to the hook-disabled git push
command only.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 951b20d9-6ab5-4738-9003-bfd3cee07005

📥 Commits

Reviewing files that changed from the base of the PR and between dfb858a and 44976a1.

📒 Files selected for processing (1)
  • .github/workflows/studio-deploy.yml

- Regenerate workers/ai-proxy/worker-configuration.d.ts so its ALLOWED_ORIGINS
  literal matches wrangler.jsonc again.
- Declare TAVILY_API_KEY in wrangler.jsonc's secrets.required, without which
  the regeneration above is not reproducible: `wrangler types` derives the
  secret bindings from that list, so running it on a clean checkout dropped
  TAVILY_API_KEY and broke the worker's own typecheck (src/index.ts:254 reads
  env.TAVILY_API_KEY). The binding reached the committed types when #1838
  landed but the config entry did not, so the generated file could not be
  reproduced from the config it mirrors.
"CLOUDFLARE_ACCOUNT_ID",
"GEOLIBRE_AI_PROXY_TOKEN"
"GEOLIBRE_AI_PROXY_TOKEN",
"TAVILY_API_KEY"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: adding TAVILY_API_KEY to secrets.required is unrelated to this PR's stated purpose (studio.geolibre.app deploy + ALLOWED_ORIGINS). It looks like a legitimate drift fix — README.md already documents wrangler secret put TAVILY_API_KEY as a setup step — but it's worth calling out explicitly in the PR description (or splitting into its own commit) so reviewers don't wonder whether it's accidental scope creep from a rebase. Low confidence this is a problem at all; just flagging for clarity.

@github-actions

Copy link
Copy Markdown
Contributor

Code review

Bugs: None found. The workflow's ref-resolution logic (inputs.ref || github.sha at checkout, then git rev-parse HEAD to label the deployment) correctly handles both push and manual-dispatch triggers, including the documented edge case where GITHUB_SHA wouldn't reflect a rollback ref. The Clerk-key verification step and the CORS ALLOWED_ORIGINS addition were both checked against actual usage (clerk-auth.ts, ai-proxy/src/index.ts) and are consistent.

Security: No issues found. The job is correctly gated to opengeos/GeoLibre to keep forks from running with secrets, persist-credentials: false avoids leaking the default token, the deploy PAT is scoped and only used via HTTPS URL (masked by GitHub's log redaction), and the gate-verification step avoids ever printing the Clerk key.

Performance: No issues found. Build size guard (900 MB soft threshold vs. the 1 GB Pages hard limit) and orphan-commit force-push strategy are reasonable given the ~200 MB DuckDB-WASM payload.

Quality: Minor (low confidence) — the TAVILY_API_KEY addition to workers/ai-proxy/wrangler.jsonc's secrets.required list is unrelated to this PR's stated purpose. It appears to be a legitimate catch-up fix (the README already documents this secret) rather than a bug, but it's scope creep worth calling out explicitly since it wasn't mentioned in the PR description. Flagged inline.

CLAUDE.md: No violations found; this PR doesn't touch any of the areas with explicit mirrored-constant/catalog rules, and the new workflow follows the existing pages.yml/pr-preview.yml conventions for env var wiring.

@giswqs
giswqs merged commit fee927d into main Aug 11, 2026
14 of 15 checks passed
@giswqs
giswqs deleted the feat/studio-deploy branch August 11, 2026 02:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants