--- id: "req-0010" status: approved discovery: "dcy-0010" criteria: create: - "ac-0042" - "ac-0043" - "ac-0044" update: [] retire: [] satisfy: [] --- # Service token rename without secret rotation ## Objective 운영자가 활성 service token의 bearer token과 권한·binding을 교체하지 않고 식별용 이름만 안전하게 변경할 수 있게 한다. 변경은 concurrent issue/rename과 경쟁하더라도 기존 active-name uniqueness를 지키며, CLI는 interactive와 automation 환경 모두에서 secret을 노출하지 않는 명확한 결과를 제공해야 한다. ## Scope - 활성 service token 한 건의 `name`만 동일 durable identity에서 변경한다. - 기존 active service-token name uniqueness를 concurrent conflict의 최종 권위로 사용하고 충돌은 전체 rename을 실패시킨다. - 존재하지 않는 활성 이름, 같은 이름, revoked-name reuse를 서로 구분해 안정적으로 처리한다. - `pfhub service-token rename NAME --new-name NEW_NAME [--force/-f]`와 table/JSON 결과를 제공한다. - repository, service, CLI, 문서와 unit/real-PostgreSQL 검증을 함께 갱신한다. ## Constraints - Rename transaction 자체는 `id`, token secret/hash/prefix, owner, permission, token type, expiry, `last_used_at`/revocation timestamps, runtime/daemon binding 등 `name` 외 저장 필드를 변경하지 않는다. - rename은 token rotation, issue, revoke 경로를 호출하지 않고 기존 bearer token의 authentication principal을 보존한다. Rename 이후의 인증은 기존 인증 계약에 따라 `last_used_at`을 갱신할 수 있으며 이는 rename mutation에 포함되지 않는다. - duplicate-name 판단은 애플리케이션의 사전 조회가 아니라 PostgreSQL partial unique index를 최종 권위로 삼으며, 실패 시 partial mutation이 없어야 한다. - raw token, token hash 또는 connection credential은 CLI table/JSON, error, log, test evidence에 출력하지 않는다. - 기존 migration `20260520_0022`의 partial unique index를 사용하며 신규 schema migration이나 backfill을 추가하지 않는다. - 현재 `service-token` command와 HTTP API의 기존 의미 및 응답 계약을 변경하지 않는다. ## Non-Goals - revoked token row rename - service-token name의 신규 문자셋·길이·정규화 정책 - owner, permission, expiry, runtime/daemon binding 변경 - HTTP rename endpoint 또는 다른 repository의 producer/consumer 변경 - production token rename 또는 production rollout