Implement first user onboarding mechanism#54
Merged
JoshuaAFerguson merged 11 commits intoNov 16, 2025
Merged
Conversation
…back system Implements a production-ready admin user onboarding system with multiple configuration methods for maximum flexibility and security. ## Multi-Layered Approach Priority 1: Helm Chart (Production) - Auto-generates secure 32-character random password - Stores in Kubernetes Secret with 'keep' policy - Displays retrieval command in Helm NOTES - Supports custom passwords via values.yaml - Supports existing secrets for external secret management Priority 2: Environment Variable (Manual Deployments) - Reads ADMIN_PASSWORD from environment - Works with docker-compose, bare metal, CI/CD - Validates password strength (8+ characters) - Hashes with bcrypt before storage Priority 3: Setup Wizard (First-Run & Recovery) - Browser-based setup at /api/v1/auth/setup - Only enabled when admin has no password - Password strength validation (12+ characters for admin) - Email validation and password confirmation - Auto-disables after configuration - Atomic database transaction prevents race conditions ## Password Reset Implements ADMIN_PASSWORD_RESET for account recovery: - Set environment variable with new password - Restart API to apply reset - Remove variable after reset completes - Prominent logging for security awareness ## Implementation Details ### Helm Chart - chart/templates/admin-credentials.yaml: Admin password secret - chart/templates/app-secrets.yaml: General secrets (PostgreSQL, JWT) - chart/templates/NOTES.txt: Updated with credentials retrieval - chart/templates/api-deployment.yaml: Inject ADMIN_PASSWORD env var - chart/values.yaml: Add auth.admin configuration section ### API Backend - api/internal/db/database.go: ensureAdminPassword() cascading fallback - api/internal/db/database.go: checkPasswordReset() for recovery - api/internal/handlers/setup.go: Setup wizard API endpoints - GET /api/v1/auth/setup/status: Check if setup required - POST /api/v1/auth/setup: Complete admin configuration ### Documentation - docs/ADMIN_ONBOARDING.md: Comprehensive 400+ line guide - All three onboarding methods with examples - Password reset procedures - Security best practices - Troubleshooting section - QUICKSTART.md: Updated with admin login instructions ## Security Features ✅ Auto-generated random passwords (32 chars, high entropy) ✅ Bcrypt password hashing (cost 10) ✅ Password strength validation (8+ for env, 12+ for wizard) ✅ Kubernetes Secret encryption (if configured) ✅ helm.sh/resource-policy: keep (survives uninstall) ✅ Single-use setup wizard (auto-disables after use) ✅ Atomic database transactions (prevents race conditions) ✅ Input validation and sanitization ✅ No password exposure in logs or API responses ## Benefits - **Production-Ready**: Helm chart with automated secret management - **Flexible**: Works in any deployment environment - **Recoverable**: Never get locked out of admin account - **Secure**: Multiple layers of password protection - **User-Friendly**: Setup wizard for non-technical users - **Well-Documented**: 400+ line comprehensive guide Closes #TBD
Implements the React UI components for the browser-based setup wizard, completing the 3-tier admin onboarding system. ## Components Added ### SetupWizard.tsx (New Page) - Browser-based admin password configuration interface - Checks setup status on mount via API - Auto-redirects if setup not required - Password strength validation (12+ chars) - Password confirmation field - Email validation - Loading and success states - Informational panel explaining onboarding methods - Material-UI styled with dark theme Features: - Real-time password strength validation - Clear error messages with hints - Auto-redirect to login after successful setup - Responsive design with Container/Paper layout - Progress indicators during API calls - Common weak password detection - Educational information about admin onboarding priority ### API Client Updates (api.ts) - getSetupStatus(): Check if setup wizard should be enabled - setupAdmin(): Submit admin credentials to backend Returns: - setupRequired: boolean - adminExists: boolean - hasPassword: boolean - message: string ### Routing (App.tsx) - Added public route: /setup - Eagerly loaded (not lazy) for immediate access - No authentication required (public route) ## User Flow 1. User visits /setup 2. Component checks setup status via API 3. If setup not required: - Show message - Auto-redirect to /login after 3 seconds 4. If setup required: - Display setup wizard form - Validate password strength (12+ chars) - Confirm password matches - Submit to backend API - Show success message - Redirect to /login after 2 seconds ## Integration with Backend Connects to existing backend endpoints: - GET /api/v1/auth/setup/status - POST /api/v1/auth/setup Handles backend errors: - 403 Forbidden: Setup disabled - 400 Bad Request: Validation errors - 409 Conflict: Race condition (another request completed setup) - 500 Internal Server Error: Database errors ## Security Features ✅ Password strength validation (12+ characters) ✅ Common weak password detection ✅ Password confirmation to prevent typos ✅ Email format validation ✅ Auto-disable after setup complete ✅ Clear error messages without exposing internals ✅ HTTPS recommended in production ## UI/UX Enhancements - Loading spinner while checking status - Progress bar when redirecting - Success/error alerts with auto-dismiss - Disabled state during submission - Informational panel explaining fallback system - Material-UI icons (AdminPanelSettings, Check, Info) - Responsive layout for mobile/desktop - Dark theme matching StreamSpace branding Fixes #TBD (blank blue screen at /setup)
…ment script The API expects DB_* prefix environment variables (DB_HOST, DB_PORT, etc.) but the kubectl deployment script was using DATABASE_* prefix, causing connection failures. Changes: - DATABASE_HOST → DB_HOST - DATABASE_PORT → DB_PORT - DATABASE_NAME → DB_NAME - DATABASE_USER → DB_USER - DATABASE_PASSWORD → DB_PASSWORD - Added DB_SSLMODE=disable - Added NAMESPACE from fieldRef This aligns with the Helm chart configuration and allows the API to connect to PostgreSQL successfully. Fixes API CrashLoopBackOff: dial tcp [::1]:5432: connection refused
…source_quotas
Migration 173 was failing with "pq: syntax error at or near '('" because
PostgreSQL doesn't allow function calls like COALESCE() in inline UNIQUE
constraints.
Changed from:
UNIQUE (user_id, COALESCE(team_id, ''))
To:
CREATE UNIQUE INDEX ... ON resource_quotas(user_id, team_id) WHERE team_id IS NOT NULL
CREATE UNIQUE INDEX ... ON resource_quotas(user_id) WHERE team_id IS NULL
This achieves the same uniqueness constraint (preventing duplicate quotas
for the same user/team combination) using valid PostgreSQL syntax.
…_versions Migration 221 was failing with "column 'status' does not exist" because there were two tables named `template_versions`: 1. Line 404: Simple version history for catalog templates (no status column) 2. Line 1314: Comprehensive versioning with status column for template testing The first CREATE TABLE succeeded, second was skipped due to IF NOT EXISTS, then the index creation for status column failed. Renamed the first table to `catalog_template_versions` to clarify its purpose and avoid naming conflict. Now we have three distinct template version tables: - catalog_template_versions: Repository template versions - user_session_template_versions: User custom template versions - template_versions: Main versioning system with status and testing support
Added RegisterRoutes method to SetupHandler and integrated it into the main API route setup. The setup wizard endpoints are now properly registered in the /api/v1/auth group alongside other authentication routes. Changes: - Added RegisterRoutes method to api/internal/handlers/setup.go - Initialized SetupHandler in api/cmd/main.go - Added setupHandler parameter to setupRoutes function - Registered setup routes in authGroup (public, no auth required) Routes available: - GET /api/v1/auth/setup/status - Check if setup wizard is enabled - POST /api/v1/auth/setup - Configure admin account These routes are public (no authentication required) to allow initial admin account setup before any users can log in.
Fixed Gin route registration panic caused by conflicting route patterns. The routes `/versions/:versionId` and `/:templateId/versions` were ambiguous and caused Gin to panic during route registration. Changed all version-specific routes to be nested under template ID: Before (conflicting): - GET /:templateId/versions - GET /versions/:versionId <- CONFLICT After (fixed): - GET /:templateId/versions - GET /:templateId/versions/:versionId This makes semantic sense as versions belong to specific templates. All version and test routes now follow the hierarchical pattern: /:templateId/versions/:versionId/... Fixes API startup panic at main.go:596
Fixed Gin panic caused by conflicting route parameter names. Gin doesn't
allow different parameter names at the same path position.
Changed all template versioning routes from :templateId to :id to match
the existing template CRUD routes that use 🆔
Routes:
- PATCH /api/v1/templates/:id (existing)
- DELETE /api/v1/templates/:id (existing)
- GET /api/v1/templates/:id/versions (new - now uses :id)
Also updated all handler methods to read c.Param("id") instead of
c.Param("templateId") in template_versioning.go:
- CreateTemplateVersion
- ListTemplateVersions
- GetTemplateInheritance
This resolves the panic:
':templateId' in new path conflicts with existing wildcard ':id'
Removed duplicate registration of POST /api/v1/sessions/:id/heartbeat which was being registered in both: 1. main.go setupRoutes (line 397) - h.SessionHeartbeat 2. activity.go RegisterRoutes (line 74) - h.RecordHeartbeat The ActivityHandler.RegisterRoutes() is the correct place for this route, so removed it from the main setup to avoid Gin panic: "handlers are already registered for path '/api/v1/sessions/:id/heartbeat'" Added comment noting that heartbeat registration is delegated to ActivityHandler.RegisterRoutes().
Removed duplicate registration of GET /api/v1/catalog/templates which was being registered in both: 1. main.go setupRoutes (line 618) - h.BrowseCatalog 2. catalog.go RegisterRoutes (line 80) - h.ListTemplates The CatalogHandler.RegisterRoutes() is the correct place for template catalog routes, so removed it from main.go setup. Kept repository management routes in main.go since CatalogHandler only handles template-related endpoints: - GET /catalog/repositories - POST /catalog/repositories - DELETE /catalog/repositories/:id - POST /catalog/sync - POST /catalog/install Resolves Gin panic: "handlers are already registered for path '/api/v1/catalog/templates'"
Fixed Gin panic caused by conflicting parameter names for session routes.
Changed session activity routes from :sessionId to :id to match the
existing session CRUD routes.
Route changes in main.go:
- /api/v1/sessions/:sessionId/activity -> /api/v1/sessions/:id/activity
Handler changes in sessionactivity.go:
- c.Param("sessionId") -> c.Param("id")
This resolves the panic:
':sessionId' in new path '/api/v1/sessions/:sessionId/activity/log'
conflicts with existing wildcard ':id' in existing prefix
'/api/v1/sessions/:id'
Note: Console routes (/console/sessions/:sessionId, /console/files/:sessionId)
are not affected as they're under a different path prefix.
| admin: | ||
| # Admin password (leave empty for auto-generation) | ||
| # ⚠️ SECURITY: For production, provide a secure password or use existingSecret | ||
| password: "" # Empty = auto-generate 32-character random password |
Check failure
Code scanning / CodeQL
Empty password in configuration file High
Comment on lines
+17
to
+22
| import { | ||
| AdminPanelSettings as AdminIcon, | ||
| Check as CheckIcon, | ||
| Error as ErrorIcon, | ||
| Info as InfoIcon, | ||
| } from '@mui/icons-material'; |
Check notice
Code scanning / CodeQL
Unused variable, import, function or class Note
Show autofix suggestion
Hide autofix suggestion
Copilot Autofix
AI 7 months ago
To resolve this issue, the ErrorIcon should be removed from the named imports on line 20 in the @mui/icons-material import statement of ui/src/pages/SetupWizard.tsx. This change will clean up the code, reduce confusion, and prevent unnecessary imports. Only edit the lines shown; do not change or add other features or imports. There are no other changes or dependencies related to this fix.
Suggested changeset
1
ui/src/pages/SetupWizard.tsx
| @@ -17,7 +17,6 @@ | ||
| import { | ||
| AdminPanelSettings as AdminIcon, | ||
| Check as CheckIcon, | ||
| Error as ErrorIcon, | ||
| Info as InfoIcon, | ||
| } from '@mui/icons-material'; | ||
| import { useNavigate } from 'react-router-dom'; |
Copilot is powered by AI and may make mistakes. Always verify output.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.