codex

package
v0.8.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 7, 2026 License: MIT Imports: 26 Imported by: 0

Documentation

Overview

Package codex implements the Codex credential and agent provider.

The Codex provider manages OpenAI credentials for running the Codex CLI in containers. It implements both CredentialProvider and AgentProvider interfaces.

Authentication

Codex supports OpenAI API key authentication:

  • API keys are validated against the /v1/models endpoint
  • Keys must start with "sk-" prefix
  • The real API key is never exposed to containers
  • Proxy injection adds Authorization headers at network layer

Credential Provider

The credential provider configures:

  • Proxy headers for api.openai.com with Bearer token
  • Container env with OPENAI_API_KEY placeholder (passes format validation)
  • No container mounts needed (uses staging directory approach)

Agent Provider

The agent provider handles:

  • Container preparation with staging directory
  • CLI registration for `moat codex` commands
  • Doctor diagnostics for Codex configuration

Generated Configuration

PrepareContainer writes a ~/.codex/config.toml (see NewConfig) that adapts Codex to running inside a moat container:

  • Approvals and Codex's own sandbox are off. The container is already the isolation boundary, and Codex's sandbox blocks the network the proxy provides. `moat codex --noyolo` restores Codex's own defaults.
  • shell_environment_policy.inherit = "all", so commands Codex runs keep the proxy variables (HTTP_PROXY, SSL_CERT_FILE, ...). Codex's "core" default strips them.
  • /workspace is marked trusted, skipping the first-run trust prompt.
  • Remote (proxy-relay) and local MCP servers both go in [mcp_servers]. Codex reads MCP servers from config.toml only; it ignores .mcp.json.

Placeholder Tokens

The container receives placeholder values that pass format validation:

OPENAI_API_KEY=sk-moat-proxy-injected-placeholder-...

This allows the Codex CLI to start without prompting for credentials, while the real API key is injected by the proxy at the network layer.

Index

Constants

View Source
const (
	ApprovalNever     = "never"
	ApprovalOnRequest = "on-request"

	SandboxFullAccess     = "danger-full-access"
	SandboxWorkspaceWrite = "workspace-write"
)

Approval policies and sandbox modes accepted by the Codex CLI. See https://developers.openai.com/codex/config-reference.

View Source
const (
	MinVerifiedCodexMinor = 146
	MaxVerifiedCodexMinor = 160

	// LatestVerifiedCodexVersion is the newest release verified, and the one
	// the codex-cli registry default pins (TestCodexRegistryDefaultIsLatestVerified).
	LatestVerifiedCodexVersion = "0.160.1"
)

The Codex CLI range subscription auth has been verified against: Moat's synthetic auth.json and generated config.toml load (`codex login status`, `codex --strict-config doctor`), Codex's auth.json schema matches what the grant parses, and with that auth.json staged Codex sends its traffic to chatgpt.com rather than api.openai.com even when OPENAI_API_KEY is set. Bump MaxVerifiedCodexMinor after re-running those checks on a newer release.

View Source
const CodexInitMountPath = "/moat/codex-init"

CodexInitMountPath is where the staging directory is mounted in containers.

View Source
const OpenAIAPIKeyPlaceholder = "sk-moat-proxy-injected-placeholder-0000000000000000000000000000000000000000"

OpenAIAPIKeyPlaceholder is a placeholder that looks like a valid OpenAI API key. Some tools validate the API key format locally before making requests. Using a valid-looking placeholder bypasses these checks while still allowing the proxy to inject the real key at the network layer.

View Source
const OpenAIShellEnvFileName = "openai-env.sh"
View Source
const WorkspacePath = "/workspace"

WorkspacePath is where moat mounts the workspace inside the container.

The generated config pre-trusts this path. That serves two purposes, and the second is easy to miss: besides skipping the interactive trust prompt (Codex only loads project-scoped `.codex/` layers for trusted projects), it is what lets `codex exec` run in a workspace that is not a git repository. Without a trust entry, `codex exec` exits 1 with "Not inside a trusted directory and --skip-git-repo-check was not specified" before doing any work.

Variables

View Source
var OpenAIShellEnvPath = path.Join("$HOME", ".codex", OpenAIShellEnvFileName)

Functions

func DefaultDependencies

func DefaultDependencies() []string

DefaultDependencies returns the default dependencies for running Codex CLI.

func GetCredentialName added in v0.3.1

func GetCredentialName() string

GetCredentialName returns the name under which the Codex credential is stored. Returns empty string if no credential exists.

func HasCredential

func HasCredential() bool

func NetworkHosts

func NetworkHosts() []string

NetworkHosts returns the list of hosts that Codex needs network access to. These should be added to the network allow list for containers running Codex.

func PopulateStagingDir

func PopulateStagingDir(cred *provider.Credential, stagingDir string) error

