Customer-Managed Air-Gapped Installs
Use this guide when Pretorin is installed from a customer-managed or air-gapped deployment bundle and the CLI needs to talk to that private platform instead of the hosted Pretorin service.
The platform bundle owns Kubernetes install, data seeding, embedding, and AI provider validation. The CLI owns developer and agent access to the installed platform.
Security Notes
Do not paste secret values, decoded Kubernetes secrets, API tokens, model API keys, or full environment dumps into support tickets or chat. The commands below intentionally check non-secret configuration values or secret key names only.
When validating secrets, confirm that required keys exist without decoding their values:
kubectl get secret -n pretorin pretorin-platform-secrets \
-o go-template='{{range $k, $_ := .data}}{{println $k}}{{end}}'
Platform Validation
After the platform is installed and object storage is initialized, run the bundle smoke test from the deployment bundle:
NAMESPACE=pretorin scripts/customer/validate-airgap-install.sh
The smoke test runs inside the deployed API pod and verifies:
- database connectivity
- seeded framework, package, source, document requirement, and crosswalk data
- NIST 800-53 catalog presence
- OSCAL control embedding coverage and vector dimensions
- direct local AI provider chat and embedding calls
- API-to-AI service connectivity
- dashboard AI chat streaming and chat message persistence
For staged troubleshooting, skip chat first:
NAMESPACE=pretorin scripts/customer/validate-airgap-install.sh --skip-chat
That confirms data seeding, embeddings, provider reachability, and AI service health before testing the full streaming chat path.
CLI Configuration
Point the CLI at the private platform public API endpoint:
pretorin config set platform_api_base_url https://<platform-host>/api/v1/public
pretorin config set model_api_base_url https://<platform-host>/api/v1/public/model
pretorin whoami
pretorin frameworks list
pretorin config set platform_api_base_url prompts for an API key for the new
endpoint and validates it before saving the change.
For non-interactive hosts, use environment variables:
export PRETORIN_API_KEY=<platform-api-token>
export PRETORIN_PLATFORM_API_BASE_URL=https://<platform-host>/api/v1/public
export PRETORIN_MODEL_API_BASE_URL=https://<platform-host>/api/v1/public/model
pretorin whoami
pretorin frameworks list
If you use MCP, the MCP server inherits the same CLI configuration:
pretorin mcp-serve
For Codex, Claude, Cursor, and other MCP client setup, see MCP Setup Guides.
Agent Runtime Notes
For pretorin agent run, model credential precedence is:
config.api_key(frompretorin loginagainst the customer platform)OPENAI_API_KEYconfig.openai_api_key
If the user passes --base-url explicitly (pointing the agent at a
non-platform model endpoint), the order flips to OPENAI_API_KEY first, then
falls back to the config keys.
If you want the agent runtime to use the customer platform model endpoint, keep
PRETORIN_MODEL_API_BASE_URL pointed at:
https://<platform-host>/api/v1/public/model
When PRETORIN_MODEL_API_BASE_URL is set via env or config (without an explicit
--base-url flag), the agent uses config.api_key from pretorin login
against the customer platform, so shell OPENAI_API_KEY does not override
it. Unset OPENAI_API_KEY only if you also pass --base-url and want the
model call to land on a non-platform provider.
Common Issues
| Symptom | Likely cause | First check or fix |
|---|---|---|
pretorin whoami or pretorin frameworks list hits hosted Pretorin | CLI base URL is still using hosted config | Run pretorin config list, then set platform_api_base_url to https://<platform-host>/api/v1/public. |
| CLI returns 401 or 403 | API key is for another endpoint, expired, or missing required scopes | Run pretorin login or pretorin config set platform_api_base_url ... and enter a token from the customer platform. |
pretorin agent run uses the wrong model credentials | Explicit --base-url flag flips precedence to OPENAI_API_KEY first, or stored openai_api_key config overrides the platform key | Drop --base-url and set PRETORIN_MODEL_API_BASE_URL to the customer endpoint so the agent uses config.api_key from pretorin login. |
AI provider validation failed during platform install | OPENAI_BASE_URL is wrong, missing /v1, or unreachable from the cluster | In the deployment environment, run python -m app.cli.validate_ai_provider inside the API pod and confirm DNS, port, TLS, and provider path. |
| Provider calls time out | NetworkPolicy blocks API or AI egress to the local model endpoint | Add matching API and AI NetworkPolicy egress rules, then rerun Helm upgrade. |
OPENAI_API_KEY is required or provider env is missing | Platform secret was not created or was created before env vars were exported | Rerun scripts/customer/create-customer-secrets.sh, then restart API and AI deployments. |
| Embedding count is zero or below the control count | The embedding hook failed, is still running, or the API does not have the local embedding model env | Check pretorin-api-embedding-sync-* job logs and confirm API env includes OPENAI_BASE_URL and OPENAI_EMBEDDING_MODEL. |
| Embedding dimension mismatch | Local embedding model does not return 1536-dimensional vectors | Use a 1536-dimension embedding model for OPENAI_EMBEDDING_MODEL. |
| Data seeding fails or NIST 800-53 is missing | Framework seed hook did not complete | Check pretorin-api-seed-frameworks-* job logs and rerun Helm upgrade after fixing the error. |
Smoke test passes with --skip-chat but fails without it | Provider supports basic calls but not streaming chat, tool calling, or the configured chat model | Confirm the model supports streaming chat completions and tool calls; update OPENAI_MODEL if needed. |
| Chat stream emits an error after a session is created | AI service can start the request but failed during agent execution | Check deployment/pretorin-ai logs around the smoke-test timestamp. |
Useful platform-side checks:
kubectl get pods,jobs -n pretorin
kubectl logs -n pretorin job/<failed-job-name>
kubectl exec -n pretorin deployment/pretorin-api -- \
sh -c 'env | grep -E "^(OPENAI_BASE_URL|OPENAI_MODEL|OPENAI_EMBEDDING_MODEL|OPENAI_USE_RESPONSES|AI_REQUIRE_LOCAL_PROVIDER|AI_PROVIDER_KIND|AI_PROVIDER_DEFAULT_PROFILE_ID|AI_PROVIDER_DEFAULT_PROFILE_NAME|AI_SERVICE_URL)="'
kubectl exec -n pretorin deployment/pretorin-ai -- \
sh -c 'env | grep -E "^(OPENAI_BASE_URL|OPENAI_MODEL|OPENAI_EMBEDDING_MODEL|OPENAI_USE_RESPONSES|AI_REQUIRE_LOCAL_PROVIDER|AI_PROVIDER_KIND|AI_PROVIDER_DEFAULT_PROFILE_ID|AI_PROVIDER_DEFAULT_PROFILE_NAME|AI_SERVICE_URL)="'
What Passing Looks Like
A healthy install can:
- return
pretorin whoami - list seeded frameworks with
pretorin frameworks list - run
scripts/customer/validate-airgap-install.shwithout failures - use chat in the web UI
- route MCP tools through
pretorin mcp-serve - route
pretorin agent runthrough the configured customer model endpoint