final verification — client lifecycle plan: 12/12 items confirmed
Added 12-point verification table with file:line evidence for every item. Noted two minor deviations: inline SQL (not sqlc) and synthetic Infisical IDs (real Infisical pending consolidation plan). Precondition checks enumerated with hard/soft classification.
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# Plan: Client lifecycle — enrollment through deprecation in Oikos Go
|
||||
|
||||
**Status:** Done (2026-07-08) — full API surface + transition preconditions + thin-client distribution.
|
||||
**Status:** Done (2026-07-08) — 12/12 verified. Full API + preconditions + thin-client distribution.
|
||||
|
||||
## Goal
|
||||
|
||||
|
||||
@@ -77,19 +77,33 @@ Snapshot each active plan against the actual codebase on disk. No action taken
|
||||
| Phase 3: MCP tools (`whoami`, `explain`, `preflight`, etc.) | **DONE.** All 6 in mcp/server.go. |
|
||||
| Tests | **DONE.** `client_lifecycle_test.go`: 324 lines, full e2e: planned→enroll→provisioning→active→migrating→deprecated→failed. Provision rejection, relationship edges, blast radius verified. |
|
||||
|
||||
**Score: 100%** (API + preconditions + bootstrap/poller all complete)
|
||||
**Score: 100%** (12/12 verified; see below)
|
||||
|
||||
**Transition precondition enforcement** (new in Phase 5):
|
||||
- `no-inbound-edges`: rejects destroy when relationships still point to entity
|
||||
- `backups-verified`, `secrets-revoked`, `ingress-dns-removed`: checks entity attrs
|
||||
- `age-key-enrolled-if-needed`, `mesh-joined-if-needed`: checks attrs for workstations
|
||||
- `health-check-answering`: verifies entity_status health ≠ unknown/down
|
||||
- `doc-page-complete`: requires at least one linked document
|
||||
- Soft preconditions (inventory-entry, cancelled-note, etc.): operator-confirmed via transition request
|
||||
**12-point verification (2026-07-08):**
|
||||
|
||||
**Thin-client distribution:**
|
||||
- `bootstrap.sh`: already rewritten — fetches agent files only, calls enroll API, installs context poller
|
||||
- `tools/context-poller.sh`: standalone file — polls GET /context every 5min, applies file deltas
|
||||
| # | Item | File:Line |
|
||||
|---|------|-----------|
|
||||
| 1 | POST /clients/enroll | `impl.go:1099` — age keypair, state→provisioning, audit |
|
||||
| 2 | GET /clients/{slug}/context | `impl.go:1203` — context_version + file/tool/sops deltas |
|
||||
| 3 | GET /clients/{slug}/secrets | `impl.go:1253` — scoped secret key listing |
|
||||
| 4 | POST /entities/provision | `impl.go:1279` — slug validation, provisioning_steps, hosts edge |
|
||||
| 5 | GET /entities/{slug}/provision/status | `impl.go:1388` — step-by-step polling |
|
||||
| 6 | Lifecycle transitions | `impl.go:933` — PATCH /entities/{id} with lifecycle_defs validation |
|
||||
| 7 | MCP tools (6) | `mcp/server.go:602-723` — whoami, explain, preflight, history, snapshot, secrets |
|
||||
| 8 | Precondition checks | `impl.go:1459-1551` + `ontology/validate.go:127-246` — dual impl |
|
||||
| 9 | bootstrap.sh thin-client | No git clone; curl-fetched files; API enroll; context poller install |
|
||||
| 10 | tools/context-poller.sh | 73 lines — polls /context, fetches deltas, re-runs setup scripts |
|
||||
| 11 | migration 012 | provisioning_steps, context_version, context_files, enrolled_at |
|
||||
| 12 | openapi.yaml endpoints | All 5 endpoints + 7 schemas defined; codegen in sync |
|
||||
|
||||
**Minor deviations from plan spec:**
|
||||
- `internal/db/queries/clients.sql` not created — queries are inline in impl.go (same DB operations)
|
||||
- `internal/secrets/infisical.go` lacks `CreateMachineIdentity` — enrollment uses synthetic IDs until Infisical is bootstrapped (consolidation plan #1)
|
||||
|
||||
**Transition precondition enforcement** (Phase 5):
|
||||
- Hard checks: `no-inbound-edges`, `backups-verified`, `secrets-revoked`, `ingress-dns-removed`, `age-key-enrolled-if-needed`, `mesh-joined-if-needed`, `health-check-answering`, `doc-page-complete`
|
||||
- Soft checks (operator intent): `inventory-entry`, `cancelled-note`, `preflight-passed`, `error-summary`, `replacement-live-or-role-retired`, `post-verify-passed`, `recovery-verified`, `written-off`, `ingress-live-if-public`, `doc-page-stub`
|
||||
- Parsed from `lifecycle_defs.transitions` JSONB `{requires: [...]}` at mutation time
|
||||
|
||||
---
|
||||
|
||||
|
||||
Reference in New Issue
Block a user