Skip to content

Commit 6a4c4c3

Browse files
author
Agent-Planner
committed
Merge PR AutoForgeAI#118: Traefik routing, Gemini support, Docker deployment
2 parents cd5287f + 9153a57 commit 6a4c4c3

20 files changed

Lines changed: 1185 additions & 48 deletions

.dockerignore

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
.git
2+
.gitignore
3+
.code
4+
__pycache__/
5+
*.pyc
6+
*.pyo
7+
*.pyd
8+
*.swp
9+
*.swo
10+
*.tmp
11+
.env
12+
.env.*
13+
env/
14+
venv/
15+
.venv/
16+
ENV/
17+
node_modules/
18+
ui/node_modules/
19+
ui/dist/
20+
npm-debug.log*
21+
yarn-debug.log*
22+
yarn-error.log*
23+
coverage/
24+
dist/
25+
build/
26+
tmp/
27+
*.log

.github/workflows/ci.yml

Lines changed: 54 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,33 @@
1-
name: CI
1+
name: Push CI
22

33
on:
4-
pull_request:
5-
branches: [master, main]
64
push:
7-
branches: [master, main]
5+
branches: [main]
86

97
jobs:
8+
repo-guards:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- uses: actions/checkout@v4
12+
- name: Ensure .code/ and .env are not tracked
13+
shell: bash
14+
run: |
15+
tracked_code="$(git ls-files -- .code)"
16+
tracked_env="$(git ls-files -- .env)"
17+
18+
if [ -n "$tracked_code" ] || [ -n "$tracked_env" ]; then
19+
echo "Local-only policy and secrets files must not be tracked."
20+
if [ -n "$tracked_code" ]; then
21+
echo "Tracked .code/ entries:"
22+
echo "$tracked_code"
23+
fi
24+
if [ -n "$tracked_env" ]; then
25+
echo "Tracked .env entries:"
26+
echo "$tracked_env"
27+
fi
28+
exit 1
29+
fi
30+
1031
python:
1132
runs-on: ubuntu-latest
1233
steps:
@@ -39,3 +60,32 @@ jobs:
3960
run: npm run lint
4061
- name: Type check & Build
4162
run: npm run build
63+
64+
docker-image:
65+
needs: [python, ui]
66+
runs-on: ubuntu-latest
67+
permissions:
68+
contents: read
69+
packages: write
70+
env:
71+
IMAGE_NAME: ghcr.io/${{ github.repository }}
72+
steps:
73+
- uses: actions/checkout@v4
74+
- uses: docker/setup-buildx-action@v3
75+
- uses: docker/login-action@v3
76+
with:
77+
registry: ghcr.io
78+
username: ${{ github.repository_owner }}
79+
password: ${{ secrets.GITHUB_TOKEN }}
80+
- name: Build and push image
81+
uses: docker/build-push-action@v6
82+
with:
83+
context: .
84+
file: Dockerfile
85+
platforms: linux/amd64
86+
push: true
87+
tags: |
88+
${{ env.IMAGE_NAME }}:latest
89+
${{ env.IMAGE_NAME }}:${{ github.sha }}
90+
cache-from: type=gha
91+
cache-to: type=gha,mode=max

