-
hanyul released this
2026-10-12 00:38:27 +09:00 LINKS 1.0.4
이 patch 릴리스는 이전 릴리스 1.0.3(
5e262a8dde)부터 최종 소스f9171bfa75까지를 묶었습니다. 루트 패키지는 1.0.4이고 ARCA pin은 exact 0.1.18로 그대로입니다. 1.0.3 운영 결함 하나를 고쳤습니다. VX/VX Ace 게시 직전의 원본 재확인을 stager 계정 one-shot으로 옮겼으므로, 원본을 stager 계정만 읽을 수 있는 NAS(ACL)에서도 준비가 끝까지 진행됩니다. 원본 읽기 거부와 저장소 거부는 서로 다른 code로 표시됩니다. schema는 바뀌지 않았습니다. DB 초기화와 migration이 필요 없습니다.업그레이드 주의: 1.0.3 → 1.0.4는
sh update.sh만 실행합니다(초기화 없음)- 갱신 방법: 1.0.3에서는 배포 디렉터리에서
sh update.sh만 실행합니다. 1.0.2 이하에서 올 때는 1.0.3과 같은 1회curl전환을 거칩니다. 아래 절차의 tag만1.0.4로 바꿔 새update.sh를 한 번 받고, 그다음sh update.sh를 실행합니다. 1.0.1 이하라면 먼저 host coordinator를 종료합니다(운영 가이드 '최초 설치와 이전 release에서의 전환'). schema는 바뀌지 않았고(infra/migrations/base.sha256이 1.0.3과 같고 migration은 0개)reset.sh를 실행하지 않습니다. 갱신 전 backup(sh backup.sh)은 선택입니다. - 원본 재확인 계정: VX/VX Ace 게시 직전의 원본 재확인이 stager 계정(
LINKS_RUNTIME_STAGER_UID:GID)의 one-shotruntime-package-stager(새 명령verify-source)에서 실행됩니다. 이전에는 package worker(10001)가 했습니다. 그래서 원본을 stager 계정만 읽을 수 있는 NAS(Synology ACL)에서도 준비가 seal → stage → Builder → 원본 재확인 → 게시까지 진행됩니다. 10001 package worker(runtime-package-worker)는 원본 library를 mount하지 않습니다. 운영자 추가 작업은 없습니다. 바뀐compose.yaml·coordinator script는update.sh가 설치하고,.env.production·원본 ACL·저장소 소유권은 그대로 씁니다. - 원본 권한 code 분리: 원본 읽기가 거부되면 새 code
RUNTIME_SOURCE_PERMISSION_DENIED로 끝납니다. 이 code는 재시도할 수 없습니다. 원본 접근 권한, stager 계정, NAS ACL을 확인합니다. 저장소(sealed·artifact store) 거부는 계속RUNTIME_STORE_PERMISSION_DENIED입니다. 두 code 모두 진단에는 경로 없는 원인 code(EACCES등)만 남습니다. - 1.0.3에서 실패한 준비: 1.0.3에서
RUNTIME_STORE_PERMISSION_DENIED(publishing단계, causeEACCES)로 끝난 VX/VX Ace 준비는 재시도 불가로 기록돼 있습니다. 화면의다시 시도대신 관리자 게임 관리의 실행 빌드 관리에서빌드 재생성으로 다시 요청합니다. - NAS 조건 gate: 릴리스 전에 격리
docker:24.0.2-dind에서 이 갱신을 검증했습니다. host Compose는 공식 Docker Compose v2.20.1 binary(release의 게시 checksum으로 확인)였습니다. 계정은 stager 1026:100이고, 원본 library 최상위는0:0 000에 1026만 여는 ACL을 두었습니다(10001은 읽지 못함). 1.0.3에서 VX Ace 준비가 운영과 같은RUNTIME_STORE_PERMISSION_DENIED로 실패하는 것을 재현했습니다. 이어서 설치된 1.0.3update.sh로 1.0.4 갱신,빌드 재생성으로 buildready, 재-update까지 모두 성공했습니다(아래 검증). Synology build(v2.20.1-6047-g6817716)·Synology ACL과 공식 binary·Linux POSIX ACL은 다를 수 있으므로 실제 NAS 결과는 확인 전입니다.
NAS 절차(1.0.3에서):
cd /volume1/docker/links sh update.sh성공하면 단계 표시 6줄 뒤에
Updated to 1.0.4 (catalog fd371daaf742), runtime.package ready.가 출력됩니다. 실패하면 원인 한 줄을 출력하고 nonzero로 끝납니다.원본 game library는 읽기 전용으로 유지합니다. 이번 게시 작업에서 개발·운영 DB 초기화나 NAS 배포는 실행하지 않았습니다.
VX/VX Ace 원본 재확인의 stager 계정 이동
- coordinator의 한 attempt는 seal → stage → Builder → verify-source → publish 순서입니다. seal과 verify-source는 stager 계정의
runtime-package-stager에서 실행하고, stage와 publish는 10001 package worker에서 실행합니다. sh·PowerShell coordinator 모두 verify-source를 publish 바로 앞에 두고, 둘 사이에 다른 단계는 없습니다. - verify-source는 seal이 남긴 봉인 identity를 엄격히 검사합니다. 그다음 원본을 같은 함수와 인자로 다시 확인하고, 일치 결과를 경로·제목 없이 checkpoint에 남깁니다. publish는 다른 작업보다 먼저 이 결과를 handoff와 대조합니다. 결과가 없거나 맞지 않으면 게시하지 않습니다(
RUNTIME_PACKAGE_INVALID_OUTPUT). - 봉인 뒤 원본이 바뀌면 이전과 같이
RUNTIME_SOURCE_CHANGED(재시도 가능)로 끝납니다. 원본 본문 읽기는 이전과 같이 seal 2회와 재확인 1회입니다. 게시 transaction의 source lock 보장도 바뀌지 않았습니다. - verify-source 실패(nonzero 또는 비어 있지 않은 출력)는 publish 없이 attempt 실패로 처리하며, coordinator는 다음 job으로 넘어갑니다.
원본 권한 code
RUNTIME_SOURCE_PERMISSION_DENIED(재시도 불가): seal의 복사 전 원본 검사와 verify-source의 원본 재확인에서 원본 읽기가 거부된 경우입니다. 문구는 "원본 게임 폴더를 읽을 권한이 없습니다. 관리자가 원본 접근 권한(stager 계정·NAS ACL)을 확인해야 합니다."입니다.RUNTIME_STORE_PERMISSION_DENIED의 문구에서 "원본 또는"을 뺐습니다. 이제 이 code는 저장소 거부만 뜻합니다.- MV/MZ 원본 거부는 기존대로
BOUNDARY_REJECTED입니다.
문서
- 운영 가이드(1.0.3 → 1.0.4 갱신, Stager 계정과 저장소 권한, 원본 ACL), 런타임 계약, API 계약, 보안 정책, 완료 기준선, 개발 계획(NAS gate에 verify-source 추가), tests/README를 갱신했습니다.
알려진 제한(후속 과제)
- 원본 재확인부터 게시까지의 간격이 늘었습니다. 늘어난 부분은 publish one-shot 시작, release 검증, 봉인 사본 검증입니다. 128 MiB 합성 원본에서 약 1.2초가 늘었고, 봉인 사본 검증은 게임 크기에 비례합니다. 그 사이 원본 변경은 이전과 같이 게시 transaction의 DB source lock과 scan 관찰에 맡깁니다.
- 실제 NAS(Synology ACL·btrfs)에서의 VX/VX Ace package 실행과 PowerShell coordinator 전체 실행은 NOT RUN입니다.
- 1.0.3 배포 때 Compose 2.20.1에서 관찰된 사례가 있습니다. 중단된
up이 network 없는 container를 남길 수 있는데,update.sh는 이를 감지하지 않습니다. 운영자는docker compose --env-file .env.production --profile runtime up -d --no-deps --force-recreate <service>로 복구합니다. - 1.0.3과 같은 제한:
/artifacts쓰기 거부는 기존 분류를 따릅니다.- load 뒤에 권한이 바뀌면
ARTIFACT_INVALID로 끝납니다. - 소유 계정이 섞인 sealed store는 지원하지 않습니다.
- Docker 24 graphdriver에서는 Builder config digest를 pin과 직접 대조하지 않습니다(ARCA 후속).
- 3단계 이후 실패하면 coordinator가 정지된 채 남습니다. 원인을 고친 뒤 다음
sh update.sh가 다시 기동합니다. - Player 세이브 관리 listener(3005)는 catalog caller token으로만 보호되며,
edgenetwork에서 TCP로 닿을 수 있습니다. - catalog·Player의 일반 egress는 network로 제한하지 않습니다.
update.sh는 opt-in profile container(translation-import등)를 갱신하지 않습니다.
검증과 남은 범위
- PASS: pkg-verify 브랜치(병합
c217f0d)- unit: 전체 149 files / 1,190 tests, 관련 5 files / 119 tests
- schema 32 files / 228 tests, static, runtime-workers, reset 기록기 30·
update.sh기록기 93 - Compose config 3종, PowerShell coordinator parse·
sh -n, 문서 검사,git diff --check - 격리 dind e2e(Compose 2.29.1): stager 1026:100과 1026 전용 원본에서 수정 전
publishingRUNTIME_STORE_PERMISSION_DENIED재현 → 수정 뒤 buildready. 기본 10001:10001도ready. 원본을 못 읽는 오구성은RUNTIME_SOURCE_PERMISSION_DENIED - 리뷰 최종 판정: 병합 가능(P1~P3 없음)
- PASS: 릴리스 gate(Compose v2.20.1, NAS 조건)
- 환경: 격리
docker:24.0.2-dind(overlay2, BusyBox ash), host Compose는 공식 v2.20.1 linux-x86_64 binary(release의 게시 checksum과 일치). 합성 CA의 HTTPS release 서버가 Gitea를, 합성 TLS registry가git.2ex.dev를 대신했습니다(dind daemon에만 적용). registry에는 실제 1.0.3 image와 이 릴리스의 1.0.4 image를 넣었고, 배포 파일은 1.0.3 tag와 이 릴리스 커밋의 Git blob입니다. - 운영과 같은 계정과 원본 권한: scanner·stager 1026:100,
./databind store, 원본 library 최상위0:0 000+ ACLu:1026:r-x. 10001의find /library ! -readable은/library1줄, 1026은 0줄 - 1.0.3 설치 →
reset.sh→update.sh: exit 0(106초),Updated to 1.0.3 .... MV/MZ 준비 성공. VX Ace 준비는 seal·stage·Builder 뒤publishing에서RUNTIME_STORE_PERMISSION_DENIED(causeEACCES, 재시도 불가)로 실패. 운영 로그와 같습니다 - 1.0.4 게시(registry
latest= 1.0.4, asset 없음) 뒤 설치된 1.0.3update.sh: exit 0(47초), coordinator 정지 → pull → 전체 갱신·healthy → coordinator 재기동 →Updated to 1.0.4 .... 7개 파일이 release와 같고.tmp는 0. package worker의 렌더링 mount에/library가 없습니다 - 실패한 VX Ace 준비를 관리자
빌드 재생성경로(force 요청)로 다시 요청: seal(runtime-package-stager, 1026:100) → stage → Builder → verify-source(runtime-package-stager, 1026:100) → publish → buildready. 모든 one-shot이 exit 0, attempt 1에 성공. sealed 항목은 모두 1026:100이고 Builder 계정의 읽기·탐색 실패는 0 - 설치 상태에서 재-update: exit 0(13초), 배포 파일 변화 없음, 준비 상태
ready유지 - 매 배포 뒤 결과: 12개 service의 network가 선언과 일치(불일치 0), unhealthy 0, package·runtime readiness exit 0, coordinator 재시작 0
- 환경: 격리
- PASS: 최종 1.0.4 소스. 릴리스 커밋 두 개(root version, 완료 기준선의 version 문구) 뒤 다음을 다시 통과했습니다: 문서 검사(760개 파일 / Markdown 32개), static(Prettier·ESLint·typecheck·docs-static),
git diff --check. - 게시 이미지: 같은 최종 소스에서 build했고, gate도 이 image로 실행했습니다. image 안에서 root version 1.0.4와 ARCA pin·설치본 0.1.18을 확인했습니다.
- PARTIAL: 전체 UI/제품 acceptance. 화면·fixture·package/build 성공을 실제 browser play PASS로 기록하지 않습니다.
- NOT RUN:
- Synology NAS 실제 환경(Compose v2.20.1 Synology build, Synology ACL, Docker 24 btrfs)에서의 1.0.3 → 1.0.4 갱신과 VX/VX Ace package
- PowerShell coordinator 전체 실행
- 실제 Gitea release·registry를 대상으로 한 전체 stack 갱신(gate는 합성 release 서버·registry)
- 실제 library/private game과 실제 scan
- 입력·오디오·save/reload의 실제 게임 acceptance
- live provider
- 개발 rebuild
배포 이미지와 파일
- Git annotated tag는 1.0.4이고 최종 소스는
f9171bfa75입니다. - 단일 linux/amd64 이미지:
git.2ex.dev/hanyul/links:1.0.4=git.2ex.dev/hanyul/links:latest - 원격 digest:
sha256:fd371daaf7427f4a725ab35a31e8214e6cd0114a3e9049c0a5b2af5be034ea09 - release asset은 없습니다.
update.sh가 tag1.0.4의 7개 배포 파일을 HTTPS로 받습니다. 대응은update.sh=ops/deploy-registry.sh,reset.sh=ops/reset-registry.sh,backup.sh=ops/backup-registry.sh이고, 나머지는compose.yaml·infra/docker/Caddyfile·ops/backup-verify.compose.yaml·ops/runtime-package-coordinator.sh입니다. - 1.0.3 대비 바뀐 배포 파일은 두 개입니다.
compose.yaml(package worker의 원본 library mount 제거)과ops/runtime-package-coordinator.sh(publish 직전 verify-source 단계)입니다. 나머지 5개는 같습니다.
Downloads 2
-
Source code (zip)
0
2026-10-12 00:38:27 +09:00 -
Source code (tar.gz)
0
2026-10-12 00:38:27 +09:00
- 갱신 방법: 1.0.3에서는 배포 디렉터리에서