Skip to content

feat: add optional Clerk access gate - #1841

Merged
giswqs merged 7 commits into
mainfrom
feat/optional-clerk-access
Aug 11, 2026
Merged

feat: add optional Clerk access gate#1841
giswqs merged 7 commits into
mainfrom
feat/optional-clerk-access

Conversation

@giswqs

@giswqs giswqs commented Aug 10, 2026

Copy link
Copy Markdown
Member

Summary

  • add an opt-in Clerk sign-in gate for hosted GeoLibre web deployments
  • keep public, Tauri, mobile, and embedded builds unchanged by loading Clerk only when configured
  • validate the runtime key, update nginx CSP, and document Docker and Compose configuration
  • exclude the 34.61 KB gzip Clerk integration chunk from the default PWA precache

Test plan

  • Run focused Clerk and deployment environment tests
  • Run scoped pre-commit hooks, including ESLint and the production build
  • Verify the Clerk chunk is excluded from the generated service worker precache
  • Validate the Docker entrypoint shell syntax
  • Audit translation catalog coverage

Summary by CodeRabbit

  • New Features

    • Added optional Clerk sign-in for hosted web deployments.
    • Signed-in users see account controls, while signed-out users are prompted to sign in.
    • Added optional waitlist support for restricted deployments.
    • Authentication can be enabled with the GEOLIBRE_CLERK_PUBLISHABLE_KEY setting.
    • Native and embedded applications remain unaffected.
  • Documentation

    • Added setup guidance for authentication and waitlist configuration in Docker and self-hosted deployments.
  • Tests

    • Added coverage for authentication configuration, fallback behavior, waitlist settings, and supported application environments.

Allow hosted GeoLibre deployments to require individual Clerk sign-in while keeping public, native, and embedded builds unchanged. Load Clerk on demand and keep its chunk out of the default PWA precache.
Copilot AI lite review requested due to automatic review settings August 10, 2026 22:20

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 10, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

The change adds optional Clerk sign-in for web deployments. It resolves runtime or build-time configuration, gates the desktop app when enabled, injects Docker CSP origins, preserves native and embedded behavior, and documents the deployment settings.

Changes

Clerk authentication

Layer / File(s) Summary
Clerk configuration and contract
apps/geolibre-desktop/package.json, apps/geolibre-desktop/src/lib/clerk-auth.ts, tests/clerk-auth.test.ts
Adds the Clerk runtime dependency and configuration resolvers. Tests cover precedence, trimming, truthy parsing, missing values, native builds, and embedded builds.
Clerk sign-in gate
apps/geolibre-desktop/src/components/auth/ClerkGate.tsx
Adds loading, signed-out, waitlist, and signed-in rendering through Clerk.
Conditional startup integration
apps/geolibre-desktop/src/main.tsx, apps/geolibre-desktop/src/vite-env.d.ts, apps/geolibre-desktop/vite.config.ts
Loads Clerk only for configured web deployments, uses the embed-build flag, and excludes the optional gate chunk from PWA precaching.
Docker runtime and deployment configuration
docker-compose.yml, docker/entrypoint.sh, docker/nginx.conf, docs/getting-started.md, docs/self-hosting.md
Passes and validates Clerk settings, injects Clerk CSP origins, logs the authentication mode, and documents sign-in and waitlist behavior.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Docker
  participant main_tsx
  participant ClerkGate
  participant Clerk
  participant App
  Docker->>main_tsx: Expose Clerk key and waitlist settings
  main_tsx->>main_tsx: Resolve web-only authentication configuration
  main_tsx->>ClerkGate: Load gate when a key is configured
  ClerkGate->>Clerk: Initialize ClerkProvider
  Clerk-->>ClerkGate: Return authentication state
  ClerkGate->>App: Render sign-in, waitlist, or authenticated content
Loading

Possibly related PRs

Poem

A rabbit checks the Clerk gate,
While web builds set the state.
Native paths remain free,
CSP guards the entry tree.
Hop—waitlists join the flow!

🚥 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 and concisely describes the main change: adding an optional Clerk access gate.
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/optional-clerk-access

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 10, 2026

