mirror of
https://github.com/diegosouzapw/OmniRoute.git
synced 2026-07-31 04:12:10 +03:00
fix(api): migrate deprecated Codex [features].codex_hooks to [features].hooks (#4342)
Codex renamed the `codex_hooks` feature flag to `hooks`; recent Codex CLI versions ignore the old key and warn. When OmniRoute rewrites an existing config.toml (configure/reset Codex provider) it now renames [features].codex_hooks -> [features].hooks, preserving the value and never clobbering an already-present `hooks`, then drops the deprecated key. The migration is a no-op when the flag is absent and runs on both the POST and DELETE config paths. Reported-by: Bian-Sh (https://github.com/decolua/9router/issues/1327) Co-authored-by: Bian-Sh <24520547+Bian-Sh@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
55eb1b5a14
commit
d6ce094a60
@@ -14,6 +14,7 @@ _In development — bullets added per PR; finalized at release._
|
||||
### 🔒 Security
|
||||
|
||||
- **fix(mitm): exact host membership in the MITM hosts test (CodeQL false positive)** — `tests/unit/mitm-tool-hosts.test.ts` checked host membership with `Array.includes(host)`, which CodeQL's `js/incomplete-url-substring-sanitization` heuristic misreads as a `String.includes()` URL-substring sanitization test (HIGH false positive). Switched to `.some((h) => h === host)` — identical semantics, no flagged pattern. ([#4386](https://github.com/diegosouzapw/OmniRoute/pull/4386))
|
||||
- **fix(api): migrate the deprecated Codex `[features].codex_hooks` flag to `[features].hooks`** — Codex renamed the `codex_hooks` feature flag to `hooks`; recent Codex CLI versions ignore the old key and print a deprecation notice. When OmniRoute rewrites an existing `~/.codex/config.toml` (configuring/resetting the Codex provider) it now carries the user's intent forward by renaming `[features].codex_hooks` → `[features].hooks` (preserving its value, never clobbering an already-present `hooks`) and dropping the deprecated key. No-op when the flag is absent. (thanks @Bian-Sh)
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import { cliModelConfigSchema } from "@/shared/validation/schemas";
|
||||
import { isValidationFailure, validateBody } from "@/shared/validation/helpers";
|
||||
import { getApiKeyById } from "@/lib/localDb";
|
||||
import { normalizeCodexBaseUrl } from "@/shared/utils/codexBaseUrl";
|
||||
import { migrateCodexFeatureFlags } from "@/shared/utils/codexConfig";
|
||||
|
||||
const getCodexConfigPath = () => getCliConfigPaths("codex").config;
|
||||
const getCodexAuthPath = () => getCliConfigPaths("codex").auth;
|
||||
@@ -252,6 +253,9 @@ export async function POST(request: Request) {
|
||||
/* No existing config */
|
||||
}
|
||||
|
||||
// Carry the user's intent forward off the deprecated Codex feature flag (#1327).
|
||||
migrateCodexFeatureFlags(parsed);
|
||||
|
||||
// Update only OmniRoute related fields (api_key goes to auth.json, not config.toml)
|
||||
parsed._root.model = model;
|
||||
|
||||
@@ -351,6 +355,9 @@ export async function DELETE(request: Request) {
|
||||
throw error;
|
||||
}
|
||||
|
||||
// Carry the user's intent forward off the deprecated Codex feature flag (#1327).
|
||||
migrateCodexFeatureFlags(parsed);
|
||||
|
||||
// Remove OmniRoute related root fields
|
||||
delete parsed._root.openai_base_url;
|
||||
|
||||
|
||||
30
src/shared/utils/codexConfig.ts
Normal file
30
src/shared/utils/codexConfig.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
/**
|
||||
* Helpers for generating/maintaining the Codex CLI `config.toml`.
|
||||
*/
|
||||
|
||||
interface ParsedCodexToml {
|
||||
_root: Record<string, unknown>;
|
||||
_sections: Record<string, Record<string, unknown>>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Migrate the deprecated Codex `[features].codex_hooks` flag to `[features].hooks`.
|
||||
*
|
||||
* Codex renamed the feature flag; recent Codex CLI versions ignore the old key and
|
||||
* print a deprecation notice. When OmniRoute rewrites an existing `config.toml` it
|
||||
* should carry the user's intent forward by renaming the key (preserving its value)
|
||||
* and dropping the deprecated one. A no-op when `[features]` or `codex_hooks` is
|
||||
* absent, and it never clobbers an already-present `hooks` value. (#1327)
|
||||
*
|
||||
* Operates in place on the route's parsed-TOML shape (`{ _root, _sections }`).
|
||||
*/
|
||||
export function migrateCodexFeatureFlags(parsed: ParsedCodexToml): ParsedCodexToml {
|
||||
const features = parsed?._sections?.features;
|
||||
if (!features || typeof features !== "object") return parsed;
|
||||
if (!Object.prototype.hasOwnProperty.call(features, "codex_hooks")) return parsed;
|
||||
if (!Object.prototype.hasOwnProperty.call(features, "hooks")) {
|
||||
features.hooks = features.codex_hooks;
|
||||
}
|
||||
delete features.codex_hooks;
|
||||
return parsed;
|
||||
}
|
||||
32
tests/unit/codex-config-hooks-migration.test.ts
Normal file
32
tests/unit/codex-config-hooks-migration.test.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import test from "node:test";
|
||||
import assert from "node:assert/strict";
|
||||
|
||||
// Regression for port-from-9router#1327: Codex deprecated the `[features].codex_hooks`
|
||||
// flag in favor of `[features].hooks`. The codex-settings generator parses an existing
|
||||
// config.toml and writes it back but never migrated the deprecated key, so users with an
|
||||
// old config kept a key recent Codex CLI versions ignore.
|
||||
const { migrateCodexFeatureFlags } = await import("../../src/shared/utils/codexConfig.ts");
|
||||
|
||||
test("#1327: renames deprecated [features].codex_hooks to [features].hooks", () => {
|
||||
const parsed = { _root: {}, _sections: { features: { codex_hooks: true } } };
|
||||
migrateCodexFeatureFlags(parsed);
|
||||
assert.deepEqual(parsed._sections.features, { hooks: true });
|
||||
});
|
||||
|
||||
test("#1327: keeps an existing hooks value and removes the deprecated key", () => {
|
||||
const parsed = { _root: {}, _sections: { features: { codex_hooks: true, hooks: false } } };
|
||||
migrateCodexFeatureFlags(parsed);
|
||||
assert.deepEqual(parsed._sections.features, { hooks: false });
|
||||
});
|
||||
|
||||
test("#1327: leaves a config that already uses hooks untouched", () => {
|
||||
const parsed = { _root: {}, _sections: { features: { hooks: true } } };
|
||||
migrateCodexFeatureFlags(parsed);
|
||||
assert.deepEqual(parsed._sections.features, { hooks: true });
|
||||
});
|
||||
|
||||
test("#1327: no-op when there is no [features] section", () => {
|
||||
const parsed = { _root: { model: "x" }, _sections: {} };
|
||||
migrateCodexFeatureFlags(parsed);
|
||||
assert.deepEqual(parsed._sections, {});
|
||||
});
|
||||
Reference in New Issue
Block a user