Repository navigation
fix(system-agent): resolve the platform owner through ADMIN_USERNAME, not a literal "admin" (#3262) - #3268
Conversation
… not a literal "admin" (#3262) The system agent, the Cornelius seed and the default system seed each hard-coded the owner username "admin". The admin account is created as utils.admin_identity.admin_username(), which honours ADMIN_USERNAME, so on an ADMIN_USERNAME=root install the system agent was never created ("Admin user 'admin' not found") and both seeds deferred forever as if setup had not run. #2381 fixed the same mismatch in routers/setup.py. All three now call admin_username() at use time. Existing installs are unaffected: register_agent_owner never re-owns an existing row. Fixes #3262 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
merge-train (2026-10-06): ejected — rides the next train once fixed. The owner fix is right, but it unblocks a stale persisted first-run verdict. Suggested shape: don't persist a verdict while the owner row is absent (return |
|
Resolve by running |
|
Resolve by merging |
AndriiPasternak31
left a comment
There was a problem hiding this comment.
+1 to @vybe's ejection. I reproduced it by running the real ensure_first_run_seeded() from the stale state:
- Start: ADMIN_USERNAME=root, first_run_fresh="true" saved at first boot, neither cornelius_seeded nor default_system_seeded set, 7 hand-built agents.
- dev: Cornelius is not provisioned, and the system seed returns deferred.
- This PR: Cornelius _provision runs once, the system seed passes its owner check and moves on to deploying the manifest, and brain_orb_enabled is switched on.
So vybe's (a)–(c) are needed: no saved verdict while the owner row is missing, reconcile already-stale rows, and a test from exactly that state. If that takes a while, the system-agent half is safe to ship on its own, because it has no saved verdict. Hold back the two seeder lines.
One more of the same class that isn't in vybe's note: event_dispatch_service.py:178 mints the EVT-001 loopback JWT with "sub": "admin". get_current_user looks that username up (dependencies.py:682) and returns 401 when it's missing, so on a root install every event-subscription dispatch should fail. I traced this in code and did not run it live. The fix is one line, admin_username(). Fold it in here, or file a follow-up.
Smaller:
- database.py:873/907 still read os.getenv("ADMIN_USERNAME", "admin") raw, while admin_username() strips whitespace. With ADMIN_USERNAME=" root", the user is created as " root" and every caller looks up "root". Follow-up material.
- The merge conflict is only tests/registry.json (#3243's entry landed in the same spot). Keep both entries.
What checks out: the owner swap itself is right. Each fix reverted turns its tests red as claimed (3/1/1), and 201 related tests pass. There is no admin-gate change: the system key is still scope=system. ADMIN_USERNAME renders as root in all three compose files and is in .env.example.
…n verdict (#3262) Resolving the owner through ADMIN_USERNAME unblocked a verdict stored while the owner lookup was failing: an ADMIN_USERNAME=root install that first booted empty persisted first_run_fresh=true, both seeders then deferred forever, and neither seed flag was set. Finding the owner would have provisioned Cornelius and the default system onto a mature fleet. - _resolve_first_run_verdict persists nothing while the owner row is absent. - A stored "true" with neither seed flag set and non-system agents present is reconciled to "false". - EVT-001 loopback JWT is minted for admin_username(), not a literal "admin" (get_current_user 401'd every event dispatch on a root install). - The system-agent owner test stubs Path with a class, so the raise is the promised FileNotFoundError rather than a TypeError. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…ent-owner # Conflicts: # tests/registry.json
|
Addressed the 10-06 review (vybe's ejection + @AndriiPasternak31's review) in Stale first-run verdict, items (a)–(c)
Loopback JWT: Minor: the system-agent owner test stubs Pin moved: Conflict: Mutation check: with the two service files reverted, 3 of the new tests go red. Related suites pass: ent124, 3262, ent614, 2973, ent751, ent319, cornelius, 2215, onboarding — 296 passed. Left as a follow-up: 🤖 Generated with Claude Code |
… keep-both on append-only files
|
merge-train (2026-10-07): merged as part of train #3329 (green). Before the squash, |
Summary
"admin". The admin account is created asutils.admin_identity.admin_username(), which honoursADMIN_USERNAME. On anADMIN_USERNAME=rootinstall:Admin user 'admin' not found);admin_username()at use time; the constantsSYSTEM_AGENT_OWNER,CORNELIUS_OWNERandSEED_OWNERare removed. bug(security): fresh install leaves setup_completed=false with a real admin — unauthenticated /api/setup/admin-password overwrites the admin password #2381 fixed the same mismatch inrouters/setup.py.register_agent_ownernever re-owns anagent_ownershiprow that already exists (onIntegrityErrorit only setsis_system).Changes
services/system_agent_service.py: create path (lookup, error message, MCP key owner, ownership, default permissions) and the running-branch re-registration.services/cornelius_agent_service.py,services/system_seed_service.py: the owner lookup.services/onboarding_service.py,routers/settings/retention.py,tests/unit/test_ent319_first_run_front_desk.py.tests/unit/test_3262_admin_username_owner.pyand itstests/registry.jsonentry.Test Plan
cd tests && pytest unit/test_3262_admin_username_owner.py: 5 passed. Reverting each service file separately fails its own tests (system agent 3, Cornelius 1, system seed 1).admin_identityor onboarding (19 files), shuffled with--randomly-seed=12345: 480 passed.ADMIN_USERNAME=rootand fresh data:dev: boot logsSystem agent: create_failed - Failed to create system agent: Admin user 'admin' not found, and both seeds log "deferring" althoughsetup_completedis true androotcan log in.System agent: created, and/api/system-agent/statusreports ownerroot,running,is_system: true. Both seeds proceed instead of deferring.Fixes #3262
🤖 Generated with Claude Code