14 KiB
Миграции PostgreSQL
Crank использует единственную append-only migration authority в crank-registry. admin-api и mcp-server выполняют только read-only preflight. DDL применяет one-shot binary crank-migrate, который Community Compose запускает до readiness сервисов.
Безопасная последовательность оператора
Для source Compose замените <compose> на:
docker compose -f deploy/community/docker-compose.yml --env-file deploy/community/.env.example
Для image Compose используйте docker compose -f deploy/community/docker-compose.images.yml --env-file .env. Перед обновлением уже работающей установки выполните строго:
- Read-only preflight:
<compose> run --rm migrate crank-migrate preflight. Exit0означает current, exit2— ожидаемуюmigration_required; exit1запрещает mutation до устранения причины. - Создайте и проверьте согласованный backup PostgreSQL и artifact storage. Для первой пустой установки зафиксируйте, что восстанавливать нечего.
- Проверьте immutable plan:
cargo run -p admin-api --bin crank-migrate -- plan --checkв source checkout либо<compose> run --rm migrate crank-migrate planдля образа. - Примените sequence:
<compose> run --rm migrate crank-migrate apply. - Повторите preflight и убедитесь в
{"status":"current","version":11}. - Только теперь запускайте long-running services:
<compose> up -d.
Обычный up также содержит обязательный migration job, но при upgrade он не заменяет предварительные preflight и backup. Migrator делает до десяти bounded попыток подключения с секундной паузой и затем безопасно завершается ошибкой.
Команда plan|preflight|apply читает только CRANK_DATABASE_URL/POSTGRES_*.
Master key, session secret, MCP credentials и другие service secrets не входят
в её migration config projection. Подкоманды admin-auth bootstrap-create и
admin-auth recover также используют только database config. Bootstrap
выводит одноразовый token; recovery читает новый пароль, password pepper и
current master key только из локальных файлов.
Фактический brownfield inventory
| Источник | Исторический владелец/lock | Известный контракт |
|---|---|---|
__crank_core_migrations |
crank-registry, session lock 0x4352414e4b |
columns version, description, checksum, applied_at; v1 checksum crank-community-baseline-v1 |
__crank_mcp_migrations |
MCP session store, session lock 0x4352414e4b4d4350 |
columns version, checksum, applied_at; v1 checksum mcp-transport-sessions-v1 |
__crank_ext_migrations |
прежний RegistryExtension, без общего lock |
legacy columns extension_name, version, applied_at; checksum отсутствовал |
__crank_migrations |
canonical MigrationAuthority, transaction lock 0x4352414e4b4d4947 |
append-only sequence с version/name/checksum/phase/compatibility |
__crank_migration_legacy_audit |
canonical MigrationAuthority |
только доказуемо сопоставленное legacy provenance |
Legacy extension row без зарегистрированного exact (name, version, checksum) несовместим. Community пока не публиковала extension migrations, поэтому authority не выдумывает им checksum и блокирует такие строки с legacy_conflict.
Version 4 (operation-lifecycle-v4) добавляет version-local Operation identity/provenance и DB immutability guard. Legacy rows получают legacy_observed с cutover timestamp; неизвестные historical actor/publication timestamps не фабрикуются. Published payload и parent cascade delete блокируются на уровне PostgreSQL.
Version 5 (execution-outcome-v5) добавляет nullable exact Operation version,
execution stage, stable error code, retryability и outcome certainty в Invocation
History. Legacy v4 строки остаются NULL; backfill не фабрикует классификацию.
Version 7 (master-key-identity-v7) добавляет durable master-key identity,
rotation ledger и epoch-aware Secret ciphertext metadata. Это expand-изменение:
legacy secret_versions получают default epoch 1, а target ciphertext поля
остаются NULL до operator-controlled rotation.
Version 8 (admin-auth-lifecycle-v8) добавляет local bootstrap contracts,
CSRF hash для browser sessions, login backoff ledger и bounded admin security
audit. Static startup password больше не является production bootstrap
authority: первый администратор создаётся через crank-migrate admin-auth bootstrap-create и одноразовый token в UI. Потерянный Admin password
восстанавливается локально через crank-migrate admin-auth recover с проверкой
active master-key identity; команда не раскрывает старый пароль, Secrets или
key material и отзывает browser sessions.
Контракт sequence
Machine plan находится в schemas/migration-sequence.json и проверяется командой:
cargo run -p admin-api --bin crank-migrate -- plan --check
- V1 — immutable brownfield baseline с историческим ledger token и отдельным exact-source SHA-256.
- V2 — единый exact-byte expand SQL artifact, создающий canonical ledgers и MCP session schema; его SHA-256 закреплён в executable descriptor.
- V3 — append-only expand для независимого nullable
invocation_logs.trace_id, canonical-format constraint и partial request/trace indexes; исторические строки остаютсяNULLбез fabricated backfill. - V4 — immutable Operation lifecycle и honest legacy snapshot provenance.
- V5 — nullable typed execution outcome для N/N-1 чтения истории.
- V7 — master-key identity/rotation foundation: non-secret active epoch, durable rotation state/checkpoint и target ciphertext metadata.
- V8 — admin auth lifecycle foundation: one-time bootstrap contract, CSRF session verifier, login backoff и bounded auth audit.
- V9 — immutable Agent catalog lifecycle: catalog revision и DB guards для published Agent snapshots/bindings.
- V10 — approval side-effect safety: workspace-scoped pending approval fingerprint index для full-scope deduplication.
- V11 — onboarding ProductEvents и exact credential provenance: nullable scoped
invocation_logs.platform_api_key_id, immutable localproduct_events, daily denominator rollups и partial success index. Legacy history не backfill-ится; external/unscoped credentials не получают fabricated key identity. - Каждая версия имеет contiguous
i64version, стабильное имя, lowercase SHA-256, owner, phase, explicit readable schema min/max и backfill policy. migrateтребует bounded cursor/batch policy;contractдополнительно требует tracked compatibility evidence и закрытого окна.- Добавление descriptor без executable implementation блокируется
invalid_contractдо DB I/O.
Legacy ledgers остаются readable. Down migration, destructive automatic rollback, ledger rewrite, --force и arbitrary SQL/path input отсутствуют. Полная N/N-1 upgrade/rollback qualification остаётся Story 7.2.
Диагностика и восстановление
CLI/stderr возвращают bounded JSON: code, stage, nullable numeric version, recovery. Database URL, credentials, raw SQL/driver body, row values и host paths не выводятся.
| Code | Значение | Безопасное действие |
|---|---|---|
schema_missing |
Service startup увидел пустую schema | Запустить controlled migration; не разрешать runtime DDL |
migration_required |
Schema отстаёт; preflight CLI завершает работу с exit 2 |
Проверить backup и выполнить controlled apply |
checksum_mismatch |
Artifact и ledger не совпали | Сначала проверить immutable application image/release manifest; восстанавливать БД только после доказанной ledger corruption |
partial_sequence |
Relation/ledger/structural fingerprint неполон | Не чинить вручную; сопоставить backup и matching artifact |
future_version |
База новее приложения | Установить matching application; не откатывать schema автоматически |
legacy_conflict |
Legacy provenance невозможно доказать | Сохранить backup и привлечь оператора |
lock_timeout |
Другой migration runner удерживает canonical lock | Дождаться завершения и повторить preflight |
apply_failed |
Transaction migration откатилась | Проверить matching artifact/backup, затем повторить preflight |
storage_unavailable |
PostgreSQL/transport недоступен | Проверить сеть/TLS/права; секреты в diagnostic не копировать |
config_invalid |
Database-only config невалиден | Исправить указанный config contract |
invalid_command |
Неизвестная CLI команда/аргумент | Использовать только plan, preflight, apply, `admin-auth bootstrap-create |
contract_drift |
Committed machine plan расходится с Rust authority | Перегенерировать только для новой append-only version и проверить diff |
invalid_contract |
Descriptor/implementation/window/evidence несовместимы | Исправить authoring contract до любого DB I/O |
admin_recovery_rejected |
Recovery request не прошёл local/database checks | Проверить email, secret files и active master-key identity; не создавать второго Admin |
master_key_identity_mismatch |
Local master key не совпадает с active PostgreSQL identity | Использовать правильный current/target key; не менять ciphertext вручную |
master_key_rotation_in_progress |
Есть active rotation | Выполнить resume/verify/promote или abort |
master_key_rotation_verification_failed |
Target ciphertext не прошёл проверку | Повторить rotate/verify или abort до promotion |
Admin auth operator commands
Первичная и recovery-инициализация Admin identity выполняется только локальным operator command. Значения secret material не передаются через argv:
crank-migrate admin-auth bootstrap-create --email owner@example.local
crank-migrate admin-auth recover \
--email owner@example.local \
--password-file /secure/new-admin-password.txt \
--password-pepper-file /secure/password-pepper.txt \
--master-key-file /secure/current-master.key
recover проверяет active master-key identity в PostgreSQL, заменяет verifier
существующего Admin account, отзывает все browser sessions/CSRF state и пишет
bounded audit event. Команда не выводит password, pepper, master key, Secret
plaintext или ciphertext.
Master-key rotation operator commands
crank-migrate master-key использует тот же database-only config, что и
миграции. Raw key material передаётся только через локальные файлы:
crank-migrate master-key status
crank-migrate master-key preflight --current-key-file /secure/current.key --target-key-file /secure/target.key --backup-ref offline-backup-ref
crank-migrate master-key rotate --current-key-file /secure/current.key --target-key-file /secure/target.key --backup-ref offline-backup-ref
crank-migrate master-key verify --target-key-file /secure/target.key
crank-migrate master-key promote --target-key-file /secure/target.key
crank-migrate master-key abort --rotation-id master-key-e1-to-e2
preflight не меняет active epoch, ciphertext или rotation ledger. rotate
можно повторять после interruption; команда пропускает уже staged rows и
обновляет checkpoint/counts. verify расшифровывает staged target ciphertext
target key. promote атомарно retired old active identity, registers target
identity as active и переносит target ciphertext в основной ciphertext. До
promotion текущий key остаётся рабочим; после promotion процессы нужно
перезапустить с target key.
Правила разработчика
- DDL, SQL migration assets и canonical advisory lock разрешены только в
crank-registry::migrations. - Schema развивается
expand → bounded/resumable migrate → evidence-gated contract. - Опубликованные source bytes/checksums не редактируются: добавляется новая version.
- Для каждой version обязательны fresh/current/concurrent/corrupt/rollback/data-preservation tests и explicit Community scope scan.