Sign inSign up

docker/sbx-kit-codex:0.160.1

Multi-platform
Manifest digest

sha256:58d4bd9444d3d6c200895d94163fa61a1f4e26362a0b9cd410a4f751f8d7e8ee

Last pushed

4 days by cdupuis

Type

Sandbox Kit

Manifest digest

sha256:58d4bd9444d3d6c200895d94163fa61a1f4e26362a0b9cd410a4f751f8d7e8ee

yaml
schemaVersion: "3"
displayName: Codex
author: Docker, Inc.
description: 'OpenAI''s Codex CLI as a complete workload: the sandbox-templates base with codex pinned to the published release, the OpenAI credential (API key or ChatGPT OAuth), scoped egress, and the config/auth seeds the agent needs.'
sourceUrl: https://github.com/openai/codex
kind: workload
provides:
    - [email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/ca-certificates-java@20240118
    - deb/ca-certificates@20250419
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/iputils-ping@20240905
    - deb/[email protected]
    - deb/[email protected]
    - deb/less@668
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
    - deb/[email protected]
capabilities:
    - type: com.docker.sandbox/sbx@1
    - type: com.docker.sandbox/network-policy@1
      config:
        runtime:
            allow:
                - api.openai.com:443
                - openai.com:443
                - auth.openai.com:443
                - chatgpt.com:443
                - files.openai.com:443
                - registry.npmjs.org:443
                - releases.openai.com:443
                - api.github.com:443
                - github.com:443
                - release-assets.githubusercontent.com:443
                - codeload.github.com:443
                - archive.ubuntu.com:80
                - security.ubuntu.com:80
                - ports.ubuntu.com:80
                - download.docker.com:443
    - type: com.docker.sandbox/credential@1
      optional: true
      config:
        apiKey:
            inject:
                - domain: api.openai.com
                  format: Bearer %s
                  header: Authorization
                - domain: openai.com
                  format: Bearer %s
                  header: Authorization
            name: OPENAI_API_KEY
            proxyManaged: true
        oauth:
            resourceHosts:
                - chatgpt.com
            sentinels:
                accessToken: oai-oat01-proxy-managed
                refreshToken: oai-ort01-proxy-managed
            tokenEndpoint:
                host: auth.openai.com
                path: /oauth/token
        phase: runtime
        service: openai
      description: OpenAI API access (API key or ChatGPT OAuth)
    - type: com.docker.sandbox/lifecycle@1
      config:
        install:
            - command: |
                set -e
                mkdir -p /home/agent/.codex /home/agent/.agents
                MODE="${SBX_CRED_OPENAI_MODE:-none}"
                cat > /home/agent/.codex/config.toml << 'EOF'
                approval_policy = "never"
                sandbox_mode = "danger-full-access"
                mcp_oauth_credentials_store = "file"
                # Turn-complete hook for sbx Desktop (see /usr/local/bin/sbx-codex-hook):
                # raises the desktop notification and forwards the session's model,
                # effort, token usage and git state read from this thread's rollout
                # file. `notify` is top-level and needs no hook trust; Codex spawns
                # it fire-and-forget with the event JSON as the last argument, and
                # the script is a silent no-op when no desktop server is loaded.
                notify = ["/usr/local/bin/sbx-codex-hook", "codex"]
                EOF
                # Model selection from the create-phase args. These are
                # top-level keys, so they must land here, before the
                # model_providers and projects tables below would capture
                # them. The args' patterns admit no quote or backslash, so
                # the expanded value is safe inside the TOML string.
                model='${{ kit.args.model }}'
                effort='${{ kit.args.reasoningEffort }}'
                [ -z "$model" ] || printf 'model = "%s"\n' "$model" >> /home/agent/.codex/config.toml
                [ -z "$effort" ] || printf 'model_reasoning_effort = "%s"\n' "$effort" >> /home/agent/.codex/config.toml
                case "$MODE" in
                  oauth|apikey)
                    cat >> /home/agent/.codex/config.toml << 'EOF'
                forced_login_method = "api"
                EOF
                    ;;
                esac
                if [ "$MODE" = oauth ]; then
                  cat >> /home/agent/.codex/config.toml << 'EOF'

                model_provider = "sandboxd"

                [model_providers.sandboxd]
                name = "Sandbox Proxy"
                base_url = "https://chatgpt.com/backend-api/codex"
                experimental_bearer_token = "oai-oat01-proxy-managed"
                requires_openai_auth = false
                EOF
                fi
                # Trust the workspace for launches outside the entrypoint too.
                # Keep this after all top-level config keys: the projects
                # table would otherwise capture settings like model_provider.
                ws="${WORKSPACE_DIR:-/home/agent/workspace}"
                esc=$(printf '%s' "$ws" | sed 's/\\/\\\\/g; s/"/\\"/g')
                cat >> /home/agent/.codex/config.toml <<EOF

                [projects."$esc"]
                trust_level = "trusted"
                EOF
                case "$MODE" in
                  oauth|apikey)
                    cat > /home/agent/.codex/auth.json << 'EOF'
                {
                  "OPENAI_API_KEY": "proxy-managed"
                }
                EOF
                    ;;
                  *)
                    rm -f /home/agent/.codex/auth.json
                    ;;
                esac
              description: Seed Codex config/auth from SBX_CRED_OPENAI_MODE
              env:
                - SBX_CRED_OPENAI_MODE
                - WORKSPACE_DIR
              user: agent
        startup:
            - command: |
                set -e
                [ -n "$MCP_GATEWAY_URL" ] || exit 0
                cfg="$HOME/.codex/config.toml"
                touch "$cfg"
                grep -q "^\[mcp_servers.mcp-gateway\]" "$cfg" && exit 0
                esc() { printf '%s' "$1" | sed 's/\\/\\\\/g; s/"/\\"/g'; }
                url=$(esc "$MCP_GATEWAY_URL")
                auth=$(esc "$MCP_SENTINEL_TOKEN_NAME")
                # Codex's grammar for a streamable HTTP server: the transport
                # is implied by `url` (a `command` would make it stdio; there
                # is no `type` key), and static headers go in `http_headers`.
                # A `[...headers]` sub-table is not read, so the gateway
                # would be reached without its bearer token and codex would
                # warn about both keys at startup.
                cat >> "$cfg" <<EOF

                [mcp_servers.mcp-gateway]
                url = "$url"
                http_headers = { Authorization = "Bearer $auth" }
                EOF
              description: Register the sandbox MCP gateway in ~/.codex/config.toml
              env:
                - MCP_GATEWAY_URL
                - MCP_SENTINEL_TOKEN_NAME
              user: agent
    - type: com.docker.sandbox/agent-sessions@1
      config:
        continue:
            - resume
            - --last
        list:
            - /bin/sh
            - -c
            - |
              set -eu
              tmp=$(mktemp -d)
              mkfifo "$tmp/in" "$tmp/out"
              codex app-server <"$tmp/in" >"$tmp/out" &
              pid=$!
              trap 'kill "$pid" 2>/dev/null || :; wait "$pid" 2>/dev/null || :; rm -rf "$tmp"' EXIT
              trap 'exit 130' INT
              trap 'exit 143' TERM
              exec 3>"$tmp/in" 4<"$tmp/out"

              id=0
              rpc() {
                id=$((id + 1))
                jq -nc --argjson id "$id" --arg method "$1" --argjson params "$2" \
                  '{id: $id, method: $method, params: $params}' >&3
                while IFS= read -r response <&4; do
                  if printf '%s\n' "$response" |
                    jq -e --argjson id "$id" '.id == $id' >/dev/null; then
                    printf '%s\n' "$response" | jq -e \
                      'if has("error") then error(.error | tostring) else has("result") end' >/dev/null
                    return
                  fi
                done
                echo 'Codex exited before responding' >&2
                exit 1
              }

              rpc initialize '{"clientInfo":{"name":"session_list","version":"1.0"}}'
              printf '%s\n' '{"method":"initialized","params":{}}' >&3
              : >"$tmp/sessions"

              # Match Codex's user-facing resume picker, including exec and
              # app-server sessions. Sub-agent and unknown threads stay out.
              for archived in false true; do
                cursor=null
                while :; do
                  params=$(jq -nc --argjson cursor "$cursor" --argjson archived "$archived" '
                    {
                      limit: 100, cursor: $cursor, archived: $archived,
                      sourceKinds: ["cli", "vscode", "exec", "appServer"]
                    }')
                  rpc thread/list "$params"
                  printf '%s\n' "$response" | jq -c --argjson archived "$archived" \
                    '.result.data[] + {archived: $archived}' >>"$tmp/sessions"
                  cursor=$(printf '%s\n' "$response" | jq -c '.result.nextCursor')
                  [ "$cursor" != null ] || break
                done
              done

              # Each page is ordered, but active and archived pages must be
              # sorted together before emitting the v1 ID-only result.
              jq -r -s '
                unique_by(.id)
                | sort_by(.updatedAt // 0)
                | reverse
                | .[].id' "$tmp/sessions"
        prompt:
            - --
            - '{{.Prompt}}'
        resume:
            - resume
            - '{{.SessionID}}'
    - type: com.docker.sandbox/agent-interactive-sessions@1
      optional: true
      config:
        continue:
            - resume
            - --last
        prompt:
            - --
            - '{{.Prompt}}'
        resume:
            - resume
            - '{{.SessionID}}'
        sessionPicker:
            - resume
    - type: com.docker.sandbox/agent-skills@1
      optional: true
      config:
        path: /home/agent/.agents/skills
    - type: com.docker.sandbox/agent-context@1
      config:
        contentFile: /usr/share/sandbox/kit/codex/codex-context.md
        directory: /home/agent/.codex
        filename: AGENTS.md
args:
    model:
        default: ""
        description: Codex model to use (config.toml `model`); empty keeps the CLI default
        pattern: ^[A-Za-z0-9._-]*$
        env: CODEX_MODEL
    reasoningEffort:
        default: ""
        description: Reasoning effort (config.toml `model_reasoning_effort`); empty keeps the CLI default
        pattern: ^(none|minimal|low|medium|high|xhigh|max|ultra|persistent)?$
        env: CODEX_REASONING_EFFORT
    version:
        default: 0.160.1
        description: Codex CLI release to install
        pattern: ^[0-9]+\.[0-9]+\.[0-9]+$
        buildArg: CODEX_VERSION
dockerfile: ./codex.dockerfile