artifacty 0.13.1 → 0.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,72 @@
1
+ [English](../release-checklist.md) | 한국어
2
+
3
+ <!-- 번역 기준: 9e73a9f -->
4
+
5
+ # 릴리스 체크리스트
6
+
7
+ Artifacty를 게시하거나 배포하기 전에 이 체크리스트를 사용하세요.
8
+
9
+ ## 필수 검증
10
+
11
+ ```bash
12
+ npm run release:check
13
+ ```
14
+
15
+ 이 명령어는 구문 검사, 전체 Node 테스트, 로컬 스모크 테스트를 실행합니다. 스모크 테스트에서는 다음 작업을 확인합니다.
16
+
17
+ - 토큰 인증을 사용해 HTTP 서버 시작
18
+ - 아티팩트 생성
19
+ - 탐지한 비밀 정보 차단
20
+ - 감사 로그 읽기
21
+ - 백업 기록
22
+ - MCP 도구, 리소스, 프롬프트 검색
23
+
24
+ 로컬 진단을 실행하세요.
25
+
26
+ ```bash
27
+ artifacty doctor
28
+ ```
29
+
30
+ - 복구 명령어는 임시 저장소에서만 검증하세요. [업그레이드 스냅샷과 복구](upgrade-backups.md)를 참고하세요.
31
+ - 마이그레이션이 저장소를 변경하기 전에 필수 스키마 스냅샷 생성이 완료되는지 확인하세요.
32
+ - 최소 Node.js 버전인 22.12.0을 확인하세요. 선택적으로 사용하는 Babel 8 렌더러는 Node `^22.18.0 || >=24.11.0`이 필요합니다.
33
+ - ES2024를 지원하는 브라우저에서 Mermaid 12.1.0을 확인하세요. `classic` 스타일, `dagre` 레이아웃, `default` 테마를 유지하세요.
34
+
35
+ ## 패키징
36
+
37
+ - `package.json`의 `version`과 `files`가 의도한 값인지 확인하세요.
38
+ - `npm pack --dry-run`을 실행하세요.
39
+ - 패키지 출력에 나오는 경로를 검토하세요.
40
+ - 렌더러 의존성을 포함한 패키지 크기를 검토하세요. Mermaid는 기본 의존성입니다. React, ReactDOM, Babel standalone은 사용을 제한한 React 렌더러의 선택적 의존성입니다.
41
+ - 설치 후 전역 명령어 `artifacty`, `artifacty-mcp`를 사용할 수 있는지 확인하세요.
42
+
43
+ ## 보안
44
+
45
+ - 기본 HTTP 바인드 주소를 `127.0.0.1`로 유지하세요.
46
+ - `0.0.0.0`에 바인드하기 전에 `ARTIFACTY_API_TOKEN`과 `ARTIFACTY_SHARE_MODE=lan` 또는 `team` 설정을 필수로 요구하세요.
47
+ - 루프백이 아닌 주소로 시작할 때 출력에 LAN·팀 경고가 포함되는지 확인하세요.
48
+ - `artifacty serve`가 관리 대상 백그라운드 서버를 시작하고 JSON을 반환하는지 확인하세요.
49
+ - 서버에 연결된 로그를 확인하려면 `artifacty serve --foreground`를 사용하세요.
50
+ - `artifacty service plist|unit|task --dry-run`이 macOS, Linux, Windows 서비스 정의를 생성하는지 확인하세요.
51
+ - 스크립트에서는 쿼리 토큰보다 `x-artifacty-token` 또는 `Authorization: Bearer <token>`을 사용하세요.
52
+ - 비밀 정보 검사를 우회하는 설정을 각각 검토하세요. 의도적인 임시 예외에만 `--allow-secrets`와 `ARTIFACTY_ALLOW_SECRETS=true`를 사용하세요.
53
+ - 인증, 렌더링, MCP, 네트워크 공유 동작을 변경할 때는 [보안 정책](../../SECURITY.ko.md)과 [위협 모델](threat-model.md)을 검토하세요.
54
+ - 아티팩트 HTML과 가져온 에이전트 페이로드를 신뢰할 수 없는 콘텐츠로 취급하세요.
55
+ - 스크립트를 실행하는 아티팩트 iframe에 `allow-same-origin`이 포함되지 않는지 확인하세요.
56
+ - `/assets/*`와 `/vendor/npm/*`의 JavaScript 응답이 `Origin: null` 요청에만 `Access-Control-Allow-Origin: null`을 반환하는지 확인하세요. 출처가 불투명한 샌드박스 iframe이 로컬 ESM을 가져올 수 있어야 합니다. 샌드박스 플래그를 완화하거나 와일드카드 CORS 정책을 사용해서는 안 됩니다.
57
+ - SVG 뷰어 출력에서 `<script>`, `on*` 속성, `javascript:` 링크를 제거하는지 확인하세요.
58
+ - `/raw`가 원본 소스를 유지하는지 확인하세요.
59
+ - 클라이언트 코드를 실행하는 각 렌더러를 브라우저에서 테스트하세요. 렌더링된 결과를 확인하세요. 라우트 응답이 성공했다고 해서 iframe 안에서 Mermaid나 React가 렌더링되었다고 볼 수는 없습니다.
60
+ - `ARTIFACTY_ENABLE_REACT_RENDERER`는 기본적으로 비활성화하세요. 운영자가 임의의 컴포넌트 실행 위험을 수용하는 경우에만 활성화하세요.
61
+ - 상위 애플리케이션의 CSP가 `unsafe-eval`을 허용하지 않는지 확인하세요.
62
+ - React 프레임 응답의 CSP만 `unsafe-eval`을 허용하는지 확인하세요.
63
+ - CodeQL, Scorecard, Dependabot 설정 변경이 의도한 것인지 확인하세요.
64
+ - npm 게시에 장기 유효한 npm 토큰 대신 OIDC Trusted Publishing을 계속 사용하는지 확인하세요.
65
+
66
+ ## 운영
67
+
68
+ - 업그레이드하거나 서버를 옮기기 전에 백업을 내보내세요. 아티팩트만 백업하려면 `artifacty backup`을 사용하세요. 사용자, 토큰, 감사 로그, 관계, 웹훅도 포함하려면 `artifacty backup --full`을 사용하세요.
69
+ - `artifacty audit --limit 20`에 최근 생성·업데이트·읽기·보관 이벤트가 표시되는지 확인하세요.
70
+ - `artifacty doctor`가 실패 항목을 보고하지 않는지 확인하세요. 오프라인 저장소를 의도적으로 검사하는 경우 서버 중지 경고는 허용합니다.
71
+ - 백그라운드 서비스를 설치하기 전에 `artifacty service install --dry-run`을 실행하세요.
72
+ - 다른 운영체제의 정의를 검토하려면 `--platform macos|linux|windows`를 사용하세요.
@@ -0,0 +1,275 @@
1
+ <a id="threat-model"></a>
2
+
3
+ # 위협 모델
4
+
5
+ [English](../threat-model.md) | 한국어
6
+
7
+ <!-- 번역 기준: 9e73a9f -->
8
+
9
+ Artifacty는 LLM 에이전트가 아티팩트를 주고받는 로컬 도구입니다. 기본 배포 환경은 운영자 한 명, 로컬 저장소 한 개, 신뢰할 수 있는 로컬 MCP 클라이언트로 구성됩니다.
10
+
11
+ <a id="assets"></a>
12
+
13
+ ## 보호 대상
14
+
15
+ - 생성된 코드, 보고서, 스크린샷, 미디어를 포함한 아티팩트 콘텐츠.
16
+ - 아티팩트 메타데이터, 태그, 감사 기록, 버전 이력.
17
+ - API 토큰과 시작 시 생성되는 토큰.
18
+ - 사용자 계정, 비밀번호 해시, 브라우저 세션, 개인 API 토큰.
19
+ - 로컬 MCP 클라이언트 설정 파일.
20
+ - Artifacty SQLite 데이터베이스와 불변 버전 파일.
21
+
22
+ <a id="trust-boundaries"></a>
23
+
24
+ ## 신뢰 경계
25
+
26
+ - **HTTP 브라우저 서버**: 기본적으로 로컬에서만 접근합니다. 운영자가 LAN 또는 팀 네트워크의 접근을 허용할 수 있습니다.
27
+ - **MCP stdio 서버**: MCP 클라이언트가 실행하는 로컬 프로세스입니다. 로컬 사용자 계정의 파일시스템 권한을 상속합니다. 브리지 모드에서는 로컬 저장소에 접근하는 대신 설정된 중앙 `/mcp` 엔드포인트로 JSON-RPC를 전달합니다.
28
+ - **HTTP MCP 엔드포인트**: `--mcp-http` 또는 `ARTIFACTY_MCP_HTTP=true`를 설정한 경우에만 선택적으로 `POST /mcp` 엔드포인트를 노출합니다.
29
+ - **아티팩트 렌더러**: 가능한 경우 신뢰할 수 없는 콘텐츠를 브라우저 샌드박스 안에서 렌더링합니다.
30
+ - **저장소**: 콘텐츠는 `ARTIFACTY_HOME` 아래에 저장됩니다. 해당 디렉터리에 대한 파일시스템 접근 권한이 있으면 아티팩트를 읽을 수 있습니다.
31
+ - **npm 패키지**: 자동 검사를 통과한 뒤 GitHub Actions OIDC를 통해 배포합니다.
32
+
33
+ <a id="primary-threats-and-controls"></a>
34
+
35
+ ## 주요 위협과 대응
36
+
37
+ <a id="accidental-network-exposure"></a>
38
+
39
+ ### 의도하지 않은 네트워크 노출
40
+
41
+ 위험: `0.0.0.0`에 바인딩하면 VPN이나 클라우드 VM의 공개 인터페이스를 포함한 모든 인터페이스에서 Artifacty에 접근할 수 있습니다.
42
+
43
+ 대응:
44
+
45
+ - 기본 호스트는 `127.0.0.1`입니다.
46
+ - 루프백 이외의 주소에 바인딩하려면 `ARTIFACTY_SHARE_MODE=lan|team`이 필요합니다.
47
+ - 루프백 이외의 주소에 바인딩하려면 `ARTIFACTY_API_TOKEN`도 필요합니다.
48
+ - 서버가 루프백 이외의 주소에 바인딩하면 시작 로그에 경고를 표시합니다.
49
+
50
+ 운영 지침: `0.0.0.0`보다 특정 사설 인터페이스의 IP를 사용하세요. Artifacty를 공개 인터넷에 직접 노출하지 마세요.
51
+
52
+ <a id="token-leakage"></a>
53
+
54
+ ### 토큰 유출
55
+
56
+ 위험: 쿼리 문자열에 넣은 토큰은 브라우저 방문 기록, 셸 기록, 로그, 리퍼러에 남을 수 있습니다.
57
+
58
+ 대응:
59
+
60
+ - 스크립트에서는 `x-artifacty-token` 또는 `Authorization: Bearer <token>`을 사용하는 것이 좋습니다.
61
+ - 브라우저 폼의 토큰 URL은 로컬 사용의 편의를 위해서만 제공합니다.
62
+ - 토큰은 실행 시간 차이로 정보가 드러나지 않도록 다이제스트를 비교합니다.
63
+ - 개인 API 토큰은 해시로만 저장합니다.
64
+ - 브라우저 세션 쿠키에는 `HttpOnly`와 `SameSite=Lax`를 사용합니다.
65
+
66
+ 운영 지침:
67
+
68
+ - 공유 세션이 끝나면 토큰을 교체하세요.
69
+ - 스크립트에서는 토큰 헤더를 사용하세요.
70
+ - 시작 시 생성된 토큰은 일시적인 대화형 공유에만 사용하세요.
71
+
72
+ <a id="cross-site-request-forgery"></a>
73
+
74
+ ### 사이트 간 요청 위조
75
+
76
+ 위험: 원격 웹사이트가 사용자의 브라우저에서 접근할 수 있는 Artifacty 서버에 쓰기 요청을 보낼 수 있습니다.
77
+
78
+ 대응:
79
+
80
+ - 데이터를 변경하는 브라우저 경로는 루프백 또는 동일 출처의 요청을 허용하고, 다른 출처의 쓰기 요청은 거부합니다.
81
+ - 토큰이 설정되어 있으면 API 경로에 토큰이 필요합니다.
82
+ - LAN/팀 모드는 임의의 브라우저 출처를 허용하지 않습니다.
83
+
84
+ <a id="untrusted-artifact-rendering"></a>
85
+
86
+ ### 신뢰할 수 없는 아티팩트 렌더링
87
+
88
+ 위험: HTML, SVG, Mermaid, React 콘텐츠가 열람자의 브라우저에서 코드를 실행할 수 있습니다.
89
+
90
+ 대응:
91
+
92
+ - HTML 아티팩트는 샌드박스 iframe에서 렌더링합니다.
93
+ - SVG 아티팩트는 뷰어에서 위험한 내용을 제거한 뒤 스크립트를 허용하지 않는 샌드박스 iframe에서 렌더링합니다.
94
+ - Mermaid는 `allow-same-origin`이 없는 샌드박스 iframe에서 렌더링합니다.
95
+ - `ARTIFACTY_ENABLE_REACT_RENDERER=true`를 설정하지 않으면 React는 소스만 표시합니다.
96
+ - React 렌더링을 활성화하면 별도의 샌드박스 프레임에서 실행하며, 해당 프레임에만 적용되는 콘텐츠 보안 정책(CSP)을 사용합니다.
97
+
98
+ 운영 지침: 모든 열람자가 소스를 신뢰하는 경우가 아니면 공유 세션에서 React 렌더링을 비활성 상태로 유지하세요.
99
+
100
+ <a id="secret-storage"></a>
101
+
102
+ ### 비밀 정보 저장
103
+
104
+ 위험: 에이전트가 실수로 API 키나 개인 키를 아티팩트에 게시할 수 있습니다.
105
+
106
+ 대응:
107
+
108
+ - 저장 전에 일반적인 API 키와 개인 키 패턴을 탐지합니다.
109
+ - `allowSecrets` 또는 `ARTIFACTY_ALLOW_SECRETS=true`를 설정하지 않으면 쓰기가 실패합니다.
110
+ - 검사 상태를 버전 메타데이터에 기록합니다.
111
+
112
+ 제한: 패턴 검사로 모든 민감한 데이터를 찾아낼 수는 없습니다. 검사를 통과했다고 해서 안전하게 공유할 수 있는 콘텐츠라는 뜻은 아닙니다.
113
+
114
+ <a id="mcp-tool-abuse"></a>
115
+
116
+ ### MCP 도구 악용
117
+
118
+ 위험: MCP 클라이언트는 로컬 stdio 또는 중앙 HTTP MCP 엔드포인트를 통해 아티팩트를 생성, 수정, 가져오기, 아카이브, 복원, 읽기 할 수 있습니다.
119
+
120
+ 대응:
121
+
122
+ - 기본 방식은 로컬 stdio입니다.
123
+ - HTTP MCP 엔드포인트는 명시적으로 활성화하지 않으면 비활성 상태입니다.
124
+ - 원격 MCP 요청에는 설정된 API 토큰이 필요합니다.
125
+ - stdio 브리지 모드는 토큰을 URL 대신 헤더로 보냅니다.
126
+ - 개인 토큰을 사용한 요청은 서버의 사용자 레코드에 연결됩니다. 이를 통해 아티팩트의 `publisherId`와 감사 기록의 `actor`를 식별합니다.
127
+ - MCP 쓰기는 CLI/HTTP 쓰기와 동일한 비밀 정보 검사 및 감사 기록 경로를 거칩니다.
128
+ - MCP 리소스는 읽기 전용입니다.
129
+
130
+ 운영 지침:
131
+
132
+ - 신뢰할 수 있는 클라이언트와 작업공간에만 Artifacty MCP를 설치하세요.
133
+ - 중앙 서버로 배포할 때는 리버스 프록시를 통해 TLS를 사용하세요.
134
+ - 팀 구성이 바뀌면 공유 토큰을 교체하세요.
135
+
136
+ <a id="personal-api-token-scopes"></a>
137
+
138
+ ### 개인 API 토큰 범위
139
+
140
+ 위험: 공격자가 유출된 개인 API 토큰을 사용할 수 있습니다. 읽기 전용 보고용 토큰은 아티팩트 변경이나 백업, Webhook 같은 관리자 경로의 접근을 허용하지 않는 것이 바람직합니다.
141
+
142
+ 대응:
143
+
144
+ - 각 개인 토큰은 `read`, `write`, `admin` 중에서 선택한 `scopes_json` 목록을 갖습니다. 새 토큰과 범위 기능 도입 전에 생성한 토큰의 기본값은 모두 `["read", "write"]`입니다.
145
+ - 관리자 역할의 사용자만 `admin` 범위 토큰을 소유할 수 있습니다. 그 외의 사용자가 이 범위를 요청하면 `createApiToken`이 거부합니다.
146
+ - 모든 `/api/*` HTTP 경로에서 `requireScope`(`src/lib/security.js`)를 호출합니다. 읽기 경로에는 `read`, 변경 경로에는 `write`가 필요합니다. 관리자 전용 경로(`/api/webhooks*`, `/api/admin/backup*`)에는 기존 관리자 역할 검사에 더해 `admin`이 필요합니다. 거부 시 `code: "scope_denied"`와 함께 `403`을 반환하고 `token-scope-denied` 감사 행을 기록합니다. 이 감사 기록은 토큰당 분당 한 번으로 제한합니다.
147
+ - 공유 `ARTIFACTY_API_TOKEN`과 브라우저 세션은 항상 전체 범위를 가집니다. 범위 설정은 *개인* 토큰의 권한만 좁힙니다.
148
+ - HTTP MCP에서는 토큰에 `write`가 없으면 `tools/list`에서 쓰기 도구를 제외합니다. 해당 도구를 직접 호출하면 `structuredContent.code: "scope_denied"`를 포함한 `isError` 결과를 반환하며, 도구는 실행하지 않습니다.
149
+ - 로컬 stdio는 신뢰할 수 있는 로컬 프로세스이므로 토큰 범위를 적용하지 않습니다. 다만 설정된 토큰이 개인 계정을 식별하면 해당 계정의 아티팩트 접근 규칙은 적용합니다. 사이트가 비공개 모드이면 이 개인 신원이 필요합니다.
150
+
151
+ 운영 지침: 보고 및 분석 연동에는 읽기 전용 토큰을 발급하세요. `admin` 범위 토큰은 운영자 도구에만 사용하세요.
152
+
153
+ <a id="http-and-mcp-rate-limiting"></a>
154
+
155
+ ### HTTP 및 MCP 요청 속도 제한
156
+
157
+ 위험: 침해당했거나 오작동하는 클라이언트가 과도한 쓰기 또는 검색 요청을 보낼 수 있습니다. 공격자가 `/login`에 비밀번호 추측 요청을 반복해서 보낼 수도 있습니다.
158
+
159
+ 대응:
160
+
161
+ - 메모리 기반 제한기가 1분 단위 고정 구간으로 요청을 제한합니다. 키는 `(principal, bucket)`입니다. 주체인 `principal`은 토큰 ID를 우선 사용하고, 없으면 인증된 사용자 ID, 그마저 없으면 원격 주소를 사용합니다.
162
+ - 제한 구분인 `bucket`은 다음과 같습니다. `write`는 데이터를 변경하는 `/api/*` 경로와 브라우저 쓰기 POST 요청에 적용하며, 기본값은 분당 120회입니다(`ARTIFACTY_RATE_WRITE_PER_MIN`). `auth`는 `POST /login`에 적용하며, 기본값은 주소당 분당 10회입니다(`ARTIFACTY_RATE_AUTH_PER_MIN`). `search`는 `q` 쿼리가 있는 `GET /api/artifacts`에 적용하며, 기본값은 분당 300회입니다(`ARTIFACTY_RATE_SEARCH_PER_MIN`).
163
+ - 루프백에 바인딩하면 기본적으로 제한하지 않습니다. 따라서 단일 사용자의 로컬 사용에는 요청 속도 제한이 없습니다. `ARTIFACTY_RATE_LIMIT=always`를 설정하면 루프백에서도 제한합니다. `ARTIFACTY_RATE_LIMIT=off`는 조건에 관계없이 제한을 비활성화합니다.
164
+ - 구분별 제한을 초과하면 초 단위의 `Retry-After` 헤더와 `code: "rate_limited"`를 포함해 `429`를 반환합니다. 또한 `rate-limited` 감사 행을 기록하되, `(bucket, principal)` 구간당 한 번으로 제한합니다. Streamable HTTP 전송을 사용하는 MCP 변경 도구 호출이 `write` 제한을 초과하면 HTTP 오류 대신 `structuredContent.code: "rate_limited"`를 포함한 `isError` 도구 결과를 반환합니다.
165
+ - 제한기는 프로세스별 메모리에 존재하므로 재시작하면 초기화됩니다. 같은 저장소를 사용하는 여러 서버 프로세스 사이에서 제한 상태를 공유하지 않습니다.
166
+
167
+ 운영 지침: 더 높은 처리량이 필요한 연동에는 `*_PER_MIN` 환경 변수 값을 높이세요. 루프백 이외의 인터페이스에서는 요청 속도 제한을 활성 상태로 유지하세요.
168
+
169
+ <a id="request-and-content-size-limits"></a>
170
+
171
+ ### 요청 및 콘텐츠 크기 제한
172
+
173
+ Artifacty 서버 프로세스는 다음 바이트 제한을 적용합니다. 리버스 프록시의 제한과는 별개입니다.
174
+
175
+ | 제한 대상 | 값 | 상수 / 환경 변수 |
176
+ | --- | --- | --- |
177
+ | 아티팩트 버전 콘텐츠 | 16 MiB | `MAX_ARTIFACT_BYTES` (`src/lib/storage.js`) |
178
+ | 백업 가져오기 본문 | `src/lib/backup.js` 참고 | `MAX_BACKUP_BYTES` |
179
+ | 댓글 본문 | 16 KiB | `MAX_COMMENT_BYTES` (`src/lib/storage.js`) |
180
+ | 일반 JSON/폼 요청 본문 | `MAX_ARTIFACT_BYTES + 1024` | `readJsonBody`/`readFormBody`의 기본 `limitBytes` (`src/server.js`) |
181
+
182
+ 요청 본문이 제한을 초과하면 파싱하기 전에 `413`으로 거부합니다.
183
+
184
+ <a id="webhook-ssrf-and-secret-handling"></a>
185
+
186
+ ### Webhook SSRF 및 비밀키 처리
187
+
188
+ 위험: Webhook URL을 제어하는 공격자는 Artifacty 서버가 보내는 HTTP 요청에 영향을 줄 수 있습니다. Webhook 비밀키가 유출되면 공격자가 서명된 전달 요청을 위조할 수 있습니다. SSRF는 이처럼 서버가 의도하지 않은 대상으로 요청을 보내게 하는 공격입니다.
189
+
190
+ 대응:
191
+
192
+ - Webhook 대상의 프로토콜은 `http` 또는 `https`여야 합니다.
193
+ - 루프백(`127.0.0.0/8`, `::1`), 링크 로컬(`169.254.0.0/16`, `fe80::/10`), 사설 대역(`10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `fc00::/7`), CGNAT(`100.64.0.0/10`), IETF 프로토콜 할당 대역(`192.0.0.0/24`), 벤치마크 대역(`198.18.0.0/15`), 멀티캐스트(`224.0.0.0/4`), `0.0.0.0/8`, 그리고 위 대역에 대응하는 IPv4-mapped IPv6 주소(`::ffff:0:0/96`)는 Webhook 대상 호스트로 허용하지 않습니다. 예외는 `ARTIFACTY_WEBHOOK_ALLOW_PRIVATE=true`를 설정한 경우뿐입니다. 이 설정은 로컬 개발과 테스트 전용이며, 공유 서버나 인터넷에서 접근할 수 있는 서버에서는 절대 설정하면 안 됩니다. IPv4 검사는 네 부분의 점으로 구분한 십진수 표기뿐 아니라 모든 기존 `inet_aton` 리터럴 표기를 32비트 값으로 변환한 뒤 대역을 검사합니다. 여기에는 십진수, 8진수, 16진수, 1~3개 부분으로 줄인 표기(예: `2130706433`, `0177.0.0.1`, `0x7f000001`, `127.1`)가 포함됩니다. IPv6 검사에서는 그룹을 비교하기 전에 `::`와 존 ID를 완전히 풀어 처리합니다. 따라서 차단 주소를 다른 형식으로 표현해도 정규 표기와 동일하게 거부합니다. 예를 들어 `::1`을 `[0:0:0:0:0:0:0:1]`로 적어도 거부합니다.
194
+ - 이 방어는 URL 호스트명의 리터럴 주소만 검사하며, Webhook 생성 시에만 실행합니다(`assertPublicWebhookUrl`, 테스트에서도 검증). DNS를 조회하지 않으며, 전달 시점에 다시 검사하지도 않습니다. 실제 외부 HTTP 요청을 보낼 때에만 사설 또는 루프백 주소로 해석되는 호스트명은 이 방어로 잡아내지 못합니다. DNS 리바인딩이나 Webhook 생성 후 DNS 레코드가 변경된 경우가 이에 해당합니다. Webhook 생성은 관리자가 신뢰할 수 있는 입력으로 수행하는 작업으로 취급해야 하며, 신뢰할 수 없는 호출자에게 안전하게 공개할 수 있는 기능으로 보아서는 안 됩니다.
195
+ - 전달 요청은 `redirect: "manual"`을 사용하며 리다이렉트를 따라가지 않습니다. Webhook 대상은 3xx 응답을 이용해 차단된 주소로 전달 요청을 보낼 수 없습니다.
196
+ - Webhook 비밀키는 생성 응답에서 한 번만 보여주며, 이후 평문으로 저장하거나 반환하지 않습니다. 저장하는 값은 `secretHash = sha256(secret)`이며, 모든 전달 요청은 `X-Artifacty-Signature: sha256=HMAC-SHA256(key = secretHash, body = <raw request body>)`로 서명합니다. 생성 응답의 원본 비밀키를 보관한 수신자는 로컬에서 `sha256(secret)`을 계산해 동일한 키를 얻은 뒤 HMAC을 검사합니다. 따라서 서버는 이후 전달 요청에 서명할 때 원본 비밀키를 다시 읽을 필요가 없습니다.
197
+ - 사용자 계정이 하나라도 있으면 관리자만 Webhook을 생성할 수 있습니다. 계정이 없는 단일 사용자 모드에서는 설정된 API 토큰을 가진 사람이 생성할 수 있습니다. 이는 다른 모든 쓰기 경로의 신뢰 경계와 같습니다.
198
+ - 전달이 연속 20회 실패하면 Webhook을 비활성화하고 `webhook-deliver-failed` 감사 행을 기록합니다. 관리자가 삭제한 뒤 다시 생성하기 전까지 비활성 상태를 유지합니다.
199
+
200
+ 운영 지침:
201
+
202
+ - 직접 제어하거나 신뢰하는 Webhook 엔드포인트만 등록하세요.
203
+ - HTTPS 대상을 우선 사용하세요.
204
+ - 비밀키 노출이 의심되면 Webhook을 삭제하세요.
205
+ - 새 비밀키로 Webhook을 다시 생성하세요. 서명에 사용하는 `secretHash`도 함께 교체됩니다.
206
+
207
+ <a id="artifact-visibility-and-ownership"></a>
208
+
209
+ ### 아티팩트 공개 범위와 소유권
210
+
211
+ 위험: 한 사용자가 권한 없이 다른 사용자의 아티팩트를 읽거나 변경할 수 있습니다. 소유자가 공유할 의도가 없었던 민감한 초안도 여기에 포함됩니다.
212
+
213
+ 대응:
214
+
215
+ - 관리자는 `/admin/access`에서 사이트 모드를 공개 또는 비공개로 선택합니다.
216
+ - 공개 모드에서 각 아티팩트는 `visibility`(`private` 또는 `team`, 기본값 `team`)와 `ownerUserId`를 갖습니다. 일반 아티팩트 경로를 통해 `private` 아티팩트를 읽거나 쓸 수 있는 사람은 소유자 또는 관리자뿐입니다. 익명 브라우저 방문자는 `team` 아티팩트를 읽을 수 있고, 인증된 주체는 이를 쓸 수 있습니다. API 인증 요구사항은 계속 적용됩니다. `ARTIFACTY_TEAM_WRITE=owner`를 설정하면 이러한 쓰기를 소유자와 관리자로 제한합니다.
217
+ - 사이트가 비공개 모드이면 개인 신원이 필요합니다. 소유자와 관리자는 계속 접근할 수 있습니다. 다른 사용자에게는 사용자 또는 팀 단위로 부여한 권한이 필요합니다. 부여할 수 있는 권한은 읽기, 댓글 작성, 편집이며, 일치하는 권한 중 가장 강한 권한을 적용합니다. 토큰 범위는 여기에 추가 제한을 둡니다.
218
+ - 아카이브, 복원, 공유, 공개 범위 또는 소유권 변경은 소유자나 관리자만 할 수 있습니다. 이 규칙은 두 사이트 모드 모두에 적용합니다.
219
+ - 호출자가 아티팩트를 읽을 수 없으면 서버는 `404`/`ARTIFACT_NOT_FOUND`를 반환합니다. 아티팩트의 존재 자체가 드러나는 것을 막기 위한 동작입니다. 읽을 수는 있지만 필요한 쓰기 또는 관리 권한이 없으면 `code: "forbidden"`과 함께 `403`을 반환합니다.
220
+ - 목록 쿼리는 메타데이터 검색과 FTS 검색 모두에 SQL 접근 검사를 적용합니다. 읽을 수 없는 대상을 가리키는 관계에는 대상 요약 없이 `{ restricted: true }`를 반환합니다.
221
+ - 공유 `ARTIFACTY_API_TOKEN`에는 개인 신원이 없습니다. 공개 모드에서는 `team` 아티팩트를 읽고 쓸 수 있지만 `private` 아티팩트는 볼 수 없습니다. 비공개 모드에서는 아티팩트를 읽거나 생성할 수 없습니다. 다른 서버 경로에서 관리자 권한이 있더라도 아티팩트 접근을 위한 개인 신원을 얻는 것은 아닙니다.
222
+ - 사용자 계정이 없는 공개 모드에서는 사용자 접근 검사를 적용하지 않습니다.
223
+
224
+ 운영 지침: 서로 신뢰하지 않는 당사자는 별도의 저장소를 사용하세요. 관리자는 자신의 저장소에 있는 모든 아티팩트를 읽고 쓰거나 다른 소유자에게 재할당할 수 있습니다.
225
+
226
+ <a id="public-share-links-and-network-restrictions"></a>
227
+
228
+ ### 공개 공유 링크와 네트워크 제한
229
+
230
+ 위험: 공유 링크를 복사하면 링크를 가진 누구에게나 아티팩트가 노출될 수 있습니다. 잘못된 네트워크 정책은 서버를 노출하거나 관리자의 접근을 막을 수 있습니다.
231
+
232
+ 대응:
233
+
234
+ - 공유 링크는 읽기 전용 접근을 제공합니다. 소유자 또는 관리자가 생성하고 폐기합니다. 링크는 최신 버전 또는 특정 고정 버전을 가리킬 수 있습니다.
235
+ - 링크에는 만료 시점이 있습니다. 사이트가 비공개 모드이면 관리자가 허용하지 않는 한 사용할 수 없습니다. 서버는 토큰 해시를 저장하며 원본 토큰은 생성 시에만 보여줍니다.
236
+ - 공유 페이지에는 아티팩트 소유권, 태그, 이력, 내부 아티팩트 URL을 표시하지 않습니다. `Referrer-Policy: no-referrer`와 `Cache-Control: no-store`를 사용합니다.
237
+ - 공유 링크를 포함한 모든 HTTP 요청에 설정된 IP/CIDR 허용 목록을 적용합니다. 서버는 TCP 연결 상대의 주소를 검사하며 전달 헤더는 무시합니다.
238
+ - 네트워크 변경에는 관리자의 현재 주소가 포함되어야 합니다. 변경은 확정하기 전까지 대기 상태로 유지됩니다. 확정하지 않은 채 만료되면 이전 정책을 복구합니다. 관리자가 대기 중인 변경을 직접 되돌릴 수도 있습니다.
239
+
240
+ 운영 지침: 공유 링크는 자격증명처럼 취급하세요. 의도하지 않은 수신자에게 전달되면 링크를 폐기하세요. 리버스 프록시를 사용할 때는 네트워크 정책에 서버가 TCP 연결 상대로 보는 프록시의 주소를 고려하세요.
241
+
242
+ <a id="retention-purge-gate"></a>
243
+
244
+ ### 보존 정책의 영구 삭제 허용 조건
245
+
246
+ 위험: 잘못된 보존 정책은 아티팩트와 버전 파일을 영구 삭제할 수 있습니다. 예를 들어 운영자가 `purgeArchivedAfterDays`를 너무 낮게 설정하거나 대상 아티팩트를 검토하지 않고 적용할 수 있습니다. 영구 삭제는 보존 설정이 유발할 수 있는 유일한 되돌릴 수 없는 작업입니다.
247
+
248
+ 대응:
249
+
250
+ - `archiveAfterDays`, `purgeArchivedAfterDays`, `auditRetentionDays`, `eventRetentionRows`, `keepTags`를 변경하는 것만으로는 데이터를 삭제하지 않습니다. 새 정책은 다음 정리 작업이나 명시적인 `artifacty retention run` 실행 때 적용됩니다.
251
+ - `artifacty retention run`과 `POST /api/admin/retention/run`은 기본적으로 `dryRun: true`입니다. 저장소를 변경하지 않고 아카이브, 영구 삭제, 기록 정리 대상을 보고서로 반환합니다. `/admin/retention`도 같은 보고서를 표시하므로 관리자는 적용 전에 검토할 수 있습니다.
252
+ - 아카이브는 콘텐츠를 삭제하지 않고 활성 목록에서 아티팩트를 제외합니다. `artifacty restore`로 되돌릴 수 있습니다. 접근 조건은 `archiveArtifact`에 이미 있는 소유자 또는 관리자 검사뿐입니다.
253
+ - 영구 삭제는 되돌릴 수 없으며, 서버 환경에 `ARTIFACTY_RETENTION_ALLOW_PURGE=true`도 설정해야 합니다. 영구 삭제 후보가 있지만 이 허용 조건을 설정하지 않았으면 정리 결과에 `purgeSkipped: true`로 기록합니다. 알림 없이 아무 동작도 하지 않거나 그대로 삭제하지 않습니다. CLI의 `--allow-purge` 플래그와 브라우저의 "Allow purge" 체크박스는 모두 같은 환경 변수 검사를 사용하며, 별도의 우회 수단을 제공하지 않습니다.
254
+ - 적용한 정리 작업마다 `retention-sweep` 감사 요약 행을 하나 기록합니다(`actor`는 `system:retention`). 영구 삭제할 아티팩트마다 삭제 전에 별도의 `retention-purge` 감사 행도 기록합니다. `retention-purge` 행은 `auditRetentionDays`에 따른 정리 대상에서 제외하므로, 삭제된 아티팩트가 오래전에 사라졌더라도 감사 로그에서 영구 삭제를 추적할 수 있습니다.
255
+ - 영구 삭제는 외래 키를 통해 연쇄 삭제되는 종속 행(댓글, 관계, 임베딩)과 함께 해당 아티팩트의 `events` 행과 검색 인덱스 항목도 삭제합니다. 이벤트와 검색 인덱스에는 아티팩트를 참조하는 외래 키가 없으므로 `ON DELETE CASCADE`에 의존하지 않고 명시적으로 삭제합니다. 감사 로그 행만은 의도적으로 남겨두며, 이 행이 영구 삭제가 발생했다는 기록이 됩니다.
256
+
257
+ <a id="out-of-scope"></a>
258
+
259
+ ## 범위 밖의 기능
260
+
261
+ - 별도의 TLS/인증 프록시 없는 공개 인터넷 호스팅.
262
+ - OAuth. 개인 API 토큰 범위와 사용자 또는 팀 단위의 아티팩트 권한은 위에서 설명한 대로 지원합니다.
263
+ - 저장 데이터 암호화.
264
+ - 임의의 아티팩트 콘텐츠에 대한 악성코드 분석.
265
+
266
+ <a id="security-review-checklist"></a>
267
+
268
+ ## 보안 검토 체크리스트
269
+
270
+ - `npm run release:check`를 실행하세요.
271
+ - 중요한 저장소에서 `artifacty integrity`를 실행하세요.
272
+ - 로컬 이외의 공유에는 토큰과 신뢰할 수 있는 LAN/VPN을 사용하는지 확인하세요.
273
+ - 필요한 경우가 아니면 `ARTIFACTY_ENABLE_REACT_RENDERER`를 비활성 상태로 유지하세요.
274
+ - 스크립트에서는 쿼리 토큰보다 토큰 헤더를 우선 사용하세요.
275
+ - 작업공간 파일을 커밋하기 전에 생성된 MCP 설정을 검토하세요.
@@ -0,0 +1,152 @@
1
+ [English](../upgrade-backups.md) | 한국어
2
+
3
+ <!-- 번역 기준: 9e73a9f -->
4
+
5
+ # 업그레이드 스냅샷과 복구
6
+
7
+ Artifacty는 기존 저장소를 새 스키마로 마이그레이션하기 전에 로컬 스냅샷을 생성합니다. 이 스냅샷은 필수입니다. 스냅샷 생성이나 검증에 실패하면 마이그레이션 전에 작업을 중단합니다.
8
+
9
+ 저장소의 원래 상태를 복구할 때는 업그레이드 스냅샷을 사용하세요. 다른 환경으로 옮길 수 있는 JSON 백업과 저장소 이전에는 `artifacty backup`과 `artifacty export`를 사용하세요. 두 백업 방식은 별개입니다. `artifacty restore <id>`는 보관한 아티팩트를 복원하는 명령이며, 저장소 스냅샷을 복원하지 않습니다.
10
+
11
+ ## 애플리케이션 자체 업데이트
12
+
13
+ 애플리케이션 업데이트 도구와 스키마 마이그레이션 스냅샷은 목적이 다릅니다. 아티팩트 ID 없이 `artifacty update`를 실행하면 애플리케이션을 업데이트합니다. `artifacty upgrade`도 같은 명령입니다. `artifacty update <id>`는 기존과 같이 아티팩트를 수정합니다.
14
+
15
+ ### 릴리스 확인과 선택
16
+
17
+ ```bash
18
+ artifacty update --check
19
+ artifacty upgrade --check --target-version <version> --home /path/to/store
20
+ ```
21
+
22
+ `--check`는 설치, 서비스, 저장소를 변경하지 않고 릴리스를 확인합니다. 다른 CLI 플랫폼에서도 사용할 수 있으며, 자동 설치 지원 여부도 표시합니다. 릴리스를 조회하려면 네트워크 연결은 필요합니다. 관리 대상 서비스에서는 명령어를 실행한 CLI 버전만 보는 것이 아니라, 해당 서비스가 사용하는 패키지 버전을 비교합니다. `--target-version`에는 정확한 버전을 지정합니다. 이 옵션이 없으면 최신 릴리스를 선택합니다. `--home`으로 보호할 저장소를 지정합니다. 자동 다운그레이드는 지원하지 않습니다. 이전 버전을 명시적으로 지정하면 거부합니다. `latest`가 설치된 버전보다 낮으면 현재의 더 최신 버전을 그대로 유지합니다.
23
+
24
+ 설치된 버전이 0.14.0 이전이라면 다음 명령어로 업데이트 도구를 시작하세요.
25
+
26
+ ```bash
27
+ npx --yes artifacty@latest update --home /path/to/store && export PATH="$HOME/.local/bin:$PATH"
28
+ ```
29
+
30
+ 이 명령어는 POSIX Linux 셸 문법을 사용합니다. 업데이트가 성공하면 현재 세션에서 `PATH`의 앞에 `~/.local/bin`을 둡니다. 이후 세션에서도 사용하려면 셸의 `PATH`에 해당 디렉터리를 추가하세요.
31
+
32
+ 업데이트 도구를 사용하려면 `latest` 태그가 0.14.0 이상을 가리켜야 합니다.
33
+
34
+ ### 브라우저에서 업데이트
35
+
36
+ 관리자 계정으로 브라우저에 로그인하세요. **관리 → 서버 업데이트**(`/admin/update`)를 여세요. 이 경로에서는 API 토큰으로 브라우저 세션을 대신할 수 없습니다.
37
+
38
+ 1. **업데이트 확인**을 선택하세요. 서비스를 설치하거나 다시 시작하지 않고 npm의 최신 릴리스를 조회합니다.
39
+ 2. 브라우저 업데이트를 지원하고 새 버전이 있으면 표시된 대상 버전을 검토하세요.
40
+ 3. 백업과 재시작에 동의하는 확인란을 선택하세요.
41
+ 4. **백업 후 업데이트**를 선택하세요.
42
+ 5. 서버가 다시 시작되는 동안 화면을 열어 두세요. 재연결 후 업데이트 결과를 확인하세요.
43
+
44
+ 확인은 10분 후 만료되며 버전을 조회한 브라우저 세션에만 유효합니다. 만료되거나 설치된 버전이 바뀌면 다시 확인하세요. 폼 요청의 출처는 서버와 정확히 같아야 합니다. 비밀번호를 다시 입력할 필요는 없습니다.
45
+
46
+ 브라우저 설치는 이 서버가 root가 아닌 사용자로 실행되는 Linux systemd 사용자 서비스인 경우에만 지원합니다. 다른 설치 환경에서도 최신 릴리스를 조회할 수 있지만 이 화면에서 업데이트를 시작할 수는 없습니다. 작업자는 독립적인 systemd 임시 서비스로 실행되므로 Artifacty 서버를 중지해도 업데이트 작업은 계속됩니다. 상태는 아티팩트 저장소 밖의 `~/.local/share/artifacty/update-jobs`에 보관합니다.
47
+
48
+ 화면을 열거나 상태를 조회하는 것만으로 npm에 접속하거나 패키지를 설치하지 않습니다. 상태 조회는 중지된 작업자를 찾기 위해 systemd를 확인할 수 있습니다. 작업 시작 여부가 불확실하면 작업을 예약 상태로 유지합니다. 작업자가 중단되었거나 복구가 끝나지 않았다면 성공으로 처리하지 않습니다. 다음 업데이트 전에 수동으로 상태를 확인해야 합니다. 복구를 검증할 때까지 남아 있는 스냅샷과 릴리스를 보존하세요.
49
+
50
+ ### 자동 설치의 지원 범위
51
+
52
+ 자동 설치와 재시작은 Linux의 systemd 사용자 서비스 `com.artifacty.server`를 지원합니다. 서비스를 실행하는 사용자로 업데이트 도구를 실행하세요. 유닛은 Artifacty 설치 도구가 생성하는 단순한 `ExecStart` 형식을 사용해야 합니다. 선택한 저장소의 `--home`도 명시해야 합니다. 지원하지 않는 명령어 확장이나 따옴표 형식이 있으면 서비스를 중지하기 전에 업데이트를 중단합니다. 자동 업데이트는 root 실행을 거부합니다. root 소유의 전역 패키지를 교체하려고 root로 실행하지 마세요.
53
+
54
+ 업데이트 도구는 `~/.local/share/artifacty/releases`에 패키지를 준비합니다. systemd 드롭인 설정으로 관리 대상 서비스의 실행 파일을 변경하며, 기존 인자와 환경 변수는 유지합니다. 사용자 소유 실행 파일은 `~/.local/bin`에 둡니다. 이 디렉터리가 `PATH`에 없으면 실행 파일을 사용하기 전에 추가하세요. 기존에 있던 관리 대상이 아닌 파일은 덮어쓰지 않습니다. 기존 root 소유 전역 패키지는 변경하지 않습니다. `PATH`에서 다른 명령어를 먼저 찾는다면 결과에 제공한 절대 경로 `nextCommand`를 사용하세요. 셸 설정은 자동으로 변경하지 않습니다.
55
+
56
+ macOS, Windows, 포그라운드 서버, 분리된 백그라운드 서버, 임의의 서비스 유닛은 자동 전환을 지원하지 않습니다. 이러한 환경에서는 수동 설치와 스냅샷 절차를 사용하세요.
57
+
58
+ ### 저장소 보호와 롤백
59
+
60
+ 업데이트 전에 같은 저장소를 사용하는 다른 HTTP 서버와 로컬 MCP 클라이언트를 중지하세요. 지원하는 systemd 서비스는 업데이트 도구가 직접 관리합니다. 저장소를 열고 있는 다른 모든 프로세스를 찾을 수는 없습니다. 업데이트 중에는 서비스를 사용할 수 없습니다. 저장소를 롤백하면 스냅샷 이후에 기록한 변경 사항은 사라집니다. 이 절차를 진행하는 동안 다른 쓰기 작업을 실행하지 마세요.
61
+
62
+ 실행 중인 서비스는 중지하기 전에 현재 상태를 확인합니다. 바인드 주소나 IP 정책 때문에 확인할 수 없으면 서비스를 중지하기 전에 업데이트를 거부합니다. 지원하지 않는 서비스 설정도 중지 전에 오류로 처리합니다.
63
+
64
+ 준비 디렉터리에 지정한 정확한 버전의 패키지를 설치하고 검증합니다. 그다음 관리 대상 서비스를 중지하고, 코드를 전환하기 전에 스냅샷을 생성하고 검증합니다. 서비스가 실행 중이었다면 전환 후에 다시 시작하고 상태와 PID를 확인합니다. 중지 상태였던 서비스는 중지 상태를 유지합니다. 롤백에 필요한 이전 코드와 서비스 설정도 보존합니다. 전환이나 재시작에 실패하면 변경한 코드, 서비스 설정, 저장소를 복원한 뒤 이전 서비스를 다시 시작하는 롤백을 시도합니다. 서비스 중지에 실패하면 서비스가 저장소에 계속 기록할 수 있으므로 저장소를 복원하지 않습니다. 복원된 저장소에는 스냅샷 시점의 인증 정보와 보안 상태가 포함됩니다. 클라이언트의 재접속을 허용하기 전에 복구 오류를 확인하세요.
65
+
66
+ 전환 중에 프로세스나 호스트가 갑자기 종료되면 `update.lock`이 남거나 서비스가 중지 상태로 남을 수 있습니다. 다음 업데이트는 무조건 재시도하지 않고 잠금 상태를 보고합니다. 스냅샷, 준비한 릴리스, 복구 파일을 보존하세요. 수동으로 다시 시도하기 전에 서비스와 복구 상태를 확인하세요. 자동 롤백은 처리 가능한 오류에 대응하며, 전원 장애나 강제 프로세스 종료 후의 복구를 보장하지 않습니다.
67
+
68
+ 다시 시작한 서비스가 정상 동작할 때까지 스냅샷과 업데이트 결과를 보관하세요. 자동 롤백을 완료하지 못하면 명시적인 오류를 반환하고 `backupId`를 남깁니다. 해당 스냅샷으로 아래 복구 절차를 진행하세요. 복구 파일을 삭제하거나, 지원하지 않는 스키마를 이전 빌드로 강제로 열지 마세요.
69
+
70
+ ## 스냅샷을 생성하는 시점
71
+
72
+ - **스키마 마이그레이션:** 기존 저장소를 마이그레이션하기 전에 항상 스냅샷을 생성합니다. 기존 `index.json` 방식의 저장소도 포함합니다. 새로 만든 빈 저장소에는 스냅샷이 필요하지 않습니다.
73
+ - **애플리케이션 업데이트:** `ARTIFACTY_BACKUP_ON_UPDATE=true`로 설정하면 애플리케이션 버전이 바뀔 때도 기존 저장소의 스냅샷을 생성합니다. 기본값은 비활성화입니다.
74
+ - **애플리케이션 버전을 알 수 없는 경우:** 업데이트 설정을 활성화한 상태에서 애플리케이션 버전 기록이 없는 기존 저장소를 처음 열면 기준 스냅샷을 생성합니다. 이 스냅샷의 원본 애플리케이션 버전은 알 수 없습니다. 이후 같은 버전으로 열 때는 다시 생성하지 않습니다.
75
+ - **복원:** 저장소를 교체하기 전에 현재 상태의 복구 스냅샷을 생성하고 검증합니다.
76
+
77
+ 업그레이드하거나 복원하기 전에 해당 저장소를 사용하는 HTTP 서버와 MCP 프로세스를 모두 중지하세요. 서비스, 포그라운드 서버, 로컬 stdio MCP 클라이언트도 포함합니다. Artifacty는 관리 대상 서버의 PID 기록을 확인하지만, 이 기록만으로 저장소를 열고 있는 모든 프로세스를 찾을 수는 없습니다.
78
+
79
+ 스냅샷은 `ARTIFACTY_HOME/upgrade-backups/<id>/`에 저장합니다. 기본 홈 디렉터리는 `~/.artifacty`입니다.
80
+
81
+ ## 스냅샷에 포함되는 내용
82
+
83
+ 각 스냅샷에는 파일 크기와 SHA-256 해시를 기록한 매니페스트가 있습니다. 다음 항목도 포함합니다.
84
+
85
+ - 모든 테이블과 보안 상태를 포함한, 일관성이 유지되는 원본 SQLite 데이터베이스
86
+ - 데이터베이스 또는 기준으로 사용하는 기존 인덱스가 참조하는 모든 버전 파일
87
+ - 기존 `index.json` 파일이 있으면 해당 파일
88
+
89
+ 검증 과정에서는 파일 해시, SQLite 무결성, 버전 파일 참조를 확인합니다. 관련 없는 파일, 프로세스 기록, 로그, 전체 설치 디렉터리는 스냅샷에 포함하지 않습니다. 스냅샷에는 인증 정보와 보안 기록이 있으므로 비공개로 보관하세요.
90
+
91
+ `ARTIFACTY_UPGRADE_BACKUP_KEEP`으로 자동 스냅샷 보관 개수를 지정합니다. 기본값은 `3`이며, `1`부터 `1000`까지의 정수를 사용할 수 있습니다. 업그레이드가 성공하면 오래된 자동 스키마·업데이트 스냅샷을 정리합니다. 이 설정으로 수동 스냅샷이나 복구 스냅샷을 정리하지는 않습니다.
92
+
93
+ ## 스냅샷 확인
94
+
95
+ 저장소를 열거나 마이그레이션하지 않고 스냅샷 목록을 조회하세요.
96
+
97
+ ```bash
98
+ artifacty backups list --home /path/to/store
99
+ ```
100
+
101
+ 출력에서 `id`를 복사하세요. 해당 스냅샷을 검증하세요.
102
+
103
+ ```bash
104
+ artifacty backups verify <id> --home /path/to/store
105
+ ```
106
+
107
+ 검증이 성공하면 응답에 `valid: true`가 포함됩니다. 목록 조회는 매니페스트만 확인하므로 전체 검증을 대신할 수 없습니다. 저장소를 체크아웃한 환경에서는 `artifacty` 대신 `node src/cli.js`를 사용하세요.
108
+
109
+ ## 스냅샷 복원
110
+
111
+ 복원하면 현재 데이터베이스, 버전 파일, 기존 인덱스를 교체합니다. 스냅샷 이후의 변경 사항은 더 이상 현재 상태에 반영되지 않습니다. 복원 직전의 상태는 별도의 복구 스냅샷에 보관합니다.
112
+
113
+ **보안 상태도 이전 상태로 돌아갑니다.** 이전 비밀번호, 권한, 네트워크 규칙, 세션, API 토큰, 공유 링크 기록이 다시 현재 상태가 될 수 있습니다. 스냅샷 이후에 폐기한 세션, 토큰, 링크도 아직 만료되지 않았다면 다시 유효해질 수 있습니다. 사용자의 재접속을 허용하기 전에 복원된 보안 상태를 검토하세요.
114
+
115
+ 1. 이 저장소를 사용하는 서버, 서비스, MCP 프로세스를 모두 중지하세요.
116
+ 2. `backups list`에서 스냅샷을 선택하세요.
117
+ 3. `backups verify`로 검증하세요.
118
+ 4. 명시적인 확인 옵션을 넣어 복원하세요.
119
+
120
+ ```bash
121
+ artifacty backups restore <id> --confirm restore-store --home /path/to/store
122
+ ```
123
+
124
+ 5. 응답의 `recoveryBackupId`를 저장하세요.
125
+ 6. 클라이언트를 다시 연결하기 전에 복원된 보안 설정을 검토하세요.
126
+
127
+ 복원 작업은 선택한 스냅샷을 마이그레이션하지 않습니다. 현재 애플리케이션으로 열면 보호 절차를 거치는 마이그레이션이 다시 시작될 수 있습니다. 복원된 스키마를 지원하지 않는 빌드는 저장소를 열지 않습니다.
128
+
129
+ ## 현재 저장소가 손상된 경우의 복구
130
+
131
+ 현재 저장소를 검증할 수 없어 복구 스냅샷을 만들 수 없으면 `RECOVERY_BACKUP_FAILED`를 반환합니다. 손상된 저장소를 덮어쓰지 않습니다.
132
+
133
+ 1. 손상된 홈 디렉터리와 그 안의 스냅샷을 그대로 보존하세요.
134
+ 2. 새 빈 홈 디렉터리를 만드세요.
135
+ 3. 선택한 스냅샷 디렉터리를 새 홈의 `upgrade-backups/` 디렉터리에 복사하세요. 원래 스냅샷 ID와 디렉터리 내용을 유지하세요.
136
+ 4. `backups verify <id> --home /path/to/new-home`을 실행하세요.
137
+ 5. `backups restore <id> --confirm restore-store --home /path/to/new-home`을 실행하세요.
138
+ 6. 새 홈을 사용하기 전에 복원된 데이터와 보안 설정을 검토하세요.
139
+
140
+ 손상된 데이터베이스를 새 홈에 복사하지 마세요. 선택한 스냅샷이 데이터베이스와 참조하는 버전 파일을 제공합니다.
141
+
142
+ ## 중단된 복원 작업의 복구
143
+
144
+ `.restore-<uuid>` 디렉터리가 남아 있으면 `RESTORE_INCOMPLETE` 오류로 작업을 중단합니다.
145
+
146
+ 1. 해당 디렉터리와 영향을 받은 홈 디렉터리 전체를 보존하세요.
147
+ 2. `.restore-<uuid>/restore.json`을 읽으세요.
148
+ 3. `recoveryBackupId`를 찾으세요. 이 ID는 복원이 중단되기 전 상태의 스냅샷을 가리킵니다.
149
+ 4. 해당 복구 스냅샷을 새 빈 홈의 `upgrade-backups/` 디렉터리에 복사하세요.
150
+ 5. 위 명령어로 새 홈에서 검증하고 복원하세요.
151
+
152
+ 검사를 우회하려고 중단된 복원 디렉터리를 삭제하지 마세요. 이 디렉터리에는 복구에 필요한 증거가 있으며, 이전 데이터베이스와 파일도 들어 있을 수 있습니다.
@@ -0,0 +1,60 @@
1
+ [English](../writing-style.md) | 한국어
2
+
3
+ <!-- 번역 기준: 9e73a9f -->
4
+
5
+ # 문서 작성 스타일
6
+
7
+ Artifacty의 영어 문서는 ASD-STE100에서 착안한 스타일을 사용합니다. 한국어 문서에도 같은 명료성 원칙을 적용하되, 자연스러운 한국어 표현을 사용합니다. 이 문서는 편집 지침이며 ASD-STE100 준수를 주장하지 않습니다.
8
+
9
+ 문장과 절차 작성 규칙을 일관되게 적용하세요. 의미를 더 정확하게 전달할 수 있다면 기술 용어를 사용하세요. 소개 문장은 자연스럽게 쓰세요. 프로젝트의 ‘75%’ 목표는 이런 균형을 뜻하며, 표준 준수 점수가 아닙니다.
10
+
11
+ ## 영어 문서의 문장과 용어
12
+
13
+ - 한 문장에는 하나의 핵심 내용을 담으세요. 명료성이 좋아진다면 긴 문장을 나누세요.
14
+ - 책임을 구분해야 할 때는 관리자, 아티팩트 소유자, 사용자, 서버 등 주체를 밝히세요.
15
+ - 능동태를 우선 사용하세요. 주체를 알 수 없거나 중요하지 않으면 수동태를 사용하세요.
16
+ - 같은 개념에는 같은 용어를 사용하세요. UI 이름, API 필드, CLI 명령어를 정확히 맞추세요.
17
+ - artifact, MCP, webhook, CIDR 등 정착된 용어를 유지하세요. 익숙하지 않은 용어는 처음 사용할 때 설명하세요.
18
+ - 완전한 문장을 만드는 데 필요한 단어는 유지하세요. 설명문을 압축된 메모처럼 쓰지 마세요.
19
+ - 고정된 단어 수 제한을 강제하지 마세요. 제한된 사전에 맞추기 위해 정확한 용어를 바꾸지 마세요.
20
+
21
+ ## 지시와 동작 설명
22
+
23
+ - 행동을 설명하기 전에 전제 조건과 적용 조건을 밝히세요.
24
+ - 번호가 있는 각 단계에는 하나의 행동을 담으세요. 그 행동을 수행하는 명령어 또는 UI 요소를 보여 주세요.
25
+ - 독자가 행동을 검증하는 데 필요하다면 예상 결과를 밝히세요.
26
+ - 기본값, 권한, 예외, 복구 동작을 명시하세요.
27
+ - 필수 사항과 권장 사항을 구분하세요. 명세에 나오는 MUST, SHOULD, MAY의 의미를 유지하세요.
28
+ - 설명문을 편집할 때 명령어, 식별자, URL, 예제, 기술적 제약을 유지하세요.
29
+ - 계획 중인 기능은 계획임을 밝히세요. 설계 제안을 현재 동작처럼 설명하지 마세요.
30
+
31
+ ## 문서 유형에 따른 적용
32
+
33
+ 설치 안내, API 참조, 보안 문서에는 이 규칙을 가장 엄격하게 적용하세요. README 소개, 설계 근거, 출시 글에서는 문장이 자연스럽게 이어지도록 설명해도 됩니다. 독자에게 필요한 설명은 유지하세요. 조건이나 예외를 생략한다면 짧은 글도 도움이 되지 않습니다.
34
+
35
+ 영어 문서에서는 다음과 같이 씁니다.
36
+
37
+ > By default, share links do not work in private mode. An administrator must enable them in Access settings.
38
+
39
+ 이 예문은 ‘비공개 모드에서는 기본적으로 공유 링크가 동작하지 않으며, 관리자가 접근 설정에서 활성화해야 한다’는 뜻입니다. 기본값, 책임 주체, 설정 위치를 명시합니다.
40
+
41
+ 표준의 목적과 구성은 [공식 ASD-STE100 소개](https://www.asd-ste100.org/about.html)를 참고하세요.
42
+
43
+ ## 한국어 문서 작성 기준
44
+
45
+ 한국어 문서에도 같은 명료성 원칙을 적용합니다. 다만 영어의 문장 구조나 어휘 규칙을 그대로 옮기지 않고, 자연스러운 한국어 어순과 흐름을 살립니다. ‘75% 강도’는 편집 방향을 뜻하며, 표준 준수율을 뜻하지 않습니다.
46
+
47
+ - 한 문장에는 하나의 핵심 내용을 담습니다. 서로 밀접한 내용은 자연스럽게 연결하고, 짧게 쓰기 위해 문장을 지나치게 끊지 않습니다.
48
+ - 조건이나 전제는 행동보다 먼저 설명합니다. 절차는 단계별로 나누고, 필요한 경우 예상 결과와 확인 방법을 덧붙입니다.
49
+ - 권한이나 책임을 구분해야 할 때는 주체를 밝힙니다. 문맥상 분명한 주어는 반복하지 않습니다.
50
+ - 번역투, 불필요한 수동 표현, 명사만 나열하는 문장을 피합니다. 예를 들어 ‘설정의 변경이 가능합니다’보다 ‘설정을 변경할 수 있습니다’로 씁니다.
51
+ - 같은 개념에는 같은 용어를 사용합니다. 화면 이름은 해당 언어의 실제 UI 표기와 맞추고, 명령어·API 필드·코드 식별자는 그대로 유지합니다.
52
+ - 익숙한 기술 용어는 억지로 번역하지 않습니다. 설명이 필요한 용어는 처음 나올 때 간단히 풀이합니다.
53
+ - 기본값, 예외, 제한, 복구 조건을 생략하지 않습니다. 필수 사항과 권장 사항도 명확히 구분합니다.
54
+ - 설명문은 ‘합니다’체를 기본으로 씁니다. 절차에서는 필요한 행동을 ‘선택하세요’, ‘실행하세요’처럼 직접 안내합니다.
55
+
56
+ 예를 들어 다음과 같이 씁니다.
57
+
58
+ > 비공개 모드에서는 기본적으로 공유 링크를 사용할 수 없습니다. 관리자가 접근 설정에서 공유 링크를 허용해야 합니다.
59
+
60
+ 설치·API·보안 문서에는 이 기준을 엄격하게 적용합니다. 소개 글과 설계 배경에서는 정확성을 유지하면서 문장이 자연스럽게 이어지도록 씁니다.
@@ -1,5 +1,7 @@
1
1
  # MCP Public API
2
2
 
3
+ English | [한국어](ko/mcp-public-api.md)
4
+
3
5
  Artifacty's MCP server is the primary interface for agent-to-agent integration.
4
6
  It uses local stdio MCP by default. The browser server can also expose a
5
7
  token-protected HTTP `/mcp` endpoint. Stdio bridge mode lets a client use local
@@ -1,5 +1,7 @@
1
1
  # Network Sharing
2
2
 
3
+ English | [한국어](ko/network-sharing.md)
4
+
3
5
  Artifacty stores artifacts locally. By default, the server binds to `127.0.0.1` for use on one machine. You can bind to a non-local address for a short sharing session. This exposes the server to other machines.
4
6
 
5
7
  ## Recommended Defaults
@@ -1,5 +1,7 @@
1
1
  # Release Checklist
2
2
 
3
+ English | [한국어](ko/release-checklist.md)
4
+
3
5
  Use this checklist before publishing or distributing Artifacty.
4
6
 
5
7
  ## Required Verification
@@ -1,5 +1,7 @@
1
1
  # Threat Model
2
2
 
3
+ English | [한국어](ko/threat-model.md)
4
+
3
5
  Artifacty is a local artifact exchange for LLM agents. Its default deployment
4
6
  uses one operator, one local store, and trusted local MCP clients.
5
7