릴리스
TRUSCA 릴리스는 vX.Y.Z 형식의 git 태그를 push하면 시작됩니다. 나머지는
.github/workflows/release.yml
워크플로가 처리합니다. 목표는 하나입니다. 사용자가 실제로 pull하게 될 바로 그
이미지로 설치가 되는지 확인하기 전에는 어떤 릴리스도 공개하지 않습니다.
게이트 개요
워크플로는 네 단계를 순서대로 실행하며, 각 단계는 앞 단계에 의존합니다.
build— 각 이미지(trusca-backend,trusca-backend-worker,trusca-frontend)를 amd64와 arm64 네이티브 러너에서 빌드하고 GitHub Container Registry에 다이제스트 단위로 push합니다.merge— 이미지마다 멀티아치 매니페스트 리스트를 만들고 버전 태그를 붙입니다(X.Y.Z는 불변,X.Y는 이동 가능 —:latest는 절대 쓰지 않습니다).release— GitHub Release를 draft로 생성합니다. 릴리스 노트는docs-site/docs/release-notes/X.Y.Z.md가 있으면 그것을, 없으면 GitHub가 자동 생성한 노트를 씁니다. 이 잡은 릴리스 자신의 소스 트리에 대한 CycloneDX SBOM도 생성해(syft) Release 자산으로 첨부합니다(trusca-X.Y.Z.cdx.json) — SCA 제품은 자기 SBOM을 함께 내놓습니다.release-gate— 방금 발행한X.Y.Z이미지를 pull해서 프로덕션docker-compose.yml을 기동합니다. 이때 작은 오버레이docker-compose.smoke.yml이 backend와 frontend 포트를 노출해 Traefik/DNS/TLS 없이도 스모크를 돌릴 수 있게 합니다. 그다음 문서화된 Quickstart first-scan 스모크를 실행합니다. 헬스 폴링 →create_super_admin→ 로그인 → projects API 순서입니다. 성공하면gh release edit <tag> --draft=false --latest로 Release를 공개합니다.
build ──▶ merge ──▶ release (draft) ──▶ release-gate ──▶ 공개 (draft=false)
다이제스트 버전 GitHub Release 발행 이미지 pull 스모크 통과 시에만
push 태그 아직 숨김 + first-scan 스모크 공개 + latest
이미지를 먼저 발행하고 Release는 나중에 공개하는 이유
컨테이너 이미지는 Release가 존재하기 전에 build와 merge에서 발행됩니다.
이는 의도된 설계입니다. 게이트는 운영자가 하는 방식 그대로 실제 발행 이미지를
pull해서 실행해봐야만 설치 가능 여부를 증명할 수 있기 때문입니다. Release는
사람에게 알리는 공지이므로, 그 증명이 끝날 때까지 draft로 붙잡아 둡니다.
실패 시 동작
release-gate의 어느 단계든 실패하면 공개 단계는 건너뜁니다. 이 단계에는
if: always() 가드가 없어 성공 경로에서만 실행되기 때문입니다. 결과는 이렇습니다.
- 이미지 태그는 발행된 채로 남아 pull할 수 있습니다.
X.Y.Z와X.Y는merge단계에서 push되었고 되돌리지 않습니다. 운영자는 그대로 pull할 수 있고, 워크플로를 다시 돌리면 같은 이미지를 재사용합니다. - GitHub Release는 draft로 남습니다. Releases 페이지에 보이지 않고,
latest로 표시되지 않으며, 워처에게 알림이 가지 않습니다. 이미지가 기동에 실패한 릴리스는 아무것도 공지하지 않습니다.
복구하려면 원인을 고친 뒤 같은 태그로 워크플로를 다시 실행합니다(또는 tag
입력으로 수동 실행). release 잡은 멱등적입니다. 기존 draft는 그대로 두고,
release-gate가 같은 발행 이미지를 다시 pull해 스모크를 다시 돌립니다. 스모크가
통과할 때만 draft가 공개로 바뀝니다.
게이트가 릴리스와 무관한 이유(예: 인프라 문제)로 실패하는데 릴리스 자체는 따로
검증했다면, 메인테이너가 gh release edit vX.Y.Z --draft=false --latest로 직접
공개할 수 있습니다. 되도록 게이트를 고치는 편이 낫습니다.
릴리스 절차
- 벤더링된 endoflife.date 스냅숏을 갱신해 릴리스가 최신 수명 주기 데이터를
담게 합니다(EOL 판정은 이 파일에서 오프라인으로 스탬프됩니다).
apps/backend에서python3 scripts/refresh_eol_snapshot.py를 실행하고, 갱신된 스냅숏을 릴리스 준비 변경과 함께 커밋합니다. - 문서 일괄 점검 — 릴리스는 문서와 함께 나갑니다. 태그 전에:
docs-site/docs/release-notes/X.Y.Z.md에 릴리스 노트를 작성합니다 (EN + KO 미러,sidebars.ts배선 포함). 내용은CHANGELOG.md의[Unreleased]섹션에서 가져오고, 가져온 항목은 새[X.Y.Z]제목 아래로 옮깁니다.[Unreleased]항목을 한 번 더 훑어, 사용자 대면 기능이 릴리스 노트만이 아니라 해당 가이드 페이지(user-guide / admin-guide / ci-integration)에도 반영됐는지 확인합니다. 가이드 섹션이 없는 기능은 릴리스 차단 사유입니다 — "문서 동행" 규칙을 가장 싸게 고칠 수 있는 시점에 강제하는 장치입니다.- 새 UI 화면이 나갔다면
make screenshots-capture로 스크린샷을 캡처해 가이드 섹션에서 참조합니다.
.env.example의IMAGE_TAG를X.Y.Z로 올립니다.- 태그를 push합니다.
git tag vX.Y.Z && git push origin vX.Y.Z. release-gate잡을 지켜봅니다. 초록색이 되면 Release가 자동으로 공개되고latest로 표시됩니다. 별도 수동 작업은 필요 없습니다.
함께 보기
- 시작하기 — dev 스택, 첫 PR.
- Docker Compose 설치 — 게이트가 실증하는 운영자 설치 경로.
- Quickstart — 게이트 스모크가 본뜬 first-scan 시나리오.