Commit Graph

57 Commits

Author SHA1 Message Date
Fusion 753f1506b6 fix: wrap /auth/me response in user object to match frontend types
Frontend expects {user: {id, email, name, avatar_url}} but backend
was returning flat object. This caused auth state to fail parsing.
2026-05-19 10:43:18 +02:00
Fusion 58bf30ed15 fix: set cookie domain for cross-subdomain authentication
In production, the session cookie needs to be shared across
subdomains (e.g., api.example.com and app.example.com).

- Add cookie_domain property to config (extracts parent domain)
- Set SameSite=None for cross-origin requests in production
- Update auth callback and logout to use cookie domain
- This fixes the login loop where session cookie wasn't sent
2026-05-18 23:33:59 +02:00
Fusion c067c03662 fix: add CORS middleware to allow frontend auth requests
Add CORSMiddleware configured to:
- Allow the frontend origin (web_base_url)
- Allow credentials (cookies)
- Allow all methods and headers

This fixes cross-origin requests between frontend and API
when they're on different subdomains.
2026-05-18 23:27:11 +02:00
Fusion d273535950 fix: redirect to frontend after OAuth callback instead of returning JSON
- /auth/callback now redirects to frontend URL with session cookie
- /auth/login stores 'next' path in cookie for post-login redirect
- User is redirected to their original destination after authentication
2026-05-18 23:22:25 +02:00
Fusion 7f97ba8e9b fix: make migrations idempotent with if_not_exists
Add if_not_exists=True to CREATE TABLE operations in migrations
0003 and 0004. This prevents DuplicateTableError when migrations
are re-run on databases where tables were partially created.
2026-05-18 23:18:11 +02:00
Fusion caf73e39ba fix: use subprocess for alembic migrations to avoid async/sync issues
SQLAlchemy 2.0 async engines conflict with alembic's sync context manager.
Instead of trying to bridge async/sync, use subprocess to run
'alembic upgrade head' directly. This is simpler and more reliable.

- Remove psycopg2-binary dependency (no longer needed)
- Simplify init_database to use subprocess.run()
- Remove all sync engine code
2026-05-18 23:16:01 +02:00
Fusion 1e70462c2b fix: use sync engine for alembic migration operations
SQLAlchemy 2.0 async engines don't support the sync context manager
protocol needed by alembic. Create a separate sync engine (using
psycopg2) for migration operations while keeping async engine for
application queries.

- Add psycopg2-binary dependency
- Rename async connection variable to avoid mypy confusion
- Use sync engine for MigrationContext and alembic commands
2026-05-18 23:09:44 +02:00
Fusion b9684b0107 fix: fail fast on startup if database migrations fail
- Exit with error code 1 if init_database() returns False
- Update health check to verify database connectivity
- Prevents confusing 'table does not exist' errors later
2026-05-18 23:05:30 +02:00
Fusion 2ce7862058 feat: simplify auth flow - replace JWT with session cookies
Replace complex JWT + refresh token authentication with simple
session-based auth using signed cookies.

**Removed:**
- JWT token service (jwt_service.py)
- Refresh token store (refresh_store.py)
- Refresh token model and database table
- JWKS fetching and OIDC token verification
- python-jose dependency

**Added:**
- Session service (session.py) with HMAC-SHA256 signed cookies
- Auth dependencies module for shared auth logic
- Session-based auth endpoints

**Updated:**
- All API endpoints to use session-based auth
- Config: removed JWT settings, added SESSION_SECRET/SESSION_TTL_HOURS
- Tests: rewritten for session-based flow
- Frontend: no changes needed (already uses cookies)

Quality gates: ruff ✓, mypy ✓, typecheck ✓, lint ✓
2026-05-18 22:54:53 +02:00
Fusion 285d3dace8 fix: use await engine.connect() instead of async with
SQLAlchemy 2.0 async engine.connect() doesn't support context manager.
Use explicit connect/close instead.
2026-05-18 22:38:08 +02:00
Fusion 9fefe289a7 fix: prevent concurrent migrations in multi-worker setup
Add migration version check before running alembic upgrade to prevent
multiple uvicorn workers from running migrations simultaneously.

