ci: deploy studio.geolibre.app on every push to main - #1842
Conversation
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.
|
Caution Review failedThe pull request is closed. ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: ASSERTIVE Plan: Pro Plus Run ID: 📒 Files selected for processing (2)
📝 WalkthroughWalkthroughThe change adds an automated workflow that builds and publishes ChangesStudio deployment
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
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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
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. Comment |
🔍 Cloudflare PR preview
|
🔍 GitHub Pages PR preview
|
There was a problem hiding this comment.
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
📒 Files selected for processing (2)
.github/workflows/studio-deploy.ymlworkers/ai-proxy/wrangler.jsonc
Code reviewBugs: None found. The Security: None found. The Clerk-gate verification step correctly matches the exact secret value (not just its public prefix) using 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:
CLAUDE.md: No violations — this PR only touches Overall this is a well-documented, carefully reasoned workflow addition; I cross-checked its claims against |
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.
Code reviewBugs
Security
Performance
Quality
CLAUDE.md
|
- 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.
Code reviewBugs: None found. Traced through the workflow's env/fallback logic end-to-end — Security: None found. 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:
CLAUDE.md: No violations. New workflow follows the existing |
There was a problem hiding this comment.
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 winPin the Node.js version used for deployment.
The repository declares only
node >=22and 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 liftRestrict the manual deployment ref before exposing the deployment token.
inputs.refcan select untrusted code. That code can create.git/hooks/pre-commitor.git/hooks/pre-pushduringnpm cior the build. The current publish step runs both hooks withSTUDIO_DEPLOY_TOKENset, which exposes the token.Validate the selected commit against protected refs before
npm ci. Removeapps/geolibre-desktop/dist/.gitbeforegit init. Disable hooks for bothgit commitandgit push. ExposeSTUDIO_DEPLOY_TOKENonly 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
📒 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" |
There was a problem hiding this comment.
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.
Code reviewBugs: None found. The workflow's ref-resolution logic ( Security: No issues found. The job is correctly gated to 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 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 |
Summary
.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 tomain(plus manual dispatch with a ref, for rollback)https://studio.geolibre.appto the AI proxy'sALLOWED_ORIGINSWhy the site is not deployed with
actions/deploy-pagesThe gated instance is hosted from a separate private repo,
opengeos/studio.geolibre.app, which holds only the built site.actions/deploy-pagesdeploys 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'sgh-pagesbranch 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:
VITE_GEOLIBRE_CLERK_PUBLISHABLE_KEYSTUDIO_DEPLOY_TOKENopengeos/studio.geolibre.app.And, outside this repo: the
CNAME studio → opengeos.github.ioDNS record (DNS only — a proxied record blocks GitHub's certificate provisioning), and thestudio.geolibre.appdomain 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.mjsships those prefixes as literals in its own key validation, and they land in theClerkGatechunk 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/aiproxy, and no CSP (Pages cannot set response headers). The Clerk gate controls rendering, not data — the AI Worker is protected only by itsOriginallowlist, 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 --fileson both changed files (includes the fullnpm build)dist/assets; confirmed a non-matching key fails the guardopengeos/studio.geolibre.appcreated,gh-pagesseeded with a placeholder +.nojekyll, Pages enabled on that branch with the custom domainSummary by CodeRabbit