Core provider update contract — v0.4.24
Status: implemented; real-version runtime qualification pending. This document describes required behavior, not proof of a supported end-to-end provider upgrade.
Authority and boundaries
A selected BaseHarbor release must own immutable provider image digests, versions, compatibility metadata and the complete SQL / Secrets / Identity reference set. No mutable latest resolution is permitted. The immutable catalog is embedded in internal/coreupdate/releases/v0.4.24.json; runtime inventory must match the selected catalog, including dedicated Keycloak backing SQL.
The Core update domain is implemented in internal/coreupdate. It operates on owned realizations, not merely provider types: installation, placement scope, instance and owner form the identity. An external or foreign provider must not be changed automatically.
The planner distinguishes:
no_change: version, image and digest all identical;safe_reconcile: an explicitly proven compatible stateless path;backup_recovery_required: a supported data-bearing path with a verified recovery point;migration_required: a supported schema/data migration with explicit verification and recovery requirements;unsupported: refuse before mutation and report the actionable reason.
A PostgreSQL major version change is currently unsupported by the generic planner: it needs a separately proven, provider-native migration path. Image replacement alone is never evidence that data was upgraded.
Transaction semantics
- Resolve the exact BaseHarbor release and all Core expected digests.
- Inspect installed owned shared and application-isolated realizations; discover any external providers without taking ownership.
- Compute the plan and preflight all changes before mutation.
- Require verified recovery-point hooks for every data-bearing upgrade.
- Apply through the existing provider-native Core lifecycle and persist stage/result evidence.
- Probe actual SQL, Secrets and Identity usability, not merely container readiness.
- Resume incomplete owned state idempotently. Never promise rollback for irreversible data migrations.
- Report success only when every affected realization and Core semantics verify successfully.
Explicit HA point recovery
baha update --recover --version VERSION --yes restores the selected owned Core's PostgreSQL and etcd DCS to the verified update backup point. It does not install a release or replace the CLI. Transactions after that backup point are not included; an update failure never triggers this data rewind automatically.
Recovery holds the Core lifecycle lock, validates Core/Target/release identity, checks immutable physical and DCS artifacts, and rejects credential/environment drift. PostgreSQL writers are stopped before the old DCS. The new DCS starts from the verified isolated restore; the PostgreSQL primary is seeded through a stream into a separate owned volume, and replicas rebuild into separate empty volumes. Actual mounts, mTLS DCS identity/quorum, SQL authentication, Patroni health and replication must verify before commit. Original volumes and the prior manifest are retained.
A committed replay verifies the active cluster without recreating members or replaying extraction. Ambiguous fencing, partial volume seeding or interrupted commit requires reconciliation; it never reactivates both old and new data. A subsequent update uses a new transaction directory without renaming the active DCS bind directories. Existing plaintext DCS installations and PostgreSQL major migrations remain unsupported.
The isolated acceptance gate exercises replica-first replacement and switchover with the same pinned image, a failed replica, real PostgreSQL WAL/SQL restoration, live DCS cutover, original-volume preservation and committed replay. This does not by itself certify compatibility of another Spilo/PostgreSQL image or a full provider-version migration.
Human and machine parity
baha update --check, human update output, JSON, MCP and protected HTTP must be projections of the same plan/result domain. The existing self-update implementation only handles binary/release assets and MUST NOT report a complete Core upgrade until the provider update integration and semantic verification are present.
Release evidence required
- Immutable provider set and installed-version discovery
- No restart for unchanged realizations
- PostgreSQL compatible upgrade, plus fail-closed unsupported major upgrade
- OpenBao sealed/unsealed and recovery state preservation
- Keycloak post-migration authentication/issuer verification
- Shared updated exactly once; isolated handled independently
- Foreign provider untouched
- Injected partial failure and retry, without duplicated state
- Docker rootless and Podman rootless runtime proof
- Evidence bound to the release candidate SHA and provider digests
The initial planner and hook tests prove only contract behavior; they do not qualify the real provider mutation paths.
Native provider admission
The manager AppRole deliberately excludes OpenBao's default policy. Its scoped manager policy must grant update on sys/capabilities-self so preflight can inspect its own application-policy rights. No authority to inspect other tokens is granted. Existing installations whose manager policy lacks this endpoint must have an authorized administrator reconcile that narrow policy before upgrading; Core refuses before provider mutation and never recreates a root token or silently broadens its authority.
OpenBao accepts strictly newer patches in the same major/minor stream; the candidate targets 2.7.1. Keycloak follows that same patch rule for HA. The explicitly admitted single-Core 26.7.5 → 26.8.0 path stops/recreates the one member and uses verified SQL/configuration backup and recovery. Other minor/major paths are refused before mutation. A completed native transaction verifies the unchanged immutable inventory and registered application Secret scopes; the narrower binary-only admission rule is not reused to reject those already verified applications.