Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 10 additions & 2 deletions scripts/diagnostics/windows-version-control/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
# Windows synchronous runtime-selection control

This optional Rust control exercises `GET /v1/models` in a separate Bun process
using the repository's unchanged `tests/helpers/native-main-owner-child.ts`.
using the repository's `tests/helpers/native-main-owner-child.ts`.
It does not connect to a running proxy, install accounts, or replay turns.
It is a reproducer, not a runtime fix or proof of a historical production cause.

Expand All @@ -10,6 +10,14 @@ authentication values, and an ephemeral loopback listener. It is configured
with no real credentials and one unavailable loopback provider. Other network
egress is not blocked or audited.

Every native-owner fixture server injects `nativeOwnerRestartService` from
`tests/helpers/native-owner-restart-service.ts`. Codex desktop/app-server state
queries return a synthetic unknown result and restart requests fail without
catalog synchronization, host process enumeration or process signalling. This
boundary applies even when a client presents the fixture authentication values;
redirected homes and descendant Jobs alone are not process-control isolation.
The diagnostic's model-list and native-profile operations are unchanged.

```powershell
cargo test --locked --manifest-path scripts/diagnostics/windows-version-control/Cargo.toml --test async_contracts -- --test-threads=4
cargo clippy --locked --manifest-path scripts/diagnostics/windows-version-control/Cargo.toml --all-targets -- -D warnings
Expand Down Expand Up @@ -54,7 +62,7 @@ call chain. Keep profiles and fixture artifacts private; publish bounded scalar
results and repository-relative function names instead.

To compare installed source with the repository fixture, use a separately owned
scratch mirror containing a byte-identical copy of the helper and package
scratch mirror containing byte-identical copies of both helper files and package
metadata, with `src` and `node_modules` links to the desired installation.
The fixture must perform no writes to that installation. Links alone do not
enforce read-only access. Verify the profile's source module paths and source
Expand Down
110 changes: 110 additions & 0 deletions tests/codex-integration/codex-restart-route.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
* Plan: devlog/_fin/260815_gui_codex_restart/010_phase1_backend_endpoint.md
*/
import { describe, expect, test } from "bun:test";
import { mkdtempSync, readFileSync, rmSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { startServer } from "../../src/server";
import { helperPath } from "../helpers/repo-root";
import { nativeOwnerRestartService, NATIVE_OWNER_RESTART_REFUSAL } from "../helpers/native-owner-restart-service";
import { handleSystemRoutes } from "../../src/server/management/system-routes";
import type { ManagementContext } from "../../src/server/management/context";
import {
Expand Down Expand Up @@ -162,3 +168,107 @@ describe("POST /api/system/codex-restart", () => {
});
});


describe("native-owner fixture process-control boundary", () => {
test("the fixture installs its non-operating service on the common server startup path", () => {
// This source-wiring guard complements the real route dispatch checks below. Do not import
// the helper here: its top level starts a server and reads the stdin control protocol.
const source = readFileSync(helperPath("native-main-owner-child.ts"), "utf8");
const from = source.indexOf("function start(");
const to = source.indexOf("const primary = start();");
expect(from).toBeGreaterThanOrEqual(0);
expect(to).toBeGreaterThan(from);
expect(source.slice(from, to)).toContain("codexRestartService: nativeOwnerRestartService");
});

test("state queries use a synthetic unknown result without host process enumeration", async () => {
const response = await handleSystemRoutes(contextFor(CODEX_APP_SERVER_STATE_PATH, "GET", nativeOwnerRestartService));
expect(response?.status).toBe(200);
expect(await response!.json()).toEqual({ state: "unknown", runningCount: 0 });
});

test("restart is refused instead of invoking the live service or claiming a successful restart", async () => {
await expect(handleSystemRoutes(contextFor(CODEX_RESTART_PATH, "POST", nativeOwnerRestartService)))
.rejects.toThrow(NATIVE_OWNER_RESTART_REFUSAL);
// A refused call does not poison a later read or make the next restart succeed.
expect(await nativeOwnerRestartService.readState()).toEqual({ state: "unknown", runningCount: 0 });
await expect(nativeOwnerRestartService.performRestart()).rejects.toThrow(NATIVE_OWNER_RESTART_REFUSAL);
});

test("servers on the common startup path serve the injected service over authenticated HTTP", async () => {
// The child's start() is a thin wrapper over this same startServer call: driving real
// listeners proves the managementApi -> ctx.deps forwarding cannot silently drop the
// boundary while the source guard above still passes. Primary and extra fixture
// servers share one injection path, so both are exercised here. The sentinel restart
// body is one the live implementation could never emit: it does not fabricate a pid.
const root = mkdtempSync(join(tmpdir(), "ocx-restart-boundary-"));
const previousHome = process.env.OPENCODEX_HOME;
const previousCodexHome = process.env.CODEX_HOME;
const previousAdminToken = process.env.OPENCODEX_ADMIN_AUTH_TOKEN;
process.env.OPENCODEX_HOME = root;
process.env.CODEX_HOME = root;
process.env.OPENCODEX_ADMIN_AUTH_TOKEN = "restart-boundary-admin";
const sentinel: CodexRestartResponse = {
success: true,
stateBefore: "unknown",
synced: false,
requested: [424242],
stopped: [424242],
surviving: [],
failed: [],
code: "stopped",
};
const calls: string[] = [];
const observed = {
readState: async () => {
calls.push("readState");
return nativeOwnerRestartService.readState();
},
performRestart: async () => {
calls.push("performRestart");
return sentinel;
},
};
// startServer probes service ownership on every boot; without this seam it inspects the
// developer machine's installed service state — the host coupling this fixture exists to
// remove (the same seam native-main-owner-child.ts injects). "foreign" is deliberate: it
// fences native-main admission with no lifecycle machinery, which this restart-route test
// does not exercise; "owned" would start a real owner drive on the fixture home.
const deps = {
inspectNativeCodexOwnership: () => ({
ownership: "foreign",
reason: "restart route test fixture",
}),
managementApi: { codexRestartService: observed },
};
const primary = startServer(0, deps);
const extra = startServer(0, deps);
try {
const headers = { "x-opencodex-api-key": "restart-boundary-admin" };
for (const server of [primary, extra]) {
const state = await fetch(new URL(CODEX_APP_SERVER_STATE_PATH, server.url), { headers });
expect(state.status).toBe(200);
expect(await state.json()).toEqual({ state: "unknown", runningCount: 0 });
const restart = await fetch(new URL(CODEX_RESTART_PATH, server.url), { method: "POST", headers });
expect(restart.status).toBe(200);
expect(await restart.json()).toEqual(sentinel);
}
expect(calls).toEqual([
"readState", "performRestart",
"readState", "performRestart",
]);
} finally {
await primary.stop(true);
await extra.stop(true);
for (const [name, value] of [
["OPENCODEX_HOME", previousHome],
["CODEX_HOME", previousCodexHome],
["OPENCODEX_ADMIN_AUTH_TOKEN", previousAdminToken],
] as const) {
if (value === undefined) delete process.env[name];
else process.env[name] = value;
}
rmSync(root, { recursive: true, force: true, maxRetries: 10, retryDelay: 50 });
}
});
});
5 changes: 4 additions & 1 deletion tests/helpers/native-main-owner-child.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {
import type { NativeProfileKey, NativeProfileKeyProvider } from "../../src/codex/native-profile-types";
import { drainAndShutdown } from "../../src/server";
import { startServer } from "../../src/server";
import { nativeOwnerRestartService } from "./native-owner-restart-service";

const required = (name: string): string => {
const value = process.env[name];
Expand Down Expand Up @@ -137,7 +138,9 @@ function start(home = codexHome): ReturnType<typeof startServer> {
}
: undefined,
},
managementApi: { nativeProfileApi: { manager } },
// Synthetic homes do not isolate OS process-control APIs. Every server, including extra
// fixture instances, must inject the entire restart service rather than using live defaults.
managementApi: { nativeProfileApi: { manager }, codexRestartService: nativeOwnerRestartService },
});
servers.push(server);
return server;
Expand Down
17 changes: 17 additions & 0 deletions tests/helpers/native-owner-restart-service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/** The native-owner fixture must not enumerate or restart the operator's desktop. */
import type {
CodexAppServerStateResponse,
CodexRestartResponse,
} from "../../src/lib/codex-restart-contract";

export const NATIVE_OWNER_RESTART_REFUSAL = "Codex desktop restart is disabled in the native-owner fixture";

/** Complete service injection: neither state reads nor restart requests reach production I/O. */
export const nativeOwnerRestartService = Object.freeze({
async readState(): Promise<CodexAppServerStateResponse> {
return { state: "unknown", runningCount: 0 };
},
async performRestart(): Promise<CodexRestartResponse> {
throw new Error(NATIVE_OWNER_RESTART_REFUSAL);
},
});
Loading