ship/thin shell phase 1 - #6266
Conversation
matthewevans
commented
Jul 21, 2026
- feat(client): thin-shell frontend groundwork (Workstream A)
- feat(desktop): thin-shell bootstrap page and migration commands (Workstream B)
- chore: gitignore the bootstrap dist build output
- ci: dedicated shell-release workflow and thin-shell release trim (Workstream C)
A.1-A.2 platform detection and remote-shell service workers A.3 updater badge coordination and manual checks A.4 legacy storage and Supabase session migration A.5-A.6 first-party shell navigation and shell version A.7-A.8 sidecar removal and remote-load marker
…stream B) B.1: point the shell at the bootstrap dist, remove sidecar bundle inputs, and use the R2 updater manifest. B.2: scope local and remote Tauri capabilities with application command permissions. B.3: add the minimal bootstrap Vite entry for storage export and marker-aware navigation. B.4: register the migration commands while preserving the config-driven setup hook. B.5: persist, non-destructively read, confirm, and mark migration state under app local data.
…kstream C) C.1 adds the signed, stamped shell release workflow and R2 updater manifest publication. C.2 removes legacy Tauri release dependencies and retargets the CI compile stub. C.3 carries the R2 updater manifest forward for legacy updater clients. C.4 leaves nightly-release.yml unchanged. C.5 removes the development sidecar build/install path.
There was a problem hiding this comment.
Code Review
This pull request introduces a bundled bootstrap page to handle offline navigation and legacy storage migration in a Tauri application before loading the remote-origin shell. It adds Rust-side migration commands, updates Tauri capabilities and permissions, and implements an update status ownership mechanism to coordinate the shared status badge between the service worker, Tauri updater, and chunk loader. Feedback on the changes highlights a medium-severity issue in the global external link handler where parsing a malformed URL with new URL() can throw an uncaught exception and crash the document-level click listener.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
|
|
||
| const href = anchor.getAttribute("href"); | ||
| if (!href || !EXTERNAL_URL_RE.test(href)) return; | ||
| if (!isBundledTauriOrigin() && FIRST_PARTY_ORIGINS.has(new URL(href).origin)) return; |
There was a problem hiding this comment.
[MEDIUM] Uncaught exception risk in document-level click handler.
Evidence: client/src/services/externalLinks.ts:46.
Why it matters: If an anchor has a malformed URL starting with http:// or https:// (e.g., https:// or containing spaces), new URL(href) will throw an uncaught exception, crashing the global capture-phase click listener.
Suggested fix: Wrap the new URL parsing in a try...catch block to handle malformed URLs gracefully.
let url: URL;
try {
url = new URL(href);
} catch {
return;
}
if (!isBundledTauriOrigin() && FIRST_PARTY_ORIGINS.has(url.origin)) return;| - uses: actions/setup-node@v4 | ||
| with: | ||
| node-version: 22 | ||
| cache: pnpm |
There was a problem hiding this comment.
P0: Release workflow caches build dependencies
Release workflow caches pnpm dependencies, enabling cache poisoning into release artifacts.
Remove cache: pnpm from the build-shell job in release workflows.
AI prompt
Check if this security scanner issue is valid. If so, understand the root cause and fix it. If appropriate, update or add tests. Keep the change focused and preserve intended behavior.
<file name=".github/workflows/shell-release.yml">
<violation number="1" location=".github/workflows/shell-release.yml:172">
<priority>P0</priority>
<title>Release workflow caches build dependencies</title>
<evidence>The build-shell job in the shell-release workflow uses actions/setup-node with cache: pnpm. In a release workflow triggered by version tags, the shared pnpm cache is also writable by default-branch CI jobs. A compromised or poisoned cache entry from any other workflow can inject malicious dependencies into release artifacts.</evidence>
<recommendation>Remove cache: pnpm and cache-dependency-path from the build-shell job. Rely on a clean pnpm install --frozen-lockfile in release workflows so artifacts are built from lockfile-defined dependencies only.</recommendation>
</violation>
</file>
| done | ||
|
|
||
| - name: Build shell | ||
| uses: tauri-apps/tauri-action@v0 |
There was a problem hiding this comment.
P1: Third-party action pinned to mutable tag
tauri-action is pinned to mutable v0 tag, risking supply chain compromise.
Pin to a full commit SHA with a version comment.
AI prompt
Check if this security scanner issue is valid. If so, understand the root cause and fix it. If appropriate, update or add tests. Keep the change focused and preserve intended behavior.
<file name=".github/workflows/shell-release.yml">
<violation number="2" location=".github/workflows/shell-release.yml:248">
<priority>P1</priority>
<title>Third-party action pinned to mutable tag</title>
<evidence>uses: tauri-apps/tauri-action@v0 is pinned to a mutable major-version tag. If the action repository is compromised, the v0 tag can be force-pushed to a malicious commit, injecting arbitrary code into the release build.</evidence>
<recommendation>Pin to a specific commit SHA and append a version comment. For example, find the SHA for the intended v0.x.y release and use uses: tauri-apps/tauri-action@ followed by the full 40-character SHA and a comment such as # v0.x.y.</recommendation>
</violation>
</file>
| test -s artifacts/update.json | ||
|
|
||
| - name: Create shell release | ||
| uses: softprops/action-gh-release@v2 |
There was a problem hiding this comment.
P1: Third-party release action pinned to mutable tag
action-gh-release is pinned to mutable v2 tag, risking supply chain compromise.
Pin to a full commit SHA with a version comment.
AI prompt
Check if this security scanner issue is valid. If so, understand the root cause and fix it. If appropriate, update or add tests. Keep the change focused and preserve intended behavior.
<file name=".github/workflows/shell-release.yml">
<violation number="3" location=".github/workflows/shell-release.yml:344">
<priority>P1</priority>
<title>Third-party release action pinned to mutable tag</title>
<evidence>uses: softprops/action-gh-release@v2 is pinned to a mutable major-version tag. If the action repository is compromised, the v2 tag can be force-pushed to a malicious commit, potentially leaking the GITHUB_TOKEN or modifying release assets.</evidence>
<recommendation>Pin to a specific commit SHA and append a version comment. For example, find the SHA for the intended v2.x.y release and use uses: softprops/action-gh-release@ followed by the full 40-character SHA and a comment such as # v2.x.y.</recommendation>
</violation>
</file>
| required: true | ||
| type: string | ||
|
|
||
| permissions: |
There was a problem hiding this comment.
P2: Workflow-level write permissions are overly broad
Workflow-level contents: write grants unnecessary write access to build and preflight jobs.
Restrict contents: write to the release-shell job only.
AI prompt
Check if this security scanner issue is valid. If so, understand the root cause and fix it. If appropriate, update or add tests. Keep the change focused and preserve intended behavior.
<file name=".github/workflows/shell-release.yml">
<violation number="4" location=".github/workflows/shell-release.yml:13">
<priority>P2</priority>
<title>Workflow-level write permissions are overly broad</title>
<evidence>permissions: contents: write at the workflow level grants write access to every job, including resolve-shell-ref and shell-preflight which only read source code, and build-shell which only compiles artifacts. Only the release-shell job needs contents: write to publish a GitHub release.</evidence>
<recommendation>Set permissions: {} at the workflow level and move permissions: contents: write into the release-shell job only. Grant other jobs the minimal read permissions they need, such as contents: read for actions/checkout.</recommendation>
</violation>
</file>
…er (phase-rs#7687) `detectServerUrl()` probed `http://localhost:9374/health` whenever `isTauri()` was true and returned `ws://localhost:9374/ws` on a hit. That probe served the bundled phase-server sidecar, which phase-rs#6266 (97e376a) deleted along with `services/sidecar.ts` and its `spawnSidecar(port = 9374)`; that commit touched `serverDetection.ts` only to repoint the `isTauri` import at `./platform`, so the probe outlived the thing it probed for. The current native engine reserves an ephemeral port (`native_engine.rs`) and is reached over the shell's IPC bridge (`nativeEngineSocket.ts`), never through a URL from here — so the probe can only capture an unrelated phase-server. `GameProvider.tsx` resolves the game socket through `detectServerUrl()` while the lobby, lookup and host/pregame sockets dial `serverAddress` directly. In a desktop shell on a machine running any phase-server on 9374, that split sends the game socket to the local server while everything else reaches the chosen one: a host's post-`GameStarted` socket never arrives, and a joiner's `JoinGameWithPassword` lands on a server that answers "Game not found in lobby". Matching protocol versions make the wrong handshake succeed, so the only symptom is an unexplained "connection failed". The stored-address health check goes too. It returned `stored`, and the fallback below it returns `stored` for the same input set, so it could not change the result — it only spent up to 2s of `fetch` timeout before every online connect. Assisted-by: ClaudeCode:claude-opus-5