#!/usr/bin/env zsh set -euo pipefail CODEX_MCP_ENV_FILE="${CODEX_MCP_ENV_FILE:-${HOME}/.codex/mcp.env}" MCPGW_SELECTED_SERVERS_FILE="${MCPGW_SELECTED_SERVERS_FILE:-${HOME}/.ora-gateway/selected-servers.json}" MCPGW_OP_TOKEN_FILE="${MCPGW_OP_TOKEN_FILE:-${HOME}/.ora-gateway/op-token}" CODEX_DEVOPS_AUTH_SCRIPT="${CODEX_DEVOPS_AUTH_SCRIPT:-${HOME}/bin/codex-devops-auth.sh}" CODEX_BIN="${CODEX_BIN:-/opt/homebrew/bin/codex}" CODEX_WRAPPER_CODEX_PROFILE="${CODEX_WRAPPER_CODEX_PROFILE:-}" CODEX_WRAPPER_DEFAULT_CODEX_PROFILE="${CODEX_WRAPPER_DEFAULT_CODEX_PROFILE:-gpt-5-5}" CODEX_WRAPPER_AUTH_ENV_FILE="" CODEX_WRAPPER_DEDICATED_AGENT_PID="" CODEX_WRAPPER_DEDICATED_AGENT_SOCK="" log() { print -u2 -- "$@" } cleanup() { if [[ -n "${CODEX_WRAPPER_DEDICATED_AGENT_PID}" && -n "${CODEX_WRAPPER_DEDICATED_AGENT_SOCK}" ]]; then SSH_AGENT_PID="${CODEX_WRAPPER_DEDICATED_AGENT_PID}" SSH_AUTH_SOCK="${CODEX_WRAPPER_DEDICATED_AGENT_SOCK}" ssh-agent -k >/dev/null 2>&1 || true fi if [[ -n "${CODEX_WRAPPER_AUTH_ENV_FILE}" ]]; then rm -f "${CODEX_WRAPPER_AUTH_ENV_FILE}" >/dev/null 2>&1 || true fi } sanitize_mcpgw_output() { local line clean redacted while IFS= read -r line || [[ -n "${line}" ]]; do clean="$(printf '%s\n' "${line}" | perl -pe 's/\e\]8;;.*?\a//g; s/\e\[[0-?]*[ -\/]*[@-~]//g')" redacted="$(printf '%s\n' "${clean}" | sed -E \ -e 's#https?://[^[:space:]]+#[redacted URL]#g' \ -e 's#([Aa][Cc][Cc][Ee][Ss][Ss]_[Tt][Oo][Kk][Ee][Nn]=)[^[:space:]]+#\1[redacted]#g' \ -e 's#([Ii][Dd]_[Tt][Oo][Kk][Ee][Nn]=)[^[:space:]]+#\1[redacted]#g' \ -e 's#([Rr][Ee][Ff][Rr][Ee][Ss][Hh]_[Tt][Oo][Kk][Ee][Nn]=)[^[:space:]]+#\1[redacted]#g' \ -e 's#([Ss][Ee][Cc][Uu][Rr][Ii][Tt][Yy]_[Tt][Oo][Kk][Ee][Nn]=)[^[:space:]]+#\1[redacted]#g' \ -e 's#([Cc][Ll][Ii][Ee][Nn][Tt]_[Ss][Ee][Cc][Rr][Ee][Tt]=)[^[:space:]]+#\1[redacted]#g' \ -e 's#([Pp][Uu][Bb][Ll][Ii][Cc]_[Kk][Ee][Yy]=)[^[:space:]]+#\1[redacted]#g' \ -e 's#([Aa][Uu][Tt][Hh][Oo][Rr][Ii][Zz][Aa][Tt][Ii][Oo][Nn]:[[:space:]]*).*#\1[redacted]#g' \ -e 's#([Cc][Oo][Oo][Kk][Ii][Ee]:[[:space:]]*).*#\1[redacted]#g' \ -e 's#([Ss][Ee][Tt]-[Cc][Oo][Oo][Kk][Ii][Ee]:[[:space:]]*).*#\1[redacted]#g' \ -e 's#([^[:space:]]*/)?[.]oci/config#[redacted OCI config path]#g' \ -e 's#(Config written to: ).*#\1[redacted config path]#')" log "${redacted}" done } is_truthy() { case "${1:-}" in 1|true|TRUE|yes|YES|on|ON) return 0 ;; *) return 1 ;; esac } codex_home() { print -r -- "${CODEX_HOME:-${HOME}/.codex}" } codex_profile_file_exists() { local profile="$1" [[ -r "$(codex_home)/${profile}.config.toml" ]] } resolve_codex_profile() { if [[ -n "${CODEX_WRAPPER_CODEX_PROFILE}" ]]; then print -r -- "${CODEX_WRAPPER_CODEX_PROFILE}" return 0 fi if codex_profile_file_exists "${CODEX_WRAPPER_DEFAULT_CODEX_PROFILE}"; then print -r -- "${CODEX_WRAPPER_DEFAULT_CODEX_PROFILE}" fi return 0 } args_include_codex_profile() { local arg for arg in "$@"; do case "${arg}" in --profile|-p|--profile=*|-p=*|--profile-v2|--profile-v2=*) return 0 ;; esac done return 1 } codex_profile_flag() { local version_output version major minor rest version_output="$("${CODEX_BIN}" --version 2>/dev/null || true)" version="${version_output##* }" major="${version%%.*}" rest="${version#*.}" minor="${rest%%.*}" if [[ "${major}" == "0" && "${minor}" =~ '^[0-9]+$' && "${minor}" -lt 134 ]]; then print -r -- "--profile-v2" return 0 fi print -r -- "--profile" } confluence_selected() { local selected_servers_file="${MCPGW_SELECTED_SERVERS_FILE}" if [[ -r "${selected_servers_file}" ]] && LC_ALL=C grep -Eiq '"(Confluence|CentralConfluence|central_confluence|central-confluence)"' "${selected_servers_file}"; then return 0 fi case ",${CODEX_MCP_SERVERS:-}," in *,Confluence,*|*,confluence,*|*,CentralConfluence,*|*,central_confluence,*|*,central-confluence,*) return 0 ;; esac return 1 } should_refresh_confluence_cookies() { if is_truthy "${CODEX_MCP_REFRESH_COOKIES:-}" || \ is_truthy "${CODEX_MCP_REFRESH_CONFLUENCE_COOKIES:-}" || \ is_truthy "${MCPGW_REFRESH_COOKIES:-}" || \ is_truthy "${CODEX_MCP_CONFLUENCE_COOKIES_STALE:-}" || \ is_truthy "${MCPGW_CONFLUENCE_COOKIES_STALE:-}"; then return 0 fi confluence_selected } run_mcpgw_required() { local mcpgw_bin="$1" shift log "MCP Gateway auth preflight: mcpgw $*" "${mcpgw_bin}" "$@" 2>&1 | sanitize_mcpgw_output local rc="${pipestatus[1]}" if [[ ${rc} -ne 0 ]]; then log "MCP Gateway auth preflight failed: mcpgw $* exited with ${rc}." exit "${rc}" fi } prepare_codex_auth() { if [[ ! -x "${CODEX_DEVOPS_AUTH_SCRIPT}" ]]; then log "Warning: Codex DevOps auth helper not found or not executable: ${CODEX_DEVOPS_AUTH_SCRIPT}" return 1 fi if ! CODEX_WRAPPER_AUTH_ENV_FILE="$(mktemp "${TMPDIR:-/tmp}/codex-devops-auth.XXXXXX")"; then log "Warning: could not create temporary Codex auth environment file." return 1 fi set +e CODEX_DEVOPS_AUTH_ENV_OUT="${CODEX_WRAPPER_AUTH_ENV_FILE}" "${CODEX_DEVOPS_AUTH_SCRIPT}" local auth_rc=$? set -e if [[ ${auth_rc} -ne 0 ]]; then log "Warning: Codex DevOps auth helper failed with exit code ${auth_rc}; could not refresh OP token." return 1 fi if [[ ! -s "${CODEX_WRAPPER_AUTH_ENV_FILE}" ]]; then log "Warning: Codex DevOps auth helper did not write an auth environment; could not refresh OP token." return 1 fi set +e source "${CODEX_WRAPPER_AUTH_ENV_FILE}" local source_rc=$? set -e if [[ ${source_rc} -ne 0 ]]; then log "Warning: could not load Codex auth environment from ${CODEX_WRAPPER_AUTH_ENV_FILE}; could not refresh OP token." return 1 fi CODEX_WRAPPER_DEDICATED_AGENT_PID="${SSH_AGENT_PID:-}" CODEX_WRAPPER_DEDICATED_AGENT_SOCK="${SSH_AUTH_SOCK:-}" } write_gateway_op_token() { local token_file="${MCPGW_OP_TOKEN_FILE}" local token_dir tmp if [[ -z "${OP_TOKEN:-}" ]]; then log "Warning: cannot write MCP Gateway OP token: OP_TOKEN is empty." return 1 fi token_dir="$(dirname -- "${token_file}")" if ! mkdir -p "${token_dir}"; then log "Warning: could not create MCP Gateway token directory: ${token_dir}" return 1 fi if ! tmp="$(mktemp "${token_file}.XXXXXX")"; then log "Warning: could not create temporary MCP Gateway OP token file for ${token_file}." return 1 fi if ! printf '%s\n' "${OP_TOKEN}" > "${tmp}"; then log "Warning: could not write temporary MCP Gateway OP token file: ${tmp}" rm -f "${tmp}" >/dev/null 2>&1 || true return 1 fi if ! chmod 600 "${tmp}"; then log "Warning: could not set permissions on temporary MCP Gateway OP token file: ${tmp}" rm -f "${tmp}" >/dev/null 2>&1 || true return 1 fi if ! mv -f "${tmp}" "${token_file}"; then log "Warning: could not install MCP Gateway OP token file: ${token_file}" rm -f "${tmp}" >/dev/null 2>&1 || true return 1 fi log "MCP Gateway auth preflight: wrote fresh operator token to ${token_file}." } refresh_gateway_auth() { local mcpgw_bin op_token_refreshed=0 mcpgw_bin="$(command -v mcpgw 2>/dev/null || true)" if [[ -n "${mcpgw_bin}" ]]; then run_mcpgw_required "${mcpgw_bin}" refresh else log "Warning: mcpgw not found on PATH; skipping MCP Gateway auth refresh." fi if prepare_codex_auth && write_gateway_op_token; then op_token_refreshed=1 else log "Warning: could not refresh OP token; continuing with existing MCP Gateway token state." fi if [[ -z "${mcpgw_bin}" ]]; then return 0 fi if [[ "${op_token_refreshed}" != "1" ]]; then log "MCP Gateway auth preflight: skipping token-dependent checks because OP token refresh failed." return 0 fi if should_refresh_confluence_cookies; then run_mcpgw_required "${mcpgw_bin}" refresh-cookies else log "MCP Gateway auth preflight: skipping mcpgw refresh-cookies; Confluence auth was not requested." fi run_mcpgw_required "${mcpgw_bin}" status } trap cleanup EXIT INT TERM if [[ -r "${CODEX_MCP_ENV_FILE}" ]]; then source "${CODEX_MCP_ENV_FILE}" fi refresh_gateway_auth if is_truthy "${CODEX_WRAPPER_DRY_RUN:-}"; then log "CODEX_WRAPPER_DRY_RUN is set; skipping Codex launch." exit 0 fi codex_args=() if ! args_include_codex_profile "$@"; then resolved_codex_profile="$(resolve_codex_profile)" if [[ -n "${resolved_codex_profile}" ]]; then codex_args+=("$(codex_profile_flag)" "${resolved_codex_profile}") fi fi codex_args+=(-a on-request -s danger-full-access "$@") "${CODEX_BIN}" "${codex_args[@]}"