Skip to content

Use Linux release assets for updater#253

Open
avifenesh wants to merge 5 commits into
ilysenko:mainfrom
avifenesh:codex/linux-release-updater-friendly
Open

Use Linux release assets for updater#253
avifenesh wants to merge 5 commits into
ilysenko:mainfrom
avifenesh:codex/linux-release-updater-friendly

Conversation

@avifenesh
Copy link
Copy Markdown
Collaborator

Summary

  • Make codex-update-manager check this repository's GitHub Releases instead of the upstream DMG URL.
  • Select the matching native package asset for the current system (.deb, .rpm, or .pkg.tar.*) and install that release asset directly.
  • Treat an empty releases feed as a clean idle state so the updater is safe before the first release is published.

Why

The updater should follow the Linux project releases as the source of truth. This keeps user updates aligned with the packages published by codex-desktop-linux, rather than rebuilding from OpenAI's macOS artifact on every client machine.

Scope

This is intentionally narrow: no feature-selection UI changes, no appcast support, and no release automation changes.

Validation

  • cargo fmt --all -- --check
  • cargo test -p codex-update-manager
  • cargo clippy --workspace --all-targets -- -D warnings
  • git diff --check
  • Smoke: codex-update-manager check-now against the live repo releases API returns idle when no releases are published yet.

@Leay15
Copy link
Copy Markdown
Collaborator

Leay15 commented May 20, 2026

@avifenesh You read my mind. I was actually thinking about publishing distro packages so it can be installed from there, and letting codex-update-manager handle all the required actions on each user's machine.

That way, we could avoid distributing OpenAI's proprietary DMG.

@avifenesh
Copy link
Copy Markdown
Collaborator Author

Screenshot From 2026-05-20 04-33-38 Screenshot From 2026-05-20 04-34-47 Screenshot From 2026-05-20 05-15-11

@avifenesh
Copy link
Copy Markdown
Collaborator Author

Screenshot From 2026-05-20 04-33-38 Screenshot From 2026-05-20 04-34-47 Screenshot From 2026-05-20 05-15-11

@Leay15 its also looks nice

@avifenesh avifenesh marked this pull request as ready for review May 20, 2026 02:30
Copy link
Copy Markdown
Owner

@ilysenko ilysenko left a comment

Choose a reason for hiding this comment

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

Thanks for the work here, but I do not think we should merge this direction.

This changes the updater source of truth from "each user downloads the official OpenAI Codex DMG and rebuilds locally" to "install Linux packages from this repository's GitHub Releases". If those release packages bundle the Codex Desktop app/resources, we would effectively be redistributing OpenAI's proprietary desktop product ourselves.

I think this repo should continue distributing only the Linux adaptation/build tooling, while the upstream Codex app is obtained from OpenAI by each user during install/update. The updater UX and feature-selection pieces may still be useful, but the public Linux release-asset install path should not land unless the release assets contain only our own code/metadata or we have explicit permission to redistribute Codex Desktop.

@avifenesh
Copy link
Copy Markdown
Collaborator Author

avifenesh commented May 20, 2026

Thanks for the work here, but I do not think we should merge this direction.

This changes the updater source of truth from "each user downloads the official OpenAI Codex DMG and rebuilds locally" to "install Linux packages from this repository's GitHub Releases". If those release packages bundle the Codex Desktop app/resources, we would effectively be redistributing OpenAI's proprietary desktop product ourselves.

I think this repo should continue distributing only the Linux adaptation/build tooling, while the upstream Codex app is obtained from OpenAI by each user during install/update. The updater UX and feature-selection pieces may still be useful, but the public Linux release-asset install path should not land unless the release assets contain only our own code/metadata or we have explicit permission to redistribute Codex Desktop.

@ilysenko
I actually built it to follow Codex upstream updates, then changed to follow the repo so I won't break the versioning.
I can change it back to follow the codex upstream and update on the user machine, but the PR will be much larger, it requires actually doing what today the repo does or the installer does.

