Files
portfolio-hub/.proofline/lines/line-0010/dcy-0010.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

6.1 KiB

id, status
id status
dcy-0010 confirmed

Service token rename without secret rotation

Problem

pfhub service-token은 활성 service token을 이름으로 조회해 rotate, rebind, revoke할 수 있지만 이름만 바꾸는 명령은 제공하지 않는다. 이름 오타나 명명 규칙을 교정하려면 새 token을 발급하고 기존 token을 revoke해야 하므로, label 변경만 필요한 경우에도 raw bearer token과 client 배포를 교체해야 한다.

기대 상태는 활성 service token의 동일한 durable row에서 name만 원자적으로 변경하고 기존 bearer token, identity, owner, permission, expiry, runtime/daemon binding을 유지하는 것이다. CLI는 확인 prompt와 non-interactive --force를 제공하고 table/JSON에서 secret 없이 변경 결과를 반환해야 한다.

Evidence

  • E-001 GitHub Issue #5 (https://github.com/fourblocks2020/portfolio-hub/issues/5)는 pfhub service-token rename NAME --new-name NEW_NAME [--force]와 name-only 변경, active-name uniqueness, missing/duplicate/no-op 오류, table/JSON 출력을 요구한다. 원문은 commit 17d6cbe3ba4ec10842bafb4af90709ef83fe721f의 docs/issues/issue-0005-original.md에 byte-for-byte 보존되어 있다.
  • E-002 app/cli/commands/service_tokens.py의 current command set은 list, issue, rotate, rebind, revoke, migrate-null-daemon이며 rename path가 없다. revoke_service_token()은 --force/-f와 typer.confirm()의 기존 UX를 제공한다.
  • E-003 app/services/auth_service.py::AuthService는 active service token lookup, issue/rotate/rebind/revoke lifecycle을 소유한다. issue_service_token()은 PostgreSQL UniqueViolation을 이미 존재하는 서비스 토큰 이름입니다: {name}으로 변환한다.
  • E-004 app/repositories/postgres.py::get_service_token_by_name()은 name, token_type='service', revoked_at IS NULL로 active row만 조회한다. 같은 파일의 cold-start schema와 migration app/db/alembic/versions/20260520_0022_service_token_unique_index_fix.py는 idx_auth_tokens_service_name_unique partial unique index로 active service-token name uniqueness를 이미 강제한다.
  • E-005 app/repositories/portfolio_repository.py::PortfolioRepository에는 rename contract가 없으며 app/schemas/auth.py에도 rename CLI response가 없다.
  • E-006 AuthToken/PostgreSQL row는 token identity와 secret-derived 값, permission, owner, expiry, runtime/daemon binding을 name과 별도 column으로 보존한다. raw token은 저장하지 않으므로 name-only invariant는 row before/after 비교와 기존 bearer token 재인증으로 검증해야 한다.
  • E-007 current main baseline 996127f2155a71c1085c4fbf35b504cc3c43439c에서 관련 구현이 없고, Issue #5 및 service token rename keyword의 기존 구현 PR도 없다.
  • E-008 현재 ProofLine active AC 검색 결과 service-token label rename lifecycle을 소유하는 criterion은 없다. service-token authorization 및 daemon-scope criteria는 회귀 대상일 뿐 이 신규 capability를 satisfy하지 않는다.

Scope

  • S-001 AC admission은 durable CLI behavior를 소유하는 신규 REQ/AC create로 분류한다. Approved REQ 원문과 기존 active AC 의미는 변경하지 않는다.
  • S-002 PortfolioRepository와 PostgreSQL adapter에 active service token의 name만 바꾸는 단일 UPDATE ... RETURNING contract를 추가한다. 새 이름 사전 조회를 uniqueness 권위로 사용하지 않고 기존 partial unique index가 concurrent conflict를 결정한다.
  • S-003 AuthService에 missing active token, duplicate active name, same-name success no-op를 구분하는 rename contract를 추가한다. new_name == name도 active row 존재를 확인하며 repository write는 하지 않는다.
  • S-004 pfhub service-token rename NAME --new-name NEW_NAME [--force/-f]를 추가한다. prompt 취소는 success exit와 zero write이고, 결과는 token_id, old_name, new_name, changed만 table/JSON으로 출력한다.
  • S-005 성공 rename은 동일 row의 name 외 모든 column과 기존 bearer-token authentication principal을 보존한다. raw/masked token을 출력하거나 token generation/hash/revoke 경로를 호출하지 않는다.
  • S-006 unit/service/CLI와 loopback real-PostgreSQL integration으로 success, missing, active collision, revoked-name reuse, same-name no-op, prompt/force, secret non-disclosure, protected-field invariants와 concurrent conflict를 검증한다.
  • S-007 existing interface documentation과 CLI examples를 additive contract에 맞춰 갱신하며 기존 service-token lifecycle/auth/daemon-scope 회귀를 유지한다.

Out of Scope

  • OS-001 raw token rotation, reissue, revoke 또는 secret 표시
  • OS-002 token owner, permission, type, expiry, runtime/daemon binding 변경
  • OS-003 revoked token row 자체의 rename
  • OS-004 service-token name 문자셋·길이·정규화에 대한 신규 정책
  • OS-005 HTTP API endpoint, database schema migration, historical backfill
  • OS-006 다른 repository 변경, production rollout 또는 production token mutation

Risks and Unknowns

Risks

  • R-001 애플리케이션의 “이름 사용 가능” 사전 조회만으로 충돌을 판단하면 concurrent rename/issue가 race한다. single-statement update와 partial unique index를 authority로 사용하고 실제 PostgreSQL 경쟁 테스트로 완화한다.
  • R-002 update projection이나 CLI response에 secret-derived/internal field가 포함되면 정보 노출 또는 unintended mutation이 생긴다. canonical auth-token projection을 반환하되 CLI response를 네 개의 비밀이 아닌 필드로 제한하고 negative test를 둔다.
  • R-003 same-name no-op가 존재 확인 없이 성공하면 missing token을 정상 처리하거나 revoked row를 오인할 수 있다. active lookup 성공을 no-op의 precondition으로 고정한다.
  • R-004 application rollback은 이미 완료된 metadata rename을 자동으로 되돌리지 않는다. 필요한 경우 동일 command로 이전 이름에 다시 rename하며 production 실행은 별도 운영 승인으로 둔다.