Add docs and project files - force for Culurien
This commit is contained in:
167
docs/4_LOG/December_2025/2025-12-16_EnsureAdminUser_Fix_Plan.md
Normal file
167
docs/4_LOG/December_2025/2025-12-16_EnsureAdminUser_Fix_Plan.md
Normal file
@@ -0,0 +1,167 @@
|
||||
# REDFLAG ENSUREADMINUSER CRITICAL BUG - COMPREHENSIVE FIX PLAN
|
||||
|
||||
## BACKGROUND
|
||||
- RedFlag was designed as SINGLE-ADMIN system (author is original developer, abhors enterprise)
|
||||
- Originally just JWT tokens for agents, later added single-admin web dashboard
|
||||
- Database schema has multi-user scaffolding but never implemented
|
||||
- EnsureAdminUser() exists but breaks single-admin password updates
|
||||
|
||||
## THE PROBLEM
|
||||
**EnsureAdminUser() exists in single-admin system where it doesn't belong:**
|
||||
```go
|
||||
func (q *UserQueries) EnsureAdminUser(username, email, password string) error {
|
||||
existingUser, err := q.GetUserByUsername(username)
|
||||
if err == nil && existingUser != nil {
|
||||
return nil // Admin user already exists ← PREVENTS PASSWORD UPDATES!
|
||||
}
|
||||
_, err = q.CreateUser(username, email, password, "admin")
|
||||
return err
|
||||
}
|
||||
```
|
||||
|
||||
**In single-admin system: admin exists = admin already exists, so password never updates**
|
||||
|
||||
## EXECUTION ORDER BUG
|
||||
**New version broken:**
|
||||
```
|
||||
Main starts → EnsureAdminUser(empty password) → isSetupComplete() → welcome mode
|
||||
```
|
||||
- Admin user created with empty/default password BEFORE setup
|
||||
- Setup runs but admin already exists → no password update
|
||||
- Login fails
|
||||
|
||||
**Legacy version worked:**
|
||||
```
|
||||
Main starts → config check → if failed → welcome mode → return
|
||||
```
|
||||
- No admin user created if setup incomplete
|
||||
- After setup restart → EnsureAdminUser with correct password
|
||||
|
||||
## COMPREHENSIVE CLEANUP PLAN
|
||||
|
||||
### PHASE 1: ANALYSIS
|
||||
1. **Document everything added in commit a92ac0ed7 (Oct 30, 2025)**
|
||||
- What auth system was being implemented?
|
||||
- Why multi-user scaffolding if never intended?
|
||||
- What was the original intended flow?
|
||||
|
||||
2. **Identify all related multi-user scaffolding:**
|
||||
- Database schemas with role system
|
||||
- Auth handlers with role checking
|
||||
- User management functions that exist but are unused
|
||||
|
||||
3. **Map the actual authentication flow:**
|
||||
- Agent auth (JWT tokens)
|
||||
- Web auth (single admin password)
|
||||
- How they relate/interact
|
||||
|
||||
### PHASE 2: CLEANUP
|
||||
|
||||
#### REMOVE MULTI-USER SCAFFOLDING
|
||||
1. **Database cleanup:**
|
||||
```
|
||||
users table: Keep email field (for admin) but remove role system
|
||||
- ALTER TABLE users DROP COLUMN role (or default to 'admin')
|
||||
- Remove unused indexes if any
|
||||
```
|
||||
|
||||
2. **Code cleanup:**
|
||||
- Remove role-based authentication checks
|
||||
- Simplify user models to remove role field
|
||||
- Remove unused user management endpoints
|
||||
|
||||
#### FIX ENSUREADMINUSER
|
||||
**Option A: Delete entirely and replace with EnsureSingleAdmin**
|
||||
```go
|
||||
func (q *UserQueries) EnsureSingleAdmin(username, email, password string) error {
|
||||
// Always update/create admin with current password
|
||||
existingUser, err := q.GetUserByUsername(username)
|
||||
if err != nil {
|
||||
// User doesn't exist, create it
|
||||
return q.CreateUser(username, email, password, "admin")
|
||||
}
|
||||
|
||||
// User exists, update password
|
||||
return q.UpdateAdminPassword(existingUser.ID, password)
|
||||
}
|
||||
```
|
||||
|
||||
**Option B: Modify existing to update instead of return early**
|
||||
- Keep function name but change logic to always ensure password matches
|
||||
|
||||
#### FIX EXECUTION ORDER
|
||||
**In main.go:**
|
||||
```go
|
||||
// BEFORE: EnsureAdminUser comes before setup check
|
||||
// AFTER: Move EnsureAdminUser AFTER setup is confirmed complete
|
||||
|
||||
// Check if setup is complete FIRST
|
||||
if !isSetupComplete(cfg, signingService, db, userQueries) {
|
||||
startWelcomeModeServer()
|
||||
return
|
||||
}
|
||||
|
||||
// THEN ensure admin user with correct password
|
||||
if err := userQueries.EnsureSingleAdmin(cfg.Admin.Username, cfg.Admin.Username+"@redflag.local", cfg.Admin.Password); err != nil {
|
||||
log.Fatalf("Failed to ensure admin user: %v", err)
|
||||
}
|
||||
```
|
||||
|
||||
**Add password update function if not exists:**
|
||||
```go
|
||||
func (q *UserQueries) UpdateAdminPassword(userID uuid.UUID, newPassword string) error {
|
||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(newPassword), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
query := `UPDATE users SET password_hash = $1 WHERE id = $2`
|
||||
_, err = q.db.Exec(query, hashedPassword, userID)
|
||||
return err
|
||||
}
|
||||
```
|
||||
|
||||
### PHASE 3: VALIDATION
|
||||
1. **Fresh install test:**
|
||||
- Start with clean database
|
||||
- Run setup with custom password
|
||||
- Restart
|
||||
- Verify login works with custom password
|
||||
|
||||
2. **Password change test:**
|
||||
- Existing installation
|
||||
- Update .env with new password
|
||||
- Restart
|
||||
- Verify admin password updated
|
||||
|
||||
3. **Agent auth compatibility:**
|
||||
- Ensure agent JWT auth still works
|
||||
- Verify no regression in agent communication
|
||||
|
||||
### PHASE 4: SIMPLIFICATION
|
||||
**Given ETHOS principles (anti-enterprise):**
|
||||
- Remove all complexity around multi-user
|
||||
- Single admin = single configuration
|
||||
- Remove unused user management code
|
||||
- Simplify to essentials only
|
||||
|
||||
**Questions for original developer:**
|
||||
1. What was the original intent when adding web auth?
|
||||
2. Were there plans for multiple admins or was this just scaffolding?
|
||||
3. Should we remove the entire role system or just simplify it?
|
||||
4. Is keeping email field useful for single admin or should we simplify further?
|
||||
|
||||
## NEXT STEPS
|
||||
1. Analyze commit a92ac0ed7 thoroughly
|
||||
2. Get approval from original developer for cleanup approach
|
||||
3. Implement fixes in development branch
|
||||
4. Test thoroughly on fresh installs
|
||||
5. Remove multi-user scaffolding definitively
|
||||
6. Document final single-admin-only architecture
|
||||
|
||||
## RATIONALE
|
||||
RedFlag is NOT enterprise:
|
||||
- No multi-user requirements
|
||||
- Single admin for homelab/self-hosted
|
||||
- Simpler = better
|
||||
- Follow original design philosophy
|
||||
Reference in New Issue
Block a user