feat(cli): merge oxicloud binary and cli
this feature to simplify the creation of only 1 binary for multiple architecture
This commit is contained in:
@@ -41,7 +41,9 @@ Mirrors the `tests/api/` shell pattern (run.sh, test.env, separate server port).
|
||||
|
||||
### 2. Rust bulk seeder — `src/bin/load-seed.rs`
|
||||
|
||||
New binary registered in `Cargo.toml` alongside `generate-openapi` and `migrate-nfc-filenames`.
|
||||
New binary registered in `Cargo.toml` alongside `generate-openapi`
|
||||
(the historical `migrate-nfc-filenames` bin has since been folded into
|
||||
`oxicloud migrate nfc-filenames` — see `docs/plan/bundled-binary.md` § 1b).
|
||||
|
||||
**CLI:**
|
||||
```
|
||||
@@ -158,7 +160,7 @@ Matches existing recipe naming (`test-*`, `front-*`, `api-test`).
|
||||
- `.github/workflows/load-nightly.yml`, `load-smoke.yml`
|
||||
|
||||
**Modify:**
|
||||
- `Cargo.toml` — add `[[bin]] name = "load-seed" path = "src/bin/load-seed.rs"` after the `migrate-nfc-filenames` entry
|
||||
- `Cargo.toml` — add `[[bin]] name = "load-seed" path = "src/bin/load-seed.rs"` after the `generate-openapi` entry (the `migrate-nfc-filenames` bin referenced in earlier drafts has been folded into `oxicloud migrate nfc-filenames`)
|
||||
- `justfile` — append four `load*` recipes
|
||||
- `.gitignore` — add `tests/load/results/*.json` and `tests/load/storage/`
|
||||
|
||||
|
||||
@@ -330,7 +330,7 @@ authenticated session):
|
||||
|
||||
**Deferred:**
|
||||
- Step-up auth before link start
|
||||
- Admin-mediated link/unlink via `oxicloud-cli federation` (proper for
|
||||
- Admin-mediated link/unlink via `oxicloud federation` (proper for
|
||||
"user changed IdP email" recovery scenario)
|
||||
- OCM link (same shape, different kind)
|
||||
- Multi-federation (multiple linked identities per user — see
|
||||
|
||||
@@ -62,7 +62,7 @@ and ordering are the load-bearing decisions here.
|
||||
## Preconditions before we start the wipe
|
||||
|
||||
Every one of these MUST hold. Adding a pre-flight check in
|
||||
`oxicloud-cli opaque wipe-legacy` (proposed below) that refuses to run
|
||||
`oxicloud opaque wipe-legacy` (proposed below) that refuses to run
|
||||
otherwise.
|
||||
|
||||
1. **`OXICLOUD_AUTH_OPAQUE_MODE=opaque_only`** on the deployment for at
|
||||
@@ -174,7 +174,7 @@ it can't, since login-link users just clicked email — no proof-of-current).
|
||||
|
||||
### The wipe migration
|
||||
|
||||
Delivered as `oxicloud-cli opaque wipe-legacy` — a dedicated subcommand,
|
||||
Delivered as `oxicloud opaque wipe-legacy` — a dedicated subcommand,
|
||||
NOT a schema migration. Reasons:
|
||||
- Idempotent (won't re-wipe already-nulled rows)
|
||||
- Pre-flight refuses when preconditions aren't met (unlike a migration
|
||||
@@ -207,7 +207,7 @@ UPDATE auth.users
|
||||
|
||||
Output: `N password_hash columns nulled. M users still have password_hash
|
||||
because they don't meet the OPAQUE-migrated preconditions — inspect via
|
||||
`oxicloud-cli opaque wipe-legacy --dry-run` and address separately.`
|
||||
`oxicloud opaque wipe-legacy --dry-run` and address separately.`
|
||||
|
||||
The `WHERE` clause is intentionally strict: OIDC users, externals, and
|
||||
under-migrated users are ALL left alone. The strict version is safer than
|
||||
@@ -232,7 +232,7 @@ can drop the legacy password code:
|
||||
6. `has_password` field on `UserDto` / `AdminUserSummaryDto`: delete (always
|
||||
false, meaningless signal)
|
||||
7. `admin`-badge `password` chip: delete (same reason)
|
||||
8. `oxicloud-cli opaque reset --user X` for legacy-recovery: still useful
|
||||
8. `oxicloud opaque reset --user X` for legacy-recovery: still useful
|
||||
as an emergency lever (envelope somehow corrupted, need to force
|
||||
re-registration via recovery-magic-link), but its "silent-migration
|
||||
handles the recovery" semantics become "recovery-magic-link handles the
|
||||
@@ -269,7 +269,7 @@ running smoothly for the indicated period."
|
||||
| G1 | Land task #31: change_password OPAQUE-lockout fix + hybrid-user password gate | Days |
|
||||
| G2 | Land recovery-magic-link admin reset flow | Weeks |
|
||||
| G3 | Land OPAQUE-verify-current + change_password redesign that COMPOSES the two (Argon2-verify AND OPAQUE-verify both work; use whichever the user has) | Weeks |
|
||||
| G4 | Ship `oxicloud-cli opaque wipe-legacy` (dry-run only initially, no destructive flag) | Days |
|
||||
| G4 | Ship `oxicloud opaque wipe-legacy` (dry-run only initially, no destructive flag) | Days |
|
||||
| G5 | Add admin-dashboard metric: "N users still on legacy (`password_hash IS NOT NULL AND !opaque_migrated`)" | Days |
|
||||
| G6 | Operator switches deployment to `opaque_only` mode | ✅ already possible |
|
||||
| G7 | Wait 90+ days at `opaque_only`, watch the metric drop to 0 | Months |
|
||||
|
||||
@@ -324,7 +324,7 @@ at), boot fails fast with a clear error. Operator has two ways out:
|
||||
restart.
|
||||
2. **CLI repair flag on the `oxicloud` binary itself**:
|
||||
```
|
||||
oxicloud --select-storage <name>
|
||||
oxicloud storage select <name>
|
||||
```
|
||||
Behaviour: parse `.env`, verify `<name>` exists in `_ENTRIES` (fail-fast
|
||||
with the available names listed if not), connect to DB, UPDATE
|
||||
@@ -334,7 +334,7 @@ at), boot fails fast with a clear error. Operator has two ways out:
|
||||
|
||||
The bare-flag on the shipped binary is chosen over a separate `just`
|
||||
recipe or auxiliary bin because:
|
||||
- **Docker-friendly**: `docker exec oxicloud oxicloud --select-storage foo`
|
||||
- **Docker-friendly**: `docker exec oxicloud oxicloud storage select foo`
|
||||
— no need to install extra tooling in the container.
|
||||
- **Systemd-friendly**: can be run as a `ExecStartPre=` one-shot before the
|
||||
main service unit.
|
||||
@@ -377,7 +377,7 @@ foundational; the rest layer on top independently within reason.
|
||||
| 5 | Cutover state machine: on migration `Completed`, write `active_backend_name = target_name`, keep read-only on. Boot on new backend after operator restart. | 4 | ~half day |
|
||||
| 6 | Admin storage tab rewrite: list entries, show active, migrate dropdown, read-only banner. Delete Save form + S3 field editors + .env cutover hint. | 1, 3, 4 | 1 day |
|
||||
| 7 | `?storage=<name>` on `blobs_consistency` + `backend_consistency`. `JobRunArgs.storage` plumbing, `TriggerJobQuery.storage`, entry-resolver at run start, params records probed name. Retire `verify_migration` + its DTO + its route + its handler. | 1, 3 | 1 day |
|
||||
| 8 | `oxicloud --select-storage <name>` bare-flag repair command on the main binary. Parses `.env`, verifies entry exists, UPDATEs DB, exits. Boot-time missing-entry error message points at it. See §Fallback. | 2 | ~quarter day |
|
||||
| 8 | `oxicloud storage select <name>` bare-flag repair command on the main binary. Parses `.env`, verifies entry exists, UPDATEs DB, exits. Boot-time missing-entry error message points at it. See §Fallback. | 2 | ~quarter day |
|
||||
|
||||
**Total: ~5-6 days end to end.** Slices 6 and 7 can proceed in parallel with
|
||||
each other once 1-5 land. Slice 8 is an ops nicety, could ship whenever.
|
||||
@@ -414,8 +414,8 @@ Per slice, plus these end-to-end scenarios in Hurl:
|
||||
→ 400 with known-names list. No run row created.
|
||||
9. **Missing entry at boot**: `active_backend_name = "gone"` but `_ENTRIES`
|
||||
doesn't include it → boot aborts with the specific message pointing at
|
||||
`oxicloud --select-storage <name>` (with the available names filled in).
|
||||
Re-run the binary with `--select-storage local_main` → verifies + updates
|
||||
`oxicloud storage select <name>` (with the available names filled in).
|
||||
Re-run the binary with `storage select local_main` → verifies + updates
|
||||
DB + exits 0. Restart the server → boots cleanly on `local_main`.
|
||||
10. **Encryption key invalid**: `OXICLOUD_STORAGE_<N>_ENCRYPTION_KEY=badbase64`
|
||||
→ boot aborts with entry name + reason (not valid base64 / wrong length).
|
||||
|
||||
Reference in New Issue
Block a user