Skip to content

feat(desktop): persisted release/preview channel selection with deliberate manifest publication - #6268

Merged
matthewevans merged 1 commit into
mainfrom
ship/channel-selection
Jul 21, 2026
Merged

feat(desktop): persisted release/preview channel selection with deliberate manifest publication#6268
matthewevans merged 1 commit into
mainfrom
ship/channel-selection

Conversation

@matthewevans

Copy link
Copy Markdown
Member

Shell: persist typed release/preview channel preference and return it with migration state.

Bootstrap: select and probe the persisted channel in its single IPC roundtrip.

Client: remember remote-shell channel switches and provide a localized return-to-release badge.

CI: publish the updater manifest only through an explicit, validated dispatch workflow.

…erate manifest publication

Shell: persist typed release/preview channel preference and return it with migration state.

Bootstrap: select and probe the persisted channel in its single IPC roundtrip.

Client: remember remote-shell channel switches and provide a localized return-to-release badge.

CI: publish the updater manifest only through an explicit, validated dispatch workflow.
@matthewevans
matthewevans enabled auto-merge July 21, 2026 10:24

@superagent-security superagent-security Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Superagent found 1 security concern(s).

TAG: ${{ inputs.tag }}
GH_TOKEN: ${{ github.token }}
steps:
- uses: actions/checkout@v4

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1: Workflow uses unpinned GitHub Actions in sensitive publish workflow

Publish workflow references actions by mutable tag instead of pinned SHA.

Pin actions/checkout and actions/setup-node to full commit SHAs with version comments.

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/publish-shell-manifest.yml">
<violation number="1" location=".github/workflows/publish-shell-manifest.yml:26">
<priority>P1</priority>
<title>Workflow uses unpinned GitHub Actions in sensitive publish workflow</title>
<evidence>The publish-shell-manifest.yml workflow references actions by mutable version tags (actions/checkout@v4 at line 26 and actions/setup-node@v4 at line 43) instead of full-length commit SHAs. This workflow handles the CLOUDFLARE_API_TOKEN and CLOUDFLARE_ACCOUNT_ID secrets, and a tag reference can be moved to point at a different commit, so a compromised or moved tag could run untrusted code with access to those credentials.</evidence>
<recommendation>Pin both actions to full-length commit SHAs with version comments, e.g. uses: actions/checkout@&lt;full-sha&gt; # v4.1.1 and uses: actions/setup-node@&lt;full-sha&gt; # v4.0.3. SHA-pinning prevents a moved tag from running untrusted code with access to the Cloudflare publish credentials.</recommendation>
</violation>
</file>

@gemini-code-assist gemini-code-assist 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.

Code Review

This pull request introduces support for persisting and navigating between different remote content channels ('release' and 'preview') in the Tauri desktop application. It updates the bootstrap process, adds Rust-side commands to store and retrieve channel preferences, and introduces a PreviewBadge component in the frontend for channel switching. Feedback focuses on adhering to the repository's architectural rule R2 by replacing boolean fields (such as remote_load_ok) with typed enums or unions in both Rust and TypeScript, and optimizing the PreviewBadge component to avoid instantiating new URL on every render.

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.

Comment on lines +26 to +29
pub struct StashLegacyStorageResult {
pub remote_load_ok: bool,
pub channel: Channel,
}

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.

medium

[MEDIUM] Avoid bool fields on structs per R2. Evidence: client/src-tauri/src/migration.rs:26-29.

Why it matters: Boolean fields do not express the design space as clearly as typed enums and violate the repository's hard architectural rules.

Suggested fix: Replace remote_load_ok: bool with a typed enum such as RemoteLoadStatus.

/// The remote load status of the shell.
#[derive(Clone, Copy, Debug, Default, Deserialize, PartialEq, Eq, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum RemoteLoadStatus {
    #[default]
    Pending,
    Success,
}

/// The bootstrap's one-roundtrip migration and remote-navigation state.
#[derive(Debug, PartialEq, Eq, Serialize)]
pub struct StashLegacyStorageResult {
    pub remote_load_status: RemoteLoadStatus,
    pub channel: Channel,
}
References
  1. A bool field never expresses the design space; the project uses typed enums like ControllerRef, Comparator, PlayerScope, Option<T>, and dedicated discriminated unions instead. (link)