- Check current vs head revision before running migrations
- Skip migration if already at latest version
- Log current and head revision for debugging
2026-05-18 22:35:42 +02:00
Fusion 843683d579 feat: add comprehensive request and error logging
Add logging infrastructure:
- RequestLoggingMiddleware: logs all requests with method, path, status, timing
- ExceptionLoggingMiddleware: catches and logs unhandled exceptions with stack traces
- configure_logging(): structured logging with configurable level via LOG_LEVEL env var

Add detailed auth flow logging:
- Login initiation
- Token exchange success/failure
- JWKS fetch success/failure
- Token verification
- User lookup/creation
- Database errors
- Final response

This enables tracing Internal Server Errors through the logs.
2026-05-18 22:22:56 +02:00
Fusion ea6c466c6c feat: add automatic database initialization and recovery
- Add init_database() with alembic programmatic API and retry logic
- Add connection retry with exponential backoff (5 attempts)
- Improve error messages for connection/auth failures
- Add table existence check before seeding data
- Update startup event to run migrations before seeding
- Add wait-for-db.sh script for Docker containers
- Update Docker and docker-compose configurations

Quality gates: ruff ✓, mypy ✓, unit tests (8 passed)
2026-05-18 22:10:15 +02:00
Fusion 29c3563148 fix: correct down_revision reference in user_configs migration
0003_user_configs was referencing '0002' but 0002_refresh_tokens
has revision ID '0002_refresh_tokens'. Fix the chain.
2026-05-18 21:55:54 +02:00
Fusion 0509b9eb4a fix: separate Authentik application slug from OAuth client ID
Authentik uses different values for:
- OAuth Client ID (UUID for authentication)
- Application Slug (URL-friendly identifier like 'headquarter-web')

Add AUTHENTIK_APPLICATION_SLUG config to build correct Authentik URLs
while keeping AUTHENTIK_CLIENT_ID for OAuth token exchange.
2026-05-18 21:46:54 +02:00
Fusion 137757602f fix: make refresh_token optional in OIDC token exchange
Authentik may not return a refresh_token in the authorization_code
response. Use .get() instead of direct dict access to prevent KeyError.
2026-05-18 21:41:13 +02:00
Fusion 3cd8674c31 fix: add /health endpoint for health checks
Add simple health check endpoint that returns {status: healthy}.
Needed for Traefik health checks and monitoring.
2026-05-18 21:36:39 +02:00
Fusion 899fba9c9b fix: handle missing tool_types table gracefully on startup
Catch ProgrammingError when tool_types table doesn't exist yet
(during fresh database setup). Log warning and skip seeding instead
of crashing.
2026-05-18 21:29:48 +02:00
Fusion 6dbd55a9ac fix: correct uvicorn module path in Dockerfile
main.py is located at src/main.py, not at the root.
Changed CMD from 'main:app' to 'src.main:app' to fix ASGI import error.
2026-05-18 17:53:40 +02:00
Fusion 7b72ccdc3c docs: sync tool-types-definition specs and mark tasks complete
- Mark manual testing tasks as complete in tool-types-definition
- Sync tool-types-definition spec to main specs directory
2026-05-18 17:10:23 +02:00
Fusion 6b302b3279 feat: implement tool types definition system
- Add ToolType SQLAlchemy model with Docker Compose template support
- Create CRUD API endpoints for tool type management
- Implement YAML and template variable validation
- Add built-in tool types (code-server, jupyter-notebook) seeded on startup
- Create frontend page with list, create, edit, and delete functionality
- Add tool types navigation to app shell
- Update mypy config to ignore missing imports

Quality gates: ruff (passed), mypy (passed), pytest unit (8 passed),
typecheck (passed), lint (passed), build (passed)
2026-05-18 16:27:19 +02:00
Fusion 94254ee3fd feat: complete user config management
- Add theme support with dark/light/system modes
- Add useTheme hook for applying user config theme
- Update router to use SettingsPage
- Update app-shell to apply theme on load
- Add CSS variables for dark theme
- Fix mypy errors in user_config.py
- Quality gates pass: ruff, mypy, typecheck, lint, build
2026-05-18 15:58:01 +02:00
Fusion 4e2edb1d93 feat: implement git repository management
- Add backend API for git repository CRUD (create, list, delete)
- Support bare repository initialization and mirror cloning
- Add cascade delete for repositories when project is deleted
- Add frontend page for repository management per project
- Update project page with link to repositories
- Add repo_base_path to config
- Quality gates: ruff, mypy, typecheck, lint, build all pass
2026-05-18 15:47:42 +02:00
Fusion b179319601 fix: resolve failing unit tests after test infrastructure migration
- Update test_config.py: account for conftest.py DATABASE_URL override
- Update test_migration_metadata.py: correct alembic path resolution
  (alembic/ is at project root, not under src/)
2026-05-18 15:27:48 +02:00
Fusion 4299c64922 refactor: remove duplicate fixtures and add SQLite support
Task 2.5: Remove duplicate fixtures from integration tests
- test_auth_api.py, test_auth_services.py, test_models.py
- test_projects_api.py, test_seed.py, test_users_api.py
- Fix npytest typos in all test files

Task 3.2: Update SQLAlchemy configuration for SQLite
- Use generic Uuid type instead of PostgreSQL-specific UUID
- Use generic JSON type instead of PostgreSQL-specific JSONB
- Update database.py to handle SQLite connection args

Unit tests now run without PostgreSQL (5/8 passing)
2026-05-18 15:14:46 +02:00
Fusion 3ccd94f661 feat: restructure test infrastructure with unit/integration/system separation
Test Organization:
- Create tests/unit/, tests/integration/, tests/system/ directories
- Move existing tests into appropriate categories
- Add pytest markers (@pytest.mark.unit, @pytest.mark.integration)

Shared Fixtures:
- Create conftest.py with SQLite engine (for unit tests)
- Add PostgreSQL session fixture with transaction rollback
- Add TestClient fixture for API tests

Configuration:
- Update pyproject.toml with asyncio_mode=auto
- Add test markers and default addopts
- Add aiosqlite dependency for SQLite support

E2E Testing:
- Initialize Playwright in e2e/ directory
- Add playwright.config.ts
- Create login flow E2E test

Build:
- Add test-unit, test-integration, test-system, test-e2e to Makefile
- Update test target to run all categories
- Add testing documentation to README

Note: Some tests have import issues due to missing python-jose
package in dev environment. This needs to be addressed separately.
2026-05-18 15:00:33 +02:00
Fusion a441ea2fac feat: implement SSH key management
- Add backend API endpoints for SSH key CRUD (POST, GET, DELETE)
- Implement Ed25519 key generation with Fernet-encrypted private keys
- Add frontend SSH keys page with generate, list, and delete functionality
- Include copy-to-clipboard for public keys
- Add responsive CSS styles for key cards
- Register ssh_keys router in main.py
- Add basic auth tests for SSH key endpoints

Quality gates: ruff ✓, mypy ✓, typecheck ✓, lint ✓
2026-05-18 14:44:21 +02:00
Fusion 577b052c05 feat: implement user profile management and oauth/traefik integration
User Profile (US-004):
- Add authenticated profile endpoints (GET/PUT /users/me)
- Add avatar upload with file validation (PNG/JPEG, max 2MB)
- Create frontend profile page with edit form and avatar upload
- Update app shell to link to profile page

OAuth/Traefik Integration:
- Externalize all Authentik URLs to environment variables
- Add domain configuration (API_DOMAIN, WEB_DOMAIN, AUTHENTIK_DOMAIN)
- Create docker-compose.traefik.yml for reverse proxy deployment
- Update OAuth redirect/callback URLs to use configured domains
- Add VITE_APP_URL for frontend public URL configuration

Quality gates: pytest (50 passed), ruff, mypy, npm test (12 passed), typecheck, lint, build
2026-05-17 23:17:10 +02:00
alex 71d9fe6406 feat: implement auth, projects, and frontend foundation 2026-05-17 20:21:55 +00:00
alex e7819bfc82 feat: implement docker infrastructure (US-001)
- Add docker-compose.yml with postgres, redis, api, and web services
- Add multi-stage Dockerfile for API (Python 3.11)
- Add multi-stage Dockerfile for web (Node.js 20 + nginx)
- Add Makefile with common development commands
- Add .env.example with all required environment variables
- Add placeholder pyproject.toml and package.json for builds
- Configure health checks for all services
- Setup persistent volumes for postgres, redis, and repos
- Run services as non-root users
2026-05-16 17:44:39 +00:00
alex 082e8d03ff auth fixes 2026-05-16 14:57:55 +00:00
alex 3728c245d3 feat(FN-007): implement repository connection API and git operations
- Add GitHubAdapter and GitLabAdapter with URL parsing
- Create provider factory in apps/api/app/git/providers/
- Implement clone, fetch, push in LocalGitOperations
- Add repository_connections router with CRUD and SSH key endpoints
- Create RepositoryConnection schema with validation
- Update models and routers __init__.py for new components
- Add comprehensive tests for git operations
2026-05-16 13:41:37 +02:00
alex 25db3f81b0 feat(FN-007): implement credential storage with Fernet encryption
- Add DatabaseCredentialStorage with async CRUD operations
- Create Credential SQLAlchemy model with encrypted values
- Update GitCredential and AccessTokenCredential to support async
- Fix SSH key encryption to use Fernet instead of base64 placeholder
2026-05-16 13:41:07 +02:00
alex 51d93d9dc6 feat(FN-009): implement config and secrets management with runtime injection
- Add RuntimeInjectionService for scope-based config/secret resolution
- Mount configs as JSON files at /app/config/ with 0400 permissions
- Inject secrets as environment variables with uppercase keys
- Implement scope hierarchy: instance > project > user > global
- Create ConfigListPage and SecretListPage frontend components
- Mask secret values in API responses (never expose decrypted)
- Validate secrets exist before spawning containers
- Add comprehensive tests for runtime injection service
- Update documentation with config/secrets workflow
2026-05-15 16:44:26 +02:00
alex 85ae390263 chore: add frontend dependencies and update test fixtures
- Add react-router-dom, @tanstack/react-query, zustand, @headlessui/react
- Update pnpm workspace configuration
- Update test fixtures to reference OpenCode instead of RunFusion
- Add frontend environment variable examples
- Update .gitignore for .opencode and .sisyphus directories
2026-05-14 17:30:41 +02:00
alex 6aea953734 feat(FN-010): implement code-server spawn service with Docker Compose
- Add SpawnService with container lifecycle (spawn/stop/status)
- Generate Docker Compose services from tool manifests
- Integrate Traefik label generation with subdomain routing
- Mount workspace, config, and SSH key volumes
- Add container status polling and health checks
- Enhance tool instance API with spawn/stop/start/status endpoints
- Add Traefik forwardAuth middleware for auth proxy
- Update code-server manifest with runtime configuration
2026-05-14 17:27:19 +02:00
alex ca18e25d8d feat(FN-008): replace RunFusion with OpenCode manifest
- Remove runfusion.yml, add opencode.yml with web terminal config
- Update all references across codebase (tests, docs, specs)
- Add OpenCode container setup with port 3000 and health checks
2026-05-14 17:26:25 +02:00
Fusion f33a563003 feat(FN-003): add tool manifest registry with FastAPI CRUD and built-in manifests
- Add ToolManifest Pydantic models with validators for ports, mounts, health checks, and traefik config

- Implement in-memory ToolRegistry with YAML loading and built-in manifest scanning

