[verified] docs: harden Gitea access and release contracts
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
---
|
||||
name: gitea-release
|
||||
description: 승인된 Gitea 버전을 준비·태깅하고 산출물을 게시한다.
|
||||
version: 0.1.0
|
||||
version: 0.3.0
|
||||
author: genichin, Hermes Agent
|
||||
license: MIT
|
||||
platforms: [linux]
|
||||
@@ -13,7 +13,7 @@ metadata:
|
||||
|
||||
# Gitea Release
|
||||
|
||||
Gitea repository cache를 사용해 버전 준비, 검증, 태깅과 프로젝트별 산출물 게시를 수행한다. Cache 규칙은 [Repository cache 운영 지침](../../../../operations/repository-cache.md)을 정본으로 사용한다.
|
||||
Gitea repository cache를 사용해 버전 준비, 검증, 태깅과 프로젝트별 산출물 게시를 수행한다. Gitea 인증과 readback은 [Gitea authenticated access 운영 지침](../../../../operations/gitea-access.md), cache 규칙은 [Repository cache 운영 지침](../../../../operations/repository-cache.md)을 정본으로 사용한다.
|
||||
|
||||
## 사용 시점
|
||||
|
||||
@@ -41,7 +41,7 @@ Issue 구현, PR merge, 임의 버전 선택, 기존 tag 이동, artifact 덮어
|
||||
|
||||
### 프로젝트별 처리
|
||||
|
||||
Target repository의 release contract가 담당한다.
|
||||
Target repository의 `.gitea/release.yaml` contract가 담당한다.
|
||||
|
||||
- version source와 함께 변경할 lockfile
|
||||
- test, lint와 build 명령
|
||||
@@ -51,7 +51,37 @@ Target repository의 release contract가 담당한다.
|
||||
- smoke test와 게시 명령
|
||||
- digest, checksum 또는 provenance 검증
|
||||
|
||||
Release contract가 없거나 모호하면 기존 workflow, build metadata와 문서를 읽어 확인된 사실만 보고한다. 이미지 이름, registry, credential, 명령 또는 artifact를 추측하지 않는다.
|
||||
기존 workflow, build metadata와 문서는 contract 작성·검토의 근거일 뿐 게시 정본이 아니다. Contract가 없거나 모호하면 확인된 사실만 보고하고 준비 commit 또는 게시를 시작하지 않는다. 이미지 이름, registry, credential, 명령 또는 artifact를 추측하지 않는다.
|
||||
|
||||
## Repository release contract
|
||||
|
||||
Repository root의 `.gitea/release.yaml`을 프로젝트별 릴리즈 정본으로 사용한다. Safe YAML mapping으로 읽고 duplicate key, alias·custom tag, 알 수 없는 schema·field·adapter·artifact type을 거부한다. 현재 지원 schema는 exact `gitea-agent/release/v1`이다.
|
||||
|
||||
### 공통 계약
|
||||
|
||||
- `version.sources`는 version을 읽고 변경할 repository-relative path, format과 selector를 선언한다. 현재 지원 format은 dotted key를 지정하는 `toml`과 top-level 문자열 대입 이름을 지정하는 `python-assignment`다.
|
||||
- `version.lockfiles`는 version source와 함께 갱신·검증할 lockfile을 선언한다. 현재는 `uv.lock`의 exact package entry만 지원한다.
|
||||
- `version.tag_template`은 `{version}`으로 exact tag를 만든다.
|
||||
- `prepare.runtime`은 검증 runtime을, `prepare.commands[].argv`는 순서대로 실행할 명령과 인수를 선언한다.
|
||||
- `artifacts[]`는 `type`, build 또는 source 처리, smoke, publish와 authoritative verify 항목을 선언한다.
|
||||
- Credential에는 secret 값이 아니라 active profile에서 읽을 환경변수 이름만 기록한다.
|
||||
|
||||
`argv`는 shell command가 아니다. 각 항목을 argument 배열로 직접 실행하고 glob, command substitution, redirection, pipe, shell variable expansion을 적용하지 않는다. 빈 argument, 문자열이 아닌 argument 또는 실행 파일이 repository 계약과 무관하면 거부한다.
|
||||
|
||||
지원 placeholder는 `{version}`, `{tag}`, `{commit}`, `{run_id}`뿐이다. `{commit}`은 prepared full SHA, `{run_id}`는 이번 local 실행에만 사용하는 비밀이 아닌 충돌 방지 식별자다. 다른 placeholder, 재귀 치환 또는 치환 결과의 shell 재해석을 금지한다.
|
||||
|
||||
Contract의 모든 path와 build context는 release worktree 내부의 non-symlink 경로로 해석돼야 한다. `..`, absolute path, symlink escape와 worktree 밖 script를 거부한다. Contract 자체가 symlink이면 중단한다.
|
||||
|
||||
### Artifact adapter
|
||||
|
||||
- `type: container`는 build adapter, exact platform·context·Dockerfile, smoke checks, registry·repository, credential 이름, tags, overwrite 정책과 readback 항목을 요구한다. Build한 하나의 local image를 smoke test하고 그 동일 image digest만 게시한다. 재빌드 결과를 대신 게시하지 않는다.
|
||||
- `type: source`는 container build를 실행하지 않는다. Tag만으로 제공되는 source archive 또는 별도 승인된 Gitea Release·attachment를 `publish`에 명시하고 checksum readback을 요구한다.
|
||||
|
||||
지원하지 않는 artifact type이나 adapter는 구현을 추측하지 않고 중단한다. `latest`, 암묵적 channel, 계약에 없는 tag·attachment 또는 default registry를 추가하지 않는다.
|
||||
|
||||
### Contract 고정
|
||||
|
||||
Contract를 읽은 exact bytes의 SHA-256, schema와 path를 `state.json`에 기록한다. `.gitea/release.yaml`은 prepared commit tree에 포함돼야 한다. 준비 검증, tag 생성, build와 publish 직전에 prepared tree의 contract hash를 다시 계산해 기록값과 비교한다. 차이가 있으면 이전 검증과 prepared 상태를 무효화한다.
|
||||
|
||||
## 승인 계약
|
||||
|
||||
@@ -81,7 +111,7 @@ Tag 또는 artifact를 외부에 게시하려면 다음이 필요하다.
|
||||
Repository마다 동시에 하나의 release workflow만 허용한다.
|
||||
|
||||
```text
|
||||
/opt/data/gitea-agent/repositories/<owner>/<repository>/
|
||||
<harness-root>/repositories/<owner>/<repository>/
|
||||
├── locks/release.lock
|
||||
└── worktrees/release/
|
||||
├── state.json
|
||||
@@ -94,15 +124,15 @@ Repository마다 동시에 하나의 release workflow만 허용한다.
|
||||
- 기존 release worktree를 reset, clean, rebase, checkout, force-remove 또는 덮어쓰지 않는다.
|
||||
- 실패한 release worktree는 증거 보존을 위해 자동 제거하지 않는다.
|
||||
|
||||
`state.json`에는 최소한 schema `gitea-agent.release-worktree/v1`, repository identity, base SHA, requested version·tag, prepared commit SHA와 단계 상태를 기록한다. Credential, PID 또는 secret 값은 기록하지 않는다.
|
||||
`state.json`에는 최소한 schema `gitea-agent.release-worktree/v1`, repository identity, base SHA, requested version·tag, prepared commit SHA, contract path·schema·SHA-256과 단계 상태를 기록한다. Credential 이름은 기록할 수 있지만 credential 값, PID 또는 secret 값은 기록하지 않는다.
|
||||
|
||||
## 절차
|
||||
|
||||
### 1. Target과 cache 확인
|
||||
|
||||
1. 요청의 repository, version, tag와 승인 범위를 추출한다.
|
||||
2. Gitea MCP로 authenticated identity, repository metadata, default branch와 SHA를 읽는다.
|
||||
3. `operations/repository-cache.md`에 따라 cache를 검증하거나 초기화한다.
|
||||
2. Canonical authenticated Gitea API adapter로 identity, repository metadata, default branch와 SHA를 읽는다.
|
||||
3. `operations/repository-cache.md`를 새로 읽고 실제 문서 경로에서 `<harness-root>`와 repository cache root를 계산·검증한 뒤 cache를 검증하거나 초기화한다.
|
||||
4. Release lock 아래 repository lock을 획득해 exact origin을 prune/fetch한다.
|
||||
5. Gitea default-branch SHA와 local mirror ref 일치를 확인한다.
|
||||
|
||||
@@ -119,23 +149,29 @@ Repository마다 동시에 하나의 release workflow만 허용한다.
|
||||
|
||||
### 3. 프로젝트 계약 조사
|
||||
|
||||
1. `search_files`와 `read_file`로 version metadata, lockfile, test, build, 기존 workflow와 release 문서를 읽는다.
|
||||
2. Version 변경 파일, 준비 검증과 게시 adapter를 구분한다.
|
||||
3. 정확한 게시 대상이나 credential 가용성을 확인할 수 없으면 수정 전에 중단한다.
|
||||
1. Release worktree root의 exact `.gitea/release.yaml` 존재, regular-file 유형과 경로 경계를 확인한다.
|
||||
2. Safe YAML로 읽고 exact schema, 허용 field, argument 배열, placeholder와 path를 검증한다.
|
||||
3. `version.sources`와 `version.lockfiles`를 `read_file`로 읽어 현재 선언 version이 서로 일치하는지 확인한다. 요청된 exact version과 다르면 stage 4에서 변경할 exact path와 selector를 version allowlist로 고정한다.
|
||||
4. `tag_template` 결과가 요청된 exact tag와 일치하는지 확인한다.
|
||||
5. `prepare.commands`, artifact type, build·smoke·publish adapter, exact target과 verify 항목을 분리한다.
|
||||
6. Contract bytes의 SHA-256을 계산해 path·schema와 함께 `state.json`에 기록한다.
|
||||
7. Credential 값은 읽거나 출력하지 않은 채 선언된 이름이 active profile에 존재하고 exact target에 사용할 수 있는지만 확인한다.
|
||||
8. 기존 workflow, build metadata와 release 문서는 contract와 충돌하는 stale 지시가 없는지 검토한다. 충돌하면 contract를 임의 해석하지 않고 중단한다.
|
||||
|
||||
완료 조건: 변경 파일 allowlist, 준비 검증 명령과 프로젝트별 게시 절차가 명확하다.
|
||||
완료 조건: 검증된 contract hash에 변경 파일 allowlist, exact 준비 명령, artifact adapter, 게시 대상과 authoritative readback이 모두 고정돼 있다.
|
||||
|
||||
### 4. 버전 변경과 준비 commit
|
||||
|
||||
1. 승인된 exact version만 allowlist 파일에 반영한다.
|
||||
2. Project-defined 준비 test와 정적 검사를 실행한다.
|
||||
3. 수정·미추적 파일 전체를 검사하고 allowlist 밖의 변경이 있으면 중단한다.
|
||||
4. Exact path만 stage하고 staged diff, secret, 삭제와 whitespace 오류를 검토한다.
|
||||
5. Non-amended local commit을 생성한다.
|
||||
6. Commit의 parent, tree, version·tag 일치와 clean worktree를 검증한다.
|
||||
7. `state.json`에 prepared full SHA와 검증 결과를 기록한다.
|
||||
1. 승인된 exact version만 contract의 `version.sources`와 `version.lockfiles` allowlist에 반영한다.
|
||||
2. Contract 변경이나 다른 non-version 변경은 사용자에게 명시적으로 승인된 exact path만 별도 allowlist에 포함한다.
|
||||
3. `prepare.commands`를 선언 순서대로, worktree root에서 shell 없이 exact `argv`로 실행한다. Exit code와 비민감 결과를 기록한다.
|
||||
4. 수정·미추적 파일 전체를 검사하고 두 allowlist 밖의 변경이 있으면 중단한다.
|
||||
5. Exact path만 stage하고 staged diff, secret, 삭제와 whitespace 오류를 검토한다.
|
||||
6. Non-amended local commit을 생성한다.
|
||||
7. Commit의 parent, tree, version·tag, contract hash 일치와 clean worktree를 검증한다.
|
||||
8. `state.json`에 prepared full SHA, contract hash와 검증 결과를 원자적으로 기록한다.
|
||||
|
||||
완료 조건: 승인된 버전 변경만 포함한 하나의 검증된 local commit이 존재한다.
|
||||
완료 조건: 승인된 exact 변경만 포함하고 contract와 준비 검증이 고정된 local prepared commit이 존재한다.
|
||||
|
||||
### 5. 게시 gate
|
||||
|
||||
@@ -147,6 +183,8 @@ Repository마다 동시에 하나의 release workflow만 허용한다.
|
||||
- 필요한 credential과 target이 확인됐다.
|
||||
- 필수 test와 check가 exact prepared commit에서 성공했다.
|
||||
- Worktree HEAD와 tree가 준비 검증 이후 바뀌지 않았다.
|
||||
- Prepared tree의 `.gitea/release.yaml` hash가 `state.json`과 일치한다.
|
||||
- Contract의 모든 adapter, target, tag와 verify 항목이 지원된다.
|
||||
|
||||
하나라도 불명확하면 외부 상태를 변경하지 않는다.
|
||||
|
||||
@@ -155,15 +193,21 @@ Repository마다 동시에 하나의 release workflow만 허용한다.
|
||||
1. 승인된 exact tag를 prepared commit에 생성한다.
|
||||
2. Explicit remote URL과 refspec으로 신규 tag만 non-force push한다.
|
||||
3. Gitea readback으로 remote tag target이 prepared SHA와 일치하는지 확인한다.
|
||||
4. Project release contract의 build, smoke test와 publish 절차를 그대로 실행한다.
|
||||
5. 승인된 artifact와 immutable commit-derived tag만 게시한다.
|
||||
4. Prepared tree에서 contract hash를 다시 검증한다.
|
||||
5. `type: container`이면 contract의 exact platform·context·Dockerfile과 label로 한 번 build하고 선언된 smoke checks를 같은 local image에 실행한다.
|
||||
6. Registry credential은 선언된 환경변수에서만 읽고 URL, argv, Git config, state 또는 로그에 넣지 않는다. Redirect를 거부하고 exact registry origin에만 보낸다.
|
||||
7. `overwrite: false`이면 모든 선언 remote image tag의 부재를 확인한 뒤 검증한 동일 local image를 선언된 tag로 게시한다.
|
||||
8. `type: source`이면 container 명령을 건너뛰고 contract와 별도 게시 승인에 선언된 Gitea Release 또는 attachment만 게시한다.
|
||||
9. 승인된 artifact와 immutable commit-derived tag만 게시한다.
|
||||
|
||||
`latest`, 추가 channel, 추정 artifact 또는 기존 tag를 게시·이동·덮어쓰지 않는다.
|
||||
|
||||
### 7. 권위 있는 검증
|
||||
|
||||
- Gitea remote tag target을 다시 읽는다.
|
||||
- 게시 artifact의 version, digest 또는 checksum을 authoritative target에서 읽는다.
|
||||
- Contract의 `verify` 항목을 모두 authoritative target에서 읽는다.
|
||||
- Container는 최소 digest, platform과 prepared SHA revision label을 검증한다.
|
||||
- Source attachment는 exact filename, size와 checksum을 검증한다.
|
||||
- Artifact provenance가 prepared SHA와 일치하는지 확인한다.
|
||||
- 여러 tag를 게시했다면 모두 같은 승인 artifact를 가리키는지 확인한다.
|
||||
- Gitea Release가 별도 승인됐다면 target, metadata와 attachments를 다시 읽는다.
|
||||
@@ -184,6 +228,8 @@ Partial failure, dirty state, 미게시 commit 또는 불확실한 readback에
|
||||
## 실패 처리
|
||||
|
||||
- Version, tag, commit, artifact 또는 target을 추측하지 않는다.
|
||||
- `.gitea/release.yaml`이 없거나 schema·hash·path·adapter 검증에 실패하면 준비 commit과 게시를 시작하지 않는다.
|
||||
- Workflow나 README를 contract의 대체 정본으로 사용하지 않는다.
|
||||
- 기존 tag를 force-update, 삭제 또는 재생성하지 않는다.
|
||||
- 기존 artifact를 덮어쓰거나 삭제하지 않는다.
|
||||
- 실패한 build를 임의 변경으로 수리하지 않는다.
|
||||
|
||||
Reference in New Issue
Block a user