142 lines
4.9 KiB
Bash
Executable file
142 lines
4.9 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
CODEX_HOME_DIR="${CODEX_HOME:-$HOME/.codex}"
|
|
CONFIG_PATH="${CODEX_CONFIG_PATH:-$CODEX_HOME_DIR/config.toml}"
|
|
API_BASE="${API_BASE:-http://127.0.0.1:8000}"
|
|
DRY_RUN=0
|
|
SKIP_VERIFY=0
|
|
MCP_MODE="remove"
|
|
MCP_NAME="${STATE_HUB_MCP_NAME:-dev-hub}"
|
|
MCP_COMMAND="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/codex-state-hub-mcp.sh"
|
|
|
|
usage() {
|
|
cat <<'USAGE'
|
|
Usage: scripts/configure-codex.sh [options]
|
|
|
|
Enable direct network access for Codex workspace-write sandboxes and verify
|
|
that the sandbox can reach the local State Hub.
|
|
|
|
Options:
|
|
--codex-home DIR Codex home containing config.toml. Default: $CODEX_HOME or ~/.codex.
|
|
--api-base URL State Hub API base. Default: http://127.0.0.1:8000.
|
|
--dry-run Show the configuration change without writing it.
|
|
--skip-verify Do not run the sandboxed State Hub health check.
|
|
--with-mcp Opt in to the experimental slim State Hub MCP server.
|
|
--skip-mcp Do not add or remove a State Hub MCP registration.
|
|
-h, --help Show this help.
|
|
USAGE
|
|
}
|
|
|
|
while [ "$#" -gt 0 ]; do
|
|
case "$1" in
|
|
--codex-home)
|
|
test -n "${2:-}" || { echo "ERROR: --codex-home requires a directory" >&2; exit 2; }
|
|
CODEX_HOME_DIR="$2"
|
|
CONFIG_PATH="$CODEX_HOME_DIR/config.toml"
|
|
shift 2
|
|
;;
|
|
--api-base)
|
|
test -n "${2:-}" || { echo "ERROR: --api-base requires a URL" >&2; exit 2; }
|
|
API_BASE="$2"
|
|
shift 2
|
|
;;
|
|
--dry-run) DRY_RUN=1; shift ;;
|
|
--skip-verify) SKIP_VERIFY=1; shift ;;
|
|
--with-mcp) MCP_MODE="add"; shift ;;
|
|
--skip-mcp) MCP_MODE="skip"; shift ;;
|
|
-h|--help) usage; exit 0 ;;
|
|
*) echo "ERROR: unknown argument: $1" >&2; usage >&2; exit 2 ;;
|
|
esac
|
|
done
|
|
|
|
python3 - "$CONFIG_PATH" "$DRY_RUN" <<'PY'
|
|
import re
|
|
import sys
|
|
import tomllib
|
|
from pathlib import Path
|
|
|
|
path = Path(sys.argv[1])
|
|
dry_run = sys.argv[2] == "1"
|
|
original = path.read_text(encoding="utf-8") if path.exists() else ""
|
|
if original:
|
|
tomllib.loads(original)
|
|
|
|
header = "[sandbox_workspace_write]"
|
|
lines = original.splitlines()
|
|
start = next((i for i, line in enumerate(lines) if line.strip() == header), None)
|
|
|
|
if start is None:
|
|
if lines and lines[-1].strip():
|
|
lines.append("")
|
|
lines.extend([header, "network_access = true"])
|
|
else:
|
|
end = next(
|
|
(i for i in range(start + 1, len(lines)) if re.match(r"^\s*\[", lines[i])),
|
|
len(lines),
|
|
)
|
|
setting = next(
|
|
(i for i in range(start + 1, end) if re.match(r"^\s*network_access\s*=", lines[i])),
|
|
None,
|
|
)
|
|
if setting is None:
|
|
lines.insert(end, "network_access = true")
|
|
else:
|
|
lines[setting] = "network_access = true"
|
|
|
|
updated = "\n".join(lines).rstrip() + "\n"
|
|
tomllib.loads(updated)
|
|
|
|
if updated == original:
|
|
print(f"OK: {path} already enables sandbox workspace-write network access")
|
|
elif dry_run:
|
|
print(f"DRY-RUN: would enable sandbox_workspace_write.network_access in {path}")
|
|
else:
|
|
path.parent.mkdir(parents=True, exist_ok=True)
|
|
temporary = path.with_suffix(path.suffix + ".tmp")
|
|
temporary.write_text(updated, encoding="utf-8")
|
|
temporary.chmod(0o600)
|
|
temporary.replace(path)
|
|
print(f"OK: enabled sandbox_workspace_write.network_access in {path}")
|
|
PY
|
|
|
|
if [ "$MCP_MODE" = "add" ]; then
|
|
if [ "$DRY_RUN" -eq 1 ]; then
|
|
echo "DRY-RUN: would register Codex MCP server $MCP_NAME -> $MCP_COMMAND"
|
|
elif ! command -v codex >/dev/null 2>&1; then
|
|
echo "WARN: codex is not on PATH; State Hub MCP registration was skipped." >&2
|
|
elif CODEX_HOME="$CODEX_HOME_DIR" codex mcp get "$MCP_NAME" >/dev/null 2>&1; then
|
|
echo "OK: Codex MCP server $MCP_NAME is already registered"
|
|
else
|
|
CODEX_HOME="$CODEX_HOME_DIR" codex mcp add "$MCP_NAME" -- "$MCP_COMMAND"
|
|
echo "OK: registered Codex MCP server $MCP_NAME -> $MCP_COMMAND"
|
|
fi
|
|
elif [ "$MCP_MODE" = "remove" ]; then
|
|
if [ "$DRY_RUN" -eq 1 ]; then
|
|
echo "DRY-RUN: would remove Codex MCP server $MCP_NAME if registered"
|
|
elif command -v codex >/dev/null 2>&1 \
|
|
&& CODEX_HOME="$CODEX_HOME_DIR" codex mcp get "$MCP_NAME" >/dev/null 2>&1; then
|
|
CODEX_HOME="$CODEX_HOME_DIR" codex mcp remove "$MCP_NAME"
|
|
echo "OK: removed Codex MCP server $MCP_NAME; use REST/statehub CLI by default"
|
|
else
|
|
echo "OK: Codex MCP server $MCP_NAME is not registered"
|
|
fi
|
|
fi
|
|
|
|
if [ "$DRY_RUN" -eq 1 ] || [ "$SKIP_VERIFY" -eq 1 ]; then
|
|
exit 0
|
|
fi
|
|
|
|
if ! command -v codex >/dev/null 2>&1; then
|
|
echo "WARN: codex is not on PATH; configuration was written but not verified." >&2
|
|
exit 0
|
|
fi
|
|
|
|
HEALTH_URL="${API_BASE%/}/state/health"
|
|
if timeout 10 codex sandbox -- curl -fsS --max-time 3 "$HEALTH_URL" >/dev/null 2>&1; then
|
|
echo "OK: Codex sandbox can reach State Hub at $HEALTH_URL"
|
|
else
|
|
echo "WARN: Codex sandbox still cannot reach $HEALTH_URL." >&2
|
|
echo "WARN: A managed permission profile may enforce restricted networking/--unshare-net." >&2
|
|
echo "WARN: Retry State Hub REST/CLI commands with escalated execution or change the managed profile." >&2
|
|
fi
|