7.3 KiB
Cloud runtime configuration
Cloud-managed servers store nonsecret startup and application choices in the
private instance_settings singleton cloud-runtime-config:v1. The row contains
version: 1, an increasing revision, and a strict allowlist of configuration
fields. It is separate from the normal instance settings row and is not exposed
by the instance settings API.
The canonical managed-instance predicate applies: a nonblank Cloud tenant token
or the presence of PAPERCLIP_MANAGED_CONFIG, including a blank value, selects
this configuration path. Invalid managed feature documents still retain their
existing validation at application startup.
Startup and authority
- The hosting environment supplies
DATABASE_URLand, if needed,DATABASE_MIGRATION_URL. Cloud requires a PostgreSQL URL and never falls back to embedded PostgreSQL. Credentials, trust keys, provider configuration and deployment wiring needed before the database connection remain supplied by the environment or the existing secret system. - After schema migration and database connection, startup reads the private runtime configuration row. An existing invalid row or a database error stops startup. Neither condition selects a legacy file or an old process snapshot.
- If no row exists, startup imports the legacy config once. It uses
PAPERCLIP_CONFIGwhen supplied, otherwise the instance home config path. It does not search working-directory ancestors. A truly absent file saves an authoritativeconfig: nullmarker. This retains the existing dynamic environment/image defaults, including authentication and secret strictness. The marker never enables a later file fallback. A present malformed, linked, nonregular, or oversized file stops initialization. Reads and stored snapshots are limited to 64 KiB. - The seed uses an insert that does not replace an existing row. Concurrent initializers read the committed winner. Later starts do not inspect the legacy file, even when it is absent, corrupt, or changed.
- Startup publishes a detached configuration snapshot, restores the signed Cloud runtime identity, then initializes telemetry, secret-provider defaults, authentication and application services. A saved telemetry opt-out therefore takes effect before a telemetry client can be created.
Existing operator environment overlays keep precedence over saved values. Reading an overlaid value does not save it back to the database. Credentials and connection URLs are never copied into this JSONB row.
Cloud does not load instance or working-directory .env files and does not run
legacy worktree configuration repair. The hosting system must supply those
bootstrap variables directly. In particular, a database connection kept only
in .env cannot bootstrap this path. Self-hosted configuration and dotenv
behavior remain unchanged.
Field ownership
The table lists every field consumed from the existing config file and the
remaining known schema fields. Environment-only Config fields, such as
heartbeat maintenance flags and feedback-export credentials, retain their
existing environment sources and are not frozen into the saved snapshot.
| Config file fields | Cloud owner |
|---|---|
server.deploymentMode, exposure, bind, customBindHost, host, port, allowedHostnames, serveUi |
Saved runtime configuration, with existing environment overlays. |
auth.baseUrlMode, publicBaseUrl, disableSignUp |
Saved runtime configuration, with environment overlays and the signed Cloud identity restoration. Saved URLs cannot contain userinfo, query parameters, or fragments. |
database.backup.enabled, intervalMinutes, retentionDays, dir |
Saved runtime configuration, with existing backup environment overlays. |
database.mode, connectionString |
Cloud bootstrap requires the environment DATABASE_URL. The legacy URL is never saved. |
database.embeddedPostgresDataDir, embeddedPostgresPort |
Local embedded-database settings. Cloud does not use embedded PostgreSQL or these paths. |
storage.provider, localDisk.baseDir, s3.bucket, s3.region, s3.endpoint, s3.prefix, s3.forcePathStyle |
Saved runtime configuration, with existing environment overlays. Saved endpoints cannot contain userinfo, query parameters, or fragments. |
secrets.provider, strictMode, localEncrypted.keyFilePath |
Saved nonsecret provider choice and locator, with existing environment overlays. No key bytes are imported or saved. |
telemetry.enabled |
Saved choice, passed to the existing telemetry initialization and opt-out policy before client creation. |
llm.provider |
Saved provider metadata. |
llm.apiKey |
Never saved. The existing OpenAI model-discovery consumer uses OPENAI_API_KEY first. A legacy OpenAI key requires that environment credential before import, or startup stops. Claude key metadata has no server consumer. |
logging.mode, logDir, updates.checkEnabled |
Nonsecret legacy/CLI metadata is preserved. Server logging continues to use its existing environment configuration. |
$meta |
CLI file-write metadata is not application authority. The compatibility view synthesizes valid metadata. |
| Unknown extension keys | No server config consumer exists. They are excluded from the strict saved allowlist, including any unknown credential fields. |
A saved path is a locator. This change does not make local storage objects, backup bytes, logging files, or secret-key bytes durable. Their storage owners and existing environment/secret mechanisms retain responsibility for those bytes. Restart tests prove configuration restoration under a different home; they do not prove durable file, secret, or backup storage.
Internal update and migration interface
cloudRuntimeConfigService(db) provides inspectStored(handle?),
seedIfAbsent(config, handle?), and replace(config, expectedRevision, handle?).
Each method accepts a database or transaction handle. A migration can compose a
config seed, related settings and a receipt in one transaction.
Replacement validates the same allowlist, locks the singleton row, checks the expected revision, and increases it. A stale revision fails. There is no new public configuration endpoint or settings UI. Startup consumers use a snapshot; a saved replacement takes effect on the next initialization/restart.
readLegacyCloudRuntimeConfig(env?) returns the validated nonsecret candidate
without writing it. initializeCloudRuntimeConfig performs the standalone
one-time seed and publishes its committed snapshot. Integrated migration
receipts and deployed Cloud qualification are separate consumers of this
interface.
Verification
server/src/__tests__/cloud-runtime-config.test.ts exercises real PostgreSQL
clients, concurrent writes, transaction rollback, changed homes, a fresh Node
process, environment precedence, secret exclusion, invalid data and database
failure. It uses embedded PostgreSQL by default. A dedicated disposable database
can be selected with PAPERCLIP_RUNTIME_CONFIG_TEST_DATABASE_URL when the host
cannot start embedded PostgreSQL. That database must be reserved for this test.
The test applies the current schema before use.
The startup orchestration controls in
server-startup-feedback-export.test.ts hold configuration initialization and
verify that telemetry, authentication and app construction wait for it. These
local controls do not claim a live Cloud rollout.