feat(authority): seed default + installation tenants via migration (SPRINT_20260422_005)
Closes the bootstrap gap two parallel QA agents surfaced on 2026-04-22: fresh Authority DBs lacked the `default` tenant row so setup-wizard admin creation failed with users_tenant_id_fkey and /connect/token returned invalid_grant. Fix is on the migration path per AGENTS.md §2.7; the init script stays seeds-only as established in SPRINT_20260422_003. - New embedded migration 003_seed_default_tenants.sql performs `INSERT ... ON CONFLICT (tenant_id) DO NOTHING` for `default` and `installation`. Numeric prefix (not S-prefix) so the migration runner's Startup category auto-applies it; S-prefix files route to Seed category which is intentionally manual-only per StartupMigrationHost.cs:158. - `default` is strictly required (Authority's StandardPluginBootstrapper.DefaultTenantId; /internal/users bootstrap inserts under this FK). `installation` is not Authority-FK-referenced today but matches the empirical workaround both QA agents converged on and serves as defense for cross-service inserts that join authority.tenants.tenant_id. Fresh-volume verification (docs/qa/authority-default-tenant-20260422/): 1. docker compose down -v (20 volumes removed incl. compose_postgres-data) 2. docker compose up -d — 62 containers, Authority healthy in ~15s. 3. Startup log: applying 001 (144ms) → 002 (13ms) → 003 (7ms). authority.tenants contains default + installation. 4. POST /api/v1/setup/sessions → 201; database/valkey/migrations prereqs ran; admin/execute with admin/Admin@Stella2026! → 200 "Bootstrap administrator 'admin' ensured successfully." 5. POST /connect/token (password, stellaops-cli, ui.admin openid) → 200 + JWT carrying role=admin, stellaops:tenant=default. 6. docker compose restart authority → "Database is up to date for Authority." Clean no-op. Docs: docs/modules/authority/architecture.md §1.1 "Seeded bootstrap tenants (migration-owned)". Cross-link added to the archived prior sprint's Decisions & Risks so the lineage is traceable. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
138
docs/qa/authority-default-tenant-20260422/EVIDENCE.md
Normal file
138
docs/qa/authority-default-tenant-20260422/EVIDENCE.md
Normal file
@@ -0,0 +1,138 @@
|
||||
# Evidence: Authority default-tenant bootstrap (AUTH-SEED-002)
|
||||
|
||||
- **Sprint**: `docs/implplan/SPRINT_20260422_005_Authority_default_tenant_bootstrap.md`
|
||||
- **Task**: AUTH-SEED-002 (fresh-volume verification that the setup-wizard admin
|
||||
flow succeeds without manual SQL inserts).
|
||||
- **Date (UTC)**: 2026-04-22
|
||||
- **Host**: local dev (Docker Desktop)
|
||||
- **Image rebuilt**: `stellaops/authority:dev` (SHA 01d8c359fb92) — contains new
|
||||
`003_seed_default_tenants.sql` embedded resource.
|
||||
|
||||
## Verification summary
|
||||
|
||||
| # | Step | Status | Artifact |
|
||||
|---|------|--------|----------|
|
||||
| 1 | `docker compose -f docker-compose.stella-ops.yml down -v` (destroy volumes) | PASS | stack stopped, 20 volumes removed incl. `compose_postgres-data` |
|
||||
| 2 | `docker compose -f docker-compose.stella-ops.yml up -d` (fresh volumes) | PASS | 62 containers started, authority healthy in ~15s |
|
||||
| 3 | Authority startup applies migration 003 automatically | PASS | see `06-authority-migration-logs.txt`, `07-schema-migrations.txt` |
|
||||
| 4 | `POST /api/v1/setup/sessions` + `.../steps/admin/execute` with `admin / Admin@Stella2026!` | PASS | see `01-create-session.json`, `03-pre-admin-steps.json`, `04-admin-execute.json` |
|
||||
| 5 | `POST /connect/token` returns 200 + JWT (not `invalid_grant`) | PASS | see `05-connect-token.json` |
|
||||
| 6 | Authority restart against same volume is a clean no-op | PASS | log line `Migration: Database is up to date for Authority.` |
|
||||
|
||||
## Key log excerpts
|
||||
|
||||
### 3) Migration runner applies 003 on the fresh DB (authority container startup)
|
||||
|
||||
```
|
||||
[14:32:39 INF] Migration: 3 pending startup migration(s) for Authority.
|
||||
[14:32:39 INF] Migration: Applying 001_initial_schema.sql (Startup)...
|
||||
[14:32:39 INF] Migration: 001_initial_schema.sql completed in 144ms.
|
||||
[14:32:39 INF] Migration: Applying 002_drop_deprecated_audit_tables.sql (Startup)...
|
||||
[14:32:39 INF] Migration: 002_drop_deprecated_audit_tables.sql completed in 13ms.
|
||||
[14:32:39 INF] Migration: Applying 003_seed_default_tenants.sql (Startup)...
|
||||
[14:32:39 INF] Migration: 003_seed_default_tenants.sql completed in 7ms.
|
||||
[14:32:39 INF] Migration: Applied 3 migration(s) for Authority in 694ms.
|
||||
```
|
||||
|
||||
### 3) `authority.schema_migrations` ledger after fresh bring-up
|
||||
|
||||
```
|
||||
migration_name | category | applied_at | duration_ms
|
||||
--------------------------------------+----------+-------------------------------+-------------
|
||||
001_initial_schema.sql | startup | 2026-04-22 14:32:39.066637+00 | 132
|
||||
002_drop_deprecated_audit_tables.sql | startup | 2026-04-22 14:32:39.199035+00 | 4
|
||||
003_seed_default_tenants.sql | startup | 2026-04-22 14:32:39.21278+00 | 3
|
||||
```
|
||||
|
||||
### 3) `authority.tenants` rows present after auto-migrate (no manual inserts)
|
||||
|
||||
```
|
||||
tenant_id | name | display_name | status
|
||||
--------------+--------------+---------------------+--------
|
||||
default | Default | Default Tenant | active
|
||||
installation | Installation | Installation Tenant | active
|
||||
(2 rows)
|
||||
```
|
||||
|
||||
### 4) Admin bootstrap succeeds via the public setup-wizard HTTP surface
|
||||
|
||||
Prerequisite steps (`database`, `valkey`, `migrations`) completed cleanly, then:
|
||||
|
||||
```
|
||||
POST /api/v1/setup/sessions/setup-installation-20260422143427/steps/admin/execute
|
||||
→ HTTP 200
|
||||
"stepId":"admin","status":"completed",
|
||||
"message":"Step applied successfully.",
|
||||
validationResults:[{
|
||||
"checkId":"check.auth.admin.exists","status":"passed",
|
||||
"message":"Bootstrap administrator 'admin' ensured successfully."
|
||||
}]
|
||||
```
|
||||
|
||||
Admin user persisted under the seeded `default` tenant (the FK the setup
|
||||
wizard requires):
|
||||
|
||||
```
|
||||
id | tenant_id | username | status | enabled
|
||||
--------------------------------------+-----------+----------+--------+---------
|
||||
07b6e4c4-2a3a-42f0-ae1f-6b3ed4b5ca97 | default | admin | active | t
|
||||
```
|
||||
|
||||
### 5) `/connect/token` password grant returns a live admin JWT
|
||||
|
||||
```
|
||||
POST https://stella-ops.local/connect/token
|
||||
grant_type=password
|
||||
client_id=stellaops-cli
|
||||
username=admin
|
||||
password=Admin@Stella2026!
|
||||
scope=ui.admin openid
|
||||
→ HTTP 200
|
||||
{
|
||||
"access_token": "eyJ...",
|
||||
"token_type": "Bearer",
|
||||
"expires_in": 1800,
|
||||
...
|
||||
}
|
||||
```
|
||||
|
||||
Decoded claims show `sub`, `preferred_username=admin`, `role=admin`,
|
||||
`stellaops:tenant=default`, `client_id=stellaops-cli`.
|
||||
|
||||
### 6) Authority restart is a pure no-op
|
||||
|
||||
```
|
||||
[14:35:44 INF] Migration: Starting migration check for Authority...
|
||||
[14:35:45 INF] Migration: 1 optional seed migration(s) are pending for Authority. They remain manual-only and will not run at startup.
|
||||
[14:35:45 INF] Run manually when needed: stella system migrations-run --module Authority --category seed
|
||||
[14:35:45 INF] Migration: Database is up to date for Authority.
|
||||
```
|
||||
|
||||
Confirms migration 003 is idempotent (checksum matched, ledger accepted,
|
||||
zero rows changed on replay — the `INSERT ... ON CONFLICT DO NOTHING`
|
||||
protects the seed).
|
||||
|
||||
## Artifacts
|
||||
|
||||
- `01-create-session.json` — `POST /api/v1/setup/sessions` response
|
||||
- `02-admin-execute.json` — first admin-step attempt before prereqs
|
||||
(documents the "Blocked by incomplete dependencies: Migrations" gate
|
||||
that forces the wizard to run the DB/valkey/migrations steps first)
|
||||
- `03-pre-admin-steps.json` — database / valkey / migrations step responses
|
||||
- `04-admin-execute.json` — successful admin-step apply
|
||||
- `05-connect-token.json` — admin token issuance
|
||||
- `06-authority-migration-logs.txt` — full `Migration:` log timeline
|
||||
- `07-schema-migrations.txt` — `authority.schema_migrations` ledger
|
||||
- `08-tenants.txt` — `authority.tenants` contents after fresh bring-up
|
||||
- `09-admin-user.txt` — admin row with `tenant_id='default'` FK reference
|
||||
|
||||
## Conclusion
|
||||
|
||||
The fresh-volume setup flow now completes without any manual SQL insert
|
||||
into `authority.tenants`. The regression that forced two FE-QA agents
|
||||
(`fe-qa-006-relsec`, `fe-qa-007-evidops`) to hand-seed `default` /
|
||||
`installation` during SPRINT_20260421_006/007 is resolved by migration
|
||||
`003_seed_default_tenants.sql`, applied by the Authority persistence
|
||||
assembly's startup migration runner (wired in SPRINT_20260422_003 /
|
||||
AUTH-MIGRATE-002, so no new runtime wiring was required — only the
|
||||
additional embedded SQL resource).
|
||||
Reference in New Issue
Block a user