Files
portfolio-hub/docs/issues/issue-0005-original.md
T
genichin deaaa96c46 feat: add service token rename command (#40)
* docs: preserve original issue 5 body

* feat: add service token rename command

* test: normalize rich option errors
2026-09-19 21:19:39 +09:00

4.0 KiB

  • 유형: Feature / Enhancement
  • 우선순위: Medium
  • 영역: CLI / 인증 (pfhub service-token)
  • 대상 버전: portfoliohub 0.1.0 (commit 58899b1)

배경 / 문제

현재 pfhub service-token 하위 명령은 list / issue / rotate / rebind / revoke / migrate-null-daemon 6개뿐이며, 기존 서비스 토큰의 name 을 변경하는 명령이 없다.

  • name 은 rotate / rebind / revoke 의 조회 키로 쓰인다 (app/cli/commands/service_tokens.py — 각 명령이 name 인자로 토큰을 찾음).
  • 이름을 바꾸려면 현재로선 issue(새 이름으로 신규 발급) → revoke(기존 폐기)가 유일한 우회 경로다.
  • 이 우회는 토큰 값(평문)까지 새로 바뀌므로, 단순히 라벨만 정리하려는 경우에도 모든 클라이언트·데몬의 토큰을 재배포해야 한다. 이름 오타 수정, 명명 규칙 정비 등에 과도한 비용이 든다.

요구사항

기존 서비스 토큰의 name 만 변경하고 토큰 값·바인딩은 그대로 유지하는 CLI 명령을 추가한다.

제안 인터페이스

pfhub service-token rename NAME --new-name NEW_NAME [--force]
  • NAME (인자): 현재 서비스 토큰 이름 (조회 키)
  • --new-name (필수 옵션): 변경할 새 이름
  • --force (옵션): 확인 프롬프트 생략 (revoke 명령과 동일 패턴)

수용 기준 (Acceptance Criteria)

  1. NAME 으로 활성(비폐기) 서비스 토큰을 찾아 name 을 NEW_NAME 으로 변경한다.
  2. 다음 값은 변경되지 않는다: 토큰 값(평문)·token_hash·token_prefix· permission·token_type·daemon_id·runtime_id·expires_at·token_id.
  3. 이름 유일성 검증: NEW_NAME 이 다른 활성 서비스 토큰과 충돌하면 명확한 에러로 거부한다.
    • DB에는 이미 부분 유니크 인덱스가 존재한다: idx_auth_tokens_service_name_unique ON auth_tokens(name) WHERE token_type='service' AND revoked_at IS NULL (app/repositories/postgres.py:190-193) — UniqueViolation 을 사용자 메시지로 변환할 것.
  4. 에러 처리:
    • NAME 에 해당하는 활성 서비스 토큰이 없으면 → "서비스 토큰을 찾을 수 없습니다: NAME"
    • NEW_NAME 이 이미 사용 중이면 → "이미 존재하는 서비스 토큰 이름입니다: NEW_NAME"
    • NEW_NAME == NAME 이면 → 변경 없음 안내 후 정상 종료
  5. 출력: token_id, 기존 name, 변경된 name 을 표시 (table / json 양쪽 지원).
  6. --force 미지정 시 변경 전 확인 프롬프트를 띄운다.

구현 범위 (참고)

  • CLI: app/cli/commands/service_tokens.py 에 rename 명령 추가.
  • 서비스: app/services/auth_service.py 에 rename_service_token(name, new_name) 추가 — issue_service_token 과 동일하게 psycopg.errors.UniqueViolation 을 ValueError 로 변환.
  • 리포지토리: app/repositories/postgres.py 에 UPDATE auth_tokens SET name=%s WHERE ... 메서드 추가 및 app/repositories/portfolio_repository.py 프로토콜에 시그니처 추가.
  • 스키마: app/schemas/auth.py 에 rename 응답용 CLI 모델 추가 (기존 ServiceToken*CliResponse 패턴 따름).
  • 테스트: 정상 변경 / 미존재 토큰 / 이름 충돌 / 동일 이름 케이스.

범위 외 (Out of Scope)

  • 토큰 값 회전(rotation)은 본 기능에 포함하지 않는다. 값 변경이 필요하면 기존 rotate 를 사용한다.
  • 폐기된(revoked) 토큰의 이름 변경은 지원하지 않는다 (유일성 인덱스가 활성 토큰만 대상으로 함).
  • 서비스 토큰 이름 형식(문자셋) 검증 규칙은 현재 issue 에도 없으므로 본 이슈에서 신규 도입하지 않는다. (별도 정비가 필요하면 분리 이슈로 다룬다.)

비고

  • 관련: service-token 마스킹 이슈(해결 완료). 본 기능은 토큰 값을 노출/변경하지 않으므로 마스킹과 무관하다.
  • governance: 신규 CLI 명령 추가이므로 draft-req → batch delivery 흐름 대상으로 검토.