PopulateStagingDir populates the Codex staging directory with auth configuration.

Files added:

  • auth.json (synthetic subscription tokens or a placeholder API key), or nothing at all when no credential was granted

SECURITY: The real token is NEVER written to the container filesystem. Authentication is handled by the TLS-intercepting proxy at the network layer.

func RenderOpenAIShellEnv added in v0.8.0

func RenderOpenAIShellEnv() string

func UnverifiedVersionWarning added in v0.8.1

func UnverifiedVersionWarning(version string) string

UnverifiedVersionWarning returns a warning when version passes ValidateVersion but is newer than the verified range, and "" otherwise. Callers append the remedy that fits where the CLI runs (host or image).

func ValidateVersion added in v0.8.0

func ValidateVersion(version string) error

ValidateVersion rejects Codex CLI versions subscription auth is known not to work with: an unreadable version, one older than the verified range, or a new major version.

A version newer than the verified range is accepted — see UnverifiedVersionWarning. Codex releases a minor version every few days, so a hard ceiling broke `moat grant codex` for anyone who had simply updated. Accepting it is safe because an auth schema change fails loudly rather than leaking anything: the grant rejects an auth.json it cannot parse, Codex rejects a synthetic auth.json it does not understand, and the real token never enters the container either way.

func WriteCodexConfig

func WriteCodexConfig(stagingDir string, cfg Config) error

WriteCodexConfig writes cfg as config.toml in the staging directory. moat-init copies it to ~/.codex/config.toml at container startup.

Types

type AuthKind added in v0.8.0

type AuthKind int

AuthKind is the credential a run stages for Codex. Every auth-dependent decision in this package routes through it so staging, config, and the container's version gate cannot disagree about which mode is in effect.

const (
	// AuthNone means no Codex credential was granted. Codex is left
	// unauthenticated so it prompts for login, rather than being handed a
	// fabricated subscription the proxy will never honor.
	AuthNone AuthKind = iota
	// AuthAPIKey is a stored OpenAI API key, injected on api.openai.com.
	AuthAPIKey
	// AuthSubscription is a stored ChatGPT subscription, injected as a scoped
	// credential bundle on the ChatGPT Codex backend.
	AuthSubscription
)

func ResolveAuthKind added in v0.8.0

func ResolveAuthKind(cred *provider.Credential) AuthKind

ResolveAuthKind maps a resolved credential to the staging mode it implies. An unrecognized provider is treated as AuthNone: guessing wrong here writes an auth file that claims an authentication Codex does not actually have.

type Config added in v0.8.0

type Config struct {
	// Both are omitempty: clearing a field must drop the key so Codex uses its
	// own default. Emitting `chatgpt_base_url = ”` instead configures an empty
	// origin, which is not the same thing.
	CLIAuthCredentialsStore string                   `toml:"cli_auth_credentials_store,omitempty"`
	ChatGPTBaseURL          string                   `toml:"chatgpt_base_url,omitempty"`
	ApprovalPolicy          string                   `toml:"approval_policy"`
	SandboxMode             string                   `toml:"sandbox_mode"`
	ShellEnvironmentPolicy  ShellEnvironmentPolicy   `toml:"shell_environment_policy"`
	Projects                map[string]ProjectConfig `toml:"projects,omitempty"`
	MCPServers              map[string]MCPServer     `toml:"mcp_servers,omitempty"`
}

Config is the subset of ~/.codex/config.toml that moat generates.

Scalar keys must stay ahead of the table-valued ones: TOML assigns bare key/value pairs to the table they follow, so a scalar emitted after [shell_environment_policy] would land inside it.

func NewConfig added in v0.8.0

func NewConfig(requireApproval bool) Config

NewConfig returns the base Codex configuration for a moat container.

requireApproval selects between the two policies moat supports:

  • false (default): approvals off and Codex's own sandbox off. The container is already the isolation boundary, and Codex's sandbox blocks the network the moat proxy provides, so nesting it breaks any command the agent runs that needs the network or writes outside the workspace.
  • true (--noyolo): Codex's own defaults, so it prompts before acting and confines commands to the workspace with the network off.

The environment policy is always "all". Codex's "core" default keeps only PATH/HOME/SHELL/TMPDIR/LANG/LOGNAME/USER, which strips HTTP_PROXY, SSL_CERT_FILE, and NODE_EXTRA_CA_CERTS from every command Codex spawns - i.e. exactly the variables that route a container command through the moat proxy. moat curates the container environment already.

type DoctorSection

type DoctorSection struct{}

DoctorSection implements doctor.Section for Codex configuration.

func (*DoctorSection) Name

func (d *DoctorSection) Name() string

Name returns the section name.

func (*DoctorSection) Print

func (d *DoctorSection) Print(w io.Writer) error

Print outputs Codex diagnostic information.

type Grant

type Grant struct{}

func NewGrant

