Skip to content

devlog/api-plumbing/api-keys-from-your-terminal-to-ci-and-production-90.md

API Keys from Your Terminal to CI and Production

Keep API keys out of your terminal history

The easiest credential leak starts with a harmless-looking command: export a literal key, commit a configuration file, or enable shell tracing while debugging. This walkthrough uses Bash locally, GitHub Actions for CI, and a Linux host running systemd 247 or newer in production.

Fluxo gives your tools one key and one base URL, https://api.fluxorelay.com. That makes configuration simpler, but also makes that key worth protecting: treat it as a billing credential. Create separate keys for development, CI, and production wherever your account supports them.

Load a development key without saving it in Git

Start inside your project. Ignore local secret files before creating any, and disable shell tracing before handling credentials. These commands leave your key in the current shell environment without putting its value in command history.

printf '\n.env\n.env.*\n!.env.example\n.venv/\n' >> .gitignore — set +x; IFS= read -r -s -p 'Fluxo development key: ' FLUXO_API_KEY; printf '\n'; export FLUXO_API_KEY

Export the endpoint separately. Configuration belongs in source control; credentials do not. Ignoring a file also does not remove it from Git if it was already tracked.

export OPENAI_BASE_URL=https://api.fluxorelay.com — Environment variables are convenient, but child processes inherit them. Run these commands in a dedicated terminal, avoid dumping your environment into bug reports, and close that shell when finished.

Verify the key with a small Python request

Create an isolated environment and install the OpenAI SDK. For repeatable CI builds, commit your reviewed dependency lockfile.

python3 -m venv .venv — .venv/bin/python -m pip install openai

Choose GPT-6 Astra or Claude Sonnet 5.5, then copy its exact API model identifier from Fluxo into this prompt. Display names and request identifiers can differ.

IFS= read -r -p 'API model identifier: ' FLUXO_MODEL; export FLUXO_MODEL

Save this single line as probe.py. It reads either a local environment variable or the systemd credential used below, and prints only the response text.

import os; from pathlib import Path; from openai import OpenAI; directory = os.getenv('CREDENTIALS_DIRECTORY'); key = Path(directory, 'fluxo_api_key').read_text().strip() if directory else os.environ['FLUXO_API_KEY']; client = OpenAI(api_key=key, base_url='https://api.fluxorelay.com'); response = client.chat.completions.create(model=os.environ['FLUXO_MODEL'], messages=[{'role':'user','content':'Reply with OK.'}], max_tokens=16); print(response.choices[0].message.content) — .venv/bin/python probe.py

Inject the CI key through GitHub Actions secrets

Authenticate the GitHub CLI, then upload your separate CI key through its hidden prompt. Store the model identifier as an ordinary repository variable.

gh auth login — gh secret set FLUXO_API_KEY

gh variable set FLUXO_MODEL --body "$FLUXO_MODEL" — Save the following JSON as .github/workflows/fluxo-probe.yml; JSON is valid YAML. Commit probe.py alongside it. Manual dispatch makes each billable check intentional.

{"name":"Fluxo probe","on":{"workflow_dispatch":{}},"permissions":{"contents":"read"},"jobs":{"probe":{"runs-on":"ubuntu-latest","steps":[{"uses":"actions/checkout@v4"},{"uses":"actions/setup-python@v5","with":{"python-version":"3.12"}},{"run":"python -m pip install openai"},{"run":"python probe.py","env":{"FLUXO_API_KEY":"${{ secrets.FLUXO_API_KEY }}","FLUXO_MODEL":"${{ vars.FLUXO_MODEL }}"}}]}}}

Keep secrets away from untrusted pull-request code. GitHub masks registered values, but transformed values and application debug output can still leak credentials.

Deliver the production key with systemd credentials

On your production host, prepare the same project and virtual environment. Store its separate key in a root-owned file. The hidden prompt avoids command history; printf is a Bash builtin, so the value is not passed to an external executable.

sudo install -d -m 700 /etc/fluxo — set +x; IFS= read -r -s -p 'Fluxo production key: ' production_key; printf '\n'; printf '%s' "$production_key" | sudo sh -c 'umask 077; cat > /etc/fluxo/api-key'; unset production_key

Run the probe as your deployment user, with systemd delivering the credential as a file. Set FLUXO_MODEL on this host first.

sudo systemd-run --wait --pipe --collect --uid="$(id -un)" --property="LoadCredential=fluxo_api_key:/etc/fluxo/api-key" --working-directory="$PWD" --setenv="FLUXO_MODEL=$FLUXO_MODEL" "$PWD/.venv/bin/python" "$PWD/probe.py"

For your persistent service, use the same LoadCredential setting. This protects delivery, not a compromised application or root account.

Rotate leaked keys before cleaning up files

Revoke an exposed key immediately, replace it in each affected environment, and restart workloads. Deleting a commit does not invalidate credentials.

If you want to follow along, create a Fluxo account and start with a development key. Billing follows actual tokens, including cache reads and writes, with no monthly fee—another reason to keep test requests small.

Next in the buffer

Sign up in a minute and get credit to try every model mentioned here. Sign up →