|
|
|
@@ -156,6 +156,24 @@ Depends only on `main` as it stands after `D15`. Not sequenced behind any other
|
|
|
|
Wave 10 is complete. The three items in "Still open" below are external
|
|
|
|
Wave 10 is complete. The three items in "Still open" below are external
|
|
|
|
(security team / Okta admin), not blocked on any task in this wave.
|
|
|
|
(security team / Okta admin), not blocked on any task in this wave.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
- **T10.10 — Audit `manage_users.py promote`.** Raised in review after T10.8:
|
|
|
|
|
|
|
|
`cmd_promote()` changed a user's role with no audit trail at all, unlike the
|
|
|
|
|
|
|
|
identical role change from the web Admin Console (`app.py`'s
|
|
|
|
|
|
|
|
`set_user_role()` → `log_event()`, action `"role_changed"`). Not a new
|
|
|
|
|
|
|
|
privilege — anyone with Portainer/container-exec access to `wp_api` already
|
|
|
|
|
|
|
|
has shell access to the database directly, same trust tier D16 already named
|
|
|
|
|
|
|
|
for this command — but there was no record of who ran it or what changed.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Built: `cmd_promote()` now writes an `AuditLog` row with the same
|
|
|
|
|
|
|
|
`action`/`detail` shape `set_user_role()` uses (`{"from": old_role, "to":
|
|
|
|
|
|
|
|
role}`), tagged `"via": "cli"` (mirrors JIT provisioning's own `"via":
|
|
|
|
|
|
|
|
"okta_jit"` tag) and `actor="cli:manage_users"` — a container shell exec
|
|
|
|
|
|
|
|
carries no signed-in identity to attribute the change to a real person, so
|
|
|
|
|
|
|
|
it names the tool rather than guessing one. Verified end to end against a
|
|
|
|
|
|
|
|
scratch SQLite database: the audit row lands with the exact expected shape,
|
|
|
|
|
|
|
|
the role change persists, and the existing "no such user" refusal still
|
|
|
|
|
|
|
|
exits 1 with no partial write.
|
|
|
|
|
|
|
|
|
|
|
|
- **T10.9 — Rollback-aware deploy runbook.** Raised after hazard review found
|
|
|
|
- **T10.9 — Rollback-aware deploy runbook.** Raised after hazard review found
|
|
|
|
`DEPLOY-runbook-2026-08-04.md`'s Rollback section has no case for a migration whose
|
|
|
|
`DEPLOY-runbook-2026-08-04.md`'s Rollback section has no case for a migration whose
|
|
|
|
`downgrade()` cannot restore the data it drops — see `D17`. `T10.4`'s
|
|
|
|
`downgrade()` cannot restore the data it drops — see `D17`. `T10.4`'s
|
|
|
|
@@ -183,10 +201,33 @@ Depends only on `main` as it stands after `D15`. Not sequenced behind any other
|
|
|
|
|
|
|
|
|
|
|
|
## Still open
|
|
|
|
## Still open
|
|
|
|
|
|
|
|
|
|
|
|
- The OIDC claim mapping (`T10.3`).
|
|
|
|
- The `Business Technology Group` pilot assignment in Okta. Originally six names
|
|
|
|
- Final confirmation of the redirect/callback URI (`https://wp.controls.dev/api/auth/okta/callback`
|
|
|
|
(Carlee Swihart, Drew Hilliard, Matt Mabrey, Nick Siegfried, Rachel Schreiber, Terry
|
|
|
|
proposed, pending security).
|
|
|
|
Sajan); Cody and Cameron added 2026-09-09. Adrian added only Matt at first,
|
|
|
|
- The `Business Technology Group` pilot assignment in Okta.
|
|
|
|
deliberately, pending the live sign-in confirmation below — awaiting his response to
|
|
|
|
|
|
|
|
add the rest of the group now that it has.
|
|
|
|
|
|
|
|
|
|
|
|
Closed since first written: admin bootstrap and break-glass posture, previously open
|
|
|
|
Closed since first written: admin bootstrap and break-glass posture, previously open
|
|
|
|
questions, decided in `D16` (2026-09-03) and folded into `T10.4` above.
|
|
|
|
questions, decided in `D16` (2026-09-03) and folded into `T10.4` above.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
**Closed 2026-09-09, live in production:** the redirect/callback URI
|
|
|
|
|
|
|
|
(`https://wp.controls.dev/api/auth/okta/callback`) is confirmed working, and so is the
|
|
|
|
|
|
|
|
OIDC claim mapping (`T10.3`) — `preferred_username` (the code's documented default,
|
|
|
|
|
|
|
|
never actually confirmed by name in Request 50649's thread) is correct, no
|
|
|
|
|
|
|
|
`OKTA_IDENTITY_CLAIM` override needed. Both settled by an actual live sign-in against
|
|
|
|
|
|
|
|
the real Okta tenant after `main` was merged (`cc64c88`) and deployed: Matt signed in
|
|
|
|
|
|
|
|
as himself, matched his existing pre-Okta admin account by `find_user()` rather than
|
|
|
|
|
|
|
|
JIT-provisioning a duplicate (the account already existed — this app has ~40 real
|
|
|
|
|
|
|
|
users, not the seeded test fixture), landed on `index.html` signed in, admin role and
|
|
|
|
|
|
|
|
project access untouched. One real deploy-time snag on the way, worth recording since
|
|
|
|
|
|
|
|
it's exactly the Case B scenario `DEPLOY-runbook-2026-09-03.md` anticipated: the first
|
|
|
|
|
|
|
|
redeploy left `OKTA_CLIENT_ID`/`OKTA_CLIENT_SECRET`/`OKTA_ISSUER` as empty rows in
|
|
|
|
|
|
|
|
Portainer (env var names added, values never filled in) — caught via
|
|
|
|
|
|
|
|
`is_configured()`'s all-four-required check failing closed (the 503 "Sign-in is
|
|
|
|
|
|
|
|
temporarily unavailable"), not silently. A second snag after filling those in:
|
|
|
|
|
|
|
|
`OKTA_ISSUER` was pasted without its `https://` scheme, which surfaced as
|
|
|
|
|
|
|
|
`httpx.UnsupportedProtocol` from Authlib's OIDC discovery fetch rather than anything
|
|
|
|
|
|
|
|
the app's own code raises deliberately — the exact case the runbook's Notes flagged as
|
|
|
|
|
|
|
|
having no startup-time confirmation (`okta_auth.describe()` still has no caller,
|
|
|
|
|
|
|
|
`BL-028`). Both fixed by correcting the env var values in Portainer and redeploying;
|
|
|
|
|
|
|
|
neither needed the backup or the database.
|
|
|
|
|