From ab6cdcb501c640f011dbf21d14630f49af6ed0ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EB=A8=B8=EB=8B=88=ED=8E=98=EB=8B=88?= Date: Fri, 20 Mar 2026 23:22:07 +0900 Subject: [PATCH] docs: add galaxis-agent CI/CD design spec --- .../2026-03-20-galaxis-agent-cicd-design.md | 129 ++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 docs/superpowers/specs/2026-03-20-galaxis-agent-cicd-design.md diff --git a/docs/superpowers/specs/2026-03-20-galaxis-agent-cicd-design.md b/docs/superpowers/specs/2026-03-20-galaxis-agent-cicd-design.md new file mode 100644 index 0000000..2dce705 --- /dev/null +++ b/docs/superpowers/specs/2026-03-20-galaxis-agent-cicd-design.md @@ -0,0 +1,129 @@ +# galaxis-agent Gitea Actions CI/CD 설계 스펙 + +## Goal + +galaxis-agent 리포에 Gitea Actions 기반 CI/CD를 구성한다. PR에서는 테스트만 실행하고, `main` push 시 테스트 통과 후 Oracle VM에 자동 배포한다. + +## Infrastructure + +- **Gitea**: `ssh://git@152.69.231.161:7798/quant/galaxis-agent.git` +- **Oracle VM**: A1 (4코어 ARM64, 24GB) — Gitea + act_runner + Docker 운영 +- **act_runner**: 설치/등록 완료 (galaxis-po에서 사용 중) +- **Runner label**: `ubuntu-latest` + +## Workflow 구성 + +### 1. `.gitea/workflows/ci.yml` — PR 검증 + +**트리거:** PR 생성/업데이트 (target: `main`) + +**파이프라인:** +``` +checkout → uv 설치 → uv sync --frozen → pytest → 결과 리포트 +``` + +**상세:** +- `runs-on: ubuntu-latest` +- Python 3.12-slim 환경 +- `uv sync --frozen`으로 의존성 설치 (lock 파일 기반) +- `uv run python -m pytest --tb=short -q` 실행 +- 외부 서비스 의존성 없음 (모든 테스트 mock 기반, SQLite tempfile) + +### 2. `.gitea/workflows/deploy.yml` — 배포 + +**트리거:** `main` branch push + +**파이프라인:** +``` +checkout → uv 설치 → uv sync → pytest +→ Docker CLI + Compose 설치 +→ .env 생성 (Gitea secrets) +→ galaxis-net 네트워크 확인/생성 +→ build-sandbox.sh 실행 +→ docker compose build → docker compose up -d +→ health check (메인 + 개별 엔드포인트) +``` + +**상세:** + +#### Step: 테스트 +- ci.yml과 동일한 테스트 실행 +- 실패 시 배포 중단 + +#### Step: Docker CLI + Compose 설치 +- galaxis-po 패턴과 동일 +- `apt-get install docker.io` + compose plugin 설치 + +#### Step: .env 생성 +- Gitea secrets에서 환경변수 조합 +- 기본값이 있는 변수는 워크플로우에 하드코딩 + +#### Step: 네트워크 확인 +- `docker network inspect galaxis-net` 실패 시 `docker network create galaxis-net` + +#### Step: 샌드박스 이미지 빌드 +- `./build-sandbox.sh` 실행 + +#### Step: 배포 +- `docker compose --project-name galaxis-agent build` +- `docker compose --project-name galaxis-agent up -d` + +#### Step: Health check +- 메인: `curl -sf http://localhost:8100/health` (5초 간격, 최대 60초) +- 개별: `/health/gitea`, `/health/discord`, `/health/queue`, `/health/costs` +- 실패 시 워크플로우 fail → 수동 대응 + +## Gitea Secrets + +### 필수 (리포 Settings > Secrets에 등록) + +| Secret | 용도 | +|--------|------| +| `ANTHROPIC_API_KEY` | Claude API | +| `GITEA_TOKEN` | Gitea API 접근 | +| `GITEA_WEBHOOK_SECRET` | Webhook 검증 | +| `DISCORD_TOKEN` | Discord Bot | +| `DISCORD_CHANNEL_ID` | Discord 채널 | +| `DISCORD_BOT_USER_ID` | Discord 봇 ID | +| `FERNET_KEY` | 암호화 키 | +| `AGENT_API_KEY` | Agent API 인증 | + +### 하드코딩 (기본값) + +| 변수 | 값 | +|------|-----| +| `GITEA_URL` | `http://gitea:3000` | +| `GITEA_EXTERNAL_URL` | `https://ayuriel.duckdns.org` | +| `LANGGRAPH_URL` | `http://langgraph-server:8123` | +| `AUTONOMY_LEVEL` | `conservative` | +| `DEFAULT_REPO_OWNER` | `quant` | +| `DEFAULT_REPO_NAME` | `galaxis-po` | +| `SANDBOX_IMAGE` | `galaxis-sandbox:latest` | +| `SANDBOX_MEM_LIMIT` | `4g` | +| `SANDBOX_CPU_COUNT` | `2` | +| `SANDBOX_TIMEOUT` | `600` | +| `TEST_DATABASE_URL` | `postgresql://user:pass@postgres:5432/galaxis_test` | +| `LOG_FORMAT` | `json` | +| `DAILY_COST_LIMIT_USD` | `10.0` | +| `PER_TASK_COST_LIMIT_USD` | `3.0` | + +## deploy.sh와의 관계 + +- `deploy.sh`는 수동 배포 도구로 유지 (SSH 접속 시 사용) +- 워크플로우는 `deploy.sh`를 호출하지 않고 step으로 직접 실행 +- pre-flight 체크 중 Docker/Compose/네트워크는 워크플로우에서 처리 + +## 롤백 + +- 자동 롤백 없음 +- health check 실패 시 워크플로우 fail 표시 → 수동 대응 +- 수동 롤백: `docker compose down && git checkout <이전_커밋> && ./deploy.sh` + +## 파일 구조 + +``` +.gitea/ + workflows/ + ci.yml # PR 검증 (테스트만) + deploy.yml # main push → 테스트 + 배포 +```