Prototype owner-only administrator account management

This commit is contained in:
Quintine committed 2026-09-29 22:46:33 +10:00
1 parent ac8742c829
commit 882d006b3c
24 files changed
+3438 -15

No files matched your search

+50
View File
@@ -0,0 +1,50 @@
# Administrator account management
Open **Administration → Accounts** as an enabled owner. Operators, viewers and room hosts cannot list or change administrator accounts. The directory shows account names, roles, enabled status and timestamps in pages of 25. It never returns access keys, their hashes or administrator sessions.
## Provision and protect a key
Choose a name, owner/operator/viewer role and operational reason, then review the exact account ID, name, role and reason before confirming. The browser generates a new UUID and 256-bit personal access key with Web Crypto. It saves the exact request in this tab before sending it. The server stores only its SHA-256 hash and returns account metadata, **not the key**. After confirmation, save the one-time displayed key privately and explicitly clear its tab record. Refresh restores an unconfirmed request or the confirmed key until it is cleared. If the response is uncertain, retry the same saved request; do not generate a replacement request or discard the only key copy. Do not place keys in reasons, screenshots, issue reports or shared logs.
## Change or disable access
Choose an enabled account other than your own. Review its exact name, ID,
current role, requested new role or disable, and operational reason before
sending. A role change uses the current account timestamp; a stale target
is rejected and must be reviewed again. Disabling blocks the key and
permanently invalidates current sessions; this page cannot re-enable the
account. **Do not manually re-enable its database row:** without a separate
key rotation, its old access key would become usable again. Provision a new
account instead. Another owner must perform a self-demotion or self-disable.
The database refuses to remove the final enabled owner. Existing game rooms,
seats and recovery kits are not modified.
Each operation has an exact saved identifier and request fingerprint. Concurrent or repeated identical requests resolve to one account change and one actor-attributed audit record; a different request cannot reuse that identifier. Live owner role, session expiry/generation and target version are rechecked at the database write, not inferred from the rendered page. An uncertain role or disable response can be retried from this tab; a conflicting or revoked request remains blocked for review. Tab records are scoped to the original owner account.
Action history shows successful account operations with safe role changes and an operational reason for authorized readers. External CLI provisioning or revocation may still have no human actor attribution. Rejected attempts are not yet part of that history. No browser account operation grants access to a playing seat or reveals saved game data.
## Verification and remaining work
Implementation: [account query and transactions](../db/admin-accounts.ts), [request contract](../lib/admin-accounts.ts), [route](../app/api/admin/accounts/route.ts), [page](../app/admin/accounts/page.tsx) and [additive operation receipt](../drizzle/0019_admin_accounts.sql). Keep the original owner-protection and session-revocation triggers in migration `0008`.
```sh
npm test -- admin-accounts admin-audit
npm run test:integration -- admin-boundary
```
The source-bound local checkpoint passes 5,780 offline tests, 55 HTTP
integration tests, the app build and Drizzle migration check. An isolated
Request/Response route-handler smoke exercised owner provisioning, exact
replay, directory read and foreign-origin denial; it did not use a network
server or persistent administrator account. Browser owner fixtures blocked
or intercepted POSTs and verified one-time key recovery and mobile disable
confirmation. Independent security and persistence reviews resolved
unchanged-role audit no-ops, missing point-of-risk copy and a logout-all
timestamp rollback.
Use an isolated owner and disposable target for authenticated end-to-end
account changes; never use a person's normal owner key in a destructive QA
flow. Client/browser fixtures alone do not prove a signed-in **network**
HTTP mutation or production deployment. Key rotation, re-enabling a
disabled account, failed-attempt audit, complete administration and live
acceptance remain unfinished.
+10 -5
View File
@@ -17,9 +17,11 @@ Each record identifies the action, time, room/seat/account where recorded, actor
operational reason when permitted, and bounded before/after settings. Expand
**Recorded settings** for the public configuration, lifecycle flags, revisions,
AI difficulty or changed player circle. Names come from current administrator
accounts; deleted accounts retain their recorded identifiers. External account
provisioning/revocation records have no human actor attribution, and the page
explicitly says so. A **Recorded** outcome means the operation was applied; a
accounts; deleted accounts retain their recorded identifiers. Web-managed
provisioning, role changes and disabling identify the acting owner and record
the supplied reason. External CLI provisioning/revocation may lack human
actor attribution, and the page says so. A **Recorded** outcome means the
operation was applied; a
room-control operation may successfully save identical settings, and later
operations may supersede it. It does not assert the room's current state.
@@ -51,7 +53,10 @@ and uses the existing no-store, cookie-varying administration boundary.
Implementation: [query/projection](../db/admin-audit.ts),
[response contract](../lib/admin-audit.ts),
[route](../app/api/admin/audit/route.ts), [page](../app/admin/audit/page.tsx).
No schema migration is needed.
The original nine-source read needed no migration. Owner account management
adds a safe `reason` field and durable retry receipts in additive
[migration 0019](../drizzle/0019_admin_accounts.sql); it does not add a
new raw game or message source.
```sh
npm test -- admin-audit
@@ -71,7 +76,7 @@ sources under its five-term compound-query limit, with live role demotion and
filtered reads. Materialized groups keep the unified query within that limit.
Existing records cover successful operations only. Failed/rejected attempts,
additional account-management actions, full operational health/diagnostics,
key rotation and re-enable, full operational health/diagnostics,
backup/import/restore and the remaining participant support are still required.
Local/browser/source-bound evidence is separate from deployed acceptance, which
must identify the actual running revision and use authorized QA access.
+8 -1
View File
@@ -9,7 +9,7 @@ recovery and persistence systems where suitable.
| Area | Required behavior | Stage |
| --- | --- | --- |
| Administrator access | Personal access keys, server-enforced owner/operator/viewer roles, persistent eight-hour sessions, individual/all-session sign-out and operator provisioning/revocation. A room host is not a site administrator. Account-management UI and further operational permissions remain. | Prototyped |
| Administrator access | Personal access keys, server-enforced owner/operator/viewer roles, persistent eight-hour sessions and individual/all-session sign-out. [Owner-only account management](ADMIN_ACCOUNTS.md) adds a paginated directory, browser-created one-time keys, role changes, disabling, live authority and exact retries. A room host is not a site administrator. Key rotation/re-enable, failed-attempt history and further operational permissions remain. | Prototyped, partial |
| Room directory | Search room codes/public player names, filter status/rules/availability, sort and paginate; show host, roster, modules, game change time, pause/join flags and bounded decision ownership. Detailed setup/shared-window ownership remains. | Prototyped |
| Create and configure | [Create a lobby](ADMIN_ROOM_CREATION.md) with an explicitly owned new host seat, Basic/Advanced preview and initial AI configuration; invite humans and use ordinary lobby controls/voluntary host-seat handover. [Neutral lobby configuration](ADMIN_LOBBY_CONFIGURATION.md) adds rules/modules, AI seats and host assignment to an existing human without private access. Reserved human seats remain. | Prototyped, partial |
| Lifecycle and removal | [Pause/resume and joining locks](ADMIN_ROOM_CONTROLS.md), [administrative close/reopen](ADMIN_ROOM_CLOSURE.md) and [recoverable removal/restoration](ADMIN_ROOM_REMOVAL.md) have controls, durable audit, exact retries and player/AI enforcement. [Archive/unarchive](ADMIN_ROOM_ARCHIVE.md) has separate directory filters and exact retries. Permanent deletion and bulk actions remain missing. | Prototyped, partial |
@@ -53,6 +53,13 @@ Disabling an account invalidates its sessions; later re-enabling it cannot resto
them. The database refuses to disable, demote or delete the final enabled owner.
No default key, public account creation or host-to-administrator promotion exists.
[Manage accounts](ADMIN_ACCOUNTS.md) lets a current owner provision a personal
key, change another administrator’s role or disable its access. The exact
request and generated key remain tab-scoped through uncertain responses;
the server never returns a key. The owner reviews the target and reason
before submitting, and no game or seat is modified. Key rotation and
re-enabling disabled accounts are not available in this prototype.
[Participant AI](ADMIN_PARTICIPANT_AI.md) lets owners/operators support an absent
human in a paused, started game. The player retains access and takeback controls;
the administrator receives no private seat. Resume remains a separate action.
+10
View File
@@ -6,6 +6,16 @@ Expansion starts and full rules/publication acceptance remain gated.**
## Current checkpoint and work
The owner-only [administrator accounts](ADMIN_ACCOUNTS.md) prototype now
lists accounts, provisions a browser-generated one-time personal key, changes
another account’s role and disables access. Server actions repeat live owner
authority and target-version checks at commit, preserve exact tab-scoped
retries and attribute successful changes in action history without exposing
keys or saved games. Key rotation/re-enable, rejected-attempt history,
authenticated positive **network** HTTP on a dedicated isolated QA account, deployed
acceptance and the rest of full administration remain unfinished. This code
is not in the last verified live image.
The bounded [Advanced Moritani Assassinate Leaders preview](MORITANI_ASSASSINATE_LEADERS.md)
now has repeatable genuine games across two through six supported seats.
Five samples completed 2,511 accepted actions, no rejected candidates
+37
View File
@@ -1,5 +1,42 @@
# Dune implementation status
## 29 September 2026 — owner account management prototype
The [account page](ADMIN_ACCOUNTS.md) lists only safe metadata to a live
owner. Provisioning uses a tab-scoped, browser-generated 256-bit key and an
exact durable operation receipt; only its SHA-256 hash enters the database.
Owners can change another account’s role or disable it after reviewing the
name, ID, current/desired role and reason. Database writes repeat live owner
authority and target-version checks, retain the final-owner trigger, and
attribute the single successful provision/role/disable audit event. Disabled
sessions fail immediately; room and seat rows remain untouched. Rotation,
re-enable, failed-attempt audit and complete administration remain pending.
An isolated direct D1 smoke provisioned a disposable account, changed its
role, disabled it, confirmed its old key/session fail and verified safe
owner-attributed history without a raw key. An isolated Request/Response
route-handler smoke confirmed owner provision, exact replay, directory read
and foreign-origin denial without contacting a persistent database. Focused
account/access/audit regressions include an additive migration preserving
existing room, seat, credential and audit bytes. The local browser showed
signed-out denial at phone width; intercepted owner fixtures displayed exact
owner-role disable confirmation, retained a one-time key after refresh and
hid directory/key controls after a focus-triggered demotion. Browser fixture
POSTs never reached an account database. Authenticated positive **network**
HTTP and live NAS acceptance remain untested.
Independent security review found and corrected unchanged-role audit no-ops
and incomplete final disable confirmation. A separate persistence review
reproduced a logout-all timestamp rollback; the account version is now
monotonic and a stale disable rejects. Both follow-up read-only reviews
reported no remaining scoped finding. The first focused HTTP run found a
test assuming JSON for Vite’s foreign-origin 403; the corrected boundary
test passes 3/3, and the full local HTTP suite passes 55/55.
`npm run check` passes typecheck, lint and 5,780/5,780 offline cases;
`npm run build` and `drizzle-kit check` pass. These results do not certify
complete administration, authenticated production mutations or deployment.
## 29 September 2026 — Advanced Moritani assassination sample matrix
The reusable offline runner now supports the explicitly gated