# task-2483 — BOT_GITHUB_TOKEN 갱신 사이클 복구

- 작업 유형: **merge automation recovery / infrastructure hardening**
- 작업 레벨: **Lv.3**
- 위임팀: **dev3-team (라 / 다그다)**
- 우선순위: **★★★ 최우선 — merge automation recovery blocker**
- 일시: 2026-05-07
- TTL: 8시간

## 본 task의 본질 — 회장 명시

> refresh_bot_token.py 유실로 systemd timer의 BOT_GITHUB_TOKEN 갱신 사이클 실패. 이로 인해 bot-authored PR 생성, Gemini auto-review, no-admin merge chain, task-2481 dogfooding layer 5가 모두 차단됨. 해당 토큰 갱신 사이클을 복구하고 자동 머지 체인의 기반 인증 경로를 다시 green 상태로 만든다.

## allowed_resources

```yaml
allowed_resources:
  paths:
    - "scripts/refresh_bot_token.py"
    - "scripts/refresh_bot_token/**"
    - "utils/github_app_token*.py"
    - "utils/bot_token_loader*.py"
    - "tests/regression/test_refresh_bot_token*.py"
    - "tests/regression/test_github_app_token*.py"
    - "memory/tasks/task-2483*"
    - "memory/reports/task-2483*"
    - "memory/plans/tasks/task-2483/**"
    - "memory/events/task-2483*"
    - "memory/orchestration-audit/bot-token-refresh.jsonl"
    # systemd unit (사용자 디렉토리)
    - "/home/jay/.config/systemd/user/refresh-bot-token.service"
    - "/home/jay/.config/systemd/user/refresh-bot-token.timer"
  forbidden_paths:
    - ".github/workflows/**"
    - "scripts/dispatch.py"
    - "scripts/finish-task.sh"
    - "scripts/done-watcher.sh"
    - "scripts/taskctl.py"
    - "memory/events/task-2472*"
    - "memory/events/task-2479*"
    - "memory/events/task-2481*"
    - ".secrets/**"  # PEM 위치만 참조, 키 자체 수정 금지
  forbidden_actions:
    - admin_override
    - branch_protection_bypass
    - force_merge
    - workflow_modification
    - personal_pat_substitution  # 회장 명시 금지
    - token_secret_logging       # 키/토큰 원문 로그 출력 금지
    - dispatch_surface_overlap_logic_change
    - finish_task_surface_contract_change
    - task_2481_unauthorized_done
    - insuro_required_checks_structure_change
```

## 0. 배경 — 차단 evidence

- `scripts/refresh_bot_token.py`: workspace 전체 검색 0건 (이전 anu-direct 작성, 유실)
- `~/.config/systemd/user/refresh-bot-token.timer`: active (waiting), 50분 간격
- `~/.config/systemd/user/refresh-bot-token.service`: ExecStart=`/usr/bin/python3 /home/jay/workspace/scripts/refresh_bot_token.py` (파일 없음 → status=203/EXEC 실패 추정)
- BOT_GITHUB_TOKEN graphql 401 (task-2481 dogfooding layer 5 차단 사유)
- task-2481 DOGFOODING_PENDING 상태로 본 task 완료 의존

## 1. 작업 범위 (11단계 — 회장 명시)

### Step 1. refresh_bot_token.py 존재 여부 및 유실 원인 확인
- workspace + worktree + .secrets 등 전체 검색
- git log/diff에서 삭제 commit 추적 (`git log --all --diff-filter=D -- scripts/refresh_bot_token.py`)
- 삭제 actor + commit 식별 (별도 incident 보고용)

### Step 2. 복원 또는 재작성
- git history에 살아있으면 `git show <sha>:scripts/refresh_bot_token.py > 복원`
- history에도 없으면 동일 기능 재작성:
  - GitHub App credentials 로드 (env `BOT_GITHUB_APP_ID`, `BOT_GITHUB_INSTALLATION_ID`, `BOT_GITHUB_PRIVATE_KEY_PATH`)
  - PEM 키 읽어 JWT 생성 (cryptography 또는 PyJWT)
  - JWT로 installation token endpoint 호출 (`POST /app/installations/{id}/access_tokens`)
  - 응답 토큰을 `BOT_GITHUB_TOKEN` env 또는 지정 파일에 저장
  - audit jsonl append (`memory/orchestration-audit/bot-token-refresh.jsonl`)

### Step 3. GitHub App credentials 로딩 경로 검증
- `BOT_GITHUB_APP_ID=3616524` (메모리 박제)
- `BOT_GITHUB_INSTALLATION_ID=129882070`
- `BOT_GITHUB_PRIVATE_KEY_PATH`: 메인 `~/.secrets/jeon-jonghyuk-taskctl-bot.2026-05-05.private-key.pem` + 백업 `/home/jay/workspace/.secrets/jeon-jonghyuk-taskctl-bot.2026-05-05.private-key.pem`
- 메인 부재 시 백업 자동 fallback 로직 포함

### Step 4. installation token 발급 로직 검증
- JWT iat/exp 정상 (10분 이내, ±60초 시계 보정)
- API 응답 `token` 필드 + `expires_at` 필드 사용
- 실패 시 fail-closed (구 토큰 보존, audit reject 기록)