Comment on lines +131 to +135
let remote_load_ok = stage_legacy_storage_marker(files, json)?;
Ok(StashLegacyStorageResult {
remote_load_ok,
channel: read_channel_preference(files),
})

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.

medium

[MEDIUM] Update stage_legacy_storage to use the new RemoteLoadStatus enum. Evidence: client/src-tauri/src/migration.rs:131-135.

Why it matters: This aligns the implementation with the R2-compliant RemoteLoadStatus enum instead of using a raw boolean.

Suggested fix: Map the boolean result of stage_legacy_storage_marker to the RemoteLoadStatus enum.

    let remote_load_ok = stage_legacy_storage_marker(files, json)?;
    let remote_load_status = if remote_load_ok {
        RemoteLoadStatus::Success
    } else {
        RemoteLoadStatus::Pending
    };
    Ok(StashLegacyStorageResult {
        remote_load_status,
        channel: read_channel_preference(files),
    })

Comment on lines +13 to +16
interface LegacyStorageResult {
remote_load_ok: boolean;
channel: Channel;
}

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.

medium

[MEDIUM] Avoid bool fields in shared state per R2. Evidence: client/bootstrap/bootstrap.ts:13-16.

Why it matters: Using a boolean field for remote load status violates the repository's architectural rule R2 and doesn't scale as well as a typed enum.

Suggested fix: Replace remote_load_ok: boolean with a typed enum/union RemoteLoadStatus = "pending" | "success".

Suggested change
interface LegacyStorageResult {
remote_load_ok: boolean;
channel: Channel;
}
type RemoteLoadStatus = "pending" | "success";
interface LegacyStorageResult {
remote_load_status: RemoteLoadStatus;
channel: Channel;
}
References
  1. A bool field never expresses the design space; the project uses typed enums like ControllerRef, Comparator, PlayerScope, Option<T>, and dedicated discriminated unions instead. (link)

Comment on lines +58 to 64
const { remote_load_ok: remoteLoadOk, channel } = await stashLegacyStorage();
const destination = channelUrl(channel);

if (await remoteLoadSucceededBefore()) {
location.replace(channelUrl);
if (remoteLoadOk) {
location.replace(destination);
return;
}

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.

medium

[MEDIUM] Update the bootstrap navigation check to use the new remote_load_status enum. Evidence: client/bootstrap/bootstrap.ts:58-64.

Why it matters: This aligns the client-side bootstrap with the R2-compliant RemoteLoadStatus enum.

Suggested fix: Check if remote_load_status is "success" instead of a boolean.

Suggested change
const { remote_load_ok: remoteLoadOk, channel } = await stashLegacyStorage();
const destination = channelUrl(channel);
if (await remoteLoadSucceededBefore()) {
location.replace(channelUrl);
if (remoteLoadOk) {
location.replace(destination);
return;
}
const { remote_load_status, channel } = await stashLegacyStorage();
const destination = channelUrl(channel);
if (remote_load_status === "success") {
location.replace(destination);
return;
}

Comment on lines +34 to +35
const isPreviewRemoteShell =
isRemoteTauriShell && window.location.origin === new URL(__PREVIEW_SITE_URL__).origin;

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.

medium

[MEDIUM] Avoid instantiating new URL on every render of PreviewBadge. Evidence: client/src/components/chrome/PreviewBadge.tsx:34-35.

Why it matters: Creating a new URL object on every render is inefficient and can be easily avoided since __PREVIEW_SITE_URL__ is a static string with no trailing slash or path.

Suggested fix: Directly compare window.location.origin with __PREVIEW_SITE_URL__.

Suggested change
const isPreviewRemoteShell =
isRemoteTauriShell && window.location.origin === new URL(__PREVIEW_SITE_URL__).origin;
const isPreviewRemoteShell =
isRemoteTauriShell && window.location.origin === __PREVIEW_SITE_URL__;

@superagent-security superagent-security Bot added the pr:flagged Superagent: PR flagged for security review label Jul 21, 2026
@matthewevans
matthewevans added this pull request to the merge queue Jul 21, 2026
Merged via the queue into main with commit 58fc112 Jul 21, 2026
12 of 13 checks passed
@matthewevans
matthewevans deleted the ship/channel-selection branch July 21, 2026 11:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:flagged Superagent: PR flagged for security review

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant