Files
jsahnandClaude Opus 4.8 8dfda00c12 feat(run-agent): send X-Admin-Token so backend AuthGate accepts CI calls
The backend now has a global AuthGateMiddleware: every data route
(workspaces/lookup, upload-agent, sse/...) requires auth, returning
401 {"detail":"authentication required"} otherwise. CI authenticates with
the service token via the X-Admin-Token header (proxies any user_id).

- run_agent_api.py: read ADMIN_API_TOKEN from env, attach X-Admin-Token to
  both httpx clients (all lookup/upload/sse/action/cancel calls); warn if unset
- run-agent.yml: inject ADMIN_API_TOKEN from Gitea repo secret
- Gitea repo secret ADMIN_API_TOKEN registered
- TEST_WORKFLOW.md / .env.example: document ADMIN_API_TOKEN (.env local, secret in CI)

Verified end-to-end: workspaces/lookup for user_id=jhogyu now resolves
(401 -> 200), e.g. Aug_2026_Test -> 3523fa2b-...

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-08-20 17:02:12 +09:00

153 lines
6.9 KiB
Markdown

# Agent YAML 실행 워크플로우 — 테스트 방법
지정한 Agent YAML 을 AgentBackend API 로 실행하는 Gitea Actions 워크플로우
([.gitea/workflows/run-agent.yml](.gitea/workflows/run-agent.yml) +
[scripts/run_agent_api.py](scripts/run_agent_api.py)) 를 돌리는 방법 정리.
실행 흐름 (SKILL.md §0.6 경로 A):
`workspaces/lookup`(이름→UUID) → `upload-agent` 등록 → SSE `start` →
`stage_complete` 자동 confirm → `execution_complete`.
전체 이벤트/`final_output`/`summary` 는 아티팩트로 저장된다.
---
## 0. `.env` 설정 (토큰)
> ⚠️ **`.env` 는 절대 커밋하지 말 것.** `.gitignore` 에 등록되어 있다
> (`git check-ignore .env` 로 확인). 토큰 값은 이 문서에도 적지 않는다.
프로젝트 루트에 `.env` 파일을 만들고 아래 형식으로 채운다 (값은 실제 토큰):
```dotenv
GITEA_TOKEN=<Gitea Personal Access Token> # 워크플로우 dispatch / API 용
ADMIN_API_TOKEN=<백엔드 AuthGate 서비스 토큰> # 백엔드 데이터 라우트 인증용
```
- `GITEA_TOKEN` 발급: Gitea → Settings → Applications → Generate New Token, 스코프 **`write:repository`**
- `ADMIN_API_TOKEN`: 백엔드 컨테이너 env `ADMIN_API_TOKEN` 값 (전역 AuthGate 통과용
서비스 토큰). 스크립트가 이 값을 읽어 모든 백엔드 요청에 `X-Admin-Token` 헤더로 보낸다.
없으면 `workspaces/lookup`·`upload-agent`·`sse` 전부 `401 authentication required`.
- 사용 후에는 **폐기(revoke)** 권장.
- 템플릿: [.env.example](.env.example) 참고 (빈 값, 커밋되어도 안전).
> **CI(워크플로우)** 는 `.env` 를 쓰지 않는다. `ADMIN_API_TOKEN` 을 **Gitea repo
> secret** 으로 등록해야 하며(이미 등록됨), 워크플로우가 `${{ secrets.ADMIN_API_TOKEN }}`
> 로 주입한다. `GITEA_TOKEN` 은 dispatch(방법 A)에서만 필요.
---
## 방법 A — Gitea API 로 트리거 (설계 의도: 러너가 실행)
`.env` 의 토큰을 읽어 `workflow_dispatch` 를 호출한다. **토큰을 화면에 출력하지 말 것.**
```bash
cd <repo root> # 이 저장소 루트
set -a; . ./.env; set +a # .env 로드 ($GITEA_TOKEN)
curl -s -X POST \
"https://git.eroomai.com/api/v1/repos/jhogyu/Liti-agent-Development/actions/workflows/run-agent.yml/dispatches" \
-H "Authorization: token $GITEA_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"ref": "main",
"inputs": {
"yaml_path": "Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.5/Stage_1_Part_1.yml",
"workspace_name": "팬아웃 테스트",
"user_id": "<user_id>"
}
}'
# 성공 시 HTTP 204 (본문 없음)
```
### 실행 상태 폴링
```bash
# 최근 run 목록
curl -s -H "Authorization: token $GITEA_TOKEN" \
"https://git.eroomai.com/api/v1/repos/jhogyu/Liti-agent-Development/actions/tasks?limit=5" \
| python3 -m json.tool
```
또는 웹 UI: `https://git.eroomai.com/jhogyu/Liti-agent-Development/actions` 의
run 상세 페이지에서 로그 확인. 완료 후 하단 **Artifacts** 에서
`agent-run-<번호>` (events.jsonl / final_output.txt / summary.md) 다운로드.
---
## 방법 B — Gitea 웹 UI 에서 실행
1. Actions 탭 → **Run Agent YAML via API** 선택
2. **Run workflow** 클릭 (⚠️ 실패한 run 의 **Re-run 은 금지** — 옛 커밋의 워크플로우가 실행됨)
3. 입력 채우기:
- `yaml_path`: 실행할 YAML 의 repo 상대경로
- `workspace_name`: 작업실 이름 (예: `팬아웃 테스트`) — UUID 자동 해석
- (또는 `workspace_id` 에 UUID 직접 입력 — override)
4. 실행 → run 페이지에서 로그/아티팩트 확인
---
## 방법 C — 로컬에서 스크립트 직접 실행 (CI 안 거침)
backend 에 네트워크로 직접 붙어 실행. `httpx`, `httpx-sse` 필요.
```bash
pip install httpx httpx-sse
python scripts/run_agent_api.py \
--yaml-path="Case_02_Comparison_Research/YAML_Prompts/1. Stage_1/v.5/Stage_1_Part_1.yml" \
--workspace-name="팬아웃 테스트" \
--user-id="<user_id>" \
--api-base="http://100.93.221.71:8800" \
--output-dir=agent_run_output
```
- 러너에서 돌 때의 `api_base` 는 `http://agent-backend:8000` (컨테이너 네트워크).
- 이 머신(Tailscale) 에서 직접 검증할 때는 `http://100.93.221.71:8800`
(= `eroomaiserver.tailabbfd5.ts.net`, 실제 데이터가 있는 backend).
---
## 워크플로우 입력 레퍼런스
| 입력 | 필수 | 기본값 | 설명 |
|------|------|--------|------|
| `yaml_path` | ✅ | — | 실행할 Agent YAML 의 repo 상대경로 |
| `workspace_name` | △ | `""` | 작업실 이름 → `GET /workspaces/lookup` 으로 UUID 해석 |
| `workspace_id` | △ | `""` | 작업실 UUID 직접 지정(override). 비우면 name 으로 해석 |
| `user_id` | ✅ | — | AgentBackend user_id (실행 계정) |
| `user_input` | | `""` | Agent 에 전달할 user_input |
| `start_stage_index` | | `0` | 시작 stage 인덱스 |
| `api_base` | | `http://agent-backend:8000` | 내부 컨테이너 주소 (/api 접두사 없음) |
| `max_runtime_seconds` | | `9000` | 총 실행 상한(초). 3h infra 상한보다 짧게 |
> `workspace_name` 또는 `workspace_id` **중 하나는 반드시** 지정 (둘 다 비우면 실패).
작업실 이름↔UUID 목록 확인:
```bash
curl -s -H "X-Admin-Token: $ADMIN_API_TOKEN" \
"http://100.93.221.71:8800/workspaces/lookup?user_id=<user_id>" | python3 -m json.tool
```
---
## 전제 조건 (서버 인프라)
| 항목 | 설정 | 이유 |
|------|------|------|
| act_runner 네트워크 | `config.yaml` 의 `container.network` = 백엔드 도커 네트워크 | job 컨테이너가 `agent-backend:8000` 을 DNS 로 찾으려면 같은 네트워크여야 함 |
| 동시 실행 | `config.yaml` 의 `runner.capacity` 상향 (예: 20) | agent job 은 SSE 대기(I/O 바운드)라 슬롯을 오래 점유 → capacity 낮으면 큐 적체 |
| 아티팩트 | `actions/upload-artifact@v3` (v4 아님) | Gitea 는 아티팩트 v3 프로토콜만 지원 (v4 는 GHESNotSupportedError) |
| 실행 시간 | `max_runtime`(150m) < `timeout-minutes`(175m) < 3h | Gitea/act_runner 3h 강제종료 전에 스스로 정리 |
---
## 트러블슈팅 (겪었던 이슈)
| 증상 | 원인 | 해결 |
|------|------|------|
| `HTTP 302` → Google OAuth 로 리다이렉트 | 공개 URL(legalpoc.eroomai.com)이 OAuth 프록시 뒤 | `api_base` 를 내부 주소로 |
| 고쳤는데도 계속 302 | 실패 run 을 **Re-run** (옛 커밋 실행) | **Run workflow** 로 새로 실행 |
| `Name or service not known` | job 컨테이너가 백엔드 네트워크 밖 | act_runner `container.network` 설정 |
| job 이 pending 에서 대기 | `capacity=1` 로 슬롯 부족 | `runner.capacity` 상향 |
| `GHESNotSupportedError` (아티팩트) | Gitea 는 v4 미지원 | `upload-artifact@v3` |
| `/workspaces` 빈 배열 | `eroom-server`(다른 머신, 빈 DB) 로 요청 | `eroomaiserver`(100.93.221.71) 로, 경로는 `/workspaces/lookup` |