diff --git a/.github/workflows/auto-merge-claude.yml b/.github/workflows/auto-merge-claude.yml new file mode 100644 index 0000000..d75afb2 --- /dev/null +++ b/.github/workflows/auto-merge-claude.yml @@ -0,0 +1,30 @@ +name: Auto-merge Claude branches to main + +# Trigger on any push to claude/* branches +on: + push: + branches: + - 'claude/**' + +jobs: + merge-to-main: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Checkout repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 + token: ${{ secrets.GITHUB_TOKEN }} + + - name: Configure git + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + + - name: Merge into main + run: | + git checkout main + git merge origin/${{ github.ref_name }} -m "Auto-merge ${{ github.ref_name }} into main" + git push origin main diff --git a/README.md b/README.md index a3c7683..eb32749 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ **Self-hosted mission management, flight log analysis, GPS flight replay with video export, AI report generation, invoicing, and real-time airspace monitoring for commercial drone operators.** -**Version 2.55.2** | [Quick Start](#quick-start) | [Features](#features) | [Configuration](#configuration) | [Contributing](CONTRIBUTING.md) | [License](LICENSE) +**Version 2.55.5** | [Quick Start](#quick-start) | [Features](#features) | [Configuration](#configuration) | [Contributing](CONTRIBUTING.md) | [License](LICENSE) --- diff --git a/backend/Dockerfile b/backend/Dockerfile index acb9684..df11f84 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -1,6 +1,7 @@ FROM python:3.12-slim -# Install system dependencies for WeasyPrint, fonts, geospatial libs, and gosu +# Install system dependencies for WeasyPrint, fonts, geospatial libs, gosu, and curl +# Cache-bust: v2.55.5 (added curl for Docker healthcheck) RUN apt-get update && apt-get install -y --no-install-recommends \ build-essential \ libpango-1.0-0 \ @@ -17,6 +18,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ fonts-liberation \ fonts-dejavu-core \ fonts-noto-core \ + curl \ gosu \ && rm -rf /var/lib/apt/lists/* \ && fc-cache -f diff --git a/backend/app/main.py b/backend/app/main.py index 374b280..28a8f34 100644 --- a/backend/app/main.py +++ b/backend/app/main.py @@ -208,22 +208,46 @@ async def lifespan(app: FastAPI): await seed_demo_data(demo_session) logger.info("STARTUP: Demo data seeded") - # Post-seed verification: log the admin hash state + # Post-seed verification: ensure admin can actually log in from app.models.user import User - from app.auth.jwt import verify_password + from app.auth.jwt import verify_password, hash_password async with async_session() as verify_session: result = await verify_session.execute( select(User).where(User.username == settings.admin_username) ) admin = result.scalar_one_or_none() if admin: - env_matches = verify_password(settings.admin_password, admin.hashed_password) + _hash = admin.hashed_password or "" + _hash_ok = _hash.startswith("$2b$") and len(_hash) == 60 + env_matches = verify_password(settings.admin_password, _hash) if _hash_ok else False logger.info( - "STARTUP: Admin '%s' hash=%s... env_password_matches=%s", + "STARTUP: Admin '%s' hash=%s... hash_valid=%s env_password_matches=%s", admin.username, - admin.hashed_password[:10] if admin.hashed_password else "EMPTY", + _hash[:10] if _hash else "EMPTY", + _hash_ok, env_matches, ) + + # Auto-repair: if env password doesn't match DB hash, fix it + # This handles migration/restore scenarios where the hash is + # corrupted, truncated, or from a different password. + if not env_matches: + new_hash = hash_password(settings.admin_password) + roundtrip_ok = verify_password(settings.admin_password, new_hash) + if roundtrip_ok: + admin.hashed_password = new_hash + await verify_session.commit() + logger.warning( + "STARTUP: Admin password hash REPAIRED — env password " + "did not match DB hash (hash_valid=%s). New hash=%s...", + _hash_ok, new_hash[:10], + ) + else: + logger.critical( + "STARTUP: Admin password hash is WRONG and bcrypt " + "roundtrip FAILED — login will not work! " + "Run: docker compose exec backend python reset_admin.py" + ) else: logger.critical("STARTUP: Admin user '%s' NOT FOUND after seed!", settings.admin_username) @@ -301,7 +325,7 @@ async def lifespan(app: FastAPI): app = FastAPI( title="D.O.C — Drone Operations Command", description="Self-hosted mission management, flight log analysis, AI report generation, invoicing, telemetry visualization, and real-time airspace monitoring for commercial drone operators.", - version="2.55.2", + version="2.55.5", lifespan=lifespan, ) @@ -411,15 +435,9 @@ async def log_requests(request: Request, call_next): @app.get("/api/health") -async def health_check(db: AsyncSession = Depends(get_db)): - """Health check — verifies DB connectivity for Docker healthcheck auto-recovery.""" - from sqlalchemy import text - try: - await db.execute(text("SELECT 1")) - return {"status": "healthy", "service": "D.O.C — Drone Operations Command"} - except Exception as exc: - logger.error("Health check DB probe failed: %s", exc) - raise HTTPException(status_code=503, detail="Database unreachable") +async def health_check(): + """Lightweight health check for Docker healthcheck — just confirms the process is up.""" + return {"status": "healthy", "service": "D.O.C — Drone Operations Command"} @app.get("/api/branding") diff --git a/docker-compose.yml b/docker-compose.yml index 3cee52b..bbfad9d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -76,6 +76,7 @@ services: - WATCHTOWER_MONITOR_ONLY=${WATCHTOWER_MONITOR_ONLY:-false} - WATCHTOWER_NOTIFICATION_URL=${WATCHTOWER_NOTIFICATION_URL:-} - WATCHTOWER_NOTIFICATIONS_HOSTNAME=droneops-server + - DOCKER_API_VERSION=1.45 volumes: - /var/run/docker.sock:/var/run/docker.sock @@ -121,11 +122,11 @@ services: ollama: condition: service_healthy healthcheck: - test: ["CMD-SHELL", "python -c \"import httpx; r = httpx.get('http://localhost:8000/api/health'); r.raise_for_status()\""] + test: ["CMD-SHELL", "curl -sf http://localhost:8000/api/health || exit 1"] interval: 15s timeout: 10s retries: 5 - start_period: 30s + start_period: 45s worker: build: diff --git a/frontend/package.json b/frontend/package.json index de126c3..757a101 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,7 +1,7 @@ { "name": "doc-frontend", "private": true, - "version": "2.55.2", + "version": "2.55.5", "description": "Self-hosted drone operations command center — mission management, flight log analysis, GPS flight replay with video export, AI reports, invoicing, and airspace monitoring", "keywords": [ "drone", diff --git a/frontend/src/components/Layout/AppShell.tsx b/frontend/src/components/Layout/AppShell.tsx index 6aef239..86f4166 100644 --- a/frontend/src/components/Layout/AppShell.tsx +++ b/frontend/src/components/Layout/AppShell.tsx @@ -116,7 +116,7 @@ function NavContent({ c="#5a6478" style={{ fontFamily: "'Share Tech Mono', monospace", fontSize: '15px' }} > - v2.55.2 + v2.55.5 - v2.55.2 + v2.55.5