### Step 5. BOT_GITHUB_TOKEN 갱신 출력/저장 경로 확인
- 저장 위치: `.env.keys` 또는 별도 secrets 파일 (회장 검토)
- ⚠️ 토큰 원문은 audit jsonl에 절대 저장 금지 (sha256 hash만)
- 환경변수 export 방식 또는 source 가능한 형식

### Step 6. systemd timer/service 경로 정상화
- `~/.config/systemd/user/refresh-bot-token.service` ExecStart 경로 검증
- 필요 시 수정 (단 이미 정상이면 변경 금지)
- `systemctl --user daemon-reload` + `systemctl --user enable --now refresh-bot-token.timer`

### Step 7. systemd dry-run 또는 수동 실행으로 401 해소 확인
- `systemctl --user start refresh-bot-token.service` 즉시 실행
- `journalctl --user -u refresh-bot-token.service -n 50` 결과 확인
- 발급된 토큰으로 `curl -H "Authorization: Bearer $TOKEN" https://api.github.com/app` 200 응답

### Step 8. GitHub GraphQL API smoke test
- 새 토큰으로 `gh api graphql -f query='{viewer{login}}'` 200 응답
- task-2481 dogfooding layer 5 차단 사유 (graphql 401) 해소 검증

### Step 9. bot-authored PR 생성 경로 smoke test
- `git push --force-with-lease` 또는 dry-run으로 bot author push 검증
- gh CLI로 bot-authored PR 생성 시뮬레이션 (작은 테스트 브랜치)
- 단 실 PR 생성은 task-2481 후속에서 처리, 본 task는 인증 경로만

### Step 10. Gemini auto-review 의존 경로 smoke test
- Gemini 자동 리뷰가 사용하는 GitHub API auth 경로 확인
- 새 토큰으로 review trigger 가능한지 dry-run

### Step 11. task-2481 dogfooding layer 5 재시도 가능 여부 보고
- 본 task 완료 후 task-2481.dogfooding-pending.conditions 4가지 충족 가능한지 명시
- 가능하면 "후속 트리거 ready" 또는 불가 시 "추가 차단 항목 X"로 분리 보고

## 2. 금지 (회장 명시 7건)

- ❌ GitHub ruleset 우회 목적의 admin override 추가
- ❌ 개인 PAT로 영구 대체 (GitHub App 토큰만 사용)
- ❌ 토큰/키 원문 로그 출력 (audit는 sha256 hash만)
- ❌ task-2481을 임의 DONE 처리
- ❌ InsuRo required checks 구조 변경
- ❌ dispatch.py surface overlap 로직 변경 (Track B 영역)
- ❌ finish-task.sh surface 계약 검증 변경 (Track C 영역)

## 3. 완료 기준 (회장 명시 9건)

1. ✅ `refresh_bot_token.py` 또는 동등 복구 스크립트 존재
2. ✅ systemd timer/service 경로 정상
3. ✅ 수동 실행 PASS (status 0)
4. ✅ BOT_GITHUB_TOKEN 발급 PASS (`expires_at` 살아있음)
5. ✅ GraphQL 401 해소 PASS
6. ✅ bot-authored PR 생성 smoke PASS 또는 dry-run evidence
7. ✅ Gemini auto-review token 경로 smoke PASS 또는 의존성 상태 명확
8. ✅ task-2481 dogfooding layer 5 재개 가능/불가능 사유 명확화
9. ✅ 3문서 작성 완료 + 회귀 테스트 PASS

## 4. 산출물 (회장 명시)

1. **implementation report**: refresh_bot_token.py 코드 + GitHub App 로딩 + 갱신 로직
2. **verification report**: 9가지 완료 기준 검증 evidence (curl/gh 응답, systemctl status, journalctl 일부)
3. **operation/runbook update**: 토큰 만료 시 수동 갱신 명령, 키 분실 시 복구 절차

## 5. 시스템 3문서 참조 (필수)

- 시스템 청사진: `/home/jay/.claude/projects/-home-jay--cokacdir-workspace-autoset/memory/system_bot_orchestration_blueprint_260506.md`
- GitHub App PEM 위치 박제: `/home/jay/.claude/projects/-home-jay--cokacdir-workspace-autoset/memory/feedback_github_app_key_location_260507.md`
- DOGFOODING_PENDING 분류 룰: `/home/jay/.claude/projects/-home-jay--cokacdir-workspace-autoset/memory/feedback_dogfooding_pending_classification_260507.md`
- 봇 마이그레이션 체크리스트: `/home/jay/.claude/projects/-home-jay--cokacdir-workspace-autoset/memory/feedback_bot_migration_checklist_260507.md`

## 6. 회귀 테스트 (필수)

- `tests/regression/test_refresh_bot_token_*.py` 신설
  - JWT 생성 정상
  - PEM 메인 부재 → 백업 fallback
  - API 401 시 fail-closed (구 토큰 보존)
  - audit jsonl append-only
  - 토큰 원문 미로깅 (sha256만)
  - systemd unit 호환 (Type=oneshot exit 0)
- 기존 회귀 테스트 PASS 유지

## 7. 보고 형식

- SCQA 4섹션 명시
- 11단계 각 결과 명시 (PASS / FAIL / N/A)
- 9가지 완료 기준 evidence 포함
- forbidden_actions 위반 0건 검증

## goal_assertions (auto-generated)
- `curl -H "Authorization: Bearer $TOKEN" https://api.github.com/app`
