Skip to content
Browse documentation

OPRP 0.1.0-dev.11 · Draft documentation

Host storage and developer operations

The reference Host now has an injectable storage boundary, private online SQLite snapshots, opaque HTTP health checks and a persistent two-Host developer lab. These helpers make application development and restart/recovery testing reproducible. They do not establish a production hosting or certification service.

Replaceable storage boundary

HostStorage opens a HostDatabase exposing synchronous exec, prepared get/all/run, close and isOpen. The current reference engine requires SQLite-compatible SQL semantics and atomic synchronous transactions. Applications can inject an adapter instead of passing a filesystem path. This is an implementation boundary: OPRP does not require other Hosts to use SQLite, SQL, a filesystem, or a particular at-rest cipher.

import { ReferenceHost, SQLiteHostStorage, hostHealth } from '@convey/oprp-sdk';

const storage = new SQLiteHostStorage('/host/private/record.sqlite');
const host = new ReferenceHost(storage, identity, credential, trust, decisionProvider);
const report = hostHealth(host, now, true); // Trusted operator integrity check.

The default adapter uses a five-second busy timeout and owner-only database file permissions. The Host retains WAL/foreign-key initialization and its existing transaction/receipt/change-feed semantics. A custom adapter must preserve those semantics; the interface is not an implemented PostgreSQL or asynchronous database adapter.

Every store is bound to the Host subject and signing/encryption key identifiers. Ordinary restart and same-key credential renewal preserve access. Opening the database under a different service identity fails wrong_host_storage_owner. A populated pre-dev11 database without ownership metadata fails host_storage_upgrade_required. After verifying the historical identity and taking an independent backup, a trusted operator can explicitly pass { adoptLegacy: true } to SQLiteHostStorage for the one-time upgrade. It is never enabled by the lab or ordinary path constructor. Host service-key rotation and disaster-recovery re-enrollment need separate reviewed procedures; requester-key rotation already has its own protocol workflow.

Persistent two-Host lab

npm run host -- init .demo/host-lab
npm run host -- serve .demo/host-lab a 6771
# Separate terminal:
npm run host -- serve .demo/host-lab b 6772
# Another terminal:
npm run host -- probe .demo/host-lab a
npm run host -- probe .demo/host-lab b

Initialization creates one private folder containing synthetic service/application identities, two development authorities, a local TLS key/certificate and subsequently two independent Host/trust databases. It refuses an existing lab identity file. The folder is private and lies under ignored .demo/; never commit or share lab.json or generated key files. Host A seeds one synthetic record. Host B is empty and available for destination workflows.

Both servers bind only to 127.0.0.1. The lab's standing policy grants scopes only for its configured synthetic patient and its one signed development requester. This illustrates Host-chosen advance permission, not a recommended real-patient consent policy. All exchanges still validate credentials, payload signatures, tokens and normal protocol authorization. No global "disable authentication" flag is supplied.

Development authority status is refreshed locally with persistent monotonic sequence numbers. The Host's same-key credential is renewed while the service runs; key identities and clinical history are unchanged. Requester tooling obtains a fresh same-key credential on each invocation. This is possible because the lab owns development authority keys locally; real deployment separates verification/issuance roles and must implement actual enrollment and revocation services.

The local TLS certificate is valid for 30 days and the SDK explicitly trusts that certificate for loopback. Renew development TLS deliberately when needed; the lab does not manage publicly trusted certificates. Stop the process with SIGINT or SIGTERM to drain the server and close databases. Restart it with the same folder and node name to resume the same Host.

Health and diagnosis

Check Audience Behavior
GET /health/live Local health tooling Returns only {"status":"live"}.
GET /health/ready Local health tooling Returns ready or unavailable, with 200/503. No patient/key/queue details.
npm run host -- status … Trusted local operator Checks storage, credential/status validity and SQLite integrity; outputs only aggregate health flags.

Readiness uses a bounded storage ping and current service credential/status validation. Deep quick_check runs at startup and in the trusted status command, not on every HTTP poll. Normal exchange bodies and request URLs are not logged. Failed envelopes return a generic error without exposing cryptographic or clinical diagnostics. The development server caps payload size, headers/request time and accepted exchange content type. Production rate limiting, ingress controls and comprehensive monitoring remain required.

Private storage snapshots

npm run host -- backup .demo/host-lab a /private/operator/host-a.sqlite

The online adapter snapshot uses SQLite's backup API, checks the staged database, hashes its bytes, and installs a private file only after successful completion. It refuses an existing destination. The CLI saves a private integrity manifest alongside it. This is a full service database snapshot, including operational state, not a patient-authorized protocol export. It must remain within trusted operator storage and must have suitable Host-selected encryption and retention controls. SHA-256 detects a mismatch against a trusted manifest; it does not authenticate an attacker-controlled snapshot and manifest pair.

Keep service identities and trust configuration independently recoverable. Do not copy a live .sqlite file without its WAL state and call that a consistent backup. Preserve credential-status anti-rollback evidence and custody freshness before service recovery. An old source snapshot from before migration release must never be made writable merely by restoring it. This increment supplies snapshot/health tooling, not an automatic database-restore command that adjudicates custody rollback.

For patient-controlled export, encrypted backup or transfer, use portability and Host migration, which provide separate authorization, signatures, destination admission and custody proofs. A full service snapshot is not a substitute for those workflows.

Verification and next work

npm run host:conformance starts two persistent HTTPS servers, uses signed/encrypted SDK requests, stops/restarts the source while preserving a record, creates a live database snapshot, and checks identity/storage binding and opaque health responses. Storage tests exercise an injected adapter, owner mismatch, legacy upgrade decisions, consistent snapshots and health failure.

Next: production storage/key-custody adapters, deployment recipes, monitored background workers, secure approval/evidence integration and operational recovery exercises. Independent review and real provider conformance are still prerequisites for production claims.

View source

Documentation follows the experimental reference implementation.