Copy link
Copy Markdown
Contributor

🔍 Cloudflare PR preview

Item Value
Site https://27b58a18.geolibre-preview.pages.dev
Demo app https://27b58a18.geolibre-preview.pages.dev/demo/
Commit ed24b5a

@github-actions

github-actions Bot commented Aug 10, 2026

Copy link
Copy Markdown
Contributor

🔍 GitHub Pages PR preview

Item Value
Site https://opengeos.org/pages-preview/GeoLibre/pr-1841/
Demo app https://opengeos.org/pages-preview/GeoLibre/pr-1841/demo/
Commit ed24b5a

Note

GitHub Pages built this preview successfully, but its serving edge returned HTTP 403 when checked. The links may still be propagating.

Comment thread apps/geolibre-desktop/src/main.tsx Outdated
Comment thread docker/entrypoint.sh
@github-actions

Copy link
Copy Markdown
Contributor

Code review

Bugs / Security

  • [High confidence] Clerk sign-in gate is trivially bypassed via ?embed=1. apps/geolibre-desktop/src/main.tsx:100 computes webApp = !isTauri() && !isEmbedded(), and isEmbedded() returns true for any request carrying the plain, unauthenticated, publicly-documented ?embed=1/?embed=true query parameter (not gated on GEOLIBRE_EMBED_ORIGINS). On any deployment with GEOLIBRE_CLERK_PUBLISHABLE_KEY set, visiting https://your-deployment/?embed=1 skips resolveClerkPublishableKey's result entirely, so ClerkGate is never loaded and the full app renders with no sign-in wall — defeating the feature's whole purpose ("require individual users to sign in", per docs/self-hosting.md) for every Clerk-gated deployment. Posted inline with a suggested direction (gate strictly on !isTauri() instead of the broader embed heuristic).