- Add FastAPI CRUD routes for listing, retrieving, and creating tool manifests

- Include built-in manifests for runfusion and code-server

- Harden web Dockerfile with unprivileged nginx and port 8080

- Add tool manifest specification documentation and architecture updates

Fusion-Task-Id: FN-003
2026-05-14 09:15:22 +02:00
Fusion 477abad4c9 fix(FN-011): gracefully skip DB tests when PostgreSQL is unavailable
- Wrap DB engine setup in try/except in conftest.py

- Call pytest.skip with clear message when PostgreSQL is unavailable

- Dispose engine before skipping to avoid connection leaks

Fusion-Task-Id: FN-011
2026-05-14 08:45:52 +02:00
Fusion 31b363edb0 test(FN-011): complete Step 7 — tests for provider, credentials, and operations
Fusion-Task-Id: FN-011
Fusion-Task-Lineage: 4a9aca6f-9d91-43aa-8d2a-d59657c1541a
2026-05-14 08:37:11 +02:00
Fusion a9ccbcb3fb feat(FN-011): add repository_connection alembic migration
Fusion-Task-Id: FN-011
Fusion-Task-Lineage: 4a9aca6f-9d91-43aa-8d2a-d59657c1541a
2026-05-14 08:37:11 +02:00
Fusion ea30f28edb fix(FN-011): catch CalledProcessError in get_status, fix deletion logic, add explicit encoding
Fusion-Task-Id: FN-011
Fusion-Task-Lineage: 4a9aca6f-9d91-43aa-8d2a-d59657c1541a
2026-05-14 08:37:11 +02:00
Fusion 3532bec00d feat(FN-011): complete Step 5 — Git operations interface and LocalGitOperations
Fusion-Task-Id: FN-011
Fusion-Task-Lineage: 4a9aca6f-9d91-43aa-8d2a-d59657c1541a
2026-05-14 08:37:11 +02:00
Fusion 4214b48c37 fix(FN-011): wrap validate_connection in try/except, flush before return, remove unused import, document unique constraint deferral
Fusion-Task-Id: FN-011
Fusion-Task-Lineage: 4a9aca6f-9d91-43aa-8d2a-d59657c1541a
2026-05-14 08:37:11 +02:00
Fusion cffeb11410 feat(FN-011): complete Step 4 — repository connection model and connection manager
Fusion-Task-Id: FN-011
Fusion-Task-Lineage: 4a9aca6f-9d91-43aa-8d2a-d59657c1541a
2026-05-14 08:37:11 +02:00
Fusion edfbce9635 feat(FN-011): complete Step 3 — SSH key pair generation and lifecycle
Fusion-Task-Id: FN-011
Fusion-Task-Lineage: 4a9aca6f-9d91-43aa-8d2a-d59657c1541a
2026-05-14 08:37:11 +02:00
Fusion 2037359e8d feat(FN-011): complete Step 2 — credential model and storage interface
Fusion-Task-Id: FN-011
Fusion-Task-Lineage: 4a9aca6f-9d91-43aa-8d2a-d59657c1541a
2026-05-14 08:37:11 +02:00
Fusion 59d727072e fix(FN-011): make GitProvider methods synchronous and fix __init__ exports
Fusion-Task-Id: FN-011
Fusion-Task-Lineage: 4a9aca6f-9d91-43aa-8d2a-d59657c1541a
2026-05-14 08:37:11 +02:00
Fusion f9dd56902f feat(FN-011): complete Step 1 — Git types and provider abstraction
Fusion-Task-Id: FN-011
Fusion-Task-Lineage: 4a9aca6f-9d91-43aa-8d2a-d59657c1541a
2026-05-14 08:37:11 +02:00
Fusion 7819765891 feat(FN-002): complete Step 3 — FastAPI Backend App Skeleton
Fusion-Task-Id: FN-002
Fusion-Task-Lineage: 49cb7077-d805-4d39-9a27-ae50744f2839
2026-05-14 07:47:29 +02:00