func NewGrant() *Grant

func (*Grant) Execute

func (g *Grant) Execute(ctx context.Context) (*provider.Credential, error)

Execute starts a fresh Codex login in a private one-use CODEX_HOME. It does not import or overwrite the user's ordinary ~/.codex/auth.json.

type MCPServer

type MCPServer struct {
	Command     string            `toml:"command,omitempty"`
	Args        []string          `toml:"args,omitempty"`
	Env         map[string]string `toml:"env,omitempty"`
	Cwd         string            `toml:"cwd,omitempty"`
	URL         string            `toml:"url,omitempty"`
	HTTPHeaders map[string]string `toml:"http_headers,omitempty"`
}

MCPServer is a single entry under [mcp_servers]. Command/Args/Env/Cwd describe a stdio server; URL/HTTPHeaders describe a streamable HTTP server. Codex reads MCP servers from config.toml only - it ignores the .mcp.json file other agents use.

type ProjectConfig added in v0.8.0

type ProjectConfig struct {
	TrustLevel string `toml:"trust_level"`
}

ProjectConfig marks a project path trusted or untrusted.

type Provider

type Provider struct{}

func (*Provider) CanRefresh added in v0.8.0

func (p *Provider) CanRefresh(cred *provider.Credential) bool

func (*Provider) Cleanup

func (p *Provider) Cleanup(string)

func (*Provider) ConfigureProxy

func (p *Provider) ConfigureProxy(proxyConfig provider.ProxyConfigurer, cred *provider.Credential)

ConfigureProxy installs the real access token and account identity as one atomic bundle. Older proxy implementations do not receive a fallback static credential: failing closed is safer than widening a subscription token.

func (*Provider) ContainerEnv

func (p *Provider) ContainerEnv(*provider.Credential) []string

Subscription auth is represented by synthetic auth.json, not an API-key env var. In particular OPENAI_API_KEY must not override Codex's selected mode.

func (*Provider) ContainerMounts

func (p *Provider) ContainerMounts(*provider.Credential, string) ([]provider.MountConfig, string, error)

func (*Provider) CredentialGrant added in v0.8.0

func (p *Provider) CredentialGrant() string

CredentialGrant returns the logical Codex grant. The run resolver prefers subscription auth and falls back to an independently stored OpenAI API key.

func (*Provider) DefaultDependencies added in v0.8.0

func (p *Provider) DefaultDependencies() []string

func (*Provider) Grant

func (p *Provider) Grant(ctx context.Context) (*provider.Credential, error)

func (*Provider) IdentifiesAs added in v0.8.0

func (p *Provider) IdentifiesAs(agent string) bool

IdentifiesAs reports whether a run with the given recorded Agent field was created by the codex provider. This serves only the pre-upgrade fallback path in `moat join` — runs created before joinable_agents existed. Runs created since are matched against their persisted capability set instead.

func (*Provider) ImpliedDependencies

func (p *Provider) ImpliedDependencies() []string

func (*Provider) JoinCommand added in v0.8.0

func (p *Provider) JoinCommand(opts provider.JoinOpts) ([]string, error)

JoinCommand builds the in-container command for a joined codex session, mirroring the BuildCommand closure in runCodex (cli.go).

Approval policy and sandbox mode are deliberately absent: they live in the generated ~/.codex/config.toml so every launch path gets the same behavior, and `codex` and `codex exec` accept different flags.

func (*Provider) Name

func (p *Provider) Name() string

func (*Provider) NetworkHosts added in v0.8.0

func (p *Provider) NetworkHosts() []string

func (*Provider) PrepareContainer

func (p *Provider) PrepareContainer(ctx context.Context, opts provider.PrepareOpts) (*provider.ContainerConfig, error)

PrepareContainer sets up staging directories and config files for Codex CLI. It creates a staging directory with auth.json and config.toml files that will be copied to ~/.codex at container startup by moat-init.

func (*Provider) Refresh added in v0.8.0

func (*Provider) RefreshInterval added in v0.8.0

func (p *Provider) RefreshInterval() time.Duration

func (*Provider) RegisterCLI

func (p *Provider) RegisterCLI(root *cobra.Command)

RegisterCLI registers Codex-related CLI commands. This adds the `moat codex` command group with subcommands.

type ShellEnvironmentPolicy added in v0.8.0

type ShellEnvironmentPolicy struct {
	Inherit string `toml:"inherit"`
}

ShellEnvironmentPolicy controls the environment Codex passes to the commands it runs.

type SubscriptionAuth added in v0.8.0

type SubscriptionAuth struct {
	AccessToken  string `json:"access_token"`
	RefreshToken string `json:"refresh_token"`
	AccountID    string `json:"account_id"`
}

SubscriptionAuth is the encrypted payload stored for a Codex subscription. It is never staged into the container or sent over the daemon API.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL