* docs: preserve original issue 5 body * feat: add service token rename command * test: normalize rich option errors
69 lines
4.0 KiB
Markdown
69 lines
4.0 KiB
Markdown
|
|
- **유형**: 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 흐름 대상으로 검토.
|