Quality

  • [Low/medium confidence] docker/entrypoint.sh's CSP-rendering block (~lines 320-330) duplicates the Clerk publishable-key base64 decode/validation from the earlier block (~lines 147-157) but omits its try/except. It's currently safe only because set -e guarantees the second block never runs after an invalid key, which is a fragile, non-obvious invariant worth a comment or consolidation.
  • Everything else — the CSP template substitution, the runtime-env JSON injection, the PWA precache exclusion glob (**/ClerkGate-*.js, correctly matching Rollup's default dynamic-import chunk naming since manualChunks returns undefined for non-node_modules app code), the resolveClerkPublishableKey precedence logic and its unit tests, and the docs — looked correct and consistent with existing conventions in the file (e.g. the GEOLIBRE_COLLAB_URL/CSP pattern this mirrors).

No performance issues or CLAUDE.md violations found in the changed files beyond the above.

@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: 2

🤖 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 `@apps/geolibre-desktop/src/components/auth/ClerkGate.tsx`:
- Around line 32-37: Extend protection beyond the ClerkGate Show rendering check
by enforcing Clerk session validation at the reverse proxy or in every protected
server endpoint, including /sidecar and /ai. Ensure unauthenticated requests are
rejected before deployment resources or API handlers execute, while preserving
the existing signed-in UI behavior.

In `@docker/entrypoint.sh`:
- Around line 147-157: Update the Clerk key parsing block for clerk_key to
require the pk_test_ or pk_live_ prefix, validate the complete encoded payload
with strict Base64 decoding, and reject missing delimiters, ignored characters,
invalid padding, or payloads without exactly a trailing $. Parse the decoded
payload once, extract and validate the hostname, and reuse that hostname in the
CSP block instead of reparsing the key. Add coverage for invalid prefixes,
malformed delimiters, ignored characters, invalid padding, and valid test and
production keys.
🪄 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: ec6184a2-0944-49d9-88ba-7278b84c0dc9

📥 Commits

Reviewing files that changed from the base of the PR and between 7f10cf7 and ea1d8e0.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (11)
  • apps/geolibre-desktop/package.json
  • apps/geolibre-desktop/src/components/auth/ClerkGate.tsx
  • apps/geolibre-desktop/src/lib/clerk-auth.ts
  • apps/geolibre-desktop/src/main.tsx
  • apps/geolibre-desktop/vite.config.ts
  • docker-compose.yml
  • docker/entrypoint.sh
  • docker/nginx.conf
  • docs/getting-started.md
  • docs/self-hosting.md
  • tests/clerk-auth.test.ts

Comment thread apps/geolibre-desktop/src/components/auth/ClerkGate.tsx
Comment thread docker/entrypoint.sh
- Decide the Clerk gate from the build target, not the request: main.tsx no
  longer consults isEmbedded(), whose `?embed=1` query parameter is
  client-controlled and let any visitor render a Clerk-gated deployment with no
  sign-in wall. A new __GEOLIBRE_EMBED_BUILD__ define (GEOLIBRE_EMBED=1) keeps
  the Jupyter embed wheel ungated as intended, and documents the constraint on
  resolveClerkPublishableKey and in docs/getting-started.md.
- Give the CSP block in docker/entrypoint.sh its own try/except around the
  publishable-key base64 decode instead of depending on `set -e` and the earlier
  block having already validated the key, so a reorder or extraction cannot turn
  an invalid key into a raw traceback.
Comment thread docker/entrypoint.sh
Comment thread apps/geolibre-desktop/src/components/auth/ClerkGate.tsx

@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 `@docs/getting-started.md`:
- Around line 275-276: Update the Clerk configuration documentation around the
disabled-by-default explanation to state that Clerk is enabled when either the
deployment-time GEOLIBRE_CLERK_PUBLISHABLE_KEY or build-time
VITE_GEOLIBRE_CLERK_PUBLISHABLE_KEY is set. Clarify that both values must be
unset for Clerk to remain disabled and GeoLibre to behave as before.
🪄 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: 75c778eb-3e4a-44c8-bb9d-cfe1d1f4adfb

📥 Commits

Reviewing files that changed from the base of the PR and between ea1d8e0 and 4681a1c.

📒 Files selected for processing (6)
  • apps/geolibre-desktop/src/lib/clerk-auth.ts
  • apps/geolibre-desktop/src/main.tsx
  • apps/geolibre-desktop/src/vite-env.d.ts
  • apps/geolibre-desktop/vite.config.ts
  • docker/entrypoint.sh
  • docs/getting-started.md

Comment thread docs/getting-started.md Outdated
@github-actions

Copy link
Copy Markdown
Contributor

Both inline comments posted successfully.

Code review

Bugs

  • ClerkGate.tsx:32-33<Show when="signed-in">{children}</Show> unmounts the whole <App /> tree the instant a Clerk session ends (sign-out or expiry), discarding unsaved map/project state with no warning, unlike the careful unsaved-work handling elsewhere in this codebase (stale-chunk-reload.ts). Medium confidence.

Security

  • docker/entrypoint.sh:147-157 (and the duplicate block near line 332) — the key-validation logic checks that the value decodes to a plausible Frontend API hostname, but never confirms the value actually has a pk_/publishable-key prefix before writing it into the client-visible runtime config. A secret key pasted into GEOLIBRE_CLERK_PUBLISHABLE_KEY by mistake would likely (but not guaranteed) fail the format check rather than being deliberately rejected. Low-medium confidence; suggested an explicit prefix check as defense-in-depth.
  • CSP, key decoding/validation, webApp derivation (built from isTauri()/__GEOLIBRE_EMBED_BUILD__ rather than the spoofable isEmbedded()), and the placeholder substitution in docker/nginx.conf all check out — no injection or bypass found.

Performance

  • Nothing notable. The Clerk chunk is correctly excluded from the PWA precache and only fetched when the gate is configured.

Quality

  • The duplicated key-decode/validate logic across the two separate python -c blocks in entrypoint.sh is well-justified by an in-code comment (each is an independent process), so not flagged as an issue on its own.
  • Everything else — resolveClerkPublishableKey's precedence/trim behavior, the __GEOLIBRE_EMBED_BUILD__ build flag, docs, and docker-compose.yml wiring — is consistent and covered by the new tests.

CLAUDE.md

  • No violations found: new external host additions are correctly scoped in the nginx CSP template rather than hand-edited elsewhere, and no relevant mirrored-constant or catalog file was touched by this change.

- Validate the full Clerk publishable-key shape in docker/entrypoint.sh: require
  a pk_test_/pk_live_ prefix (so a secret key pasted into
  GEOLIBRE_CLERK_PUBLISHABLE_KEY can never be published in the runtime config
  instead of failing the boot), decode with validate=True so stray characters
  are an error rather than silently dropped, and require the decoded payload's
  trailing "$" delimiter. Mirrored in the CSP block for the same
  separate-process reason already documented there.
- Note in ClerkGate's doc comment that it gates rendering only and is not a
  server authorization boundary, pointing at the deployment guidance in
  docs/getting-started.md.
- Say in docs/getting-started.md that Clerk stays disabled only when neither the
  runtime nor the build-time key is set, and that the runtime one wins.
Comment thread docker/entrypoint.sh
Comment thread docker/entrypoint.sh Outdated
Comment thread docker/nginx.conf
Comment thread apps/geolibre-desktop/src/components/auth/ClerkGate.tsx
@github-actions

Copy link
Copy Markdown
Contributor

Code review

No correctness bugs, security holes, or performance regressions found in the core logic — this is a well-reasoned, defense-in-depth implementation (build-time-only gating via isTauri()/__GEOLIBRE_EMBED_BUILD__ rather than the spoofable isEmbedded() runtime check, strict Clerk key shape validation duplicated intentionally for fail-safety, PWA precache exclusion for the auth chunk, and clear documentation that the gate is UI-only, not a server authorization boundary). Findings below are coverage/consistency gaps, not defects in the shipped behavior.

Bugs

  • None found with meaningful confidence.

Security

  • None found. The key-derivation logic (resolveClerkPublishableKey, the build-vs-runtime env precedence, and the Frontend API host validation in entrypoint.sh) checks out; the anti-bypass reasoning around isEmbedded()/?embed=1 is correct and verified against IS_EMBED's definition in vite.config.ts.

Performance

  • None found. (The eager import("./App") alongside the Clerk gate check downloads the full app bundle to unauthenticated visitors, but since the gate is explicitly documented as UI-only and not a secrecy boundary, this isn't a regression worth flagging.)

Quality

  • docker/entrypoint.sh (~line 151-170, duplicated ~line 342-360): the Clerk key validation (prefix/base64url/host-regex/$-delimiter checks) has no automated test coverage — only the unrelated resolveClerkPublishableKey JS helper is tested. Medium confidence.
  • docker/entrypoint.sh line 358: the second (CSP-building) validation block's error message text diverges slightly from the first block's equivalent message, despite both being documented as intentionally kept in lockstep. Low confidence, cosmetic.
  • apps/geolibre-desktop/src/components/auth/ClerkGate.tsx: no test exercises the component's actual use of @clerk/react's ClerkProvider/ClerkLoading/ClerkLoaded/Show/SignIn/UserButton API, so a mismatch with this package's real exports (it's a newer, distinct package from @clerk/clerk-react) wouldn't be caught by CI. Medium confidence; I couldn't verify the package API directly (no network/node_modules access).

CLAUDE.md

  • docker/nginx.conf line 101: this file's own documented convention ("mirror a new CSP host into the Tauri CSP") isn't followed or explicitly excepted for the new Clerk/Cloudflare hosts. Functionally fine (Clerk is compiled out of the Tauri build), but the file doesn't note the exception. Low-medium confidence.

- Use the same "GEOLIBRE_CLERK_PUBLISHABLE_KEY contains an invalid Frontend API
  host." message in both entrypoint.sh Clerk blocks, so the duplicated
  validation cannot report the same failure two different ways.
- Note in docker/nginx.conf why the Clerk CSP hosts are deliberately not
  mirrored into the Tauri CSP (the gate is compiled out of the desktop and embed
  builds), so the file's own mirror-to-Tauri rule stays accurate.
Comment thread apps/geolibre-desktop/src/components/auth/ClerkGate.tsx Outdated
Comment thread docker/nginx.conf
Comment thread apps/geolibre-desktop/src/components/auth/ClerkGate.tsx
@github-actions

Copy link
Copy Markdown
Contributor

All three inline comments posted successfully. Here's the final summary.

Code review

Bugs

  • None found with high confidence. The core gating logic (resolveClerkPublishableKey, the main.tsx wiring, the entrypoint.sh Clerk-key validation/decoding) is internally consistent and well-tested for the paths I could verify.

Security

  • The docker/entrypoint.sh Clerk publishable-key validation (prefix check, base64url decode with validate=True, $ delimiter, hostname charset check) is duplicated intentionally across two separate python -c invocations (runtime config + nginx CSP), with a clear comment explaining why relying on script ordering would be fragile. Verified both copies stay in sync. No injection risk: values are JSON-encoded before being written into window.__GEOLIBRE_DEPLOYMENT_ENV__, and the CSP substitution is a literal str.replace, not shell interpolation.
  • isTauri() (used to decide whether the Clerk gate applies) is a runtime check of window.__TAURI_INTERNALS__, not a true build flag like __GEOLIBRE_EMBED_BUILD__. In principle a visitor with script-injection capability before main.tsx runs could spoof that property to skip the gate — but the PR's own docs already disclose that this is a client-side convenience gate, not a server authorization boundary, so this isn't a new risk beyond what's already acknowledged. Confidence: low, not flagged inline.
  • CSP worker-src/frame-src/connect-src are not extended with the Clerk Frontend API host itself (only script-src and the fixed bot-protection origins in frame-src) — flagged inline on docker/nginx.conf. Worth a manual sign-in test against a real Clerk app with devtools open to confirm nothing Clerk needs is silently CSP-blocked. Confidence: low-medium.

Performance

  • No issues. The Clerk chunk is dynamically imported only when a key is configured and is explicitly excluded from the PWA precache list, matching the stated goal of not penalizing public deployments.

Quality

  • Flagged inline: the @clerk/react API surface used (Show when="signed-in"|"signed-out", ClerkLoaded/ClerkLoading) differs from the older, more common @clerk/clerk-react API (<SignedIn>/<SignedOut>). I couldn't verify this against installed types (no node_modules in this environment), so it's worth confirming tsc -b/npm run typecheck actually passes and a live sign-in was exercised, not just inferred from the test plan checklist. Confidence: low.
  • Flagged inline: {children} and the floating <UserButton /> are rendered as siblings inside a single <Show> — worth a quick visual check that both render together rather than assuming Show transparently passes through multiple children. Confidence: low.
  • The two nearly-identical Clerk-key-validation Python blocks in entrypoint.sh are a deliberate, well-justified duplication (explained in comments) rather than an oversight.

CLAUDE.md

  • No violations found. No new user-facing translatable strings were introduced (Clerk's SignIn/UserButton render their own UI), CSP/tile-host conventions were followed correctly (Tauri CSP intentionally left unchanged since Clerk is compiled out of that build, matching the documented pattern for build-specific CSP hosts), and package-lock.json was updated alongside the package.json dependency addition.

Restricted (invite-only) sign-up needs no configuration here, but waitlist
mode does: Clerk renders a "Join the waitlist" link inside the sign-in card
that has nowhere to go until the app mounts a <Waitlist /> and points
waitlistUrl at it.

Serve it at the #/waitlist fragment of the gate's own page, behind a new
GEOLIBRE_CLERK_WAITLIST opt-in. Hash routing keeps the move between the two
screens a same-document navigation, and gives <SignIn routing="hash"> a
prefix its own sub-steps (#/factor-one, #/sso-callback) cannot collide with.

Off by default: on a restricted instance the form would take submissions
nobody can approve. Setting it without GEOLIBRE_CLERK_PUBLISHABLE_KEY fails
at container startup rather than silently serving a public app, and an
unrecognized value is rejected instead of read as false.

No CSP change — the waitlist form talks to the same Frontend API host, and
its bot check uses the challenges.cloudflare.com origin already allowed.
Comment thread docker/entrypoint.sh Outdated
- Keep the beforeunload unsaved-work guard alive while signed out. <App />
  mounts it, so ending a session unmounted it: the project survived (the
  Zustand store is module-scope, so signing back in re-renders it), but the
  tab could then be closed or reloaded with unsaved changes and no "Leave
  site?" prompt. Mount it in ClerkGate too, which covers exactly the window
  <App /> cannot.
Comment thread apps/geolibre-desktop/src/components/auth/ClerkGate.tsx
- Render Clerk's error status instead of a blank page. ClerkLoading and
  ClerkLoaded both return null when Clerk's status is "error" (a key that no
  longer resolves, an unreachable Frontend API, an outage), so the gate left
  nothing on screen and no way to tell a stuck deployment from a slow one.
  Add a <ClerkFailed> branch with a message and a reload action.
- Lower-case the boot-log check for GEOLIBRE_CLERK_WAITLIST. The Python
  validator compares after .lower(), so a spelling like `TRue` enabled the
  waitlist but logged the plain sign-in gate line.

@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

Caution

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

⚠️ Outside diff range comments (1)
docker/entrypoint.sh (1)

350-389: 🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

Align Docker build-time Clerk configuration with runtime CSP.

resolveClerkPublishableKey() supports VITE_GEOLIBRE_CLERK_PUBLISHABLE_KEY, but Dockerfile does not preserve it and docker/entrypoint.sh generates CSP only from GEOLIBRE_CLERK_PUBLISHABLE_KEY. A build-time-only image can therefore enable Clerk without the required CSP sources, while docs/self-hosting.md incorrectly says that an unset runtime key keeps the app public. Add Docker ARG/ENV support and derive CSP from the effective key, or explicitly reject and document build-time-only Docker configurations. State that Clerk is disabled only when both keys are unset.

🤖 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 `@docker/entrypoint.sh` around lines 350 - 389, Align Docker build-time and
runtime Clerk configuration: update Dockerfile’s Clerk ARG/ENV declarations so
VITE_GEOLIBRE_CLERK_PUBLISHABLE_KEY is preserved, and update
docker/entrypoint.sh lines 350-389 to derive CSP from the effective build-time
or runtime key. Update docs/self-hosting.md lines 144-145 to state Clerk is
disabled only when both keys are unset, and document the precedence used when
both are provided. Ensure resolveClerkPublishableKey and entrypoint validation
use the same effective-key behavior.
🤖 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 `@docker/entrypoint.sh`:
- Around line 313-316: Update the GEOLIBRE_CLERK_WAITLIST case in the entrypoint
logging block to normalize the trimmed value consistently with validation, so
mixed-case true values such as tRuE select the waitlist message. Preserve the
existing generic message for all other values.

---

Outside diff comments:
In `@docker/entrypoint.sh`:
- Around line 350-389: Align Docker build-time and runtime Clerk configuration:
update Dockerfile’s Clerk ARG/ENV declarations so
VITE_GEOLIBRE_CLERK_PUBLISHABLE_KEY is preserved, and update
docker/entrypoint.sh lines 350-389 to derive CSP from the effective build-time
or runtime key. Update docs/self-hosting.md lines 144-145 to state Clerk is
disabled only when both keys are unset, and document the precedence used when
both are provided. Ensure resolveClerkPublishableKey and entrypoint validation
use the same effective-key behavior.
🪄 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: 51030ae3-edf1-4413-88e4-9285c77913db

📥 Commits

Reviewing files that changed from the base of the PR and between 3fd834a and 66eb0b7.

📒 Files selected for processing (8)
  • apps/geolibre-desktop/src/components/auth/ClerkGate.tsx
  • apps/geolibre-desktop/src/lib/clerk-auth.ts
  • apps/geolibre-desktop/src/main.tsx
  • docker-compose.yml
  • docker/entrypoint.sh
  • docs/getting-started.md
  • docs/self-hosting.md
  • tests/clerk-auth.test.ts

Comment thread docker/entrypoint.sh Outdated
// Optional hosted-web authentication. This chunk is requested only when a
// Clerk publishable key is configured, so public deployments should not
// download it during service-worker installation.
"**/ClerkGate-*.js",

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.

Confidence: medium. This single glob assumes the whole import("./components/auth/ClerkGate") subtree (ClerkGate.tsx + @clerk/react + @clerk/shared + @tanstack/query-core + js-cookie + glob-to-regexp, none of which match a manualChunks rule) collapses into one ClerkGate-*.js chunk.

That's not guaranteed — this very file documents a case where it wasn't (a few lines up): the cesium dynamic-import boundary needed two ignore patterns, **/cesium-* and **/Cesium-*, because Rollup emitted a differently-cased facade chunk that the first glob missed. If Rollup splits any of the Clerk-only deps into a separately-named chunk (or emits a facade), it would silently slip back into the PWA precache, defeating the point of this change for public (non-Clerk) deployments.

Worth confirming against the actual dist/assets output of a production build (or better, adding an automated check, since the PR's verification of this was a manual step) rather than relying on the single glob.

Comment on lines +19 to +28
/**
* Whether to serve Clerk's waitlist form at {@link WAITLIST_HASH}. Off unless
* the deployment opts in, because it only makes sense for a Clerk instance in
* waitlist sign-up mode.
*/
waitlist?: boolean;
children: ReactNode;
}

// The gate lives on a single page with no router, so the two signed-out screens

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.

Confidence: low. ClerkFailed, Show (with when="signed-in"/"signed-out" string props), and Waitlist/waitlistUrl are a less commonly documented part of Clerk's React surface — most existing Clerk integrations use <SignedIn>/<SignedOut> wrapper components instead of a generic <Show when=...> primitive. Since @clerk/react is a brand-new dependency for this repo (this PR adds it), it's worth double-checking these exports/props against the actual installed @clerk/react@6.14.1 type declarations to make sure tsc -b is actually type-checking real APIs here rather than something that happens to compile loosely. If this was confirmed via the "production build" step in the test plan, feel free to disregard.

@github-actions

Copy link
Copy Markdown
Contributor

Code review

Bugs

  • None found with high confidence. The build-vs-runtime gating (isTauri() / __GEOLIBRE_EMBED_BUILD__, never isEmbedded()), the Docker entrypoint's Clerk key/waitlist validation and CSP templating, and the resolveClerkPublishableKey/resolveClerkWaitlistEnabled precedence logic all check out against their own tests and the surrounding code.

Security

  • None found. Publishable-key validation in docker/entrypoint.sh correctly rejects secret keys, decodes/validates the Frontend API host before embedding it in the CSP header (restricted to [A-Za-z0-9.-]+, so no header injection), and the gate is explicitly documented as a rendering-only boundary with server-side auth left to the operator. The gate is correctly keyed off the build target rather than a runtime/query-param signal, so ?embed=1 can't be used to bypass it.

Performance

  • Medium confidence: the PWA precache exclusion **/ClerkGate-*.js (apps/geolibre-desktop/vite.config.ts) assumes the entire Clerk dynamic-import subtree collapses into one predictably-named chunk. The same file documents a precedent where that assumption failed for the cesium import boundary (needing both cesium-* and Cesium-* patterns for a facade chunk), and there's no automated test verifying the built output here — only a manual check per the PR description. Worth confirming against real build output.

Quality

  • Low confidence: ClerkGate.tsx uses some less-common @clerk/react primitives (ClerkFailed, Show when="signed-in"/"signed-out", Waitlist/waitlistUrl) rather than the more commonly documented <SignedIn>/<SignedOut>. Since @clerk/react is a new dependency in this PR, worth a quick check against the installed package's type declarations to confirm these are real, current APIs.

CLAUDE.md

  • No violations found. Tauri CSP allowlist correctly left untouched with a documented rationale (Clerk is compiled out of desktop/embed builds), new user-facing strings go through t()/en.json, and docs were updated in both docs/getting-started.md and docs/self-hosting.md as required for new deployment env vars.

@giswqs
giswqs merged commit c5f3c1c into main Aug 11, 2026
30 checks passed
@giswqs
giswqs deleted the feat/optional-clerk-access branch August 11, 2026 01:38
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