.github/workflows/deploy.yml

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
name: Deploy to VPS
2+
3+
on:
4+
workflow_run:
5+
workflows: ["Push CI"]
6+
branches: [main]
7+
types:
8+
- completed
9+
10+
permissions:
11+
contents: read
12+
13+
concurrency:
14+
group: deploy-${{ github.event.workflow_run.head_branch }}
15+
cancel-in-progress: false
16+
17+
jobs:
18+
deploy:
19+
if: ${{ github.event.workflow_run.conclusion == 'success' }}
20+
runs-on: ubuntu-latest
21+
env:
22+
DEPLOY_PATH: ${{ secrets.VPS_DEPLOY_PATH || '/opt/autocoder' }}
23+
TARGET_BRANCH: ${{ secrets.VPS_BRANCH || 'main' }}
24+
VPS_PORT: ${{ secrets.VPS_PORT || '22' }}
25+
DOMAIN: ${{ secrets.VPS_DOMAIN }}
26+
DUCKDNS_TOKEN: ${{ secrets.VPS_DUCKDNS_TOKEN }}
27+
LETSENCRYPT_EMAIL: ${{ secrets.VPS_LETSENCRYPT_EMAIL }}
28+
APP_PORT: ${{ secrets.VPS_APP_PORT || '8888' }}
29+
REPO_URL: https://github.com/${{ github.repository }}.git
30+
IMAGE_LATEST: ghcr.io/${{ github.repository }}:latest
31+
IMAGE_SHA: ghcr.io/${{ github.repository }}:${{ github.event.workflow_run.head_sha }}
32+
steps:
33+
- name: Deploy over SSH with Docker Compose
34+
uses: appleboy/ssh-action@v1.2.4
35+
with:
36+
host: ${{ secrets.VPS_HOST }}
37+
username: ${{ secrets.VPS_USER }}
38+
key: ${{ secrets.VPS_SSH_KEY }}
39+
port: ${{ env.VPS_PORT }}
40+
envs: DEPLOY_PATH,TARGET_BRANCH,VPS_PORT,DOMAIN,DUCKDNS_TOKEN,LETSENCRYPT_EMAIL,APP_PORT,REPO_URL,IMAGE_LATEST,IMAGE_SHA
41+
script: |
42+
set -euo pipefail
43+
44+
if [ -z "${DEPLOY_PATH:-}" ]; then
45+
echo "VPS_DEPLOY_PATH secret is required"; exit 1;
46+
fi
47+
48+
if [ -z "${DOMAIN:-}" ] || [ -z "${DUCKDNS_TOKEN:-}" ] || [ -z "${LETSENCRYPT_EMAIL:-}" ]; then
49+
echo "VPS_DOMAIN, VPS_DUCKDNS_TOKEN, and VPS_LETSENCRYPT_EMAIL secrets are required."; exit 1;
50+
fi
51+
52+
if [ ! -d "$DEPLOY_PATH/.git" ]; then
53+
echo "ERROR: $DEPLOY_PATH is missing a git repo. Clone the repository there and keep your .env file."; exit 1;
54+
fi
55+
56+
cd "$DEPLOY_PATH"
57+
58+
if [ ! -f ./deploy.sh ]; then
59+
echo "ERROR: deploy.sh not found in $DEPLOY_PATH. Ensure the repo is up to date."; exit 1;
60+
fi
61+
62+
chmod +x ./deploy.sh
63+
64+
if [ ! -f .env ]; then
65+
echo "WARNING: .env not found in $DEPLOY_PATH. Deployment will continue without it.";
66+
fi
67+
68+
if [ "$(id -u)" -eq 0 ]; then
69+
RUNNER=""
70+
else
71+
if ! command -v sudo >/dev/null 2>&1; then
72+
echo "sudo is required to run deploy.sh as root."; exit 1;
73+
fi
74+
RUNNER="sudo"
75+
fi
76+
77+
$RUNNER env \
78+
AUTOCODER_AUTOMATED=1 \
79+
AUTOCODER_ASSUME_YES=1 \
80+
DOMAIN="${DOMAIN}" \
81+
DUCKDNS_TOKEN="${DUCKDNS_TOKEN}" \
82+
LETSENCRYPT_EMAIL="${LETSENCRYPT_EMAIL}" \
83+
REPO_URL="${REPO_URL}" \
84+
DEPLOY_BRANCH="${TARGET_BRANCH}" \
85+
APP_DIR="${DEPLOY_PATH}" \
86+
APP_PORT="${APP_PORT}" \
87+
IMAGE="${IMAGE_SHA:-$IMAGE_LATEST}" \
88+
./deploy.sh
89+
90+
echo "Running smoke test on http://127.0.0.1:${APP_PORT}/health and /readiness ..."
91+
retries=12
92+
until curl -fsS --max-time 5 "http://127.0.0.1:${APP_PORT}/health" >/dev/null; do
93+
retries=$((retries - 1))
94+
if [ "$retries" -le 0 ]; then
95+
echo "Health check failed after retries."
96+
exit 1
97+
fi
98+
echo "Waiting for health... ($retries retries left)"
99+
sleep 5
100+
done
101+
102+
retries=12
103+
until curl -fsS --max-time 5 "http://127.0.0.1:${APP_PORT}/readiness" >/dev/null; do
104+
retries=$((retries - 1))
105+
if [ "$retries" -le 0 ]; then
106+
echo "Readiness check failed after retries."
107+
exit 1
108+
fi
109+
echo "Waiting for readiness... ($retries retries left)"
110+
sleep 5
111+
done
112+
113+
echo "Service responded successfully to health and readiness."

