refactor: generate CI workflow from gate contracts
This commit is contained in:
@@ -1,6 +1,12 @@
|
||||
# CI quality-gate orchestration
|
||||
|
||||
`config/ci/gates.json` is the executable registry for all 26 gates. The Gitea
|
||||
`config/ci/gates.json` is the executable registry for all 26 gates and the sole
|
||||
workflow model. `.gitea/workflows/quality-gates.yml` is generated from that
|
||||
strict v2 contract; it is not an independent configuration authority. Update
|
||||
the registry, run `corepack pnpm generate:ci-workflow`, and commit the generated
|
||||
bytes together. `corepack pnpm check:ci-workflow` rejects missing, stale, CRLF,
|
||||
or otherwise byte-different output. `corepack pnpm check:ci` runs artifact-schema
|
||||
checking, the typed contract checker, and this workflow drift check. The Gitea
|
||||
adapter runs each gate as an independent matrix check with full fan-out and no
|
||||
soft-fail wiring.
|
||||
|
||||
@@ -36,16 +42,54 @@ Release tier의 `immutable_build`는 `dist`의 hidden `.vite` entries, raw
|
||||
`pnpm-lock.yaml`, build/module inventory와 local release/security evidence를 한
|
||||
번 생성해 run ID/attempt로 구분된 archive로 게시한다. Raw lock bytes의 SHA-256은
|
||||
dependency inventory와 candidate manifest 양쪽의 `lockfileSha256`과 같아야 한다.
|
||||
Vulnerability/provenance provider job은 같은 archive를 각각 내려받고
|
||||
`CANDIDATE_LOCKFILE_PATH`, `CANDIDATE_DIST_SHA256`를 외부 command에 전달한다.
|
||||
Promotion은 같은 archive와 두 report를 별도 경로로 내려받은 뒤 local evidence를
|
||||
read-only로 다시 계산하고 Ed25519 signature/digest를 확인한다. Promotion job에는
|
||||
build/rebuild command가 없으며 검증한 archive 자체를 그대로 승격한다.
|
||||
Producer는 게시 전에 manifest가 선언한 exact member set과 각 byte digest를
|
||||
검증하고 archive SHA-256을 job output으로 고정한다. Vulnerability/provenance
|
||||
provider job은 같은 archive를 각각 내려받아 output SHA-256과 exact member set을
|
||||
확인한 뒤 checkout과 분리된 root에만 추출하고, `CANDIDATE_LOCKFILE_PATH`와
|
||||
`CANDIDATE_DIST_SHA256`를 외부 command에 전달한다. Provider command 실행 후에는
|
||||
archive와 추출된 candidate를 다시 검증하고, strict provider JSON과 candidate
|
||||
digest가 일치할 때만 report를 업로드한다. Promotion은 같은 archive와 두 report를
|
||||
별도 경로로 내려받고 SHA/member 검증을 마친 뒤 격리된 root에 추출하여 local
|
||||
evidence를 read-only로 다시 계산하고 Ed25519 signature/digest를 확인한다.
|
||||
Promotion job에는 build/rebuild command가 없으며 검증한 archive 자체를 변경 없이
|
||||
그대로 승격한다.
|
||||
|
||||
Provider baseline은 Gitea 1.26.4 이상과 Gitea Runner 1.0.0 이상이다. 이
|
||||
workflow를 required check로 전환하기 전에 staging instance에서
|
||||
`permissions`, `gitea.run_attempt`, `actions/upload-artifact@v4`를 포함한 한
|
||||
번의 전체 provider smoke를 통과시켜야 한다. 모든 setup step은
|
||||
workflow의 provider job은 Linux runner에서 실행 권한이 있는
|
||||
`/usr/bin/bwrap`를 필수로 요구하며, 사용할 Node 실행 파일도 sandbox 안의
|
||||
`/usr/local/bin/node`로 고정한다. Provider command는 bubblewrap 안에서
|
||||
`/bin/sh -eu -c`로 비대화식 실행되고 30분 안에 종료되어야 한다. Sandbox는
|
||||
workspace를 read-only로 bind하고 `.git`을 가리며, 별도의 `untrusted`
|
||||
raw-evidence 하위 디렉터리만 writable로 노출한다. 따라서 command는 전달된
|
||||
candidate/environment 값을 읽고 지정된 raw report 하나만 기록해야 하며,
|
||||
workspace 수정, host home/toolcache 접근, sealed evidence 직접 기록에 의존하면
|
||||
안 된다. Supervisor는 provider 종류에 해당하는 credential prefix와 제한된
|
||||
환경만 전달하고, sandbox 또는 출력 경계를 만들 수 없으면 fail closed한다.
|
||||
|
||||
Workflow가 실행하는 action은 `scripts/contracts/ci-gates.ts`의 단일 typed,
|
||||
runtime-frozen registry에서만 resolve된다. `uses:`에는 repository 별칭, tag,
|
||||
branch 또는 short SHA를 허용하지 않고 다음 absolute upstream URL과 full 40-hex
|
||||
commit만 사용한다.
|
||||
|
||||
- `https://github.com/actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5`
|
||||
(`v4.3.1`)
|
||||
- `https://github.com/actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020`
|
||||
(`v4.4.0`)
|
||||
- `https://github.com/ChristopherHX/gitea-upload-artifact@81f940d004763f986ba3582c007fd842dd5cb0d7`
|
||||
(patched `v4` branch)
|
||||
- `https://github.com/ChristopherHX/gitea-download-artifact@75635f32b4c1c41c4b3d64e8f85210112ed4c9c7`
|
||||
(patched `v4` branch)
|
||||
|
||||
Gitea 1.22 공식 Actions 문서는 artifact v4 호환 경로로 이
|
||||
`ChristopherHX` patched upload/download fork를 권고한다. 이 권고는 실제
|
||||
설치 환경의 호환성을 증명하지 않으므로, 지원 baseline은 계속 Gitea 1.26.4+
|
||||
및 Gitea Runner 1.0.0+이며 action 변경은 registry, semantic tests, snapshot과
|
||||
generated workflow를 함께 갱신해야 한다.
|
||||
|
||||
이 workflow를 required check로 전환하기 전에 staging instance에서
|
||||
`permissions`, `gitea.run_attempt`, 위 digest-pinned patched artifact action을
|
||||
포함한 한 번의 실제 end-to-end provider smoke를 반드시 통과시켜야 한다.
|
||||
mock/local generation 결과는 required-check enablement evidence가 아니다. 모든 setup step은
|
||||
`node-version-file: .nvmrc`를 사용하므로 CI Node.js 버전은 `.nvmrc`의 exact
|
||||
pin과 같다. CI contract는 `.nvmrc`가 full semantic version인지, 모든 job이 이
|
||||
파일을 사용하는지 함께 검사한다. `ubuntu-latest` runner label은
|
||||
@@ -152,6 +196,18 @@ If any external provider command, report, trust path, or key ID is absent,
|
||||
promotion remains unavailable with `FAIL_UNVERIFIED`; there is no local
|
||||
generator/restore fallback.
|
||||
|
||||
Promotion verification/staging step과 promoted-release upload action 사이에는
|
||||
어떤 step도 둘 수 없고 upload에는 `if: always()`를 사용할 수 없다. 이 인접성은
|
||||
실패한 검증의 publication을 막지만 staging path를 upload action에
|
||||
cryptographically hand off하지는 않는다. 따라서 promotion runner는 trusted,
|
||||
exclusive, single-tenant여야 하고 staging step 종료부터 바로 다음 upload action이
|
||||
파일을 여는 시점까지 같은 UID로 실행되는 provider command나 다른 process가
|
||||
살아남지 않는다는 운영 가정을 만족해야 한다. 업로드된 artifact의 downstream
|
||||
consumer도 artifact service나 transfer action을 신뢰 경계 밖으로 보고, candidate
|
||||
manifest와 signed provider evidence에 바인딩된 digest를 다운로드 후 다시
|
||||
검증해야 한다. 현재 producer-side adjacency 자체는 consumer-side digest
|
||||
revalidation을 대신하지 않는다.
|
||||
|
||||
Branch protection must mark each `FE-GATE-* / <name>` check required for its
|
||||
declared tier. This repository cannot configure server-side protection by
|
||||
committing a file.
|
||||
|
||||
Reference in New Issue
Block a user