Skip to content

Operate a customer-run pilot

This is the procedure qualified for a customer-operated pilot on one host. Every step below runs in the Integration CI job pilot-lifecycle on a clean Ubuntu 24.04 container with pinned component versions. It is not a turnkey production release: container images, a compose file, a privately managed mode and server-to-server migration are not part of this pilot.

The operator tool is tools/pilot/pilot.py in the Integration repository; it keeps one deployment directory with its configuration, owner-only secrets, process ids, the gateway state (journal and payload store) and a journey record.

Prerequisites: PostgreSQL you operate (an empty database and a login without a password in the connection string — use peer authentication or a PGPASSFILE), the pinned component checkouts, and the native arraybridge_server built from them.

Terminal window
python3 tools/pilot/pilot.py install --deployment /srv/ophiolite/pilot \
--dsn "host=db port=5432 user=ophiolite dbname=ophiolite" \
--components /srv/ophiolite/components --server /srv/ophiolite/bin/arraybridge_server
python3 tools/pilot/pilot.py start --deployment /srv/ophiolite/pilot

install applies the project schema and migrations in their documented order and creates the pilot identities with the operator CLI (tools/project-admin.py): token files are written owner-only and only their hashes enter the database. No Ophiolite account, subscription or licence server is contacted. Browser sign-in through your own identity provider is configured separately (see Deployment choices).

Terminal window
python3 tools/pilot/pilot.py upgrade --deployment /srv/ophiolite/pilot \
--components /srv/ophiolite/components-next --archive /backups/before-upgrade.tar.gz

The sequence stops every process (native service, worker, gateway), takes a backup, switches to the new pinned components (and binary, with --server), re-applies the schema and migrations, starts and re-verifies every recorded exact revision and refusal. Keep each release’s components in their own directory; do not check a new release out over a running one. Downgrade is not supported: restore the before-upgrade backup into a fresh database and directory instead.

Terminal window
python3 tools/pilot/pilot.py stop --deployment /srv/ophiolite/pilot
python3 tools/pilot/pilot.py backup --deployment /srv/ophiolite/pilot --archive /backups/pilot.tar.gz
python3 tools/pilot/pilot.py restore --archive /backups/pilot.tar.gz --deployment /srv/ophiolite/restored \
--dsn "host=db2 port=5432 user=ophiolite dbname=ophiolite" --components /srv/ophiolite/components \
--server /srv/ophiolite/bin/arraybridge_server --secrets /srv/ophiolite/pilot/secrets

A backup is taken while the deployment is stopped (a controlled write pause). It holds the project database dump, the gateway journal with every payload-store object it references (verified), and the source configuration, with a SHA-256 manifest. Restore checks the whole archive before touching anything (a changed, missing, extra, duplicated or unsafe member refuses), requires an empty target database and a new directory, then restores. If a restore fails part-way, drop that database and directory and run it again; the archive is never modified. Keep backups off the host.

Retained bytes live in a content-addressed payload store. The default is a directory beside the gateway journal; set OPHIOLITE_PAYLOAD_STORE to use another place:

Terminal window
OPHIOLITE_PAYLOAD_STORE=local:/srv/ophiolite/payloads
OPHIOLITE_PAYLOAD_STORE=s3:https://objects.example.com/ophiolite-bucket/pilot
OPHIOLITE_PAYLOAD_STORE_CREDENTIALS=/srv/ophiolite/secrets/s3.json # {"access_key", "secret_key", "region"}, mode 0600

An S3-compatible store keeps the same rules as the local one: objects are written once and verified on every read, one store serves one gateway journal, unreferenced objects are removed only by the offline sweep after a grace period. Credentials come only from the private file; bucket names and keys never appear in responses. A store that cannot be reached answers “busy, retry” (HTTP 503) rather than reporting damaged data. Backups copy the objects into local files; restore fills an empty store (an interrupted restore of the same backup resumes) before the journal is published.

Limits are per deployment: OPHIOLITE_MAX_UPLOAD_BYTES (default 8 MiB, at most 32 MiB) is enforced from the declared size before any upload byte is read; OPHIOLITE_SCIENTIFIC_READS (default 2) and OPHIOLITE_SCIENTIFIC_READ_WAIT_MS (default 10000) set how many exact reads run at once and how long a request waits for a turn before “busy, retry”. Exact reads accept one HTTP byte range and always carry the whole representation’s SHA-256 in X-Content-SHA256.

Terminal window
python3 tools/pilot/pilot.py exit --deployment /srv/ophiolite/pilot --output /exports/bundle

exit exports the recorded exact revisions (well log, result, tops, survey, grid) as a portable bundle through the Python SDK, stops the server, and reads and recalculates them in a separate Python process with networking blocked. See Take exact curves with you. A backup restores a deployment; a bundle is how you use the data without one.

Who is responsible for what (customer-operated mode)

Section titled “Who is responsible for what (customer-operated mode)”
Area Operator (you) Ophiolite software
Storage Hosts the PostgreSQL database, the gateway journal and the payload store; can read all of them Stores exact bytes content-addressed; never deletes during operation
Compute Runs the native service, gateway and worker; Python calculations run on users’ computers Records runs and results; no hosted execution
Access Creates identities and project membership; configures the identity provider Enforces project membership, per-asset grants, revocation and withdrawal
Operations Backups, restores, upgrades, monitoring, TLS, network policy Provides the pilot tool, migrations and verification
Exit Chooses when to export Portable bundles readable without the server
Telemetry Disabled by default; an operator may configure an OpenTelemetry endpoint of their own Sends nothing to Ophiolite

What the operator can see: everything stored on the host — database rows (members, grants, activity), journal records (uploads, runs, receipts, sharing), payload bytes and logs. Users’ local Python work stays on their computers.

Release notes — pilot release 2026-09-27

Section titled “Release notes — pilot release 2026-09-27”
  • Sharing cutover announced. Replacing recipients without the version you saw (unconditional sharing) is deprecated. This release adds the switch OPHIOLITE_REQUIRE_CONDITIONAL_SHARING=1, which refuses it (HTTP 428, condition-required) and changes nothing. It is off by default in this release and will be on by default in the next release. Workspace and the current SDK already share conditionally.
  • New since the previous pilot release: result versions, the local payload store, portable bundles, well tops/trajectories/horizon grids, connector capability pages and explicit updates for locked sources.

Container images and compose, systemd activation with install-server.py --apply, Caddy TLS and Keycloak/browser sign-in in the automated job, ARM64, privately managed mode, server-to-server migration with identity mapping, public build inputs and licence files (E17), and the matching source/notices package.