.github/workflows/pr-check.yml

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
name: PR Check
2+
3+
on:
4+
pull_request:
5+
branches: [main]
6+
7+
permissions:
8+
contents: read
9+
10+
concurrency:
11+
group: pr-check-${{ github.event.pull_request.head.repo.full_name }}-${{ github.event.pull_request.number }}
12+
cancel-in-progress: true
13+
14+
jobs:
15+
repo-guards:
16+
runs-on: ubuntu-latest
17+
steps:
18+
- uses: actions/checkout@v4
19+
- name: Ensure .code/ and .env are not tracked
20+
shell: bash
21+
run: |
22+
tracked_code="$(git ls-files -- .code)"
23+
tracked_env="$(git ls-files -- .env)"
24+
25+
if [ -n "$tracked_code" ] || [ -n "$tracked_env" ]; then
26+
echo "Local-only policy and secrets files must not be tracked."
27+
if [ -n "$tracked_code" ]; then
28+
echo "Tracked .code/ entries:"
29+
echo "$tracked_code"
30+
fi
31+
if [ -n "$tracked_env" ]; then
32+
echo "Tracked .env entries:"
33+
echo "$tracked_env"
34+
fi
35+
exit 1
36+
fi
37+
38+
python:
39+
runs-on: ubuntu-latest
40+
steps:
41+
- uses: actions/checkout@v4
42+
- uses: actions/setup-python@v5
43+
with:
44+
python-version: "3.11"
45+
cache: "pip"
46+
cache-dependency-path: requirements.txt
47+
- name: Install dependencies
48+
run: pip install -r requirements.txt
49+
- name: Lint with ruff
50+
run: ruff check .
51+
- name: Run security tests
52+
run: python test_security.py
53+
54+
ui:
55+
runs-on: ubuntu-latest
56+
defaults:
57+
run:
58+
working-directory: ui
59+
steps:
60+
- uses: actions/checkout@v4
61+
- uses: actions/setup-node@v4
62+
with:
63+
node-version: "20"
64+
cache: "npm"
65+
cache-dependency-path: ui/package-lock.json
66+
- name: Install dependencies
67+
run: npm ci
68+
- name: Lint
69+
run: npm run lint
70+
- name: Type check & Build
71+
run: npm run build

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ temp/
66
nul
77
issues/
88

9+
# Repository-specific
10+
.code/
11+
912
# Browser profiles for parallel agent execution
1013
.browser-profiles/
1114

@@ -16,6 +19,9 @@ npm-debug.log*
1619
yarn-debug.log*
1720
yarn-error.log*
1821

22+
# Local Codex/Claude configuration (do not commit)
23+
.code/
24+
1925
# ===================
2026
# Node.js
2127
# ===================

