-
Notifications
You must be signed in to change notification settings - Fork 1.1k
fix(cli): refuse an in-place restart through a different-version CLI (carries #4529) #4545
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -732,6 +732,9 @@ function reportRestartFailure(result: Extract<ProxyRestartResult, { ok: false }> | |
| if (code === "restart_capability_unsupported") { | ||
| console.error("❌ The running proxy predates process-bound restart support; no unsafe fallback was attempted."); | ||
| console.error(" After confirming this home owns the proxy, run `ocx stop` and then `ocx start` once."); | ||
| } else if (code === "restart_version_skew") { | ||
| console.error("❌ The running proxy reports a different OpenCodex version than this CLI; restarting in place would respawn the old installation."); | ||
| console.error(" Run `ocx stop` and then `ocx start` from this installation instead."); | ||
|
Comment on lines
+735
to
+737
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win Add a CLI-path test for version-skew reporting
🤖 Prompt for AI Agents |
||
| } else { | ||
| console.error("❌ Proxy restart request could not be confirmed; no fallback stop/start was attempted."); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -22,6 +22,8 @@ import { | |
| type LiveProxy, | ||
| } from "../server/proxy-liveness"; | ||
| import type { ProxyRestartRequestOutcome } from "./tray-proxy"; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
AGENTS.md reference: src/AGENTS.md:L11-L11 Useful? React with 👍 / 👎. |
||
| import { packageVersion } from "./help"; | ||
| import { computeVersionSkew } from "./version-skew"; | ||
|
|
||
| export const SYSTEM_RESTART_REQUEST_TIMEOUT_MS = 5_000; | ||
| export const SYSTEM_RESTART_ATTESTATION_TIMEOUT_MS = 4_000; | ||
|
|
@@ -32,12 +34,23 @@ export interface BoundSystemRestartDeps { | |
| findLive?: typeof findLiveProxy; | ||
| createChallenge?: () => string; | ||
| now?: () => number; | ||
| /** Invoking CLI version for the skew guard; defaults to this bundle's package version. */ | ||
| cliVersion?: string; | ||
| } | ||
|
|
||
| function rejected(code: string): ProxyRestartRequestOutcome { | ||
| return { accepted: false, uncertain: false, error: new Error(code) }; | ||
| } | ||
|
|
||
| /** Own-bundle version for the skew comparison; an unreadable bundle is "cannot compare", not a crash. */ | ||
| function ownCliVersion(): string { | ||
| try { | ||
| return packageVersion(); | ||
| } catch { | ||
| return "unknown"; | ||
| } | ||
| } | ||
|
|
||
| function uncertain(code: string): ProxyRestartRequestOutcome { | ||
| return { accepted: false, uncertain: true, error: new Error(code) }; | ||
| } | ||
|
|
@@ -107,6 +120,18 @@ export async function requestBoundSystemRestart( | |
| return rejected("restart_capability_unsupported"); | ||
| } | ||
|
|
||
| // An in-place restart respawns the live process from its own installation | ||
| // (selfLaunchArgv in server/management/system-restart.ts), so a restart accepted | ||
| // from a different-version CLI would keep the OLD build serving while reporting | ||
| // success (#4522). Both sides already publish exactly the data doctor's skew | ||
| // diagnosis compares (packageVersion vs the /healthz version), so reuse that | ||
| // comparison and refuse before POST. Placeholder versions (unknown/0.0.0) are | ||
| // "cannot compare", not mismatch, and keep the existing behavior. | ||
| const proxyVersion = typeof body.version === "string" ? body.version : undefined; | ||
| if (computeVersionSkew(deps.cliVersion ?? ownCliVersion(), proxyVersion).skewed) { | ||
| return rejected("restart_version_skew"); | ||
|
Comment on lines
+131
to
+132
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
This adds a definite failure for an otherwise successfully attested proxy, but AGENTS.md reference: AGENTS.md:L380-L381 Useful? React with 👍 / 👎. |
||
| } | ||
|
|
||
| let observed: LiveProxy | null; | ||
| try { | ||
| observed = await (deps.findLive ?? findLiveProxy)({ deadlineAt, nowFn: now }); | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When this CLI is older than a standalone live proxy—for example CLI 2.54 with proxy 2.55—this message instructs the operator to stop the newer proxy and start this older installation, effectively downgrading it. That contradicts
computeVersionSkew(), which correctly tells an older CLI to upgrade or resolvePATH; preserve the skew direction in the rejection so only the newer-CLI/older-proxy case recommends stop/start.Useful? React with 👍 / 👎.