feat: complete Epic 1 production foundation
This commit is contained in:
+88
-3
@@ -16,12 +16,17 @@ docker compose -f deploy/community/docker-compose.yml --env-file deploy/communit
|
||||
2. Создайте и проверьте согласованный backup PostgreSQL и artifact storage. Для первой пустой установки зафиксируйте, что восстанавливать нечего.
|
||||
3. Проверьте immutable plan: `cargo run -p admin-api --bin crank-migrate -- plan --check` в source checkout либо `<compose> run --rm migrate crank-migrate plan` для образа.
|
||||
4. Примените sequence: `<compose> run --rm migrate crank-migrate apply`.
|
||||
5. Повторите preflight и убедитесь в `{"status":"current","version":3}`.
|
||||
5. Повторите preflight и убедитесь в `{"status":"current","version":11}`.
|
||||
6. Только теперь запускайте long-running services: `<compose> up -d`.
|
||||
|
||||
Обычный `up` также содержит обязательный migration job, но при upgrade он не заменяет предварительные preflight и backup. Migrator делает до десяти bounded попыток подключения с секундной паузой и затем безопасно завершается ошибкой.
|
||||
|
||||
Команда читает только `CRANK_DATABASE_URL`/`POSTGRES_*`. Master key, session secret, bootstrap password, MCP credentials и другие service secrets не входят в её config projection.
|
||||
Команда `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
|
||||
|
||||
@@ -35,6 +40,26 @@ docker compose -f deploy/community/docker-compose.yml --env-file deploy/communit
|
||||
|
||||
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`](schemas/migration-sequence.json) и проверяется командой:
|
||||
@@ -46,6 +71,20 @@ 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 <!-- community-scope: allow=one-time-token -->
|
||||
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 local `product_events`, daily
|
||||
denominator rollups и partial success index. Legacy history не backfill-ится;
|
||||
external/unscoped credentials не получают fabricated key identity.
|
||||
- Каждая версия имеет contiguous `i64` version, стабильное имя, 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.
|
||||
@@ -68,9 +107,55 @@ CLI/stderr возвращают bounded JSON: `code`, `stage`, nullable numeric
|
||||
| `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` |
|
||||
| `invalid_command` | Неизвестная CLI команда/аргумент | Использовать только `plan`, `preflight`, `apply`, `admin-auth bootstrap-create|recover` или `master-key status|preflight|rotate|verify|promote|abort` |
|
||||
| `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:
|
||||
|
||||
```bash
|
||||
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 передаётся только через локальные файлы:
|
||||
|
||||
```bash
|
||||
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.
|
||||
|
||||
## Правила разработчика
|
||||
|
||||
|
||||
Reference in New Issue
Block a user