DEVELOPMENT.md

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# AutoCoder Development Roadmap
2+
3+
This roadmap breaks work into clear phases so you can pick the next most valuable items quickly.
4+
5+
## Phase 0 — Baseline (ship ASAP)
6+
- **PR discipline:** Enforce branch protection requiring “PR Check” (already configured in workflows; ensure GitHub rule is on).
7+
- **Secrets hygiene:** Move all deploy secrets into repo/environment secrets; prohibit `.env` commits via pre-commit hook.
8+
- **Smoke tests:** Keep `/health` and `/readiness` endpoints green; add UI smoke (landing page loads) to CI.
9+
10+
## Phase 1 — Reliability & Observability
11+
- **Structured logging:** Add JSON logging for FastAPI (uvicorn access + app logs) with request IDs; forward to stdout for Docker/Traefik.
12+
- **Error reporting:** Wire Sentry (or OpenTelemetry + OTLP) for backend exceptions and front-end errors.
13+
- **Metrics:** Expose `/metrics` (Prometheus) for FastAPI; Traefik already exposes metrics option—enable when scraping is available.
14+
- **Tracing:** Add OTEL middleware to FastAPI; propagate trace IDs through to Claude/Gemini calls when possible.
15+
16+
## Phase 2 — Platform & DevX
17+
- **Local dev parity:** Add `docker-compose.dev.yml` with hot-reload for FastAPI + Vite UI; document one-command setup.
18+
- **Makefile/taskfile:** Common commands (`make dev`, `make test`, `make lint`, `make format`, `make seed`).
19+
- **Pre-commit:** Ruff, mypy, black (if adopted), eslint/prettier for `ui/`.
20+
- **Typed APIs:** Add mypy strict mode to `server/` and type `schemas.py` fully (Pydantic v2 ConfigDict).
21+
22+
## Phase 3 — Product & Agent Quality
23+
- **Model selection UI:** Let users choose assistant provider (Claude/Gemini) in settings; display active provider badge in chat.
24+
- **Tooling guardrails:** For Gemini (chat-only), show “no tools” notice in UI and fallback logic to Claude when tools needed.
25+
- **Conversation persistence:** Add pagination/search over assistant history; export conversation to file.
26+
- **Feature board:** Surface feature stats/graph from MCP in the UI (read-only dashboard).
27+
28+
## Phase 4 — Security & Compliance
29+
- **AuthN/AuthZ:** Add optional login (JWT/OIDC) gate for UI/API; role for “admin” vs “viewer” at least.
30+
- **Rate limiting:** Enable per-IP rate limits at Traefik and per-token limits in FastAPI.
31+
- **Audit trails:** Log agent actions and feature state changes with user identity.
32+
- **Headers/HTTPS:** HSTS via Traefik, content-security-policy header from FastAPI.
33+
34+
## Phase 5 — Performance & Scale
35+
- **Caching:** CDN/Traefik static cache for UI assets; server-side cache for model list/status endpoints.
36+
- **Worker separation:** Optionally split agent runner from API via separate services and queues (e.g., Redis/RQ or Celery).
37+
- **Background jobs:** Move long-running tasks to scheduler/worker with backoff and retries.
38+
39+
## Phase 6 — Testing & Quality Gates
40+
- **Backend tests:** Add pytest suite for key routers (`/api/setup/status`, assistant chat happy-path with mock Claude/Gemini).
41+
- **Frontend tests:** Add Vitest + React Testing Library smoke tests for core pages (dashboard loads, settings save).
42+
- **E2E:** Playwright happy-path (login optional, start agent, view logs).
43+
- **Coverage:** Fail CI if coverage drops below threshold (start at 60–70%).
44+
45+
## Phase 7 — Deployment & Ops
46+
- **Blue/green deploy:** Add image tagging `:sha` + `:latest` (already for CI) with Traefik service labels to toggle.
47+
- **Backups:** Snapshot `~/.autocoder` data volume; document restore.
48+
- **Runbooks:** Add `RUNBOOK.md` for common ops (restart, rotate keys, renew certs, roll back).
49+
50+
## Phase 8 — Documentation & Onboarding
51+
- **Getting started:** Short path for “run locally in 5 minutes” (scripted).
52+
- **Config matrix:** Document required/optional env vars (Claude, Gemini, DuckDNS, Traefik, TLS).
53+
- **Architecture:** One-page diagram: UI ↔ FastAPI ↔ Agent subprocess ↔ Claude/Gemini; MCP servers; Traefik front.
54+
55+
## Stretch Ideas
56+
- **Telemetry-driven tuning:** Auto-select model/provider based on latency/cost SLA.
57+
- **Cost controls:** Show per-run token/cost estimates; configurable budgets.
58+
- **Offline/edge mode:** Ollama provider toggle with cached models.
59+
60+
## How to use this roadmap
61+
- Pick the next phase that unblocks your current goal (reliability → platform → product).
62+
- Keep PRs small and scoped to one bullet.
63+
- Update this document when a bullet ships or is reprioritized.

Dockerfile

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Build frontend and backend for production
2+
3+
# 1) Build the React UI
4+
FROM node:20-alpine AS ui-builder
5+
WORKDIR /app/ui
6+
COPY ui/package*.json ./
7+
RUN npm ci
8+
COPY ui/ .
9+
RUN npm run build
10+
11+
# 2) Build the Python backend with the compiled UI assets
12+
FROM python:3.11-slim AS runtime
13+
ENV PYTHONUNBUFFERED=1 \
14+
PYTHONDONTWRITEBYTECODE=1
15+
16+
WORKDIR /app
17+
COPY requirements.txt .
18+
RUN pip install --no-cache-dir -r requirements.txt
19+
20+
# Copy source code and built UI
21+
COPY . .
22+
COPY --from=ui-builder /app/ui/dist ./ui/dist
23+
24+
EXPOSE 8888
25+
CMD ["uvicorn", "server.main:app", "--host", "0.0.0.0", "--port", "8888"]

0 commit comments

Comments
 (0)