feat(codex): support app-server secret refs (#94324)

Co-authored-by: kevinlin-openai <kevin@dendron.so>
This commit is contained in:
kevinlin-openai
2026-06-18 20:10:11 -07:00
committed by GitHub
parent a1b7118d0f
commit 741f7080a7
12 changed files with 397 additions and 22 deletions
+11 -7
View File
@@ -91,8 +91,8 @@ Supported `appServer` fields:
| `command` | managed Codex binary | Executable for stdio transport. Leave unset to use the managed binary. |
| `args` | `["app-server", "--listen", "stdio://"]` | Arguments for stdio transport. |
| `url` | unset | WebSocket app-server URL. |
| `authToken` | unset | Bearer token for WebSocket transport. |
| `headers` | `{}` | Extra WebSocket headers. |
| `authToken` | unset | Bearer token for WebSocket transport. Accepts a literal string or SecretInput such as `${CODEX_APP_SERVER_TOKEN}`. |
| `headers` | `{}` | Extra WebSocket headers. Header values accept literal strings or SecretInput values, for example `x-codex-client-session-token: "${CODEX_CLIENT_SESSION_TOKEN}"`. |
| `clearEnv` | `[]` | Extra environment variable names removed from the spawned stdio app-server process after OpenClaw builds its inherited environment. |
| `remoteWorkspaceRoot` | unset | Remote Codex app-server workspace root. When set, OpenClaw infers the local workspace root from the resolved OpenClaw workspace, preserves the current cwd suffix under this remote root, and sends only the final app-server cwd to Codex. If the cwd is outside the resolved OpenClaw workspace root, OpenClaw fails closed instead of sending a gateway-local path to the remote app-server. |
| `requestTimeoutMs` | `60000` | Timeout for app-server control-plane calls. |
@@ -149,11 +149,15 @@ must report stable version `0.125.0` or newer.
OpenClaw treats non-loopback WebSocket app-server URLs as remote and requires
identity-bearing WebSocket auth through `appServer.authToken` or an
`Authorization` header. When native Codex plugins are configured, OpenClaw uses
the connected app-server's plugin control plane to install or refresh those
plugins and then refreshes app inventory so plugin-owned apps are visible to the
Codex thread. Only connect OpenClaw to remote app-servers that are trusted to
accept OpenClaw-managed plugin installs and app inventory refreshes.
`Authorization` header. `appServer.authToken` and each `appServer.headers.*`
value can be a SecretInput; the secrets runtime resolves SecretRefs and env
shorthand before OpenClaw builds app-server start options, and unresolved
structured SecretRefs fail before any token or header is sent. When native Codex
plugins are configured, OpenClaw uses the connected app-server's plugin control
plane to install or refresh those plugins and then refreshes app inventory so
plugin-owned apps are visible to the Codex thread. Only connect OpenClaw to
remote app-servers that are trusted to accept OpenClaw-managed plugin installs
and app inventory refreshes.
## Approval and sandbox modes
+2 -2
View File
@@ -552,8 +552,8 @@ Supported `appServer` fields:
| `command` | managed Codex binary | Executable for stdio transport. Leave unset to use the managed binary; set it only for an explicit override. |
| `args` | `["app-server", "--listen", "stdio://"]` | Arguments for stdio transport. |
| `url` | unset | WebSocket app-server URL. |
| `authToken` | unset | Bearer token for WebSocket transport. |
| `headers` | `{}` | Extra WebSocket headers. |
| `authToken` | unset | Bearer token for WebSocket transport. Accepts a literal string or SecretInput such as `${CODEX_APP_SERVER_TOKEN}`. |
| `headers` | `{}` | Extra WebSocket headers. Header values accept literal strings or SecretInput values, for example `x-codex-client-session-token: "${CODEX_CLIENT_SESSION_TOKEN}"`. |
| `clearEnv` | `[]` | Extra environment variable names removed from the spawned stdio app-server process after OpenClaw builds its inherited environment. OpenClaw keeps per-agent `CODEX_HOME` and inherited `HOME` for local launches. |
| `codeModeOnly` | `false` | Opt into Codex's code-mode-only tool surface. OpenClaw dynamic tools remain registered with Codex so nested `tools.*` calls return through the app-server `item/tool/call` bridge. |
| `remoteWorkspaceRoot` | unset | Remote Codex app-server workspace root. When set, OpenClaw infers the local workspace root from the resolved OpenClaw workspace, preserves the current cwd suffix under this remote root, and sends only the final app-server cwd to Codex. If the cwd is outside the resolved OpenClaw workspace root, OpenClaw fails closed instead of sending a gateway-local path to the remote app-server. |
@@ -43,6 +43,8 @@ Scope intent:
- `tools.web.fetch.firecrawl.apiKey`
- `plugins.entries.acpx.config.mcpServers.*.env.*`
- `plugins.entries.brave.config.webSearch.apiKey`
- `plugins.entries.codex.config.appServer.authToken`
- `plugins.entries.codex.config.appServer.headers.*`
- `plugins.entries.exa.config.webSearch.apiKey`
- `plugins.entries.google-meet.config.realtime.providers.*.apiKey`
- `plugins.entries.google.config.webSearch.apiKey`
@@ -554,6 +554,20 @@
"secretShape": "secret_input",
"optIn": true
},
{
"id": "plugins.entries.codex.config.appServer.authToken",
"configFile": "openclaw.json",
"path": "plugins.entries.codex.config.appServer.authToken",
"secretShape": "secret_input",
"optIn": true
},
{
"id": "plugins.entries.codex.config.appServer.headers.*",
"configFile": "openclaw.json",
"path": "plugins.entries.codex.config.appServer.headers.*",
"secretShape": "secret_input",
"optIn": true
},
{
"id": "plugins.entries.exa.config.webSearch.apiKey",
"configFile": "openclaw.json",
+11 -2
View File
@@ -152,10 +152,10 @@
]
},
"url": { "type": "string" },
"authToken": { "type": "string" },
"authToken": { "type": ["string", "object"] },
"headers": {
"type": "object",
"additionalProperties": { "type": "string" }
"additionalProperties": { "type": ["string", "object"] }
},
"clearEnv": {
"type": "array",
@@ -254,6 +254,14 @@
}
}
},
"configContracts": {
"secretInputs": {
"paths": [
{ "path": "appServer.authToken", "expected": "string" },
{ "path": "appServer.headers.*", "expected": "string" }
]
}
},
"uiHints": {
"codexDynamicToolsLoading": {
"label": "Dynamic Tools Loading",
@@ -382,6 +390,7 @@
"appServer.headers": {
"label": "Headers",
"help": "Additional headers sent to the WebSocket app-server.",
"sensitive": true,
"advanced": true
},
"appServer.clearEnv": {
@@ -28,6 +28,10 @@ function resolveRuntimeForTest(params: RuntimeOptionsParams = {}) {
return resolveCodexAppServerRuntimeOptions({ env: {}, requirementsToml: null, ...params });
}
function envRef(id: string) {
return { source: "env" as const, provider: "default", id };
}
function requireRecord(value: unknown, label: string): Record<string, unknown> {
if (!value || typeof value !== "object" || Array.isArray(value)) {
throw new Error(`Expected ${label}`);
@@ -413,6 +417,65 @@ describe("Codex app-server config", () => {
});
});
it("passes resolved app-server SecretInput strings through to auth token and headers", () => {
const runtime = resolveRuntimeForTest({
pluginConfig: {
appServer: {
transport: "websocket",
url: "wss://codex-app-server.example.internal/ws",
authToken: " resolved-capability-token ",
headers: {
" x-codex-client-session-token ": " resolved-session-token ",
Authorization: " Bearer explicit-token ",
},
},
},
});
expectFields(runtime.start, "runtime start", {
authToken: "resolved-capability-token",
headers: {
"x-codex-client-session-token": "resolved-session-token",
Authorization: "Bearer explicit-token",
},
});
});
it("rejects unresolved app-server auth token SecretRefs at runtime option resolution", () => {
expect(() =>
resolveRuntimeForTest({
pluginConfig: {
appServer: {
transport: "websocket",
url: "wss://codex-app-server.example.internal/ws",
authToken: envRef("CODEX_APP_SERVER_TOKEN"),
},
},
}),
).toThrow(
'plugins.entries.codex.config.appServer.authToken: unresolved SecretRef "env:default:CODEX_APP_SERVER_TOKEN"',
);
});
it("rejects unresolved app-server header SecretRefs at runtime option resolution", () => {
expect(() =>
resolveRuntimeForTest({
pluginConfig: {
appServer: {
transport: "websocket",
url: "wss://codex-app-server.example.internal/ws",
authToken: "capability-token",
headers: {
"x-codex-client-session-token": envRef("CODEX_CLIENT_SESSION_TOKEN"),
},
},
},
}),
).toThrow(
'plugins.entries.codex.config.appServer.headers.x-codex-client-session-token: unresolved SecretRef "env:default:CODEX_CLIENT_SESSION_TOKEN"',
);
});
it("treats IPv6 loopback websocket app-servers as local loopback", () => {
const runtime = resolveRuntimeForTest({
pluginConfig: {
@@ -2314,6 +2377,47 @@ allowed_sandbox_modes = ["read-only", "workspace-write"]
expect(second).not.toContain("sk-second");
});
it("derives distinct shared-client keys for distinct headers without exposing them", () => {
const first = codexAppServerStartOptionsKey({
transport: "websocket",
command: "codex",
args: [],
url: "ws://127.0.0.1:39175",
headers: {
Authorization: "Bearer first",
"x-codex-client-session-token": "session-first",
},
});
const second = codexAppServerStartOptionsKey({
transport: "websocket",
command: "codex",
args: [],
url: "ws://127.0.0.1:39175",
headers: {
Authorization: "Bearer second",
"x-codex-client-session-token": "session-second",
},
});
expect(first).not.toEqual(second);
expect(
codexAppServerStartOptionsKey({
transport: "websocket",
command: "codex",
args: [],
url: "ws://127.0.0.1:39175",
headers: {
Authorization: "Bearer first",
"x-codex-client-session-token": "session-first",
},
}),
).toEqual(first);
expect(first).not.toContain("Bearer first");
expect(first).not.toContain("session-first");
expect(second).not.toContain("Bearer second");
expect(second).not.toContain("session-second");
});
it("keeps secret-derived shared-client keys stable across module reloads", async () => {
const startOptions = {
transport: "websocket" as const,
+34 -9
View File
@@ -13,6 +13,11 @@ import {
} from "openclaw/plugin-sdk/exec-approvals-runtime";
import { resolvePositiveTimerTimeoutMs } from "openclaw/plugin-sdk/number-runtime";
import { normalizeAgentId } from "openclaw/plugin-sdk/routing";
import {
buildSecretInputSchema,
normalizeResolvedSecretInputString,
type SecretInput,
} from "openclaw/plugin-sdk/secret-input";
import { normalizeTrimmedStringList } from "openclaw/plugin-sdk/string-coerce-runtime";
import { detectWindowsSpawnCommandInlineArgs } from "openclaw/plugin-sdk/windows-spawn";
import { z } from "zod";
@@ -211,8 +216,8 @@ export type CodexPluginConfig = {
command?: string;
args?: string[] | string;
url?: string;
authToken?: string;
headers?: Record<string, string>;
authToken?: SecretInput;
headers?: Record<string, SecretInput>;
clearEnv?: string[];
remoteWorkspaceRoot?: string;
codeModeOnly?: boolean;
@@ -294,6 +299,7 @@ const DEFAULT_CODEX_COMPUTER_USE_MARKETPLACE_DISCOVERY_TIMEOUT_MS = 60_000;
const DEFAULT_CODEX_APP_SERVER_NETWORK_PROXY_PROFILE_PREFIX = "openclaw-network";
const codexAppServerTransportSchema = z.enum(["stdio", "websocket"]);
const SecretInputSchema = buildSecretInputSchema();
const codexAppServerPolicyModeSchema = z.enum(["yolo", "guardian"]);
const codexAppServerApprovalPolicySchema = z.enum([
"never",
@@ -387,8 +393,8 @@ const codexPluginConfigSchema = z
command: z.string().optional(),
args: z.union([z.array(z.string()), z.string()]).optional(),
url: z.string().optional(),
authToken: z.string().optional(),
headers: z.record(z.string(), z.string()).optional(),
authToken: SecretInputSchema.optional(),
headers: z.record(z.string(), SecretInputSchema).optional(),
clearEnv: z.array(z.string()).optional(),
remoteWorkspaceRoot: codexAppServerRemoteWorkspaceRootSchema.optional(),
codeModeOnly: z.boolean().optional(),
@@ -531,7 +537,10 @@ export function resolveCodexAppServerRuntimeOptions(
const args = resolveArgs(config.args, env.OPENCLAW_CODEX_APP_SERVER_ARGS);
const headers = normalizeHeaders(config.headers);
const clearEnv = normalizeStringList(config.clearEnv);
const authToken = readNonEmptyString(config.authToken);
const authToken = normalizeCodexAppServerSecretInput({
value: config.authToken,
path: "plugins.entries.codex.config.appServer.authToken",
});
const url = readNonEmptyString(config.url);
const connectionClass = inferCodexAppServerConnectionClass({ transport, url });
const remoteAppsSubstrate: CodexAppServerRemoteAppsSubstrate = "preconfigured";
@@ -868,9 +877,9 @@ export function codexAppServerStartOptionsKey(
args: options.args,
url: options.url ?? null,
authToken: hashSecretForKey(options.authToken, "authToken"),
headers: Object.entries(options.headers).toSorted(([left], [right]) =>
left.localeCompare(right),
),
headers: Object.entries(options.headers)
.toSorted(([left], [right]) => left.localeCompare(right))
.map(([key, value]) => [key, hashSecretForKey(value, `header:${key}`)]),
env: Object.entries(options.env ?? {})
.toSorted(([left], [right]) => left.localeCompare(right))
.map(([key, value]) => [key, hashSecretForKey(value, `env:${key}`)]),
@@ -2037,11 +2046,27 @@ function normalizeHeaders(value: unknown): Record<string, string> {
}
return Object.fromEntries(
Object.entries(value)
.map(([key, child]) => [key.trim(), readNonEmptyString(child)] as const)
.map(
([key, child]) =>
[
key.trim(),
normalizeCodexAppServerSecretInput({
value: child,
path: `plugins.entries.codex.config.appServer.headers.${key}`,
}),
] as const,
)
.filter((entry): entry is readonly [string, string] => Boolean(entry[0] && entry[1])),
);
}
function normalizeCodexAppServerSecretInput(params: {
value: unknown;
path: string;
}): string | undefined {
return normalizeResolvedSecretInputString(params);
}
function normalizeStringList(value: unknown): string[] {
return normalizeTrimmedStringList(value);
}
+10
View File
@@ -1,6 +1,7 @@
/** Resolves plugin config contract metadata for scanners and secret/config policy checks. */
import { normalizeSortedUniqueStringEntries } from "@openclaw/normalization-core/string-normalization";
import type { OpenClawConfig } from "../config/types.openclaw.js";
import { findBundledPluginMetadataById } from "./bundled-plugin-metadata.js";
import { discoverOpenClawPlugins, type PluginDiscoveryResult } from "./discovery.js";
import { loadPluginManifestRegistry } from "./manifest-registry.js";
import type { PluginManifestConfigContracts } from "./manifest.js";
@@ -60,6 +61,15 @@ export function resolvePluginConfigContractsById(params: {
for (const plugin of registry.plugins) {
bundledContractFallbacks.set(plugin.id, plugin.configContracts);
}
if (bundledContractFallbacks.get(pluginId) === undefined) {
const bundledMetadata = findBundledPluginMetadataById(pluginId, {
includeChannelConfigs: false,
includeSyntheticChannelConfigs: false,
});
if (bundledMetadata?.manifest.configContracts) {
bundledContractFallbacks.set(pluginId, bundledMetadata.manifest.configContracts);
}
}
if (!bundledContractFallbacks.has(pluginId)) {
bundledContractFallbacks.set(pluginId, undefined);
}
@@ -13,6 +13,86 @@ function envRef(id: string) {
}
describe("collectPluginConfigAssignments bundled plugin manifests", () => {
it("collects Codex app-server SecretRefs from bundled manifest contracts", () => {
expect(
findBundledPluginMetadataById("codex", {
includeChannelConfigs: false,
includeSyntheticChannelConfigs: false,
})?.manifest.configContracts?.secretInputs?.paths,
).toEqual([
{ path: "appServer.authToken", expected: "string" },
{ path: "appServer.headers.*", expected: "string" },
]);
const config = {
plugins: {
entries: {
codex: {
enabled: true,
config: {
appServer: {
transport: "websocket",
url: "wss://codex-app-server.example.internal/ws",
authToken: "$CODEX_APP_SERVER_TOKEN",
headers: {
Authorization: "Bearer literal-token",
"x-codex-client-session-token": envRef("CODEX_CLIENT_SESSION_TOKEN"),
},
},
},
},
},
},
} as OpenClawConfig;
expect(
resolvePluginConfigContractsById({
config,
workspaceDir: resolveAgentWorkspaceDir(config, resolveDefaultAgentId(config)),
env: {},
fallbackToBundledMetadata: true,
fallbackToBundledMetadataForResolvedBundled: true,
pluginIds: ["codex"],
fallbackBundledPluginIds: ["codex"],
}).get("codex")?.configContracts.secretInputs?.paths,
).toEqual([
{ path: "appServer.authToken", expected: "string" },
{ path: "appServer.headers.*", expected: "string" },
]);
const context = createResolverContext({
sourceConfig: config,
env: {},
});
collectPluginConfigAssignments({
config,
defaults: undefined,
context,
loadablePluginOrigins: new Map([["codex", "bundled"]]),
});
expect({
assignments: context.assignments.map((assignment) => assignment.path).toSorted(),
warnings: context.warnings,
}).toEqual({
assignments: [
"plugins.entries.codex.config.appServer.authToken",
"plugins.entries.codex.config.appServer.headers.x-codex-client-session-token",
],
warnings: [],
});
context.assignments[0]?.apply("resolved-app-server-token");
context.assignments[1]?.apply("resolved-session-token");
expect(config.plugins?.entries?.codex?.config).toMatchObject({
appServer: {
authToken: "resolved-app-server-token",
headers: {
Authorization: "Bearer literal-token",
"x-codex-client-session-token": "resolved-session-token",
},
},
});
});
it("collects voice-call SecretRef assignments from bundled manifest contracts", () => {
expect(
findBundledPluginMetadataById("voice-call", {
+79
View File
@@ -3,8 +3,15 @@ import { describe, expect, it } from "vitest";
import { asConfig, setupSecretsRuntimeSnapshotTestHooks } from "./runtime.test-support.ts";
const EMPTY_LOADABLE_PLUGIN_ORIGINS = new Map();
const BUNDLED_CODEX_PLUGIN_ORIGINS = new Map([["codex", "bundled" as const]]);
const { prepareSecretsRuntimeSnapshot } = setupSecretsRuntimeSnapshotTestHooks();
const CODEX_APP_SERVER_TOKEN_REF = {
source: "env",
provider: "default",
id: "CODEX_APP_SERVER_TOKEN",
} as const;
function expectWarning(
snapshot: Awaited<ReturnType<typeof prepareSecretsRuntimeSnapshot>>,
expected: { code: string; path: string },
@@ -90,6 +97,78 @@ describe("secrets runtime snapshot", () => {
});
});
it("resolves active bundled Codex app-server plugin SecretRefs", async () => {
const snapshot = await prepareSecretsRuntimeSnapshot({
config: asConfig({
plugins: {
entries: {
codex: {
enabled: true,
config: {
appServer: {
transport: "websocket",
url: "wss://codex-app-server.example.internal/ws",
authToken: CODEX_APP_SERVER_TOKEN_REF,
headers: {
Authorization: "Bearer literal-token",
"x-codex-client-session-token": "${CODEX_CLIENT_SESSION_TOKEN}",
},
},
},
},
},
},
}),
env: {
CODEX_APP_SERVER_TOKEN: "resolved-app-server-token",
CODEX_CLIENT_SESSION_TOKEN: "resolved-session-token",
},
includeAuthStoreRefs: false,
loadablePluginOrigins: BUNDLED_CODEX_PLUGIN_ORIGINS,
});
expect(snapshot.config.plugins?.entries?.codex?.config).toMatchObject({
appServer: {
authToken: "resolved-app-server-token",
headers: {
Authorization: "Bearer literal-token",
"x-codex-client-session-token": "resolved-session-token",
},
},
});
});
it("fails active bundled Codex app-server plugin SecretRefs when env is missing", async () => {
await expect(
prepareSecretsRuntimeSnapshot({
config: asConfig({
plugins: {
entries: {
codex: {
enabled: true,
config: {
appServer: {
transport: "websocket",
url: "wss://codex-app-server.example.internal/ws",
authToken: CODEX_APP_SERVER_TOKEN_REF,
headers: {
"x-codex-client-session-token": "${CODEX_CLIENT_SESSION_TOKEN}",
},
},
},
},
},
},
}),
env: {
CODEX_CLIENT_SESSION_TOKEN: "resolved-session-token",
},
includeAuthStoreRefs: false,
loadablePluginOrigins: BUNDLED_CODEX_PLUGIN_ORIGINS,
}),
).rejects.toThrow('Environment variable "CODEX_APP_SERVER_TOKEN" is missing or empty.');
});
it("fails when an active exec ref id contains traversal segments", async () => {
await expect(
prepareSecretsRuntimeSnapshot({
+24 -2
View File
@@ -1,5 +1,6 @@
/** Builds the static and plugin-derived registry of secret migration targets. */
import type { PluginManifestRecord } from "../plugins/manifest-registry.js";
import { listBundledPluginMetadata } from "../plugins/bundled-plugin-metadata.js";
import { resolvePluginMetadataSnapshot } from "../plugins/plugin-metadata-snapshot.js";
import { loadChannelSecretContractApiForRecord } from "./channel-contract-api.js";
import type { SecretTargetRegistryEntry } from "./target-registry-types.js";
@@ -66,7 +67,7 @@ function listBundledWebProviderSecretTargetRegistryEntries(
}
function listBundledPluginConfigSecretTargetRegistryEntries(
bundledPlugins: readonly PluginManifestRecord[],
bundledPlugins: readonly Pick<PluginManifestRecord, "id" | "configContracts">[],
): SecretTargetRegistryEntry[] {
const entries: SecretTargetRegistryEntry[] = [];
const seen = new Set<string>();
@@ -85,6 +86,24 @@ function listBundledPluginConfigSecretTargetRegistryEntries(
return entries.toSorted((left, right) => left.id.localeCompare(right.id));
}
function listSourceBundledPluginConfigContractRecords(): Array<
Pick<PluginManifestRecord, "id" | "configContracts">
> {
return listBundledPluginMetadata({
includeChannelConfigs: false,
includeSyntheticChannelConfigs: false,
}).flatMap((metadata) =>
metadata.manifest.configContracts
? [
{
id: metadata.manifest.id,
configContracts: metadata.manifest.configContracts,
},
]
: [],
);
}
function listChannelSecretTargetRegistryEntries(
channelPlugins: readonly PluginManifestRecord[],
): SecretTargetRegistryEntry[] {
@@ -491,7 +510,10 @@ function loadSecretTargetRegistryFromPluginMetadata(params: {
return [
...CORE_SECRET_TARGET_REGISTRY,
...listBundledWebProviderSecretTargetRegistryEntries(bundledPlugins),
...listBundledPluginConfigSecretTargetRegistryEntries(bundledPlugins),
...listBundledPluginConfigSecretTargetRegistryEntries([
...bundledPlugins,
...listSourceBundledPluginConfigContractRecords(),
]),
...listChannelSecretTargetRegistryEntries(channelPlugins),
];
}
+26
View File
@@ -87,6 +87,7 @@ describe("secret target registry", () => {
it("derives bundled plugin SecretInput contract target paths from plugin manifests", () => {
const coreTargetIds = new Set(getCoreSecretTargetRegistry().map((entry) => entry.id));
expect(coreTargetIds.has("plugins.entries.voice-call.config.twilio.authToken")).toBe(false);
expect(coreTargetIds.has("plugins.entries.codex.config.appServer.authToken")).toBe(false);
const target = resolveConfigSecretTargetByPath([
"plugins",
@@ -100,5 +101,30 @@ describe("secret target registry", () => {
]);
expect(target?.entry?.id).toBe("plugins.entries.voice-call.config.tts.providers.*.apiKey");
const codexAuthTarget = resolveConfigSecretTargetByPath([
"plugins",
"entries",
"codex",
"config",
"appServer",
"authToken",
]);
expect(codexAuthTarget?.entry?.id).toBe(
"plugins.entries.codex.config.appServer.authToken",
);
const codexHeaderTarget = resolveConfigSecretTargetByPath([
"plugins",
"entries",
"codex",
"config",
"appServer",
"headers",
"x-codex-client-session-token",
]);
expect(codexHeaderTarget?.entry?.id).toBe(
"plugins.entries.codex.config.appServer.headers.*",
);
});
});