# BAT-007 Implementation - Status: completed - Batch: BAT-007 ## Plan Summary - REQ-022: revoke_tokens_by_daemon_id repository + revoke_tokens_for_daemon service + daemon CLI 연결 - REQ-023: list_service_tokens_with_null_daemon repository + 서비스 헬퍼 + migrate_null_daemon CLI ## Changed Files ### Production Code 1. `app/repositories/portfolio_repository.py` — 추상 메서드 2개 추가: `revoke_tokens_by_daemon_id`, `list_service_tokens_with_null_daemon` 2. `app/repositories/postgres.py` — 위 2개 메서드 Postgres 구현 추가 3. `app/services/auth_service.py` — 서비스 메서드 3개 추가: `revoke_tokens_for_daemon`, `list_null_daemon_service_tokens`, `find_candidate_daemons_for_user` 4. `app/cli/commands/daemon.py` — `update_daemon` 커맨드에 `--force` 옵션 + deactivate 시 service token 자동 revoke 연결 5. `app/cli/commands/service_tokens.py` — `migrate-null-daemon` 커맨드 추가 (dry-run only) ### Tests 6. `tests/test_daemon_registry.py` — `_DaemonRepo` fake에 `revoke_tokens_by_daemon_id` / `list_service_tokens_with_null_daemon` 추가; REQ-022 테스트 5건 추가 7. `tests/test_null_daemon_migration.py` — 신규 파일; REQ-023 AC-1~5 + candidate daemon 출력 테스트 6건 ## Execution Log 1. `portfolio_repository.py`: 추상 메서드 2개 추가 2. `postgres.py`: `revoke_tokens_by_daemon_id` — `UPDATE auth_tokens SET revoked_at=NOW() WHERE daemon_id=%s AND revoked_at IS NULL`; `list_service_tokens_with_null_daemon` — `WHERE token_type='service' AND daemon_id IS NULL AND revoked_at IS NULL ORDER BY created_at ASC` 3. `auth_service.py`: 3개 메서드 위임 구현 4. `daemon.py`: `--force` / `--deactivate` / `--activate` 옵션 추가; deactivate 경로에서 `repo.revoke_tokens_by_daemon_id(daemon_id)` 호출 후 revoke 건수 출력 5. `service_tokens.py`: `migrate-null-daemon` 커맨드 — `--dry-run` 없으면 즉시 exit(1) + 수동 안내; `--dry-run` 시 NULL daemon token 목록 + user별 candidate daemon ID 출력 6. `test_daemon_registry.py`: `_DaemonRepo` fake 확장; 5개 테스트 추가 7. `test_null_daemon_migration.py`: `_FakeRepo` + `create_app(repository_factory=...)` 패턴으로 CLI runner 구성; 6개 테스트 추가 8. 수정 사항: `_make_runner`에서 `obj=ctx_obj` 전달 방식은 Typer `main_callback`이 `ctx.obj`를 덮어쓰므로 `create_app(repository_factory=...)` 방식으로 교체 ## Validation ``` .venv/bin/python -m pytest -q 266 passed in 7.86s ``` - BAT-007 대상 테스트: 25개 (test_daemon_registry.py 19, test_null_daemon_migration.py 6) — 전부 PASSED - 전체 회귀: 266 passed, 0 failed ## Remaining Risks - Postgres 구현은 단위 테스트(fake repo) 기반 검증; PostgreSQL DB 통합 테스트는 별도 환경 필요 - `--deactivate` 시 revoke는 CLI 단계에서 수행 — API 경로에서 daemon deactivate가 발생할 경우 revoke 호출 별도 필요 (현재 API 경로 없음, 향후 추가 시 고려)