Files
PaperClipAI/server
Dotta 2b21fe01bc feat(runtime): backfill pre-existing HTTP-only managed runtimes to HTTPS (PAP-17158)
The automatic default only covers services that start after the deploy. A
workspace that was already running when the feature landed would keep serving
`http://127.0.0.1:<port>` as its canonical URL indefinitely, because startup
reconciliation adopted any healthy backend as-is.

Startup reconciliation now classifies every persisted managed row through
`decideManagedRuntimeExposureBackfill` and stops the eligible HTTP-only ones, so
the desired-state restart that already runs at the end of reconciliation brings
them back through the ordinary fail-closed exposure lifecycle — same workspace,
same runtime-service row, relocated port only when the old one cannot be
published.

The decision function is pure and every branch carries a reason code, because
"which pre-feature workspaces get touched" is the whole risk of this change:

- `already_exposed` makes repeated deploys and restarts converge instead of
  churning listeners.
- `deliberate_opt_out` is checked before broker availability, so an opt-out never
  depends on host state.
- `no_configured_service_entry` refuses to stop a row we could not restart —
  reprovisioning works by stopping the backend and letting desired state bring it
  back, so without a config entry we would take a service down for good.
- `stopped_defaults_on_next_start` leaves stopped rows to the start path.

A backfilled row also drops its HTTP `url` at the moment it is stopped rather
than keeping it until the restart succeeds: if the restart fails, the fail-closed
contract is no URL, not a working HTTP one.

The shared supertest setup pins `PAPERCLIP_MANAGED_RUNTIME_HTTPS=off` so suites
that start a service named `paperclip-dev` do not behave differently on a
broker-capable host than on CI; the suites that exercise the default opt back in.

Covered: 12 decision branches, plus an end-to-end integration test that starts a
pre-feature workspace on a pinned legacy port over plain HTTP, reconciles, and
asserts the same row comes back on a verified `https://<host>:<42xxx>` URL with
the old HTTP backend gone — then reconciles again and asserts zero broker calls
and an unchanged port.
2026-08-16 19:26:39 +00:00
..
2026-03-12 13:09:22 -05:00