Automated OpenCode and MCP Credentials Provisioning via SOPS¶
Previously, OpenCode server and remote Model Context Protocol (MCP) integrations (Exa, Context7) required manual credential configuration after sandbox initialization, and OPENCODE_GO_API_KEY set via environment variables did not register in OpenCode WebUI without account integration. We decided to automate credential provisioning through SOPS: secrets/opencode.env stores encrypted API keys (OPENCODE_GO_API_KEY, EXA_API_KEY, CONTEXT7_API_KEY), scripts/setup.sh decrypts them via a new --opencode flag to ~/.config/opencode/opencode.env and exports them to the environment, shared/opencode.json configures MCP servers using {env:...} header substitution and configures native OpenCode Go provider environment mapping via provider.opencode-go.env, and sandbox startup scripts export OPENCODE_API_KEY before launching opencode serve.
Considered Options¶
- Manual interactive setup via OpenCode CLI/WebUI: Require users to run
opencode auth loginor enter keys in the WebUI manually on every ephemeral sandbox creation. Rejected because it disrupts automated workflows andopencode auth loginrefuses non-interactive TTY input. - Direct SQLite database injection prior to server startup: Write credentials directly into
/root/.local/share/opencode/opencode.dbusing a custom Python script. Rejected because it couples container bootstrap to internal SQLite schemas and credential serialization formats that can drift across OpenCode releases. - Process-scoped environment without
/etc/environmentor~/.bashrcexport: Sourceopencode.envstrictly for theopencode servecommand. Rejected because subshells spawned by OpenCode and developer terminal/SSH sessions need ambient access toEXA_API_KEYandCONTEXT7_API_KEYfor CLI tools and scripts. - Post-startup REST API registration loop: Run
opencode api POST /api/integration/opencode-go/connect/keyinsidestartup.shonce the server port responds. Rejected because OpenCode's internal provider catalog boots 1–2 seconds after the HTTP port opens, causing transient 404IntegrationNotFoundErrorrace conditions on container launch. - Automated SOPS decryption with native provider environment mapping: Extend
scripts/setup.shwith an orthogonal--opencodeflag, decryptsecrets/opencode.envduring SOPS bootstrap instartup.sh, source the decrypted credentials and exportOPENCODE_API_KEYinstartup.sh, and declare"provider": { "opencode-go": { "env": ["OPENCODE_GO_API_KEY"] } }inshared/opencode.json. Accepted because it leverages OpenCode's native provider environment discovery, eliminates startup race conditions and background API polling, keeps secrets securely managed at rest via SOPS without hardcoding keys in tracked files, and activates all OpenCode Go models synchronously on server boot.
Consequences¶
scripts/setup.shaccepts--opencode(decryptssecrets/opencode.envto~/.config/opencode/opencode.envmode 0600) and exports key-value pairs into/etc/environment(if writable) and~/.bashrc.shared/opencode.jsonconfigures remote MCP serverexawith header"x-api-key": "{env:EXA_API_KEY}",context7with"oauth": falseand header"CONTEXT7_API_KEY": "{env:CONTEXT7_API_KEY}", and native provider mapping"opencode-go": { "env": ["OPENCODE_GO_API_KEY"] }.standard_sandbox/startup.shandvm_sandbox/startup.shinclude--opencodewhenENABLE_OPENCODE=1, trigger SOPS decryption, export decrypted credentials includingOPENCODE_API_KEYbefore launchingopencode serve, and rely on OpenCode's native environment discovery without background REST API calls.- If
ENABLE_OPENCODE=1is passed to sandbox runners butAGE_PRIVATE_KEYis missing from the secret collection, sandbox creation fails fast with an explicit error.