8.8 KiB
8.8 KiB
Gitea authenticated access 운영 지침
이 문서는 Gitea Agent harness가 Gitea의 authoritative state를 읽고 승인된 mutation을 수행할 때 사용하는 canonical access 계약이다. 모든 agent와 skill은 특정 transport를 정본으로 취급하지 않고, 이 문서의 identity·credential·readback 조건을 충족하는 authenticated API adapter를 사용한다.
고정 origin과 transport
- 허용된 Gitea origin은 exact
https://gitea.jsfamily.quest다. - Authenticated API adapter는 전용 Gitea MCP connection 또는 release/spec/impl 등 현재 role의 credential을 사용하는 직접 Gitea REST client일 수 있다.
- MCP method 이름, REST client 구현과 command 성공은 정본이 아니다. 위 origin이 반환한 authenticated response와 fresh readback이 정본이다.
- 다른 origin, mirror API, public web page, unauthenticated response 또는 다른 role의 adapter로 fallback하지 않는다.
- Redirect는 자동 추적하지 않는다. 특히 credential을 다른 origin에 전달하지 않는다.
Identity gate
- 모든 workflow는 첫 authoritative read 전에 authenticated adapter로 현재 사용자를 읽는다. REST adapter는 exact
GET /api/v1/user를 사용한다. - Stable numeric account ID, login과 현재 workflow role을 기록한다. Transport에 따라 login 표시가 달라도 stable account ID가 같으면 같은 identity다.
- 예상 role identity를 확인할 수 없거나 API가
401,403, redirect, malformed response 또는 anonymous identity를 반환하면 fail-closed한다. - Workflow 동안 adapter와 credential source를 바꾸지 않는다. 재인증이 필요하면 현재 operation을 중단하고 snapshot부터 다시 시작한다.
직접 REST adapter
- Base URL은 exact
https://gitea.jsfamily.quest/api/v1로 고정하고 TLS certificate 검증을 끄지 않는다. - Token은 현재 role profile의 exact
$HERMES_HOME/.env에GITEA_TOKEN으로 저장하고 해당 파일의 mode를0600으로 유지한다. Named profile에서는$HERMES_HOME이~/.hermes/profiles/<profile>이므로 같은 변수 이름을 사용해도 role별 token이 격리된다. 승인된 external secret manager를 사용하면 같은 profile scope에GITEA_TOKEN으로 주입한다. 다른 profile, inherited ambient token, interactive prompt 또는 public access로 fallback하지 않는다. - Token을 URL, command argv, Git config, remote URL, log, exception text, state, artifact 또는 repository file에 기록하지 않는다.
- Client는 token을 process 내부에서 읽어
Authorizationheader에 넣거나 보호된 file descriptor·stdin과 동등한 mechanism으로 전달한다. Secret이 shell expansion 후 argv에 나타나는 호출은 금지한다. - Response status와 JSON shape를 검증한다. Collection endpoint는 Gitea pagination metadata에 따라 마지막 page까지 읽고 cardinality를 기록한다.
429와 일시 오류는 read operation에서만 bounded retry할 수 있다. Mutation timeout·오류는 blind retry하지 않고 authoritative reconciliation을 먼저 수행한다.
Repository와 Git
- Repository metadata, default branch와 branch full SHA는 authenticated adapter로 exact target에서 읽는다.
- Git clone/fetch/push credential은 API token을 credential-bearing URL에 넣지 않고 short-lived askpass 또는 동등한 child-process mechanism으로 전달한다.
- Git command 성공만으로 remote state를 확정하지 않는다. Fetch 후 default-branch ref를 API SHA와 비교하고, push 후 exact remote ref를 authenticated adapter로 다시 읽는다.
Mutation과 readback
- Direct REST와 MCP에 동일한 승인 gate, exact payload, idempotency, drift 검사와 readback 규칙을 적용한다.
- Mutation 직전에 target identity, approval snapshot과 baseline을 다시 읽는다.
- 승인된 exact endpoint와 payload만 한 번 호출한다. Unstated default field에 의존하지 않는다.
- 성공 response만으로 완료를 주장하지 않는다. Exact target을 fresh readback하고 author stable account ID, payload, timestamp, commit/ref와 collection cardinality를 baseline과 비교한다.
- Timeout, malformed response 또는 connection loss 뒤에는 같은 mutation을 재호출하기 전에 complete collection을 한 번 읽어 결과를 reconciliation한다. 결과가 없거나 여러 개이거나 경쟁 mutation과 구분할 수 없으면 uncertain/partial로 중단한다.
Issue body update의 provider-derived readback
- 이 계약은 승인된 Issue body update에만 적용한다. 현재 origin의 실제 server version·endpoint/update 경로와 독립적으로 확인한 matching provider contract를 기존 snapshot/근거에 연결한다. 보관 소스나 snapshot 자체의 version 주장만으로 현재 서버 계약을 확정하지 않는다. Revision 필드의 API 노출 여부도 확인하며, 내부 모델 필드가 transport에 항상 노출된다고 추정하지 않는다.
- Write 직전 fresh snapshot은 target identity와 body,
updated_at, comment baseline 및 보호 필드(title·state·labels·assignees·milestone 등)를 승인 baseline과 비교한다. 노출된 revision도 비교하여 pre-write drift를 차단한다. Provider 파생 변경 허용은 write 이후에만 적용하며 drift gate나 기존 조건부 update를 완화하지 않는다. - Readback의 body는 실제 전송 artifact의 exact bytes와 같아야 한다. 보호 필드와 해당 workflow의 complete comment baseline 계약은 그대로 검증한다.
content_version이 해당 authenticated transport의 baseline과 readback에 제공되고 matching contract가 이 단일 body update에서 정확히 1 증가를 보장하면, 두 값이 boolean이 아닌 비음수 정수인지 확인하고 after == before + 1을 검증한다. 같은 body의 no-op에는 증가를 요구하지 않는다. - Revision이 누락·malformed이거나 증가가 0 또는 2 이상이거나 계약이 미확인이면 one-step 검증 성공으로 추정하지 않는다. Provider가 필드를 노출하지 않는 확인된 계약이면 비노출·검증 한계를 기록하고 workflow의 나머지 필수 검증을 적용한다. 필수 revision 근거가 부족하거나 경쟁 mutation과 구분할 수 없으면 uncertain/partial로 중단한다.
updated_at등 다른 필드도 같은 operation의 확인된 인과·타입·변경 규칙으로 각각 대조하며 일괄 비교 제외하지 않는다. Timestamp만으로 경쟁 변경이 없다고 주장하지 않는다. - 정상 파생 증가와 무관한 mutation을 구분하여 fresh readback으로 reconciliation한다. Body가 일치해도 다른 필수 검증이 실패하면 completed가 아니다. Timeout·오류·불일치 뒤에는 자동 재write하지 않는다. 보존된 baseline·payload·현재 결과로 판정하고 불확실하면 uncertain/partial로 보고한다. 별도 승인된 재개에서도 fresh identity·lease·snapshot·drift gate를 다시 통과한다.
- 이는 기존 adapter를 사용하는 main의 비교 절차이며 새 runtime checker·publisher·projection framework 또는 자동 retry를 추가하지 않는다. 문서 계약 테스트 통과는 실제 adapter 준수나 live 서버 동작을 검증한 것이 아니다.
Credential 안전
- Credential 값은 role profile의 secret store에만 저장하고 repository, harness 문서와 workflow artifact에는 저장하지 않는다.
- Child process에 credential이 필요하면 최소 범위 environment 또는 보호된 descriptor로 전달하고 종료 시 helper와 temporary file을 제거한다.
- Credential의 존재 여부, source와 cleanup 결과만 보고하며 값을 출력하지 않는다.
- Read-only 단계에는 필요한 최소 scope를, tag push·review·Issue mutation에는 승인된 작업에 필요한 scope만 사용한다.
Fail-closed 조건
다음 중 하나라도 발생하면 authenticated operation을 완료로 보고하지 않는다.
- 허용 origin 또는 target repository 불일치
- Authenticated stable account identity 확인 실패
- Role credential source 불명확 또는 다른 role credential 사용
- Redirect, TLS 검증 실패,
401,403또는 malformed API response - Pagination 미완료 또는 baseline cardinality 불명확
- Mutation 결과와 fresh readback 불일치
- Credential 노출 또는 helper cleanup 결과 불확실
보고
완료 보고에는 adapter 종류 자체보다 다음 검증 결과를 포함한다.
- exact Gitea origin
- authenticated stable account ID와 login
- exact repository와 authoritative default branch full SHA
- 사용한 transport 종류와 role credential source의 이름만 표시한 provenance
- 수행한 mutation의 exact target과 fresh readback 결과
- pagination, drift, reconciliation과 partial/fail-closed 상태
Token 값, authorization header와 credential-bearing URL은 보고하지 않는다.