From 5c9c5ca0cad9823aa88b4ef2a2b2c195da053d23 Mon Sep 17 00:00:00 2001 From: Hermes Agent Date: Fri, 14 Aug 2026 17:04:19 +0900 Subject: [PATCH] docs(proofline): capture issue 57 specification --- .proofline/criteria/ac-0004.md | 10 +-- .proofline/criteria/ac-0006.md | 10 +-- .proofline/criteria/ac-0008.md | 10 +-- .proofline/criteria/ac-0014.md | 16 ++++ .proofline/identities.json | 4 +- .proofline/lines/line-0004/dcy-0004.md | 79 +++++++++++++++++++ .../evidence/implementation-complete.md | 59 ++++++++++++++ .../evidence/implementation-progress.md | 63 +++++++++++++++ .proofline/lines/line-0004/line-0004.md | 3 + .proofline/lines/line-0004/req-0004.md | 62 +++++++++++++++ 10 files changed, 299 insertions(+), 17 deletions(-) create mode 100644 .proofline/criteria/ac-0014.md create mode 100644 .proofline/lines/line-0004/dcy-0004.md create mode 100644 .proofline/lines/line-0004/evidence/implementation-complete.md create mode 100644 .proofline/lines/line-0004/evidence/implementation-progress.md create mode 100644 .proofline/lines/line-0004/line-0004.md create mode 100644 .proofline/lines/line-0004/req-0004.md diff --git a/.proofline/criteria/ac-0004.md b/.proofline/criteria/ac-0004.md index 1ed714f..6a963e6 100644 --- a/.proofline/criteria/ac-0004.md +++ b/.proofline/criteria/ac-0004.md @@ -3,14 +3,14 @@ id: "ac-0004" status: active --- -# 검증 성공 이미지에 한정된 GHCR 게시 +# strict version-tag 검증 성공 이미지에 한정된 GHCR 게시 ## Criterion -`main` 또는 `v*` tag push의 정확한 source commit에 대해 repository가 정의한 검증 gate, image build, built-container smoke와 tested-image artifact 생성·전달·checksum·load 검증이 모두 성공한 경우에만 GitHub Actions가 registry login/push 단계에 진입해야 한다. 이 push 전 gate 중 하나라도 실패하면 registry write 없이 fail-closed 해야 한다. push 이후에만 반환되는 digest가 누락되거나 형식이 잘못되면 job은 nonzero로 종료하고 성공 output·summary를 남기지 않아야 하며, 이미 발생한 registry write를 발생하지 않은 것으로 보고해서는 안 된다. +GitHub Actions publication workflow는 strict `vX.Y.Z` tag push만 후보로 받아야 한다. 각 숫자 구성요소는 `0` 또는 leading zero 없는 non-negative decimal integer여야 하며 branch, non-push event, malformed tag, prerelease/build suffix를 거부해야 한다. workflow는 event·ref·40자리 lowercase `${GITHUB_SHA}`를 검증하고 exact source checkout 뒤 실제 `HEAD` 일치를 재검증한 다음, pinned `uv`와 repository `uv.lock`을 사용하는 full Ruff·full pytest, single image build, built-container smoke, tested image ID, archive checksum, canary scan과 immutable artifact handoff가 모두 성공한 경우에만 publish job이 registry credential과 `packages: write`를 사용해야 한다. 이 push 전 gate 중 하나라도 실패하면 registry login/push 없이 fail-closed 해야 한다. push 이후 digest 누락·형식 오류 또는 tag 간 digest 불일치는 nonzero로 종료하고 성공 output·summary를 남기지 않아야 하며, 이미 발생한 registry write를 발생하지 않은 것으로 보고해서는 안 된다. 일반 `main`/branch push는 이 workflow에서 verification이나 publication을 실행하지 않으며 별도 비게시 CI workflow는 이 criterion의 요구사항이 아니다. ## Verification -- 성공 조건: synthetic workflow fixture에서 모든 push 전 gate가 성공한 경우에만 publish job의 login/push가 실행 가능하고, push가 반환한 유효한 digest가 확인된 경우에만 성공 output과 summary가 생성된다. -- 실패·경계 조건: repository 검증, build, smoke, artifact 생성·upload·download, checksum 비교 또는 load 실패는 login/push 전 nonzero로 종료된다. push 후 digest 누락·형식 오류는 job nonzero와 성공 output·summary 부재로 이어진다. -- 검사 방법: workflow parser 기반 구조 테스트와 publication helper의 recording-runner 단위 테스트로 push 전/후 실패 시점을 분리해 검증하고, `publish.needs` 및 `packages: write`의 publish-job 한정을 정적 검사한다. 실제 최초 GHCR 실행은 별도 승인된 `main` 반영 이후 integration/release evidence로 확인한다. +- 성공 조건: synthetic strict tag-push fixture에서 exact checkout 재검증, full repository verification, single build, smoke, tested-artifact 생성·전달·checksum·load 검증을 모두 통과해야 publish job의 login/push가 실행 가능하고, 두 push가 같은 유효 digest를 반환한 뒤에만 성공 evidence가 생성된다. +- 실패·경계 조건: non-push, branch, malformed/leading-zero/prerelease/build tag, invalid source commit, checkout `HEAD` mismatch, repository 검증·build·smoke·artifact·checksum·load 실패는 registry credential/write 전에 nonzero로 종료된다. post-push digest 오류·불일치는 nonzero와 성공 evidence 부재로 이어진다. +- 검사 방법: `tests/release/test_image_contracts.py`, `tests/release/test_image_release.py`의 workflow parser·recording-runner tests로 trigger, guard 순서, exact checkout, `publish.needs`, publish-job-only `packages: write`, registry write 전후 실패 경계를 검증하고 전체 Ruff·pytest를 실행한다. 실제 tag push·GHCR write는 별도 승인된 publication evidence로 확인한다. diff --git a/.proofline/criteria/ac-0006.md b/.proofline/criteria/ac-0006.md index ee611b7..25ad508 100644 --- a/.proofline/criteria/ac-0006.md +++ b/.proofline/criteria/ac-0006.md @@ -3,14 +3,14 @@ id: "ac-0006" status: active --- -# stable SHA tag와 immutable digest 추적성 +# requester version tag·source tag와 immutable digest 추적성 ## Criterion -모든 성공 게시 이미지는 전체 40자리 lowercase hexadecimal source commit에서 결정적으로 파생된 앞 12자리 lowercase SHA tag와 전체 commit 값을 담은 `org.opencontainers.image.revision` label을 가져야 한다. SHA tag는 source를 찾기 위한 stable selector이며 배포·rollback의 불변 정본은 registry가 반환한 `sha256` digest다. `v*` tag event에서는 같은 loaded image에 해당 Git tag를 추가하지만 이동 가능한 `latest` tag는 게시하지 않아야 하며, workflow output 또는 summary는 GHCR image reference, 64-hex digest와 전체 source commit을 함께 기록해야 한다. +모든 성공 게시 이미지는 전체 40자리 lowercase hexadecimal source commit에서 결정적으로 파생된 앞 12자리 lowercase SHA tag, requester가 선택한 strict `vX.Y.Z` version tag와 전체 commit 값을 담은 `org.opencontainers.image.revision` label을 가져야 한다. version tag는 container publication authority이며 `pyproject.toml` package version과 독립적으로 취급한다. source tag와 version tag는 별도 build 없이 동일하게 검증·load된 image에 부여하고 registry가 반환한 동일 `sha256` digest를 가리켜야 한다. 이동 가능한 `latest` tag는 게시하지 않아야 하며, 성공 output·summary는 immutable GHCR image reference, 64-hex digest, 전체 source commit과 selected version tag를 함께 기록해야 한다. source tag는 source를 찾기 위한 stable selector이고 배포·rollback의 불변 정본은 registry digest다. 이미 게시된 source tag, version tag와 digest는 이 publication flow가 삭제·이동·재지정하지 않아야 한다. operator documentation은 Git version tag가 container publication authority이고 package metadata version과 독립임을 설명하며, version 선택과 tag 생성·push가 구현·검증과 분리된 requester-approved external write임을 명시해야 한다. ## Verification -- 성공 조건: `main` event는 source commit 앞 12자리 SHA tag를, `v*` event는 같은 loaded image의 SHA tag와 release tag를 생성한다. OCI revision과 summary/output의 image reference·`sha256` digest·전체 source commit이 해당 실행 입력 및 push 결과와 일치한다. -- 실패·경계 조건: source commit 형식 오류, SHA tag 파생 불일치, 빈/형식 오류 digest, source commit 불일치, release tag용 별도 build, `latest` tag 생성 또는 OCI revision 누락은 성공 output·summary를 만들 수 없다. digest 오류가 push 이후 발견되면 job은 nonzero로 종료한다. -- 검사 방법: synthetic `main`/`v*` event와 유효·무효 commit/digest를 publication helper에 입력하는 단위 테스트, Docker image label inspection, workflow의 tag/summary 정적 검사 및 `latest` 생성 금지 회귀 검사를 실행한다. +- 성공 조건: strict `vX.Y.Z` tag event는 같은 loaded image에 `:`와 `:vX.Y.Z`를 만들고 두 push가 동일한 digest를 반환한다. OCI revision과 output·summary의 immutable image reference, digest, source commit, version tag가 event와 push 결과에 정확히 일치하며 package version 값은 tag 생성·검증에 사용되지 않는다. 운영 문서는 version authority·package version 독립성·별도 승인 tag push 경계를 모두 설명하고 기존 published identity를 보존한다. +- 실패·경계 조건: source commit 또는 version tag 형식 오류, SHA tag 파생 불일치, version/package version 일치 강제, tag별 별도 build, `latest` 생성, OCI revision 불일치, digest 누락·형식 오류·tag 간 불일치가 있으면 성공 evidence를 생성할 수 없다. 기존 published tag·digest의 삭제·이동·재지정 또는 operator documentation의 version authority·별도 승인 경계 누락도 FAIL이다. push 이후 오류는 job nonzero로 유지한다. +- 검사 방법: `scripts/image_release.py`의 trigger/tag/publish helper 단위 테스트와 workflow contract test로 deterministic tag, same-loaded-image, no rebuild, same digest, no-`latest`와 output·summary exactness를 검증하고 Docker image label을 inspect한다. `docs/operations.md` contract test로 Git tag authority, package version 독립성과 requester-approved tag creation/push 경계를 검사하고, workflow·helper가 기존 published registry identity를 삭제·이동·재지정하는 command를 포함하지 않는지 정적 검사한다. 실제 registry의 두 tag·digest와 기존 identity 보존은 별도 승인된 publication run에서 immutable evidence로 확인한다. diff --git a/.proofline/criteria/ac-0008.md b/.proofline/criteria/ac-0008.md index fc28f50..917efdf 100644 --- a/.proofline/criteria/ac-0008.md +++ b/.proofline/criteria/ac-0008.md @@ -3,14 +3,14 @@ id: "ac-0008" status: active --- -# 운영 설정과 자격증명의 이미지 비포함 +# locked runtime build input과 운영 설정·자격증명의 이미지 비포함 ## Criterion -`trex-core` Dockerfile은 package 설치에 필요한 `pyproject.toml`과 `trex_core/`만 application source로 copy하고 repository 전체를 copy하지 않아야 한다. `.dockerignore`는 최소한 `.git`, `.env`, `.env.*`, `config/`와 `.proofline/`을 build context에서 제외해야 한다. image filesystem·history·inspect metadata와 export archive에는 운영 per-instance TOML, `.env`, credential, token, private key, 실제 connection string 또는 synthetic canary marker가 없어야 한다. daemon의 필수 config와 secret은 runtime에 read-only mount, secret 또는 environment로만 주입하고, 문서는 digest pin과 이전 digest rollback을 안내하며 `trex-core-reset`을 자동 rollback 절차에 포함하지 않아야 한다. +`trex-core` Dockerfile은 runtime dependency 설치에 필요한 pinned `uv` tool, `pyproject.toml`, repository-owned `uv.lock`과 allowlisted `trex_core/` package source만 application build input으로 copy하고 repository 전체를 copy하지 않아야 한다. runtime environment는 lockfile을 실제 소비하는 `uv sync --locked --no-dev --no-editable` 또는 의미상 동등한 명령으로 생성해야 한다. `.dockerignore`는 최소한 `.git`, `.env`, `.env.*`, `config/`와 `.proofline/`을 build context에서 제외해야 한다. image filesystem·history·inspect metadata와 export archive에는 운영 per-instance TOML, `.env`, credential, token, private key, 실제 connection string 또는 synthetic canary marker가 없어야 한다. 필수 config와 secret은 runtime에 read-only mount, secret 또는 environment로만 주입하고, 문서는 digest pin과 이전 digest rollback을 안내하며 `trex-core-reset`을 자동 rollback 절차에 포함하지 않아야 한다. ## Verification -- 성공 조건: 임시 build context의 제외 대상 `.env.ci-canary`에 고정 marker `TREX_SECRET_CANARY_DO_NOT_SHIP`을 둔 상태로 이미지를 빌드해도 marker가 image filesystem, `docker history --no-trunc`, `docker image inspect` 결과와 exported image archive 어디에서도 발견되지 않는다. Dockerfile에는 `COPY .`가 없고 runtime 문서는 외부 주입과 digest rollback 경계를 설명한다. -- 실패·경계 조건: 필수 ignore path 누락, repository 전체 copy, synthetic canary 또는 금지 파일·값이 검사 surface에 존재하면 FAIL이다. helper의 locally captured stdout/stderr에 canary가 노출되거나 rollback 안내가 DB reset·자동 data mutation을 실행하도록 제시해도 FAIL이다. -- 검사 방법: Dockerfile·`.dockerignore` contract test, synthetic canary가 있는 임시 context의 실제 image build, filesystem/history/inspect/export archive scan, helper의 local output 검사와 runtime documentation contract test를 실행한다. 실제 credential이나 실제 운영 connection string은 fixture·명령·evidence에 사용하지 않는다. +- 성공 조건: Dockerfile의 copy/install allowlist에 pinned `uv`, `pyproject.toml`, `uv.lock`, package source만 존재하고 locked runtime sync가 성공한다. 제외 대상 `.env.ci-canary`에 고정 marker `TREX_SECRET_CANARY_DO_NOT_SHIP`을 둔 build에서도 marker가 filesystem, `docker history --no-trunc`, `docker image inspect`와 exported archive 어디에도 없으며 runtime 문서는 외부 주입과 digest rollback 경계를 설명한다. +- 실패·경계 조건: missing/mismatched lockfile, unlocked `pip install .` 등 lock 우회, 필수 ignore 누락, broad `COPY .`, synthetic canary 또는 금지 파일·값의 검사 surface 노출은 FAIL이다. helper stdout/stderr에 canary가 노출되거나 rollback 안내가 DB reset·자동 data mutation을 포함해도 FAIL이다. +- 검사 방법: `tests/release/test_image_contracts.py`의 Dockerfile·`.dockerignore`·documentation contract tests, 의도적 `pyproject.toml`/`uv.lock` mismatch build, synthetic canary가 있는 실제 image build, filesystem/history/inspect/export archive scan과 helper local-output 검사를 실행한다. 실제 credential이나 운영 connection string은 fixture·명령·evidence에 사용하지 않는다. diff --git a/.proofline/criteria/ac-0014.md b/.proofline/criteria/ac-0014.md new file mode 100644 index 0000000..d1ddd56 --- /dev/null +++ b/.proofline/criteria/ac-0014.md @@ -0,0 +1,16 @@ +--- +id: "ac-0014" +status: active +--- + +# repository-owned lockfile 기반 runtime dependency identity + +## Criterion + +repository verification environment와 published container의 runtime environment는 같은 revision의 repository-owned `uv.lock` dependency resolution을 사용해야 한다. version-tag verification은 pinned `uv`로 `uv sync --extra dev --locked`를 수행해야 하고, Docker runtime stage는 같은 `pyproject.toml`과 `uv.lock`을 입력으로 `uv sync --locked --no-dev --no-editable` 또는 의미상 동등한 runtime-only locked installation을 수행해야 한다. lockfile이 없거나 project metadata와 불일치하거나 install command가 lock resolution을 우회하면 image build와 publication은 fail-closed 해야 한다. Git publication tag와 Python package metadata version의 독립성은 이 lock identity를 변경하지 않는다. + +## Verification + +- 성공 조건: 동일 source revision의 `pyproject.toml`과 `uv.lock`으로 dev verification sync와 runtime-only image sync가 모두 성공하며 built image에서 `trex_core` import, `trex-core-daemon`, `trex-core`, `trex-core-reset` CLI와 canonical SQL migration inventory가 network 없이 동작한다. +- 실패·경계 조건: missing lockfile, project metadata/lock mismatch, `--locked` 누락, runtime dependency를 새로 resolve하는 install, dev dependency의 runtime 포함 또는 editable install은 build/publication 전에 FAIL이다. tag version과 package version 불일치 자체는 실패 조건이 아니다. +- 검사 방법: workflow·Dockerfile contract tests로 pinned `uv`와 두 locked sync command를 검사하고, 정상 lockfile의 실제 Docker build·built-container smoke와 의도적으로 불일치시킨 `pyproject.toml`/`uv.lock` build failure를 실행한다. release 집중 테스트와 full repository regression을 함께 실행한다. diff --git a/.proofline/identities.json b/.proofline/identities.json index 42fa78c..b5cd855 100644 --- a/.proofline/identities.json +++ b/.proofline/identities.json @@ -1,5 +1,5 @@ { "schema_version": 1, - "next_line_number": 4, - "next_ac_number": 14 + "next_line_number": 5, + "next_ac_number": 15 } diff --git a/.proofline/lines/line-0004/dcy-0004.md b/.proofline/lines/line-0004/dcy-0004.md new file mode 100644 index 0000000..f896860 --- /dev/null +++ b/.proofline/lines/line-0004/dcy-0004.md @@ -0,0 +1,79 @@ +--- +id: "dcy-0004" +status: confirmed +--- +# requester-versioned·runtime-locked image publication + +## Problem + +현재 `.github/workflows/publish-image.yml`은 `main`과 `v*` push 모두에서 GHCR publication을 실행한다. 이 때문에 문서·governance-only `main` commit도 새 registry artifact를 만들며, publication을 요청자가 선택한 release version과 분리해서 통제할 수 없다. + +repository verification은 `uv sync --extra dev --locked`를 사용하지만 현재 `Dockerfile`은 `pyproject.toml`만 복사한 뒤 `pip install .`을 실행한다. 따라서 CI 검증 환경과 built image의 runtime dependency graph가 동일한 repository-owned `uv.lock` resolution을 사용한다는 보장이 없다. + +이 Discovery는 기존의 single build, built-image smoke, image ID, archive SHA-256, canary scan, OCI source revision, rebuild 없는 publish와 multi-tag same-digest 계약을 유지하면서 publication authority를 strict requester-selected version tag로 제한하고 runtime dependency identity를 lockfile에 결속한다. + +## Evidence + +- GitHub issue #57 `https://github.com/fourblocks2020/trex-core/issues/57`은 requester-versioned·runtime-locked publication 변경과 완료 조건을 기록한 원본 제안이다. +- 요청자는 모든 OQ에서 정확히 하나의 선택지를 선택한 뒤 이슈 본문 갱신과 Discovery 승인을 명시적으로 지시했다. +- 승인 결정에 따라 `vX.Y.Z` Git tag는 container publication version authority이며 `pyproject.toml`의 `[project].version`과 독립적이다. 두 값을 일치시키는 검증이나 package version 변경은 요구하지 않는다. +- 승인 결정에 따라 별도 비게시 CI를 추가하지 않는다. full Ruff와 full pytest는 strict version-tag publication gate에서 실행하고, 일반 `main`/branch push에는 이 Discovery가 별도 CI workflow를 추가하지 않는다. +- 조사 기준 source revision은 `1a2b50072238ea72186d99b3ec951fc9511100aa`이며 조사 시 `main`과 `origin/main`은 동기화되어 있고 worktree는 clean이었다. +- `.github/workflows/publish-image.yml`은 현재 `main`과 `v*` push를 모두 trigger로 사용하고, exact `github.sha` checkout 후 `uv sync --extra dev --locked`, full Ruff, full pytest, single Docker build, built-image smoke, image ID 기록, archive export·canary scan·SHA-256 기록과 immutable artifact handoff를 수행한다. 별도 publish job만 `packages: write`를 가지며 tested artifact를 재빌드 없이 게시한다. +- `Dockerfile`은 현재 `pyproject.toml`과 `trex_core/`만 copy한 뒤 `pip install --no-cache-dir .`을 실행하므로 `uv.lock`을 runtime dependency installation input으로 사용하지 않는다. +- `scripts/image_release.py::release_tags()`는 현재 `refs/heads/main`을 허용하고 `v`로 시작하는 넓은 tag 형식을 허용한다. publish helper는 archive checksum, tested/loaded image ID, OCI revision, registry credential 경계, 두 tag의 same-digest와 성공 evidence 생성을 검증하지만 strict `vX.Y.Z` event만 허용하지는 않는다. +- `tests/release/test_image_contracts.py`는 현재 `main`/`v*` trigger와 Dockerfile의 기존 COPY allowlist를 고정하고 있어 승인된 trigger·runtime lock 계약에 맞춰 변경해야 한다. +- `docs/operations.md`는 source-derived tag를 stable selector로, registry digest를 immutable deployment/rollback identity로 설명하고 runtime config·secret 외부 주입 및 reset 분리 경계를 보존한다. version tag 생성·push가 별도 사용자 승인 외부 쓰기라는 절차는 아직 설명하지 않는다. +- 기존 active AC 중 AC-0004는 `main` 또는 `v*` event의 verification-gated publication, AC-0006은 source tag·release tag·digest 추적성, AC-0008은 Docker COPY allowlist와 secret/config 비포함을 소유한다. AC-0005의 tested-artifact identity와 AC-0007의 built-container smoke는 이번 변경에서도 의미를 유지한다. +- 비교 기준 `trex-mega-swing-v2` revision `88e90caea7e4ab740ed785fc1f57aed8b6f2da5f`의 workflow는 strict `vX.Y.Z` tag-only trigger, event/ref/commit fail-closed validation, exact tagged commit checkout, locked verify, single build와 tested-artifact publication을 사용한다. workflow run `31468042611`은 `v0.1.0` tag에서 성공했다. +- 기준 revision에서 `proofline validate`는 exit `0`, `uv run ruff check .`은 `All checks passed!`, `uv run pytest -q`는 `1040 passed, 51 skipped`를 반환했다. skip은 환경 의존 integration 경계이며 현재 repository baseline이 승인된 변경을 이미 구현했다는 의미는 아니다. + +## Scope + +- AC admission은 기존 동작의 권한·식별자·build input을 변경하는 `update`와 새로운 runtime lock 동작을 정의하는 `create`다. + - `update`: AC-0004의 publication event를 일반 `main`/`v*`에서 strict version-tag-only로 변경하고 malformed/non-version event가 registry credential·write 전에 실패하도록 한다. + - `update`: AC-0006에 strict requester-selected `vX.Y.Z` version tag, source-derived tag와 version tag의 same-digest, version을 포함한 publication evidence를 반영한다. + - `update`: AC-0008의 좁은 Docker build input allowlist에 repository-owned `uv.lock`과 locked installation에 필요한 도구만 추가하면서 기존 config·credential·canary 비포함 경계를 보존한다. + - `create`: repository verification과 runtime image가 동일한 repository-owned lock resolution을 사용하고 lock mismatch 또는 unlocked runtime install을 거부하는 독립적인 장기 AC를 추가한다. + - AC-0005의 tested-artifact identity와 AC-0007의 built-container package·entrypoint smoke는 변경 없이 유지한다. +- GHCR publication workflow의 유일한 trigger는 requester가 exact source commit에 생성·push한 strict `vX.Y.Z` tag다. 각 숫자 구성요소는 `0` 또는 leading zero가 없는 non-negative decimal integer여야 하며 prerelease/build suffix, malformed tag, branch ref와 non-push event는 허용하지 않는다. +- workflow는 event·ref·40자리 lowercase source commit을 registry credential 사용 전에 fail-closed로 검증하고, exact tagged commit을 checkout했음을 다시 확인한다. +- version tag는 container publication identity이며 `pyproject.toml`의 `[project].version`과 독립적으로 취급한다. package version 일치 검사, 자동 version 증분과 package metadata 변경을 수행하지 않는다. +- 일반 `main`과 branch push는 registry login, `docker push`, `packages: write` 또는 image publication을 수행하지 않는다. 요청자 결정에 따라 이번 Scope는 일반 `main`/branch push를 위한 별도 비게시 CI workflow를 추가하지 않는다. +- 허용된 version-tag event는 exact source checkout 후 pinned `uv`와 repository-owned `uv.lock`으로 full Ruff와 full pytest를 실행하고, 성공한 경우에만 이미지를 한 번 빌드한다. +- Docker build는 `pyproject.toml`, `uv.lock`과 allowlisted package source로 runtime environment를 `uv sync --locked --no-dev --no-editable` 또는 의미상 동등한 locked 방식으로 설치한다. lock mismatch, missing lockfile 또는 lock을 우회한 runtime dependency install은 build/publication 전에 실패한다. +- 동일한 tested image에 `:`와 `:vX.Y.Z`를 부여하고 두 tag가 동일한 registry digest를 가리키는지 확인한다. immutable deployment·rollback identity는 `@sha256:`다. +- 기존 `scripts/image_release.py`의 archive checksum, tested/loaded image ID, OCI revision, canary surface scan, no-rebuild publication, registry credential 경계와 multi-tag same-digest 검증을 유지한다. +- `latest`를 생성하지 않으며 성공 evidence에는 source revision, immutable image reference, digest와 selected version tag를 함께 기록한다. +- workflow contract와 helper tests는 일반 branch/main non-publication, strict event validation, exact checkout, lock mismatch, locked runtime build, same-digest tags, no-`latest`, no-rebuild 및 기존 failure boundaries를 검증한다. +- operator documentation은 version 선택과 Git tag 생성·push가 구현과 분리된 사용자 승인 외부 쓰기이고, tag push가 verify/publication을 시작한다는 점을 설명한다. + +## Out of Scope + +- 이 Discovery 또는 후속 구현 중 concrete version 선택, version tag 생성·push, 최초·후속 GHCR package write, production deployment 또는 운영 서버 pull/restart +- 일반 `main`/branch push를 위한 별도 lint/test CI workflow 신설 또는 기존 publication workflow 외 CI 정책 변경 +- `pyproject.toml` package version 변경, version tag와 package version의 일치 강제 또는 자동 version 증분 +- 기존 published tag·digest 삭제, 이동 또는 registry retention 변경 +- live credential, 실제 account·database·RabbitMQ·Redis·KIS·portfolio-hub 연결, database migration/reset 또는 운영 데이터 변경 +- image signing, SBOM, provenance attestation, multi-architecture build와 moving `latest` +- 다른 TREX repository의 workflow, image 또는 release policy 변경 + +## Risks and Unknowns + +### Risks + +- trigger 변경 후 일반 `main` push는 새 runtime image뿐 아니라 현재 publication workflow가 제공하던 full Ruff/pytest도 실행하지 않는다. 이는 요청자가 선택한 정책이며, branch protection 또는 지속적 검증이 필요해지면 registry 권한이 없는 별도 CI 변경으로 다룬다. +- version tag와 package version을 독립적으로 두면 image `:vX.Y.Z`와 installed Python package metadata version이 다를 수 있다. container publication version authority는 Git tag임을 문서화하고, package version synchronization이 필요해지면 별도 변경으로 다룬다. +- GitHub trigger glob만으로는 malformed `v*.*.*`를 모두 배제할 수 없다. workflow 내부 helper가 strict ref/event/commit을 registry credential 전에 재검증해야 한다. +- Docker build가 lockfile을 copy만 하고 실제 runtime install에 소비하지 않으면 CI lock PASS만으로 runtime reproducibility를 주장할 수 없다. build contract와 tests가 locked runtime command 및 mismatch failure를 직접 검증한다. +- version tag와 source-derived tag를 별도 build에서 만들면 같은 release identity가 서로 다른 image를 가리킬 수 있다. 단일 tested artifact를 재빌드 없이 두 tag로 push하고 registry digest equality를 확인한다. +- 기존 commit-derived selector와 immutable digest는 보존해야 하며 migration 과정에서 과거 tag를 삭제하거나 이동하지 않는다. +- tag 생성·push는 즉시 publication workflow와 registry write를 유발할 수 있다. operator 문서가 이를 별도 사용자 승인 외부 쓰기로 명시하고 구현·테스트 중 실제 tag push를 금지한다. + +### Approval State + +- Discovery status: `confirmed` +- 승인 근거: 요청자가 이슈의 모든 OQ에서 하나의 선택지를 명시적으로 선택한 뒤 이슈 본문 업데이트와 승인을 지시했다. +- 채택 결정: version tag와 package version은 독립적으로 취급하며, 일반 `main`/branch push용 별도 비게시 CI는 추가하지 않는다. +- 추가로 필요한 제품 결정: 없음 +- 이 승인은 Discovery 범위 확인이며 Requirement/AC 승인, 구현, tag 생성·push, GHCR publication, delivery, release 또는 deployment 완료를 의미하지 않는다. diff --git a/.proofline/lines/line-0004/evidence/implementation-complete.md b/.proofline/lines/line-0004/evidence/implementation-complete.md new file mode 100644 index 0000000..b14a3c6 --- /dev/null +++ b/.proofline/lines/line-0004/evidence/implementation-complete.md @@ -0,0 +1,59 @@ +# 구현 완료 evidence + +이 파일은 ProofLine canonical lifecycle artifact가 아닌 GitHub issue comment 원문 evidence입니다. 기록된 구현·테스트 결과는 로컬 기능 브랜치의 사후 증거이며 ProofLine delivery closure, publication, release 또는 deployment 완료를 의미하지 않습니다. + +- Source URL: https://github.com/fourblocks2020/trex-core/issues/57#issuecomment-5290864375 +- Comment ID: `5290864375` +- Node ID: `IC_kwDOSvywKc8AAAABO1wu9w` +- Author: `genichin` +- Created at: `2026-08-14T07:47:03Z` +- Updated at: `2026-08-14T07:47:03Z` +- Original body SHA-256: `2a57a0b702957cb534cc9aa35e08618e76e38d9da5d1926e8055f84973783b51` +- Captured from GitHub API: `2026-08-14T16:51:15+09:00` + +## Original Comment Body + + +## 구현 완료 + +승인된 #57 범위의 requester-versioned·runtime-locked image publication 구현과 독립 검증을 완료했습니다. + +### 구현 내용 + +- GHCR publication trigger를 strict `vX.Y.Z` tag push로 제한하고 일반 `main`/branch push, non-push event, malformed·leading-zero·prerelease/build tag를 fail-closed 처리 +- exact `${GITHUB_SHA}` checkout 후 실제 `git rev-parse HEAD`를 다시 비교하여 source identity 검증 +- Git tag version을 `pyproject.toml` package version과 독립적인 container publication authority로 유지 +- Docker runtime dependency 설치가 repository-owned `uv.lock`을 실제로 소비하도록 `uv sync --locked --no-dev --no-editable` 적용 +- 기존 full Ruff·full pytest publication gate와 single build, built-image smoke, tested image ID, archive SHA-256, canary scan, OCI revision, no-rebuild publish 계약 보존 +- source-derived tag와 version tag를 같은 tested image에 부여하고 동일 registry digest를 가리키는지 검증 +- 성공 output·summary에 immutable image reference, digest, source commit과 selected version tag를 함께 기록하고 `latest` 생성 금지 +- operator documentation에 version tag 생성·push가 구현과 분리된 별도 사용자 승인 외부 쓰기임을 명시 +- 초기 후보의 checkout 재검증·version evidence 누락을 별도 후속 커밋에서 보완하여 이력을 보존 + +### 검증 결과 + +Release 집중·전체 회귀, 정적 검사, ProofLine validation, Docker build/smoke와 독립 read-only 리뷰를 모두 통과했으며 승인 차단 finding은 없습니다. + +- 최종 HEAD: `e3fa8243d926efd0b81463dbfc5403cf6e4889f9` +- 최종 tree: `ea05e23139965abed1f6a454c4ca2b5d356f8ab9` +- Release 집중 테스트: `75 passed` +- 전체 테스트: `1065 passed, 51 skipped` +- 전체 Ruff: `All checks passed!` +- `proofline validate`: exit `0` +- `git diff --check`: PASS +- checkout mismatch fail-closed 실동작: PASS +- Docker build, built-image smoke, image ID, archive export·checksum, canary scan: PASS +- image user `10001:10001`, `trex-core-daemon` entrypoint와 OCI source revision 확인 +- 독립 read-only 리뷰: **PASS**, `mutation=false`, 승인 차단 finding 없음 +- 기능 브랜치 `feat/issue-57-versioned-locked-publication`과 worktree: clean + +### 비차단 후속 권고 + +- `TREX_POSTGRESQL_TEST_DSN`이 준비되면 PostgreSQL integration 41건을 실제 DB에서 재실행 +- `TREX_RABBITMQ_TEST_URL`이 준비되면 RabbitMQ integration 9건을 재실행 +- 안전한 KIS sandbox credentials가 준비되면 sandbox integration 1건을 재실행 +- 로컬에 `actionlint`를 마련하거나 향후 GitHub workflow 실행에서 Actions-level YAML·shell 해석을 추가 확인 +- version tag 생성·push와 GHCR publication은 별도 사용자 승인 후 수행하고, 게시 결과의 source/version tag가 동일 digest를 가리키는지 실제 registry evidence로 확인 + +> 현재 상태는 **격리 기능 브랜치의 로컬 구현·검증·커밋 완료**입니다. push·PR·main 반영·version tag 생성·GHCR 게시·배포·릴리스 완료를 의미하지 않습니다. + diff --git a/.proofline/lines/line-0004/evidence/implementation-progress.md b/.proofline/lines/line-0004/evidence/implementation-progress.md new file mode 100644 index 0000000..552d72f --- /dev/null +++ b/.proofline/lines/line-0004/evidence/implementation-progress.md @@ -0,0 +1,63 @@ +# 구현 진행 상황 evidence + +이 파일은 ProofLine canonical lifecycle artifact가 아닌 GitHub issue comment 원문 evidence입니다. 기록된 구현·테스트 결과는 로컬 기능 브랜치의 사후 증거이며 ProofLine delivery closure, publication, release 또는 deployment 완료를 의미하지 않습니다. + +- Source URL: https://github.com/fourblocks2020/trex-core/issues/57#issuecomment-5290665935 +- Comment ID: `5290665935` +- Node ID: `IC_kwDOSvywKc8AAAABO1knzw` +- Author: `genichin` +- Created at: `2026-08-14T07:22:00Z` +- Updated at: `2026-08-14T07:41:51Z` +- Original body SHA-256: `c9631a1402a51de699676a4d8791c206e9b6f4e197d134e16027cdc179f96c5f` +- Captured from GitHub API: `2026-08-14T16:51:15+09:00` + +## Original Comment Body + + +## 구현 진행 상황 + +- **대상:** [Discovery] requester-versioned·runtime-locked image publication +- **브랜치:** `feat/issue-57-versioned-locked-publication` +- **기준:** `main` (`1a2b50072238ea72186d99b3ec951fc9511100aa`) +- **상태:** 🟢 로컬 구현·검증 완료 — 독립 리뷰 PASS +- **최종 업데이트:** 2026-08-14 16:41:50 KST + +### 구현 계획 및 작업 목록 + +- [x] **1. 기존 게시 안전장치와 변경 영향 범위 확인** + - tag trigger, 검증 순서, tested-image handoff, digest·canary·secret 경계와 기존 회귀 테스트를 기준선으로 고정합니다. +- [x] **2. 요청자 버전 태그 전용 게시 흐름 구현** + - strict `vX.Y.Z` tag push만 허용하고 일반 `main`/branch push와 malformed event는 registry write 전에 차단합니다. +- [x] **3. 컨테이너 runtime dependency lock 적용** + - repository의 `uv.lock`을 실제 runtime 설치에 사용하고 lock mismatch·unlocked 설치를 fail-closed 처리합니다. +- [x] **4. 이미지 식별자·게시 근거와 운영 문서 갱신** + - source tag와 version tag의 same-digest, no-`latest`, source/version/digest evidence 및 tag push 승인 경계를 반영합니다. +- [x] **5. 회귀 테스트와 전체 검증 수행** + - release contract 집중 테스트, 전체 Ruff, 전체 pytest, ProofLine validation과 가능한 local image build/smoke를 실제 실행합니다. +- [x] **6. 독립 검토와 최종 구현 근거 정리** + - 구현자와 분리된 read-only 검토를 받고, 반려 시 보완·재검증한 뒤 최종 commit과 검증 결과를 기록합니다. + +### 진행 기록 + +- 승인된 #57 Discovery 본문과 OQ 결정(A: package version 독립, B: 일반 main/branch용 별도 CI 미추가)을 구현 범위의 기준선으로 고정했습니다. +- 격리 worktree와 기능 브랜치를 `1a2b50072238ea72186d99b3ec951fc9511100aa`에서 생성했습니다. +- 기준선 확인 완료: 기존 workflow의 single build→smoke→image ID→archive checksum/canary scan→tested artifact handoff→no-rebuild publish와 publish-job-only `packages: write` 경계를 확인했습니다. +- AC 영향 범위 확인: AC-0004·AC-0006·AC-0008 update, runtime lock AC create, AC-0005·AC-0007 유지 경계로 고정했습니다. +- 변경 전 기준선 검증: `proofline validate` PASS, 전체 Ruff PASS, 전체 pytest `1040 passed, 51 skipped`; 기준 branch와 worktree는 clean입니다. +- version tag 생성·push, GHCR publication, PR, main 반영, release와 deployment는 수행하지 않습니다. +- 초기 구현 commit `cb8fcee226ab71f522fe1bbef35d60197947850c` 생성: strict tag-only trigger와 runtime `uv.lock` 설치, 기존 release safety contract 및 운영 문서 변경을 포함합니다. +- 초기 후보 검증: release 집중 `71 passed`, 전체 `1061 passed, 51 skipped`, Ruff·ProofLine·diff check PASS. skip은 PostgreSQL 41건, RabbitMQ 9건, KIS sandbox 1건입니다. +- 팀장 diff 검토에서 승인 계약 누락 2건을 확인해 최종 완료를 보류했습니다: (1) checkout 후 실제 `HEAD == GITHUB_SHA` 재검증 없음, (2) 성공 output/summary에 selected version tag evidence 없음. +- 위 2건은 계획 변경이 아니라 승인된 #57의 결함 보완이며, 초기 후보 위에 별도 수정 commit을 만들고 전체 검증·독립 리뷰를 다시 수행합니다. +- 보완 commit `e3fa8243d926efd0b81463dbfc5403cf6e4889f9` 생성: checkout HEAD 재검증과 selected version tag output/summary evidence를 추가했고 초기 커밋은 보존했습니다. +- 팀장 최종 후보 재검증: release 집중 `75 passed`, 전체 `1065 passed, 51 skipped`, Ruff·ProofLine·diff check PASS, checkout mismatch fail-closed 실동작 확인. +- Docker 재검증: built-image smoke, image ID, archive export/checksum, canary scan PASS; non-root `10001:10001`, daemon entrypoint와 OCI revision을 확인했습니다. +- 구현·검증 항목 2~5를 완료했으며, 최종 후보 `e3fa824`에 고정한 독립 read-only 리뷰를 진행합니다. +- 독립 read-only 리뷰 최종 **PASS** (`mutation=false`, target `e3fa8243d926efd0b81463dbfc5403cf6e4889f9`): release `75 passed`, 전체 `1065 passed, 51 skipped`, Ruff·ProofLine·diff check PASS, 승인 차단 finding 없음. +- skip 분류: PostgreSQL integration 41건(DSN 없음), RabbitMQ integration 9건(URL 없음), KIS sandbox 1건(credentials 없음). +- 독립 리뷰의 비차단 참고: 새 review environment는 `uv sync --extra dev --locked` 후 검증했으며, candidate Docker build/registry write는 리뷰에서 수행하지 않았습니다. Docker contract는 구현자와 팀장이 별도로 실제 build/smoke/scan으로 확인했습니다. +- 최종 기능 브랜치 HEAD와 tree는 각각 `e3fa8243d926efd0b81463dbfc5403cf6e4889f9`, `ea05e23139965abed1f6a454c4ca2b5d356f8ab9`; worktree clean. 임시 detached review worktree는 검토 후 정리했습니다. +- 현재 완료 경계는 격리 기능 브랜치의 로컬 구현·검증·커밋입니다. push, PR, main 반영, tag 생성·push, GHCR publication, release와 deployment는 수행하지 않았습니다. + +> 각 작업이 실제로 완료되고 검증될 때마다 이 댓글의 체크박스와 진행 기록을 갱신한다. 체크 표시는 구현 완료 또는 해당 검증의 실제 통과를 의미하며, 배포·릴리스 완료를 의미하지 않는다. + diff --git a/.proofline/lines/line-0004/line-0004.md b/.proofline/lines/line-0004/line-0004.md new file mode 100644 index 0000000..daa512d --- /dev/null +++ b/.proofline/lines/line-0004/line-0004.md @@ -0,0 +1,3 @@ +--- +id: "line-0004" +--- diff --git a/.proofline/lines/line-0004/req-0004.md b/.proofline/lines/line-0004/req-0004.md new file mode 100644 index 0000000..048b527 --- /dev/null +++ b/.proofline/lines/line-0004/req-0004.md @@ -0,0 +1,62 @@ +--- +id: "req-0004" +status: approved +discovery: "dcy-0004" +criteria: + create: + - "ac-0014" + update: + - "ac-0004" + - "ac-0006" + - "ac-0008" + retire: [] + satisfy: [] +--- + +# requester-versioned·runtime-locked image publication + +## Objective + +GHCR image publication authority를 요청자가 exact source commit에 생성·push하는 strict `vX.Y.Z` Git tag로 제한하고, repository verification과 container runtime installation이 동일한 repository-owned `uv.lock` resolution을 사용하게 한다. 기존의 검증 선행, single build, built-image smoke, tested artifact identity, canary·secret 방어, no-rebuild publication과 multi-tag same-digest 계약은 유지한다. + +## Scope + +- GHCR publication workflow의 유일한 trigger를 strict `vX.Y.Z` tag push로 제한한다. 숫자 구성요소는 `0` 또는 leading zero 없는 non-negative decimal integer이며 prerelease/build suffix, malformed tag, branch ref와 non-push event를 거부한다. +- event, ref와 40자리 lowercase source commit을 registry credential 또는 write 전에 fail-closed로 검증하고, exact `${GITHUB_SHA}` checkout 뒤 실제 `HEAD`를 다시 비교한다. +- strict version-tag event에서 pinned `uv`와 repository-owned `uv.lock`으로 full Ruff와 full pytest를 실행하고, 성공한 경우에만 이미지를 한 번 빌드한다. +- 일반 `main`과 branch push에서는 registry login, `docker push`, `packages: write`와 image publication을 수행하지 않으며, 요청자 결정에 따라 별도 비게시 CI workflow를 추가하지 않는다. +- Docker runtime environment는 `pyproject.toml`, `uv.lock`과 allowlisted package source만으로 `uv sync --locked --no-dev --no-editable` 또는 의미상 동등한 locked install을 수행한다. missing/mismatched lockfile 또는 unlocked install은 build/publication 전에 실패한다. +- single built image에 source commit 앞 12자리 tag와 selected `vX.Y.Z` tag를 부여하고 두 push 결과가 동일 digest인지 확인한다. `latest`는 생성하지 않는다. +- archive checksum, tested/loaded image ID, OCI revision, built-image package·CLI·migration smoke, canary surface scan, artifact handoff와 publish-job-only registry credential 경계를 유지한다. +- push 성공과 digest 검증 뒤에만 immutable image reference, digest, 전체 source commit과 selected version tag를 output·summary evidence로 기록한다. push 후 오류를 registry write 미발생으로 표현하지 않는다. +- operator documentation은 container publication version authority가 Git tag이고 package metadata version과 독립임을 설명하며, version 선택과 tag 생성·push가 구현·검증과 분리된 requester-approved external write임을 명시한다. +- workflow/parser/helper/Docker contract tests는 strict trigger, exact checkout, lock mismatch, locked runtime install, same-digest/no-`latest`, no-rebuild와 기존 실패 경계를 독립적으로 검증한다. + +## Constraints + +- Git tag version과 `pyproject.toml`의 `[project].version`을 일치시키거나 자동 증분하지 않는다. +- 기존 commit-derived selector와 immutable digest를 보존하고 기존 published tag·digest를 삭제하거나 이동하지 않는다. +- repository 전체를 Docker build input으로 copy하지 않으며 runtime config, `.env`, credential, private key, 실제 connection string, ProofLine artifact와 synthetic canary를 image에 포함하지 않는다. +- package write permission과 registry credential은 검증 job이 아닌 gated publish job에만 부여한다. +- 실제 account·database·RabbitMQ·Redis·KIS·portfolio-hub 연결, 운영 migration/reset과 다른 TREX repository 계약을 변경하지 않는다. +- Normative Design Documents: 없음. 이 REQ와 active AC가 normative specification을 소유한다. + +### Current Implementation Assessment + +- 이 문서는 이미 로컬 기능 브랜치에서 구현된 GitHub issue #57을 현재 ProofLine schema에 사후 명세화한 것이다. 과거 구현이 ProofLine delivery chronology를 따랐다는 뜻이 아니다. +- 구현은 `feat/issue-57-versioned-locked-publication`의 local commit `e3fa8243d926efd0b81463dbfc5403cf6e4889f9`(tree `ea05e23139965abed1f6a454c4ca2b5d356f8ab9`)에 있으며, baseline `1a2b50072238ea72186d99b3ec951fc9511100aa` 위 두 개의 append-only commit으로 기록되었다. 현재 local `main`과 `origin/main`에는 아직 반영되지 않았다. +- issue comment evidence에는 release 집중 `75 passed`, 전체 `1065 passed, 51 skipped`, Ruff·ProofLine·diff check, checkout mismatch fail-closed, Docker build·smoke·image ID·archive checksum·canary scan과 독립 read-only review `PASS`가 기록되어 있다. +- 환경 의존 PostgreSQL 41건, RabbitMQ 9건, KIS sandbox 1건은 설정·credential 부재로 skip되었다. 로컬 `actionlint`도 실행 파일 부재로 수행되지 않았으며 향후 hosted workflow 실행 또는 별도 도구로 확인할 비차단 검증 공백이다. +- version tag 생성·push, GHCR write, PR, main 반영, runtime rollout, deployment와 release는 수행되지 않았다. 따라서 live registry same-digest와 hosted Actions 실행 결과는 현재 `unverified` evidence다. +- 이 REQ의 `approved`와 AC의 `active`는 현재 specification authority를 나타내며 구현 통합, publication, delivery closure, release 또는 deployment 완료를 의미하지 않는다. + +## Non-Goals + +- concrete version 선택, version tag 생성·push, 최초·후속 GHCR package write, production deployment, 운영 서버 pull/restart와 post-deployment verification +- 일반 `main`/branch push용 별도 lint/test CI workflow 또는 branch protection 정책 신설 +- package version 변경, Git tag와 package version 일치 강제 또는 자동 version 증분 +- 기존 published tag·digest의 삭제·이동 또는 registry retention 변경 +- image signing, SBOM, provenance attestation, multi-architecture build와 moving `latest` +- live credential, 운영 account·database·broker·KIS 연결, database migration/reset 또는 운영 데이터 변경 +- 다른 TREX repository의 workflow, image, wire/HTTP 계약 또는 release policy 변경 +- ProofLine delivery/release lifecycle의 소급 완료 주장