Outpost software updates
The Arbitex Outpost supports two update methods:
-
Signed bundle update API (shipped in outpost-0034) — A built-in update manager that downloads, verifies, and stages update bundles via the outpost admin API. Bundles are Ed25519-signed tarballs. Recommended for connected deployments.
-
Docker image update — Pull and recreate the outpost container with a new image tag. Used for major upgrades, Kubernetes deployments, and environments where bundle-based updates are not configured.
Source: outpost/services/software_update.py, outpost/admin/routes.py
Signed bundle update API (outpost-0034)
Section titled “Signed bundle update API (outpost-0034)”Starting with outpost-0034, the outpost includes a SoftwareUpdateManager service that manages the full update lifecycle: version check → bundle download → signature verification → staging. Updates are applied by restarting the outpost process — there is no auto-apply.
Required environment variables
Section titled “Required environment variables”| Variable | Required | Description |
|---|---|---|
SOFTWARE_UPDATE_RELEASE_URL |
Yes | URL to the JSON release manifest. When set, the update manager is initialized. |
SOFTWARE_UPDATE_SIGNING_KEY |
Yes | Base64url-encoded 32-byte Ed25519 public key used to verify bundle signatures. Fail-closed: updates are rejected if this key is absent or the signature does not match. |
UPDATE_STAGE_DIR |
No | Directory for staged bundle files (default: /tmp/outpost-update-stage). |
OUTPOST_VERSION |
No | Current running version, for version comparison in the manifest check. |
If SOFTWARE_UPDATE_RELEASE_URL is not set, all update API endpoints return a 503 with "Software update not configured".
Update lifecycle
Section titled “Update lifecycle”The update process has three explicit steps, each triggered by an admin API call:
IDLE → CHECKING → AVAILABLE → DOWNLOADING → STAGED ↓ (restart) APPLIEDIf any step fails, the status transitions to ERROR. Re-trigger from the beginning (/check first).
Step 1 — Check for updates
Section titled “Step 1 — Check for updates”POST /admin/api/updates/checkAuthorization: Basic admin:<OUTPOST_EMERGENCY_ADMIN_KEY>Fetches the release manifest from SOFTWARE_UPDATE_RELEASE_URL. The manifest must include version, download_url, and signature_url. Compares the manifest version against OUTPOST_VERSION.
Response:
{ "status": "available", "current_version": "0.33.0", "latest_version": "0.34.0", "release_notes": "outpost-0034: signed bundle update API, policy simulator improvements", "download_progress": null, "staged_at": null, "staged_version": null, "staged_path": null, "signature_verified": null, "error": null}If already at the latest version, status is "idle".
Step 2 — Download and verify
Section titled “Step 2 — Download and verify”POST /admin/api/updates/downloadAuthorization: Basic admin:<OUTPOST_EMERGENCY_ADMIN_KEY>Downloads the bundle tarball and its Ed25519 signature file concurrently from the URLs in the manifest. Verifies the signature using the SOFTWARE_UPDATE_SIGNING_KEY public key.
Signature verification:
- Uses the
cryptographylibrary’sEd25519PublicKey.verify(). - Fail-closed: if
SOFTWARE_UPDATE_SIGNING_KEYis missing, the key is invalid, or the signature does not match, the download is rejected and status is set to"error". The bundle is never staged with a failed or missing signature.
Response on success:
{ "status": "staged", "current_version": "0.33.0", "latest_version": "0.34.0", "download_progress": 1.0, "staged_at": 1741824000.0, "staged_version": "0.34.0", "staged_path": "/tmp/outpost-update-stage/outpost-0.34.0.tar.gz", "signature_verified": true, "error": null}Response on signature failure:
{ "status": "error", "error": "Signature verification failed — bundle rejected (fail-closed)", "signature_verified": null}Step 3 — Check staged status
Section titled “Step 3 — Check staged status”GET /admin/api/updates/statusAuthorization: Basic admin:<OUTPOST_EMERGENCY_ADMIN_KEY>Returns the current update manager state. Use this to poll during a download or to confirm staging before applying.
| Field | Description |
|---|---|
status |
idle / checking / available / downloading / staged / error |
current_version |
Running outpost version |
latest_version |
Version from the last manifest fetch |
release_notes |
Release notes from the manifest |
download_progress |
Float 0.0–1.0 during download, 1.0 when staged |
staged_at |
UNIX timestamp when the bundle was staged |
staged_version |
Version of the staged bundle |
staged_path |
Filesystem path to the staged .tar.gz |
signature_verified |
true if the staged bundle passed signature verification |
error |
Error message if status == "error" |
Step 4 — Apply the update
Section titled “Step 4 — Apply the update”No auto-apply: once status == "staged" and signature_verified == true, apply the update by restarting the outpost process:
# Docker Composedocker compose -f docker-compose.outpost.yml restart outpost
# Kuberneteskubectl rollout restart deployment/arbitex-outpost -n arbitexOn startup, the outpost extracts the staged bundle from staged_path and loads the new binary. After restart, verify with GET /admin/api/updates/status — current_version should match staged_version and status should be "idle".
Air-gap update procedure (manual bundle placement)
Section titled “Air-gap update procedure (manual bundle placement)”In air-gap deployments (OUTPOST_AIRGAP=true) or networks where the outpost cannot reach the release manifest URL, place bundles manually:
-
Obtain the bundle from your Arbitex account team. The bundle package contains:
outpost-{version}.tar.gz— the update tarballoutpost-{version}.tar.gz.sig— the Ed25519 signature file
-
Copy the bundle to the stage directory:
Terminal window # Default stage dircp outpost-0.34.0.tar.gz /tmp/outpost-update-stage/cp outpost-0.34.0.tar.gz.sig /tmp/outpost-update-stage/ -
Trigger download (the download step also performs signature verification even for manually placed bundles, as long as the files exist at the manifest URLs or in the stage directory):
For pure air-gap with no manifest server, use the direct bundle injection endpoint if available, or restart the outpost with the
UPDATE_STAGE_DIRenvironment pointing to the bundle directory. The update manager will pick up the pre-placed bundle on startup. -
Verify signature before restart:
Terminal window # Manually verify using the same Ed25519 key# (requires cryptography package)python3 - <<'EOF'import base64from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKeykey_b64 = "<SOFTWARE_UPDATE_SIGNING_KEY>"raw_key = base64.b64decode(key_b64 + "==")public_key = Ed25519PublicKey.from_public_bytes(raw_key)bundle = open("outpost-0.34.0.tar.gz", "rb").read()sig = open("outpost-0.34.0.tar.gz.sig", "rb").read()public_key.verify(sig, bundle)print("Signature valid")EOF -
Restart the outpost to apply the staged bundle.
How the outpost detects updates
Section titled “How the outpost detects updates”The outpost sends a heartbeat to the Platform management plane every 120 seconds via mTLS. The heartbeat payload includes the current running version:
{ "version": "0.1.0", "uptime": 3600, "policy_version": "abc123", ...}The Platform heartbeat response includes a latest_version field:
{ "latest_version": "0.2.0"}When the running version differs from latest_version, the outpost logs a warning:
WARNING outpost.heartbeat: Outpost version outdated: running=0.1.0 latest=0.2.0 — update recommendedThe outpost admin status API also exposes this signal:
GET /admin/api/statusResponse:
{ "outpost_id": "op_01abc123", "policy_version": "abc123", "update_available": true, "latest_version": "0.2.0", "uptime_seconds": 7200, ...}update_available: true means the Platform has signaled that a newer version is available. The admin panel displays an update notification banner when this field is true.
Checking for updates
Section titled “Checking for updates”Admin panel
Section titled “Admin panel”Open the outpost admin panel at http://localhost:8301 (or your outpost admin URL). If an update is available, a notification banner appears at the top of the Status page:
Update available: Outpost 0.2.0 is available (running 0.1.0). See the update guide to apply.
Admin API
Section titled “Admin API”Poll the status endpoint directly:
curl -s \ -u admin:${OUTPOST_EMERGENCY_ADMIN_KEY} \ http://localhost:8301/admin/api/status \ | jq '{update_available, latest_version, policy_version}'Policy sync status and signature verification
Section titled “Policy sync status and signature verification”The sync-status endpoint shows the current policy bundle signature state alongside version information:
curl -s \ -u admin:${OUTPOST_EMERGENCY_ADMIN_KEY} \ http://localhost:8301/admin/api/sync-status \ | jq '{bundle_version, latest_version, bundle_signature_valid, bundle_verified_at}'| Field | Description |
|---|---|
bundle_version |
Policy bundle version currently loaded |
latest_version |
Latest outpost software version reported by Platform |
bundle_signature_valid |
Whether the loaded policy bundle passed signature verification |
bundle_verified_at |
UNIX timestamp of the most recent signature check |
bundle_signature_valid: true confirms the policy bundle was verified against the Platform’s signing key. This is separate from the software update — it verifies the policy configuration, not the container image.
Applying a software update
Section titled “Applying a software update”Standard update (Docker Compose)
Section titled “Standard update (Docker Compose)”The outpost runs as Docker Compose services. A software update involves pulling the new image and recreating the containers.
Step 1 — Back up the current configuration
cp .env .env.bakStep 2 — Pull the new image
docker compose -f docker-compose.outpost.yml pullThis pulls arbitex-outpost:latest (or the pinned tag in your compose file) without stopping the running containers.
Step 3 — Verify the image signature
Arbitex signs all release images with Docker Content Trust (DCT). Verify before applying:
# Enable content trust for this commandDOCKER_CONTENT_TRUST=1 docker pull arbitex/outpost:0.2.0If the image has not been signed or the signature does not match, Docker will refuse to pull it and print an error. Do not proceed if signature verification fails — contact Arbitex support.
For air-gapped deployments, see Signature verification in air-gap mode below.
Step 4 — Apply the update with a rolling restart
docker compose -f docker-compose.outpost.yml up -d --force-recreateThis recreates the containers using the newly pulled image. Existing connections to the proxy are gracefully terminated; new connections are handled by the updated container.
Step 5 — Verify the update
Wait 30 seconds for the outpost to fully initialize, then confirm the running version:
curl -s \ -u admin:${OUTPOST_EMERGENCY_ADMIN_KEY} \ http://localhost:8301/admin/api/status \ | jq '{update_available, latest_version}'Expected after a successful update:
{ "update_available": false, "latest_version": "0.2.0"}Also check the health endpoint:
curl -sf http://localhost:8300/health && echo "healthy"Kubernetes update
Section titled “Kubernetes update”If you run the outpost on Kubernetes via the Arbitex Helm chart:
Step 1 — Update the image tag in values
image: tag: "0.2.0"Step 2 — Apply the Helm upgrade
helm upgrade arbitex-outpost arbitex/outpost \ -f values-prod.yaml \ --namespace arbitexHelm performs a rolling update by default — old pods are kept running while new pods start and pass readiness checks.
Step 3 — Verify
kubectl rollout status deployment/arbitex-outpost -n arbitexkubectl exec -n arbitex deployment/arbitex-outpost -- \ curl -s -u admin:${OUTPOST_EMERGENCY_ADMIN_KEY} http://localhost:8301/admin/api/status \ | jq .latest_versionAir-gap update sideloading
Section titled “Air-gap update sideloading”In air-gap deployments (OUTPOST_AIRGAP=true), the outpost does not connect to the Platform management plane and cannot receive heartbeat responses. Update detection and application must be done manually.
Obtaining the update package
Section titled “Obtaining the update package”Contact Arbitex support or your account team to receive the air-gap update bundle for the target version. The bundle contains:
arbitex-outpost-{version}.tar— the Docker image archivearbitex-outpost-{version}.sha256— SHA-256 checksum filearbitex-outpost-{version}.sig— Ed25519 image signature
Verifying the signature
Section titled “Verifying the signature”-
Import the Arbitex release signing public key (provided by your Arbitex account team):
Terminal window # Import the public keygpg --import arbitex-release-signing.pub -
Verify the signature on the image archive:
Terminal window gpg --verify arbitex-outpost-0.2.0.sig arbitex-outpost-0.2.0.tarA successful verification prints:
gpg: Good signature from "Arbitex Release Signing Key <[email protected]>"Do not proceed if the signature is invalid or the key cannot be verified.
-
Verify the checksum:
Terminal window sha256sum -c arbitex-outpost-0.2.0.sha256Expected output:
arbitex-outpost-0.2.0.tar: OK
Loading the image
Section titled “Loading the image”docker load < arbitex-outpost-0.2.0.tarUpdating the policy bundle (air-gap policy sideload)
Section titled “Updating the policy bundle (air-gap policy sideload)”Air-gap outposts load the policy bundle from a local volume rather than syncing from the Platform. To update the policy bundle:
-
Obtain the new
policy_bundle.jsonfrom your Arbitex account team (delivered as a signed archive using the same GPG key). -
Verify the signature on the bundle archive.
-
Place the new bundle at the configured path:
Terminal window # Default path (override with AIRGAP_POLICY_PATH)cp policy_bundle.json /opt/arbitex/policies/policy_bundle.json -
Restart the outpost to load the new bundle:
Terminal window docker compose -f docker-compose.outpost.yml restart -
Verify the bundle loaded:
Terminal window curl -s \-u admin:${OUTPOST_EMERGENCY_ADMIN_KEY} \http://localhost:8301/admin/api/sync-status \| jq '{bundle_version, bundle_signature_valid}'
Applying the software update (air-gap)
Section titled “Applying the software update (air-gap)”-
Tag the loaded image to match the compose file’s image reference:
Terminal window docker tag arbitex-outpost:0.2.0 arbitex-outpost:latest -
Recreate the containers:
Terminal window docker compose -f docker-compose.outpost.yml up -d --force-recreate -
Verify as in the standard update steps above.
Signature verification in air-gap mode
Section titled “Signature verification in air-gap mode”The outpost verifies policy bundle signatures using a trusted Platform public key embedded at build time. In connected mode, the Platform signs bundles and the outpost verifies on each sync. In air-gap mode, the same verification runs when a new bundle is loaded.
bundle_signature_valid in the sync-status response reflects the most recent verification result. If this field is false after loading a new bundle, the bundle was not signed with the expected key — do not use it. Contact Arbitex support.
Rollback procedure
Section titled “Rollback procedure”Docker Compose rollback
Section titled “Docker Compose rollback”If the updated outpost is unhealthy or causing errors, roll back by specifying the previous image tag.
Step 1 — Edit the compose file to pin the previous version
services: outpost: image: arbitex/outpost:0.1.0 # previous versionStep 2 — Pull and recreate
docker compose -f docker-compose.outpost.yml pulldocker compose -f docker-compose.outpost.yml up -d --force-recreateStep 3 — Verify
curl -s \ -u admin:${OUTPOST_EMERGENCY_ADMIN_KEY} \ http://localhost:8301/admin/api/status \ | jq .update_available# Expected: true (since the rolled-back version is older than latest)After rollback, update_available will be true again — that is expected. Investigate the issue before re-applying the update.
Kubernetes rollback
Section titled “Kubernetes rollback”kubectl rollout undo deployment/arbitex-outpost -n arbitexkubectl rollout status deployment/arbitex-outpost -n arbitexThis rolls back to the previous ReplicaSet. Helm history is also available:
helm history arbitex-outpost -n arbitexhelm rollback arbitex-outpost <revision> -n arbitexUpdate checklist
Section titled “Update checklist”Before applying any update:
- Read the release notes for the target version (available at
https://docs.arbitex.ai/changelog/outpost). - Verify the image signature before loading.
- Back up
.envand any local configuration. - Test the update in a non-production outpost first if possible.
- Confirm
bundle_signature_valid: trueafter restart. - Confirm
update_available: falseafter restart (connected mode) or check the version field directly (air-gap mode). - Run a test request through the proxy to confirm DLP and policy evaluation are functioning.
See also
Section titled “See also”- Outpost deployment guide — initial installation and environment configuration
- Outpost health monitoring — heartbeat monitoring, cert expiry alerts, sync status
- Air-gap deployment — full air-gap configuration reference
- Outpost admin API — complete admin API reference for status, sync-status, and airgap-config endpoints
- Outpost Administration — budget enforcement, CredInt, health monitoring, JWT validation, PVC recovery, security hardening, SIEM direct integration
Update Modes
Section titled “Update Modes”The Outpost manages its own update lifecycle through one of three update modes:
Why auto is the default
Section titled “Why auto is the default”For most deployments, the safest Outpost is the one that is already patched. When a Critical or High severity CVE is fixed in an Outpost release, the gap between “a fix exists” and “your Outpost is running it” is pure exposure. auto mode closes that gap on your behalf — verified, health-gated, and confined to a window you choose — so you get SaaS-equivalent patch latency without giving up control of your data plane.
Every mode applies the same signature verification before any new version runs. The difference between the modes is who triggers the rollout and when, not whether patches are verified.
The three modes
Section titled “The three modes”| Mode | Behavior | Best for |
|---|---|---|
auto (default) |
The embedded Updater daemon polls the signed Arbitex release feed. When a signed Critical/High CVE patch is published, it pulls the new image digest and rolls the Outpost’s own pods within your configured maintenance window. The rollout is a single-pod canary first, health-gated, with automatic rollback on failure. | SaaS-equivalent and standard-compliance customers; most self-hosted enterprises. |
notify |
The Updater polls the feed and flags available updates in the admin UI plus an email or Slack alert — but applies nothing on its own. You click Apply to trigger the same canary → rollout flow used by auto. |
Regulated customers who require a change-control review before any production change. |
manual |
No polling and no telemetry. You pull signed patches yourself and apply them with the Outpost CLI. The patch goes through the same signature verification; only the transport is human-driven. | Air-gapped deployments and strict-compliance regimes. |
Maintenance window
Section titled “Maintenance window”In auto mode, updates apply only inside a maintenance window you configure. Outside the window, an available patch is staged and waits — it is never applied to a running pod at an unexpected time.
auto_update: window: "Sun 02:00-04:00 UTC"The window is expressed in UTC. Choose a low-traffic period that suits your operations.
Canary rollout and automatic rollback
Section titled “Canary rollout and automatic rollback”When an update is applied — whether triggered automatically in auto mode or by clicking Apply in notify mode — the Outpost rolls out progressively:
- Canary — a single pod is updated to the new digest first.
- Health gate — the canary pod must pass its health and readiness checks for a defined period before the rollout continues.
- Fleet rollout — once the canary is healthy, the remaining pods are updated.
- Automatic rollback — if the canary fails its health gate, the rollout halts and the Outpost automatically reverts to the previous known-good version.
In auto mode, the outcome of every rollout (success or failure) is reported back to Arbitex so your account team has visibility into fleet patch health.
Switching modes
Section titled “Switching modes”You can change the update mode at any time from the Outpost admin UI. The customer dashboard shows your current and available versions, update history, last patch latency, and the active mode setting.
Air-gapped manual flow
Section titled “Air-gapped manual flow”Air-gapped Outposts run in manual mode: the Outpost does not poll the release feed and emits no update telemetry. Retrieve signed patches yourself and apply them with the CLI. Verification is identical to the connected modes — only the transport differs.
-
Download the signed patch for the target version from
download.arbitex.aionto an internet-connected workstation. -
Transfer the patch to the Outpost host through your approved channel (SCP, USB media, etc.).
-
Apply the patch with the Outpost CLI:
Terminal window arbitex-outpost update --apply ./outpost-<ver>.tar.gz.sig
If the signature does not verify against the embedded trust root, the apply step fails and the current version keeps running — the same fail-closed behavior as the connected modes.
Upgrade Orchestrator Internals
Section titled “Upgrade Orchestrator Internals”All upgrade operations are orchestrated through the Outpost admin API with Ed25519 signature verification and automatic rollback on failure.
Version compatibility matrix
Section titled “Version compatibility matrix”Before upgrading, verify that your runtime environment meets the minimum requirements. The Outpost checks these automatically during the upgrade preflight step.
| Component | Min version | Recommended | Required | Notes |
|---|---|---|---|---|
| Python | 3.12.0 | 3.12.4 | Yes | Python runtime |
| FastAPI | 0.115.0 | 0.115.0 | Yes | ASGI web framework |
| Uvicorn | 0.30.0 | 0.30.0 | Yes | ASGI server |
| Pydantic | 2.5.0 | 2.9.0 | Yes | Config validation (v2) |
| httpx | 0.27.0 | 0.27.0 | Yes | Async HTTP client for platform communication |
| cryptography | 43.0.0 | 44.0.0 | Yes | TLS, Ed25519 signatures, cert verification |
| PyJWT | 2.12.0 | 2.12.1 | Yes | JWT token verification |
| opentelemetry-api | 1.27.0 | 1.27.0 | No | OpenTelemetry tracing and metrics |
| prometheus-client | 0.21.0 | 0.21.0 | No | Prometheus metrics export |
| spaCy | 3.7.0 | 3.8.0 | No | NER scanning (Tier 2 DLP) |
| onnxruntime | 1.18.0 | 1.19.0 | No | DeBERTa ONNX inference (Tier 3 DLP) |
Check compatibility at any time:
GET /admin/api/compatAuthorization: Bearer <admin-token>The response includes per-component results with pass / warn / fail / skip statuses. An overall: "fail" result means the Outpost may not function correctly after upgrade — resolve all failing components before proceeding.
Pre-upgrade checklist
Section titled “Pre-upgrade checklist”Before starting any upgrade:
- Verify configuration — ensure
SOFTWARE_UPDATE_RELEASE_URLandSOFTWARE_UPDATE_ED25519_KEYare set. (SOFTWARE_UPDATE_SIGNING_KEYis a legacy alias forSOFTWARE_UPDATE_ED25519_KEY.) - Check disk space — the preflight step requires at least 500 MB free in the staging directory:
Terminal window df -h /tmp/outpost-update-stage - Verify current health —
GET /admin/api/upgrade/statusshould show phaseidlewith no previous failed upgrade. - Drain active connections — if your deployment uses a load balancer, drain the Outpost instance from the pool before upgrading.
- Back up configuration:
Terminal window cp .env .env.pre-upgrade-backup - Run compatibility check —
GET /admin/api/compatshould returnoverall: "pass"orwarn.
How the upgrade orchestrator works
Section titled “How the upgrade orchestrator works”The upgrade orchestrator runs a 7-step workflow. Each step must succeed before the next begins. If any step fails, automatic rollback is triggered.
| Step | Phase | What happens |
|---|---|---|
| 1. Preflight | preflight |
Verifies update manager is configured, checks disk space (min 500 MB) |
| 2. Check | checking |
Fetches release manifest, compares current vs. latest version |
| 3. Download & verify | downloading |
Downloads bundle, verifies Ed25519 signature (or HMAC-SHA256 fallback), extracts |
| 4. Backup | backing_up |
Snapshots existing staged files to _upgrade_backup/ |
| 5. Apply | applying |
Validates extracted files, writes _upgrade_pending.json marker |
| 6. Post-verify | verifying |
Re-checks extracted directory integrity, computes SHA-256 of staged tarball |
| 7. Rollback (on failure) | rolling_back |
Removes pending marker, restores from backup |
Trigger the full orchestration with POST /admin/api/upgrade/run. If a step fails, rollback is automatic: the _upgrade_pending.json marker is removed, the backup is restored, and phase is set to failed with rollback_performed: true. Use GET /admin/api/upgrade/history to review the last 10 upgrade run results.
The orchestrator enforces single-execution safety via an asyncio.Lock — a second run call while an upgrade is in progress returns immediately with an error.
Platform and Cloud Portal Upgrade
Section titled “Platform and Cloud Portal Upgrade”The Outpost update procedures above cover the Outpost data plane. For a full deployment upgrade that includes the Platform backend and Cloud Portal, use the following procedures.
Prerequisites
Section titled “Prerequisites”- Admin access — platform admin credentials and shell access to the host running the deployment.
- Maintenance window — schedule downtime. Migrations lock tables; production traffic will fail during the migration step.
- Read the changelog — review
CHANGELOG.mdin the platform repository before upgrading.
Version compatibility (multi-component)
Section titled “Version compatibility (multi-component)”All Arbitex components are currently at 0.1.0 pre-release. All three components must be upgraded together — mixed-version deployments are not supported. Version drift between Platform and Outpost is detected automatically via the heartbeat mechanism.
Pre-upgrade backup
Section titled “Pre-upgrade backup”Database (PostgreSQL):
pg_dump -Fc -d arbitex_platform -f backup-platform-$(date +%Y%m%d).dumppg_dump -Fc -d arbitex_cloud -f backup-cloud-$(date +%Y%m%d).dumpVerify the dumps are non-zero before continuing.
Application config export — export the full configuration for each org before upgrading (covers DLP rules, compliance bundles, policy templates, routing rules, enterprise entitlements, and 15 other domains):
curl -s -H "Authorization: Bearer $ADMIN_TOKEN" \ "https://platform.example.com/api/v1/admin/orgs/${ORG_ID}/config/export" \ -o config-backup-$(date +%Y%m%d).jsonAudit log archive:
curl -s -X POST -H "Authorization: Bearer $ADMIN_TOKEN" \ -H "Content-Type: application/json" \ -d '{"window_days": 90}' \ "https://platform.example.com/api/v1/admin/audit/export" \ -o audit-backup-$(date +%Y%m%d).jsonVerify the chain_status field in the response is "intact".
Outpost policy cache:
cp -r "${POLICY_CACHE_PATH:-policy_cache/}" policy-cache-backup-$(date +%Y%m%d)/# For air-gap deployments also back up:cp -r "$AIRGAP_POLICY_PATH" airgap-policy-backup-$(date +%Y%m%d)/cp -r "$AIRGAP_MODEL_PATH" airgap-model-backup-$(date +%Y%m%d)/Platform upgrade (Docker Compose)
Section titled “Platform upgrade (Docker Compose)”docker compose downdocker compose pulldocker compose run --rm backend python scripts/run-migrations.pydocker compose up -dcurl http://localhost:8000/health # expected: {"status": "ok"}Platform upgrade (Kubernetes / Helm)
Section titled “Platform upgrade (Kubernetes / Helm)”helm upgrade arbitex-platform ./deploy/helm/arbitex-platform -f values.yamlkubectl rollout status deployment/arbitex-platformAlembic runs automatically as an init container — no manual migration step is needed.
Database rollback
Section titled “Database rollback”pg_restore -d arbitex_platform --clean --if-exists backup-platform-YYYYMMDD.dumppg_restore -d arbitex_cloud --clean --if-exists backup-cloud-YYYYMMDD.dumpAlternatively, use Alembic to downgrade to a specific revision: alembic downgrade <target_revision>.
Post-upgrade verification checklist
Section titled “Post-upgrade verification checklist”| Check | Command | Expected result |
|---|---|---|
| API health | curl /health |
{"status": "ok"} |
| Database migrations | python scripts/run-migrations.py --check |
No pending migrations |
| Audit chain integrity | POST /api/v1/admin/audit/export |
chain_status: "intact" |
| Outpost heartbeat | Check platform logs | Heartbeat received, version matches platform |
| DLP rules loaded | GET /api/v1/admin/dlp-rules |
Rules returned, count matches pre-upgrade |
| Config export completeness | GET /api/v1/admin/orgs/{org_id}/config/export |
20 domains present in response |
Version-by-Version Release Notes
Section titled “Version-by-Version Release Notes”Review the notes for every version between your current version and the target version. Apply changes cumulatively.
0.1.0 — Initial Release
Section titled “0.1.0 — Initial Release”Initial schema — creates base tables: users, conversations, messages, audit_logs, model_configs.
Required env vars: DATABASE_URL, JWT_SECRET_KEY.
First-time setup: call POST /api/setup to create the initial admin account. This endpoint disables itself after first use.
0.2.0 — Core Features
Section titled “0.2.0 — Core Features”Migrations 002–004: model_instructions column on model_configs; share_token on conversations; performance indexes on messages and audit_logs. No new required env vars.
0.3.0 — Rate Limits & System Config
Section titled “0.3.0 — Rate Limits & System Config”Migrations 005–006: model_rate_limits table; system_configs key-value table.
New optional: REDIS_URL — Redis connection string for rate limiting (falls back to PostgreSQL advisory locks if unset).
0.4.0 — DLP & Audit
Section titled “0.4.0 — DLP & Audit”Migrations 007–008: dlp_rules and dlp_rule_versions tables; HMAC chain columns on audit_logs (hmac_signature, prev_hmac, hmac_key_id).
New required: AUDIT_HMAC_KEY — HMAC-SHA256 key for the tamper-evident audit chain. The audit log will not write if this is unset.
New optional: AUDIT_HMAC_KEY_ID (default "default") — key identifier stored in each audit record.
0.5.0 — API Keys & Usage
Section titled “0.5.0 — API Keys & Usage”Migrations 009–010: api_keys table with hashed key storage and per-key rate limits; usage_records table for per-request token and cost tracking. No new required env vars.
0.6.0 — Alerts & DLP Policy Versioning
Section titled “0.6.0 — Alerts & DLP Policy Versioning”Migrations 011–015: alert_rules and alert_events tables; versioning columns on dlp_rules; dlp_events table; retention_policies table; user_groups and group_memberships tables.
New optional: AUDIT_SINKS (default "db") — comma-separated list: db, jsonl, webhook, splunk_hec.
0.7.0 — Enterprise Identity
Section titled “0.7.0 — Enterprise Identity”Migration 026: MFA columns on users (totp_secret, mfa_enabled, backup_codes); saml_idp_configs, webauthn_credentials, ip_allowlist_entries tables.
New env vars:
WEBAUTHN_RP_ID(default"localhost") — must match your actual domain before enabling passkeys in production. WebAuthn credentials are bound to the RP ID — changing it after credentials are registered invalidates all existing passkeys.CLOUD_CA_CERT_PATH— CA certificate for verifying Cloud Portal mTLS connections.MTLS_CA_BUNDLE— CA bundle path for outbound mTLS connections from Platform to Cloud.
0.8.0 — Security & Documentation
Section titled “0.8.0 — Security & Documentation”Migrations through 072: model_registry and model_registry_versions; passkey_policy columns on organizations; org_recovery_codes; content_categories and content_filter_rules.
New env vars (selected):
| Variable | Default | Description |
|---|---|---|
OAUTH_JWT_PRIVATE_KEY |
(required if OAuth enabled) | PEM-encoded RSA private key for signing OAuth JWTs |
POLICY_SIGNING_KEY |
(required) | Ed25519 private key for signing policy packages distributed to Outpost |
SECRETS_BACKEND |
"env" |
Secrets storage backend: env, vault, file |
DLP_INFERENCE_FAIL_MODE |
"closed" |
closed = block request on inference failure; open = allow |
LOG_FORMAT |
"text" |
json recommended for production log aggregation |