I must say that at this point we are not really distributing even if you pull the DMG, you just align the wrapper with the version an give us an easier life. Give me a green light and I'm moving the heavy electron into Rust + GPUI, and you get almost all the advanced capabilities self-implemented anyway, while the backend interacts with Codex CLI like the real Codex app.

Screenshot From 2026-05-20 09-52-01

@avifenesh
Copy link
Copy Markdown
Collaborator Author

@ilysenko With a lot of respect of course, your repo, your rule, im adjusting myself. LMK if you want it to follow the upstream anyway. I can have two update button if it matter.

@ilysenko
Copy link
Copy Markdown
Owner

Thanks, that makes sense. I opened a discussion so we can think through the updater direction with the wider community before changing the model: #257

Copy link
Copy Markdown
Collaborator Author

@avifenesh avifenesh left a comment

Choose a reason for hiding this comment

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

Two technical findings on the updater state-machine changes, independent of the design-direction concern already raised.


1. auto_install_on_app_exit is silently broken (HIGH)

The new run_check_cycle transitions to ReadyToInstall with artifact_paths.package_path set to None (line 657). The existing reconcile_pending_install (unchanged by this PR) handles ReadyToInstall by cloning package_path and returning early if it is None (app.rs:700–702). That early return skips the auto_install_on_app_exit check entirely, so the daemon never auto-installs updates detected through the new flow.

auto_install_on_app_exit defaults to true (config.rs:89), so this regression affects most users.

The old flow worked because run_check_cycle downloaded the DMG and built the package during the check itself, so package_path was always set before the daemon's reconcile loop ran. The new flow defers package acquisition to prepare_update_package_if_needed, which is only called from run_install_ready (user-triggered), never from reconcile_pending_install.

If the intent is to keep auto-install working for the no-features case, the reconcile path needs to call prepare_update_package_if_needed (which already handles headless/no-features gracefully) instead of returning early.

2. GitHub releases API pagination not handled (MEDIUM)

fetch_remote_metadata calls GET /repos/{owner}/{repo}/releases without ?per_page=N. GitHub returns at most 30 releases per page. If the repository ever accumulates more than 30 releases, select_latest_release only sees the first page and could miss the actual latest non-prerelease.

The GitHub API returns releases newest-first by default, so the practical risk is low in the near term, but it's a latent correctness gap. A simple fix is to append ?per_page=100 to the URL (the maximum allowed), or use a higher-level strategy if the repo expects many releases.


This is an auto review done by revuto.

Comment thread updater/src/app.rs
.clone()
.expect("candidate version should be set before local build");
builder::build_update(config, state, paths, &candidate_version, &downloaded.path).await?;
state.status = UpdateStatus::ReadyToInstall;
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

The check cycle now transitions to ReadyToInstall with package_path = None (set on line 657). The existing reconcile_pending_install handles ReadyToInstall at app.rs:699–702 by cloning package_path and returning early when it is None:

UpdateStatus::ReadyToInstall => {
    let Some(package_path) = state.artifact_paths.package_path.clone() else {
        return Ok(());  // ← always taken now
    };
    // auto_install_on_app_exit check never reached
}

This silently disables auto_install_on_app_exit for the new update flow. Since auto_install_on_app_exit defaults to true, most existing users will stop receiving auto-installed updates. The daemon's reconcile loop will spin every RECONCILE_INTERVAL_SECONDS doing nothing.

If the intent is to keep auto-install working (at least for the no-features case where prepare_update_package_if_needed can download the release package without a GUI prompt), the reconcile path should call prepare_update_package_if_needed instead of returning early.


This is an auto review done by revuto.

Comment thread updater/src/upstream.rs
) -> Result<RemoteMetadata> {
let response = client
.head(dmg_url)
.get(releases_api_url)
Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

This GET request fetches the default page (30 items) from the GitHub releases API. If the repository accumulates more than 30 releases, select_latest_release may not see the actual latest non-prerelease.

Consider appending ?per_page=100 to DEFAULT_RELEASES_API_URL (or passing per_page as a query parameter here) to reduce the risk. The GitHub API maximum is 100 per page, which should be sufficient for the foreseeable lifetime of this repo.


This is an auto review done by revuto.

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.

3 participants