@aldegad/safedeps 2.1.1 → 2.2.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.
package/ARCHITECTURE.md CHANGED
@@ -1,166 +1,122 @@
1
- # Safedeps Architecture (v2)
1
+ # Safedeps Architecture
2
2
 
3
- > **Note on naming**: repo v1 시절 `npm-reorg-guard` 출시됐다. v2 부터 ecosystem 통합 + advisory-first 게이트를 도입하면서 제품/CLI 이름을 **`safedeps`** 로 rename 한다. 내부 post-install rollback engine 은 v1 의 `reorg-guard` 컨셉을 그대로 계승. 이 문서는 v2 의 SSoT.
4
-
5
- 기능 분리:
6
- - **README.md** — 사용자 설치/사용 가이드 (rename 후 갱신 예정)
7
- - **SKILL.md** — 스킬 메타 + hook 선언 (Claude/Codex skill loader 가 읽는 SSoT)
8
- - **ARCHITECTURE.md** — 내부 흐름·설계 (이 문서)
3
+ > Internal design and runtime flow. User-facing setup lives in [`README.md`](./README.md); the skill manifest and hook declarations live in [`SKILL.md`](./SKILL.md). *(한국어 [ARCHITECTURE.ko.md](./ARCHITECTURE.ko.md))*
4
+ >
5
+ > **Naming** — the project shipped as `npm-reorg-guard` in v1. v2 unified ecosystems and added the advisory ledger, renaming the product and CLI to **`safedeps`**. The post-install rollback engine still inherits the v1 `reorg-guard` design, and for npm the PostToolUse effect gate is the primary enforcement surface.
9
6
 
10
7
  ---
11
8
 
12
- ## 0. 핵심 한 문장 (코덱시 합의)
9
+ ## Core idea
13
10
 
14
- > *Safedeps does not decide at install time from multiple live truths.*
15
- > *It approves one dependency spec from provider evidence first, then the hook only enforces that approved spec; reorg remains the rollback layer if the install result diverges.*
11
+ > Safedeps does not decide at install time from several live truths at once. It approves one dependency closure from provider evidence *first*; then the post-install hook treats the installed lockfile closure as the authority, and reorg rolls back any unapproved or newly-vulnerable effect.
16
12
 
17
- 번역: Safedeps install 순간에 여러 라이브 truth 동시에 조회해서 결정하지 않는다. **사전에 provider evidence 안전한 dependency spec 먼저 승인** (approve) 하고, **hook 승인된 spec 명령이 일치할 때만 통과**시킨다. **reorg install 결과가 spec 어긋날 때의 rollback layer** 로 남는다.
13
+ Approval happens **before** the install, against canonical advisory evidence. Enforcement happens **after** the install, against what actually landed on disk. For npm, the full closure (direct + transitive) is checked through OSV `/v1/querybatch` with a 24-hour per-`pkg@version` cache. Closure resolution for the other ecosystems is future work.
18
14
 
19
15
  ---
20
16
 
21
- ## 1. The Big Picture — 3-Phase Defense
17
+ ## 1. Two lanes, one umbrella
18
+
19
+ safedeps owns security gates at two distinct moments, under one skill. It absorbed the v1 `npm-reorg-guard` (install-time reorg) and then the `security-release-gates` project (release-time checks, 2026-05-24). The goal is not to pile every "security" concern into one file — it is to give the gates a single canonical owner while keeping each lane's responsibility separate (SRP).
22
20
 
21
+ ```text
22
+ ┌──────────────────────────────────────────────────────────────────────┐
23
+ │ safedeps — one security umbrella │
24
+ │ │
25
+ │ INSTALL-TIME lane RELEASE-TIME lane │
26
+ │ (during development, per install) (before a release / push) │
27
+ │ ───────────────────── ────────────────── │
28
+ │ advisory check (npm: OSV batch) safedeps scan secrets │
29
+ │ fast command gate (PreToolUse) safedeps audit deps │
30
+ │ npm effect gate (PostToolUse) safedeps hooks install|check │
31
+ │ safedeps git pre-commit │
32
+ │ scope: the package being installed scope: the whole repo tree │
33
+ │ (absorbed from │
34
+ │ security-release-gates) │
35
+ │ │
36
+ │ shared: public DBs (OSV/KEV/GHSA) · local-first · no silent │
37
+ │ fallback (a provider/scanner miss is fail-closed) │
38
+ └──────────────────────────────────────────────────────────────────────┘
23
39
  ```
24
- ┌─────────────────────────────────────────────────────────────────────┐
25
- │ │
26
- │ Phase 1: ADVISORY GATE Phase 2: HOOK ENFORCEMENT │
27
- │ ──────────────────── ──────────────────── │
28
- │ │
29
- │ 사용자 의도 │ │
30
- │ (intent: 패키지 설치 │ │
31
- │ 하고 싶다) │ │
32
- │ │ │ │
33
- │ ▼ │ │
34
- │ ┌─────────────┐ OSV.dev │ │
35
- │ │ safedeps │◄────primary─────┤ │
36
- │ check │ CISA KEV │ │
37
- │ │ │◄──hard-risk────┤ │
38
- │ │ │ GHSA │ │
39
- │ │◄──enrichment───┤ │
40
- └──────┬──────┘
41
- │ │ │
42
-
43
- │ ┌──────────────────────┐ │
44
- │ │ approved spec ledger │ │
45
- │ .safedeps/ │ │
46
- approved-specs/ │ │
47
- <hash>.json │ │
48
- │ │ • ecosystem │ │
49
- │ • package@version │ │
50
- │ │ • approved_at │ │
51
- │ │ expires_at │ │
52
- evidence sources │ │
53
- └──────┬───────────────┘ │
54
- │ │ │
55
- │ ▼ │
56
- ┌─────────────────┐ │
57
- │ │ 사용자 / Claude │ │
58
- install 명령 발행 │ │
59
- (npm install ..) │ │
60
- │ └────────┬────────┘ │
61
- │ │ │
62
- │ ▼ │
63
- │ ╔═════════════════════════╗ │
64
- │ ║ PreToolUse HOOK ║ │
65
- │ ║ safedeps-pre-guard.sh ║ │
66
- │ ╚════════╤════════════════╝ │
67
- │ │ │
68
- │ ledger 조회: │
69
- │ "이 명령의 ecosystem + │
70
- │ pkg@version 이 approved │
71
- │ spec 과 일치?" │
72
- │ │ │
73
- │ ┌────────┴────────┐ │
74
- │ ▼ ▼ │
75
- │ match O match X │
76
- │ │ │ │
77
- │ ▼ ▼ │
78
- │ 명령 실행 BLOCK + 안내 │
79
- │ │ ("safedeps │
80
- │ │ check ... 먼저 해") │
81
- │ ▼ │
82
- │ install 실행 │
83
- │ │ │
84
- │ ▼ │
85
- │ ╔══════════════════════════════╗ │
86
- │ ║ PostToolUse HOOK ║ │
87
- │ ║ safedeps-post-verify.sh ║ │
88
- │ ╚════════╤═════════════════════╝ │
89
- │ │ │
90
- │ lockfile diff vs │
91
- │ approved spec 비교 │
92
- │ │ │
93
- │ ┌────────┴────────┐ │
94
- │ ▼ ▼ │
95
- │ spec 과 동일 diverged │
96
- │ │ │ │
97
- │ ▼ ▼ │
98
- │ CONFIRM REORG │
99
- │ (clean baseline) (rollback to │
100
- │ last confirmed) │
101
- │ │
102
- │ Phase 3: POST-INSTALL SAFETY NET (v1 의 reorg engine 계승) │
103
- │ ─────────────────────────────────────────────── │
104
- │ │
105
- └─────────────────────────────────────────────────────────────────────┘
40
+
41
+ - **Install-time lane** (sections 2–13 below) — advisory check, fast command guard, and the npm effect gate + reorg. Per-package and proactive.
42
+ - **Release-time lane** the repo-tree checks from `security-release-gates` (secret scan, dependency audit, repo hook install/check, privacy profile), exposed under the `safedeps scan|audit|hooks|git` command namespace. Repo-specific policy (`.gitleaks.toml`, lockfiles) stays in the target repo; safedeps owns execution, install, and verification.
43
+
44
+ The two lanes differ in timing and scope (one package's effect before/after install vs. the whole repo before a release). They live under one umbrella but stay separated by command namespace.
45
+
46
+ **The effect-primary model is npm-only.** `pip`, `cargo`, `go`, `gem`, `maven`, and `nuget` stay on the v2.1 command-gate + reorg model until their closure resolvers land; they are not described as having PostToolUse closure authority.
47
+
48
+ ### Install-time flow
49
+
50
+ ```
51
+ intent ("I want to install this package")
52
+
53
+
54
+ ┌─────────────┐ OSV.dev ──canonical──►
55
+ safedeps │ CISA KEV ──hard-risk──► advisory check
56
+ check GHSA ──enrichment─► (Phase 1)
57
+ └──────┬──────┘
58
+ approve
59
+
60
+ ┌──────────────────────┐
61
+ approved-spec ledger │ ~/.safedeps/approved-specs/<hash>.json
62
+ ecosystem · pkg@ver + transitive_specs (npm closure)
63
+ approved_at/expires
64
+ └──────────────────────┘
65
+
66
+
67
+ install command issued ──► PreToolUse hook (fast command guard, Phase 2)
68
+ ledger match? ── miss ──► BLOCK + "run safedeps check first"
69
+ match ──► run
70
+
71
+ install runs
72
+
73
+
74
+ PostToolUse hook (npm effect gate, Phase 3)
75
+ lockfile closure vs ledger + OSV batch
76
+ ├─ approved & clean ──► CONFIRM (new safe baseline)
77
+ └─ unapproved / vulnerable ──► REORG (roll back to last confirmed)
106
78
  ```
107
79
 
108
- 핵심 통찰:
109
- - **Phase 1 = pre-install advisory gate** (새로 추가). vuln DB 조회 안전 spec 결정. 사용자/Claude install 명령 *작성하기 전에* 끝남.
110
- - **Phase 2 = hook enforcement**. hook 자체는 vuln DB 조회 함. **approved spec ledger 와의 일치만 검증**. 빠르고 결정론적.
111
- - **Phase 3 = post-install rollback**. v1 reorg engine 그대로. install 결과가 approved spec 과 어긋나면 마지막 confirmed 로 복원.
80
+ - **Phase 1 — advisory check.** For npm, safedeps builds a script-free lockfile in a temp dir (`npm install <pkg>@<version> --package-lock-only --ignore-scripts`), extracts the full closure, and queries OSV `/v1/querybatch` for direct and transitive packages together. When clean, the direct ledger entry records `transitive_specs`.
81
+ - **Phase 2 fast command gate.** The PreToolUse hook parses the command, blocks obvious unapproved installs, and snapshots dependency files. It is a best-effort advisory layer that gives the agent immediate feedback — not the final authority. On Claude Code it also rewrites an npm install to add `--ignore-scripts` (via the hook `updatedInput` capability), so the install runs inert and no lifecycle script executes until the effect gate has verified the closure.
82
+ - **Phase 3 npm primary effect gate.** The PostToolUse hook compares the actual `package-lock.json` closure against the ledger's direct entries and their `transitive_specs`, and re-queries OSV in batch. Any unapproved or vulnerable package triggers a reorg to the last confirmed snapshot. This authority is scoped to the npm closure.
112
83
 
113
84
  ---
114
85
 
115
- ## 2. Vulnerability DBSource Hierarchy
86
+ ## 2. Advisory sourcesone canonical truth
116
87
 
117
88
  ```
118
- ┌──────────────────────────────────────────────────────────────────────┐
119
- TIER 1 — PRIMARY (canonical truth) │
120
- │ ──────────────────────────────────────── │
121
- │ OSV.dev │
122
- multi-ecosystem (npm, pip, cargo, go, gem, maven, nuget, ...) │
123
- package@version 질의 표준화 │
124
- │ • Google 운영, 무료 API, JSON │
125
- │ • GHSA, RustSec, GoVulnDB 다 aggregate │
126
- │ → 모든 advisory 1차 query target │
127
- ├──────────────────────────────────────────────────────────────────────┤
128
- │ TIER 2 OVERLAY (hard-risk signal)
129
- │ ──────────────────────────────────────── │
130
- │ CISA KEV (Known Exploited Vulnerabilities) │
131
- │ • "실제 야생에서 exploit 확인" 만 추림 │
132
- │ • OSV 결과와 cross-reference: KEV 매치 hard-block (override 불가)
133
- │ → 일반 CVE vs "급박한 CVE" 구분선 │
134
- ├──────────────────────────────────────────────────────────────────────┤
135
- TIER 3 ENRICHMENT / CROSS-CHECK │
136
- │ ──────────────────────────────────────── │
137
- │ GitHub Advisory (GHSA) │
138
- │ • OSV 에 일부 들어오지만 first_patched_version / │
139
- │ vulnerable_version_range 같은 metadata 가 개발자 친화 │
140
- │ • "OSV 와 다른 결" 만 surface — discrepancy verifier 결 │
141
- │ NVD │
142
- │ • CVE 원본, CVSS 점수, CPE 매핑, hasKev flag │
143
- │ • 점수 기반 우선순위 계산 │
144
- │ deps.dev (Google) │
145
- │ • OSV 기반 + package graph metadata (depended_by, license, ...) │
146
- │ • transitive dep 위험 분석 │
147
- │ Snyk DB (optional) │
148
- │ • purl 기반 query, UI 풍부 │
149
- │ • 무료 quota 한도, configured optional feed 만 사용 │
150
- └──────────────────────────────────────────────────────────────────────┘
89
+ TIER 1 — PRIMARY (canonical truth)
90
+ OSV.dev
91
+ • multi-ecosystem (npm, pip, cargo, go, gem, maven, nuget, …)
92
+ • normalized package@version queries · free JSON API (Google)
93
+ aggregates GHSA, RustSec, GoVulnDB, and more
94
+ the first query target for every advisory
95
+
96
+ TIER 2 OVERLAY (hard-risk signal)
97
+ CISA KEV (Known Exploited Vulnerabilities)
98
+ • only "confirmed exploited in the wild"
99
+ cross-referenced with OSV results; a KEV match is a hard block (no override)
100
+ → the line between an ordinary CVE and an urgent one
101
+
102
+ TIER 3 ENRICHMENT / CROSS-CHECK
103
+ GitHub Advisory (GHSA) — developer-friendly patched-version metadata; surfaced when it disagrees with OSV
104
+ NVD — CVE source, CVSS scores, KEV flag (for score-based prioritization)
105
+ deps.dev — OSV-based package graph metadata (transitive risk)
106
+ Snyk DB optional configured feed only (free-quota limited)
151
107
  ```
152
108
 
153
- 설계 원칙: **canonical truth OSV 하나**. 다른 source enrichment 또는 overlay. 여러 라이브 source \"동급 진실\" 두면 cross-fire 발생 우리는 OSV truth 두고 KEV/GHSA/NVD/deps.dev \"OSV 다르거나, OSV 신호\" surface.
109
+ Design principle: **OSV is the one canonical truth.** Every other source is overlay or enrichment. Treating several live sources as co-equal truths invites cross-fire; instead OSV is the truth, and KEV/GHSA/NVD/deps.dev only surface signals that disagree with OSV or that OSV did not see.
154
110
 
155
111
  ---
156
112
 
157
- ## 3. Approved Spec Ledger — SSoT
113
+ ## 3. Approved-spec ledger (SSoT)
158
114
 
159
115
  `~/.safedeps/approved-specs/<hash>.json`:
160
116
 
161
117
  ```json
162
118
  {
163
- "hash": "sha256:abc123...",
119
+ "hash": "sha256:abc123",
164
120
  "ecosystem": "npm",
165
121
  "package": "@jackwener/opencli",
166
122
  "version": "1.7.16",
@@ -169,427 +125,277 @@
169
125
  "expires_at": "2026-06-18T13:00:00Z",
170
126
  "approved_by": "user@example.com",
171
127
  "evidence": {
172
- "osv": { "queried_at": "2026-05-18T13:00:00Z", "vulnerabilities": [] },
173
- "kev": { "queried_at": "2026-05-18T13:00:00Z", "exploited": false },
174
- "ghsa": { "queried_at": "2026-05-18T13:00:00Z", "advisories": [] }
128
+ "closure_checked": true,
129
+ "provider": { "type": "osv-querybatch", "results": [] },
130
+ "closure": []
175
131
  },
176
132
  "transitive_specs": [
177
- { "package": "...", "version": "...", "spec_hash": "..." }
133
+ { "ecosystem": "npm", "package": "", "version": "" }
178
134
  ]
179
135
  }
180
136
  ```
181
137
 
182
- **핵심 필드**:
183
- - `hash` — `(ecosystem, package, version)` 의 deterministic hash. hook 이 명령에서 같은 hash 추출 → ledger 조회.
184
- - `approved_at` / `expires_at` — **lifecycle TTL**. 기본 30일. 만료 후 새 CVE 가능성 있어 자동 revoke + re-check 강제.
185
- - `evidence` — 그 시점에 어느 source 가 무엇을 봤는지. audit trail.
186
- - `transitive_specs` — direct 만 아니라 transitive dep 도 ledger 에 박아 \"sub-dep 의 zero-day\" 도 감지 가능.
138
+ Key fields:
187
139
 
188
- **Lifecycle**:
140
+ - `hash` — a deterministic hash of `(ecosystem, package, version)`. The hook derives the same hash from a command and looks the ledger up by it.
141
+ - `approved_at` / `expires_at` — lifecycle TTL, 30 days by default. After expiry a new CVE may exist, so the spec is auto-revoked and re-check is forced.
142
+ - `evidence` — which source saw what, at approval time. An audit trail.
143
+ - `transitive_specs` — the full transitive closure the direct entry approved. The npm effect gate reorgs any `pkg@version` that appears in the lockfile but is in neither the direct entry nor this array.
144
+
145
+ Lifecycle:
189
146
 
190
147
  ```
191
- approve install confirm re-check
192
- ─────── ─────── ─────── ────────
193
- │ │ │ │
194
- ▼ ▼ ▼ ▼
195
- ledger 신규 hook 통과 ledger.confirmed=true daily cron
196
- approved_at=now spec hash 일치 post-verify 일치 OSV re-query
197
- expires_at=+30d │
198
-
199
- ┌──────┴──────┐
200
- ▼ ▼
201
- 여전히 clean 새 CVE 발견
202
- │ │
203
- ▼ ▼
204
- expires_at ledger revoke
205
- 연장 + 사용자 경고
206
- + (옵션) auto reorg
148
+ approve install confirm re-check (daily)
149
+ ─────── ─────── ─────── ────────────────
150
+ ledger entry ──► hook passes ──► post-verify match ──► OSV re-query
151
+ approved_at=now spec matches confirmed = true │
152
+ expires_at=+30d ▼
153
+ still clean ──► extend expiry
154
+ new CVE ──► revoke + warn (+ optional reorg)
207
155
  ```
208
156
 
209
157
  ---
210
158
 
211
- ## 4. Runtime Flow 3-Phase Detail
159
+ ## 4. Runtime flow in detail
212
160
 
213
161
  ### Phase 1 — `safedeps check <ecosystem> <pkg>@<range>`
214
162
 
215
163
  ```
216
- 사용자 / Claude:
217
- "@jackwener/opencli ^1.7.0 깔고 싶음"
164
+ safedeps check npm "@jackwener/opencli@^1.7.0"
218
165
 
166
+ ├─► ledger lookup ── hit (valid) ──► "already safe, install is fine"
167
+ │ └ miss/expired ──► proceed to check
219
168
 
220
- ┌─────────────────────────────────────────────────────────┐
221
- safedeps check npm "@jackwener/opencli@^1.7.0" │
222
- └────────────────────┬────────────────────────────────────┘
223
-
224
- ┌────────────┴────────────────────────────┐
225
-
226
- ┌──────────────┐ ┌──────────────┐
227
- resolve │ │ ledger lookup │
228
- version │ │ "이미 approved?"
229
- range │ └───────┬──────┘
230
- candidate │ │
231
- versions │ ▼
232
- └──────┬───────┘ ┌───────┴─────┐
233
- │ ▼ ▼
234
- ▼ hit (valid) miss / expired
235
- ┌──────────────┐ │ │
236
- │ OSV query │ ▼ ▼
237
- │ per version │ "이미 안전, install "새로 check"
238
- └──────┬───────┘ 해도 됨"
239
-
240
-
241
- ┌──────────────┐
242
- │ KEV overlay │
243
- │ GHSA cross │
244
- └──────┬───────┘
245
-
246
-
247
- ┌─────────────────────────────────┐
248
- │ 결과 분류: │
249
- │ • clean (no vuln) → approve │
250
- │ • patched_available → approve │
251
- │ 안전 버전으로 spec 재작성 │
252
- │ 예: ^1.7.0 → ^1.7.16 │
253
- │ • KEV hit → HARD BLOCK │
254
- │ "이 패키지는 실제 exploit 됨, │
255
- │ 설치 X. 대체 모듈: AAA, BBB" │
256
- │ • CVE 있는데 patch X → WARN │
257
- │ "취약점 있음, 사용자 결정 필요" │
258
- └─────────────────────────────────┘
259
-
260
-
261
- approved spec ledger 신규 entry 작성
262
- sha256:abc123... = {ecosystem: npm, pkg, version, ...}
169
+ resolve range → concrete version(s)
170
+
171
+
172
+ OSV query ──► KEV overlay ──► GHSA cross-check
173
+
174
+
175
+ classify:
176
+ clean → approve
177
+ patched available → approve, rewrite spec to the fixed version (^1.7.0 ^1.7.16)
178
+ KEV hit HARD BLOCK ("exploited in the wild; do not install")
179
+ CVE, no patch → WARN (user decision required)
180
+
181
+
182
+ write a new approved-spec ledger entry
263
183
  ```
264
184
 
265
- ### Phase 2 Hook Enforcement (PreToolUse / `safedeps-pre-guard.sh`)
185
+ For npm, "OSV query" runs over the **whole resolved closure** in one `/v1/querybatch` call, and the approved entry records every transitive package in `transitive_specs`.
186
+
187
+ ### Phase 2 — fast command guard (PreToolUse / `safedeps-pre-guard.sh`)
266
188
 
267
189
  ```
268
- Claude Bash 실행 요청: "npm install @jackwener/opencli@^1.7.16"
190
+ Claude runs: npm install @jackwener/opencli@^1.7.16
269
191
 
270
192
 
271
- ┌─────────────────────────────────┐
272
- safedeps-pre-guard.sh │
273
- 1. 명령 파싱: │
274
- │ ecosystem = npm │
275
- │ pkg = @jackwener/opencli │
276
- │ version_range = ^1.7.16 │
277
- │ 2. spec hash 계산 │
278
- │ 3. ledger 조회 │
279
- └────────────┬────────────────────┘
280
-
281
- ┌────────┴────────┐
282
- ▼ ▼
283
- ledger hit ledger miss
284
- (approved + (또는 expired)
285
- not expired) │
286
- │ ▼
287
- ▼ ┌──────────────────────┐
288
- PASS │ BLOCK + Claude 한테 │
289
- (명령 실행) │ 안내: │
290
- │ "이 패키지가 advisory │
291
- │ gate 통과 안 됨. │
292
- │ safedeps check ... │
293
- │ 먼저 실행해서 spec │
294
- │ approve 해야 함" │
295
- └──────────────────────┘
193
+ parse command → ecosystem, package, version_range
194
+ compute spec hash → ledger lookup
195
+
196
+ ├─ hit (approved, not expired) ──► PASS (run the command)
197
+ └─ miss / expired ──────────────► BLOCK + "run `safedeps check …` first, then retry"
296
198
  ```
297
199
 
298
- ### Phase 3 Post-Install Rollback (PostToolUse / `safedeps-post-verify.sh`)
200
+ The guard also snapshots lockfiles/manifests and keeps the v1 hardcoded pattern blocks (see section 5). It is fast and advisory; the authority is the post-install gate.
201
+
202
+ ### Phase 3 — npm primary effect gate + reorg (PostToolUse / `safedeps-post-verify.sh`)
299
203
 
300
204
  ```
301
- install 완료 → safedeps-post-verify.sh
205
+ install done → safedeps-post-verify.sh
302
206
 
303
207
 
304
- ┌─────────────────────────────────────────┐
305
- 1. lockfile entry 추출 │
306
- 2. entry spec hash 계산 │
307
- 3. ledger 비교 │
308
- 4. install script / native binary 검사 │
309
- (v1 reorg-guard 로직 그대로)
310
- └────────────┬────────────────────────────┘
311
-
312
- ┌────────┴────────┐
313
-
314
- spec 과 동일 diverged
315
- + 의심 없음 (예: transitive dep
316
- │ 이 ledger 에 없는
317
- ▼ 버전으로 깔림,
318
- CONFIRM install script 의심,
319
- (ledger 의 native binary 출현)
320
- confirmed=true) │
321
-
322
- REORG (v1 engine):
323
- • lockfile ← 마지막 confirmed snapshot
324
- • rm -rf node_modules
325
- • npm install (재설치 = ledger 와 일치)
326
- • reorg.log 기록
327
- • Claude 한테 경고
208
+ read the actual package-lock.json closure
209
+ check every pkg@version against the ledger (direct entries + transitive_specs)
210
+ re-query OSV in batch for the whole closure
211
+ inspect install scripts + native binaries (v1 reorg-guard logic)
212
+
213
+ ├─ all approved, clean, no suspicion ──► CONFIRM (new safe baseline)
214
+ └─ unapproved / vulnerable / suspicious ──► REORG:
215
+ • restore lockfile from the last confirmed snapshot
216
+ • rm -rf node_modules; reinstall to match the ledger
217
+ • append to reorg.log; message the agent
328
218
  ```
329
219
 
330
220
  ---
331
221
 
332
- ## 5. Threat Model (v2 갱신)
222
+ ## 5. Threat model
333
223
 
334
224
  ```
335
- ┌─────────────────────────────────────────────────────────────────────┐
336
- PHASE 1 ADVISORY GATE (`safedeps check`)
337
- ├─────────────────────────────────────────────────────────────────────┤
338
- 알려진 CVE 매칭 (OSV.dev 기반, multi-ecosystem) │
339
- KEV 매칭 hard-block (사용자 override 불가) │
340
- │ • patched_available 시 안전 버전으로 spec auto-rewrite │
341
- transitive dep 의 vuln 도 ledger 에 박아 sub-dep 침해 감지 │
342
- ├─────────────────────────────────────────────────────────────────────┤
343
- PHASE 2 HOOK ENFORCEMENT (`safedeps-pre-guard.sh`) │
344
- ├─────────────────────────────────────────────────────────────────────┤
345
- │ v1 의 hardcoded pattern 결도 유지 (defense-in-depth): │
346
- typosquat 명단 매치 │
347
- curl|bash pipe execution
348
- 비표준 --registry URL │
349
- install script safety disabling │
350
- eval / subshell indirection │
351
- │ + 새로운 enforcement: │
352
- │ • spec hash 가 ledger 에 없거나 expired → BLOCK + advisory gate 안내 │
353
- ├─────────────────────────────────────────────────────────────────────┤
354
- │ PHASE 3 — POST-INSTALL REORG (`safedeps-post-verify.sh`) │
355
- ├─────────────────────────────────────────────────────────────────────┤
356
- │ • install script 의 network/code execution/sensitive path 검사 │
357
- │ • base64/hex obfuscation │
358
- │ • 비표준 registry resolved URL │
359
- │ • 50+ dep explosion │
360
- │ • native binary 출현 │
361
- │ • lockfile entry 가 approved spec 과 diverged → REORG │
362
- └─────────────────────────────────────────────────────────────────────┘
225
+ ADVISORY CHECK (safedeps check)
226
+ known-CVE matching (OSV, multi-ecosystem)
227
+ • KEV match → hard block (no user override)
228
+ patched-available auto-rewrite the spec to the fixed version
229
+ transitive vulns recorded in the ledger, so sub-dependency compromise is detectable
230
+
231
+ FAST COMMAND GUARD (safedeps-pre-guard.sh)
232
+ v1 hardcoded patterns (defense-in-depth): typosquat list · curl|bash pipes ·
233
+ non-standard --registry · install-script-safety disabling · eval/subshell indirection
234
+ + fast advisory ledger check: missing/expired spec → block with advisory-gate guidance
235
+
236
+ npm PRIMARY EFFECT GATE + REORG (safedeps-post-verify.sh)
237
+ install-script network / code-execution / sensitive-path access
238
+ base64 / hex obfuscation
239
+ non-standard registry resolved URLs · 50+ dependency explosion · native binaries
240
+ npm lockfile closure diverging from approved specs / transitive_specs → REORG
363
241
  ```
364
242
 
365
- **막지 않는 (현재 한계)**:
366
- - ledger 의 approved_at 이후 새로 발견된 zero-day — daily re-check 로만 catch 가능, install 시점엔 못 잡음.
367
- - npm registry 자체의 손상.
368
- - 사용자가 `--allow-unverified` 명시 우회한 경우 (observable, log 기록).
243
+ **Install-script timing.** A package's `postinstall` script runs *during* `npm install`. On Claude Code, the Phase 2 hook injects `--ignore-scripts`, so the install is inert and scripts run only after the effect gate confirms the closure (via `npm rebuild`) — a rejected package's scripts never run. On Codex CLI, which does not expose the `updatedInput` hook capability, the install runs normally and a malicious install script can execute once before the post-install reorg cleans up. (The package's *runtime* code is removed before your app runs it on both engines; only install-time lifecycle scripts have this Codex window.)
244
+
245
+ **What it does not stop (current limits):**
246
+
247
+ - A zero-day discovered *after* `approved_at` — only the daily re-check catches it, not the install itself.
248
+ - Compromise of the npm registry itself.
249
+ - An install the user explicitly waved through with `--allow-unverified` (observable, logged).
250
+ - An attacker writing to `~/.safedeps/approved-specs/` directly under the same OS user. The ledger is a local convenience cache; until signing/HMAC or install-time re-validation is added, it is not a security boundary against a same-user attacker. (The effect gate's OSV re-query does, however, still catch a forged approval for a *known-vulnerable* package — see [`ROADMAP.md`](./ROADMAP.md) "Ledger tamper resistance".)
369
251
 
370
252
  ---
371
253
 
372
- ## 6. Provider Failure Modes (No Silent Fallback)
254
+ ## 6. Provider failure modes (no silent fallback)
373
255
 
374
256
  ```
375
- ┌────────────────────────────────────────────────────────────────────┐
376
- OSV.dev 응답 / timeout │
377
- ──────────────────── │
378
- 1차: provider cache (local TTL 24h) 사용 │
379
- │ • cache miss → fail-closed (block + "OSV 응답 없음, 재시도") │
380
- │ • 사용자 explicit `--allow-unverified` 시만 우회 + log │
381
- ├────────────────────────────────────────────────────────────────────┤
382
- CISA KEV 응답 무 │
383
- │ ──────────────────── │
384
- │ • KEV 매일 1회 download (정적 catalog), 로컬 cache 만 사용 │
385
- 24h 이상 stale 경고 │
386
- ├────────────────────────────────────────────────────────────────────┤
387
- │ GHSA / NVD 응답 무 │
388
- │ ──────────────────── │
389
- │ • enrichment 결이라 fail-open 허용 │
390
- │ • OSV 결과로만 진행 + log 에 "GHSA cross-check skipped" │
391
- └────────────────────────────────────────────────────────────────────┘
257
+ OSV.dev — no response / timeout
258
+ first: use the local provider cache (24h TTL)
259
+ • cache miss → fail-closed (block; "no OSV response, retry")
260
+ bypass only with explicit --allow-unverified, and it is logged
261
+
262
+ CISA KEV no response
263
+ • KEV is a static catalog downloaded once a day; only the local cache is used
264
+ warn when it is more than 24h stale
265
+
266
+ GHSA / NVD no response
267
+ enrichment only, so fail-open is allowed
268
+ • proceed on OSV alone and log "GHSA cross-check skipped"
392
269
  ```
393
270
 
394
- 설계 원칙: **silent fallback 금지**. 모든 우회는 observable + log. canonical truth (OSV) 응답 하면 default = fail-closed.
271
+ Design principle: **no silent fallback.** Every bypass is observable and logged. When the canonical truth (OSV) cannot answer, the default is fail-closed.
395
272
 
396
273
  ---
397
274
 
398
- ## 7. State Layout — `~/.safedeps/`
275
+ ## 7. State layout — `~/.safedeps/`
399
276
 
400
277
  ```
401
278
  ~/.safedeps/
402
- ├── approved-specs/
403
- │ ├── sha256-abc123.json ← 한 (ecosystem, package, version) 당 한 파일
404
- ├── sha256-def456.json
405
- │ └── ...
406
-
407
- ├── snapshots/ ← v1 reorg snapshot 그대로 계승
408
- ├── 20260518-130000-xyz/
409
- │ │ ├── package-lock.json
410
- │ │ ├── yarn.lock
411
- │ │ ├── pnpm-lock.yaml
412
- │ │ ├── poetry.lock ← v2 ecosystem 확장
413
- │ │ ├── uv.lock
414
- │ │ ├── Cargo.lock
415
- │ │ ├── go.sum
416
- │ │ ├── Gemfile.lock
417
- │ │ └── meta.json
418
- │ └── ...
419
-
420
- ├── confirmed_${dir_hash} ← 프로젝트별 마지막 confirmed snapshot
421
-
279
+ ├── approved-specs/ ← ledger SSoT, one JSON file per (ecosystem, package, version)
280
+ │ ├── sha256-abc123.json
281
+ └──
282
+ ├── snapshots/ ← reorg snapshots (inherited from v1, extended to all lockfiles)
283
+ └── <id>/ { package-lock.json, yarn.lock, pnpm-lock.yaml, poetry.lock, uv.lock,
284
+ │ Cargo.lock, go.sum, Gemfile.lock, meta.json }
285
+ ├── confirmed_${dir_hash} ← per-project last confirmed snapshot
422
286
  ├── cache/
423
- │ ├── osv/ ← OSV query 응답 cache (24h TTL)
424
- └── npm-@jackwener-opencli-1.7.16.json
425
- │ └── kev/ CISA KEV daily catalog
426
- │ └── kev-2026-05-18.json
427
-
428
- ├── locks/ ← atomic state (TOCTOU 방지)
429
- ├── reorg.log ← REORG event 기록 (append-only)
430
- └── advisory.log ← advisory gate event 기록 (block/approve)
287
+ │ ├── osv/ ← OSV query responses (24h TTL)
288
+ │ └── kev/ ← CISA KEV daily catalog
289
+ ├── locks/ atomic state (TOCTOU guard)
290
+ ├── reorg.log ← reorg events (append-only)
291
+ └── advisory.log ← advisory-gate decisions (approve / block)
431
292
  ```
432
293
 
433
- 설계 결정:
434
- - `approved-specs/` = ledger SSoT, JSON-per-spec (atomic write).
435
- - `snapshots/` = v1 그대로 + py/rust/go/ruby lockfile 추가.
436
- - `cache/osv/`, `cache/kev/` = provider 응답 cache (TTL).
437
- - `advisory.log` = advisory gate 의 모든 approve/block decision audit trail.
294
+ - `approved-specs/` is the ledger SSoT, one atomic JSON write per spec.
295
+ - `snapshots/` keeps the v1 design plus the Python/Rust/Go/Ruby lockfiles.
296
+ - `cache/osv/` and `cache/kev/` hold provider responses under TTL.
297
+ - `advisory.log` is the audit trail of every approve/block decision.
438
298
 
439
299
  ---
440
300
 
441
- ## 8. Multi-Ecosystem Support (v2 확장)
301
+ ## 8. Multi-ecosystem support
442
302
 
443
- | Ecosystem | Manifest | Lockfile | safedeps check 명령 |
303
+ | Ecosystem | Manifest | Lockfile | `safedeps check` |
444
304
  |---|---|---|---|
445
305
  | npm | `package.json` | `package-lock.json` | `safedeps check npm <pkg>@<range>` |
446
- | yarn | `package.json` | `yarn.lock` | `safedeps check npm <pkg>@<range>` (OSV 공통) |
306
+ | yarn | `package.json` | `yarn.lock` | `safedeps check npm <pkg>@<range>` |
447
307
  | pnpm | `package.json` | `pnpm-lock.yaml` | `safedeps check npm <pkg>@<range>` |
448
308
  | pip (Poetry) | `pyproject.toml` | `poetry.lock` | `safedeps check pypi <pkg>@<range>` |
449
309
  | pip (uv) | `pyproject.toml` | `uv.lock` | `safedeps check pypi <pkg>@<range>` |
450
310
  | pip (Pipenv) | `Pipfile` | `Pipfile.lock` | `safedeps check pypi <pkg>@<range>` |
451
- | pip (raw) | `requirements.txt` | (약함) | `safedeps check pypi <pkg>@<range>` |
311
+ | pip (raw) | `requirements.txt` | (weak) | `safedeps check pypi <pkg>@<range>` |
452
312
  | cargo | `Cargo.toml` | `Cargo.lock` | `safedeps check crates.io <pkg>@<range>` |
453
313
  | go | `go.mod` | `go.sum` | `safedeps check go <pkg>@<range>` |
454
314
  | ruby | `Gemfile` | `Gemfile.lock` | `safedeps check rubygems <pkg>@<range>` |
455
- | maven | `pom.xml` | (해당 디렉토리) | `safedeps check maven <group>:<artifact>@<range>` |
315
+ | maven | `pom.xml` | (directory) | `safedeps check maven <group>:<artifact>@<range>` |
456
316
  | nuget | `*.csproj` | `packages.lock.json` | `safedeps check nuget <pkg>@<range>` |
457
317
 
458
- ecosystem typosquat 명단·install script 위험 패턴은 별도 정적 list 로. OSV.dev ecosystem 정규화를 표준화해줘서 single API 결로 모두 cover.
318
+ OSV normalizes ecosystem names, so one API path covers all of them at advisory-check time. Per-ecosystem typosquat lists and install-script risk patterns live in separate static lists. Note that the npm effect gate (closure-vs-ledger enforcement) is npm-only today; the other ecosystems use the command-gate + reorg model.
459
319
 
460
320
  ---
461
321
 
462
- ## 9. 컴포넌트 책임 분리 (SoC)
322
+ ## 9. Component responsibilities (SoC)
463
323
 
464
- ```
465
- ┌─────────────────────────────────────────────────────────────────────┐
466
- SKILL.md Claude/Codex skill loader 읽는 SSoT.
467
- │ hook 선언 + advisory gate 사용법 안내. │
468
- ├─────────────────────────────────────────────────────────────────────┤
469
- │ README.md 사용자 install 가이드. │
470
- ├─────────────────────────────────────────────────────────────────────┤
471
- │ ARCHITECTURE.md 문서. 내부 흐름·설계. │
472
- ├─────────────────────────────────────────────────────────────────────┤
473
- │ bin/safedeps — CLI entry (advisory check, ledger 관리, │
474
- │ 재검증 등).
475
- ├─────────────────────────────────────────────────────────────────────┤
476
- │ scripts/safedeps-pre-guard.sh — PreToolUse hook. ledger 일치 검증 │
477
- │ + v1 의 hardcoded pattern. │
478
- ├─────────────────────────────────────────────────────────────────────┤
479
- │ scripts/safedeps-post-verify.sh — PostToolUse hook. lockfile diff + │
480
- │ spec 비교 + reorg. │
481
- ├─────────────────────────────────────────────────────────────────────┤
482
- │ lib/providers/ — OSV / KEV / GHSA / NVD / deps.dev / Snyk │
483
- │ adapter. 하나의 query interface. │
484
- ├─────────────────────────────────────────────────────────────────────┤
485
- │ lib/ledger/ — approved spec ledger I/O. atomic write, │
486
- │ hash 계산, TTL 검사. │
487
- └─────────────────────────────────────────────────────────────────────┘
488
- ```
324
+ | Component | Responsibility |
325
+ |---|---|
326
+ | `SKILL.md` | The SSoT the Claude/Codex skill loader reads hook declarations + advisory-gate usage. |
327
+ | `README.md` | User install guide. |
328
+ | `ARCHITECTURE.md` | This document — internal flow and design. |
329
+ | `bin/safedeps` | CLI entry advisory check, ledger management, re-check, migrate. |
330
+ | `scripts/safedeps-pre-guard.sh` | PreToolUse hook — ledger match + v1 hardcoded patterns + snapshots. |
331
+ | `scripts/safedeps-post-verify.sh` | PostToolUse hook closure-vs-ledger effect gate + reorg. |
332
+ | `lib/providers/` | OSV / KEV / GHSA (and optional NVD / deps.dev / Snyk) adapters behind one query interface. |
333
+ | `lib/ledger/` | Approved-spec ledger I/O — atomic write, hashing, TTL checks. |
334
+ | `lib/npm/closure.sh` | npm closure resolution from a lockfile. |
489
335
 
490
336
  ---
491
337
 
492
- ## 10. 비교 기존 도구들과 (정확화)
338
+ ## 10. How safedeps differs from existing tools
493
339
 
494
- | 도구 | | 동작 시점 | safedeps 차이 |
340
+ | Tool | Focus | When | Difference from safedeps |
495
341
  |---|---|---|---|
496
- | `npm audit` | materialized lock 기반 취약점 보고 | post-install | spec 결정 / 차단 함, **보고만** |
497
- | `pip-audit` / `cargo audit` / `bundler-audit` | 같은 결, 다른 ecosystem | post-install | 같음 |
498
- | **socket.dev** | SaaS risk intelligence (behavioral + static) | pre-install + post-install | 클라우드 의존, 무료 quota 한도, **외부 SaaS** |
499
- | **lavamoat** | runtime permission containment (sandbox) | runtime | install 차단 X, **무겁고 dev 단계 부담** |
500
- | **pnpm `onlyBuiltDependencies`** | lifecycle script allowlist | install 단계 | typosquat / vuln DB X, **script 차단만** |
501
- | **deps.dev** | package graph metadata | query only | active gate 아님, **데이터만** |
502
- | **OSV-Scanner** | OSV lockfile 스캔 | post-install (CI) | spec gate X, **lockfile 리포트만** |
503
- | **GitHub Dependabot** | PR 기반 dep update 권장 | repo-level (PR) | local install 차단 X, **PR 단계만** |
504
- | **`safedeps` (이것)** | **advisory gate + approved spec ledger + post-install reorg** | **pre-install + install + post-install** | **3-phase, multi-ecosystem, 로컬 first** |
505
-
506
- 차별점 요약:
507
- - 다른 도구는 \"보고\" / \"sandbox\" / \"script 차단\" / \"PR 권장\" 중 하나에 집중.
508
- - safedeps 는 **\"advisory gate (Phase 1) → hook enforcement (Phase 2) → reorg fallback (Phase 3)\" 의 3겹 defense-in-depth**.
509
- - Snyk / socket.dev 와 달리 **SaaS 의존 X, 로컬 + 공개 DB (OSV/KEV/GHSA) 만**.
342
+ | `npm audit` | report vulns from the materialized lock | post-install | reports only; no spec decision or blocking |
343
+ | `pip-audit` / `cargo audit` / `bundler-audit` | same, other ecosystems | post-install | same |
344
+ | socket.dev | SaaS risk intelligence (behavioral + static) | pre/post-install | cloud-dependent, free-quota limited, external SaaS |
345
+ | lavamoat | runtime permission sandbox | runtime | no pre-install block; heavy on the dev loop |
346
+ | pnpm `onlyBuiltDependencies` | lifecycle-script allowlist | install | no typosquat/vuln DB; script blocking only |
347
+ | deps.dev | package graph metadata | query only | data, not an active gate |
348
+ | OSV-Scanner | OSV scan of a lockfile | post-install (CI) | reports the lockfile; no spec gate |
349
+ | GitHub Dependabot | PR-based dep updates | repo (PR) | no local install block; PR stage only |
350
+ | **`safedeps`** | **advisory check + approved-spec ledger + npm effect gate + reorg** | **pre/install/post** | **closure-level enforcement, multi-ecosystem command guard, local-first** |
351
+
352
+ In short: other tools focus on one of "report," "sandbox," "script-block," or "PR suggestion." safedeps layers advisory check → fast command guard → npm effect gate + reorg into defense-in-depth, and — unlike Snyk or socket.dev — depends on no SaaS, only the local CLI plus public databases (OSV / KEV / GHSA).
510
353
 
511
354
  ---
512
355
 
513
- ## 11. 운영 로그
356
+ ## 11. Operational logs
514
357
 
515
358
  ```bash
516
- # advisory gate decision (approve / block)
517
- tail -f ~/.safedeps/advisory.log
518
-
519
- # reorg event
520
- tail -f ~/.safedeps/reorg.log
521
-
522
- # 현재 approved specs
523
- ls -lt ~/.safedeps/approved-specs/
524
-
525
- # 특정 spec 의 evidence
526
- cat ~/.safedeps/approved-specs/sha256-abc123.json | jq '.evidence'
527
-
528
- # expired specs (만료된 거 재검증 필요)
529
- find ~/.safedeps/approved-specs -name '*.json' -exec jq -r 'select(.expires_at < now) | "\(.package)@\(.version) expired \(.expires_at)"' {} \;
530
-
531
- # OSV cache 비우기 (강제 re-query)
532
- rm -rf ~/.safedeps/cache/osv/
359
+ tail -f ~/.safedeps/advisory.log # advisory-gate decisions (approve / block)
360
+ tail -f ~/.safedeps/reorg.log # reorg events
361
+ ls -lt ~/.safedeps/approved-specs/ # current approved specs
362
+ jq '.evidence' ~/.safedeps/approved-specs/sha256-abc123.json # one spec's evidence
363
+ rm -rf ~/.safedeps/cache/osv/ # clear the OSV cache (force re-query)
533
364
  ```
534
365
 
535
366
  ---
536
367
 
537
- ## 12. v1 → v2 마이그레이션
368
+ ## 12. Legacy / migration: v1 `npm-reorg-guard` → v2
538
369
 
539
- ```
540
- v1 (npm-reorg-guard) v2 (safedeps)
541
- ──────────────────── ──────────────
542
-
543
- ~/.npm-reorg-guard/ → ~/.safedeps/
544
- ~/.claude/skills/ ~/.claude/skills/
545
- npm-reorg-guard/safedeps/
546
- (old local skill path is not canonical)
547
-
548
- scripts/guard.sh → scripts/safedeps-pre-guard.sh
549
- (typosquat / pattern + ledger lookup
550
- 매칭만) + v1 pattern 유지
551
- + namespaced filename
552
-
553
- scripts/verify.sh → scripts/safedeps-post-verify.sh
554
- (lockfile diff + reorg) + approved spec diff
555
- + v1 reorg 유지
556
- + namespaced filename
557
-
558
- (없음) → bin/safedeps ← 새 CLI
559
- check / approve / revoke /
560
- re-check / ledger
561
-
562
- (없음) → lib/providers/ ← OSV / KEV / GHSA / ...
563
- (없음) → lib/ledger/ ← approved spec I/O
564
-
565
- GitHub repo:
566
- aldegad/npm-reorg-guard → aldegad/safedeps
567
- (GitHub redirect only)
568
- ```
370
+ | v1 (`npm-reorg-guard`) | v2 (`safedeps`) |
371
+ |---|---|
372
+ | `~/.npm-reorg-guard/` | `~/.safedeps/` |
373
+ | `~/.claude/skills/npm-reorg-guard/` | `~/.claude/skills/safedeps/` |
374
+ | `scripts/guard.sh` (pattern match only) | `scripts/safedeps-pre-guard.sh` (+ ledger lookup, namespaced) |
375
+ | `scripts/verify.sh` (lockfile diff + reorg) | `scripts/safedeps-post-verify.sh` (+ approved-spec diff, namespaced) |
376
+ | — | `bin/safedeps` — new CLI (check / approve / revoke / re-check / ledger) |
377
+ | | `lib/providers/`, `lib/ledger/` |
378
+ | GitHub `aldegad/npm-reorg-guard` | `aldegad/safedeps` (redirect only) |
569
379
 
570
- v1 migration:
571
- - v1 hook 등록 path (`~/.claude/skills/npm-reorg-guard/scripts/*.sh`) 는 canonical 이 아니다. settings 는 `~/.claude/skills/safedeps/scripts/*.sh` 로 갱신한다.
572
- - v1 `~/.npm-reorg-guard/` 디렉토리 발견 `~/.safedeps/` 으로 마이그레이션한다 (snapshot chain 보존).
573
- - v1 사용자는 `safedeps migrate` 줄로 ledger 신규 생성 + 기존 confirmed snapshot 들을 그대로 approved spec 으로 변환.
380
+ Migration:
381
+
382
+ - The v1 hook path (`~/.claude/skills/npm-reorg-guard/scripts/*.sh`) is not canonical; settings point at `~/.claude/skills/safedeps/scripts/*.sh`.
383
+ - When a `~/.npm-reorg-guard/` directory is found, its state migrates to `~/.safedeps/` (snapshot chain preserved).
384
+ - A v1 user runs `safedeps migrate` once: it creates the ledger and carries existing confirmed snapshots over.
574
385
 
575
386
  ---
576
387
 
577
- ## 13. 한계 + 미래 방향
388
+ ## 13. Limits and future direction
578
389
 
579
- **현재 한계 (v2 첫 출시)**:
580
- - approved_at 이후 발견된 zero-day 는 daily re-check 로만 catch.
581
- - npm/PyPI 같은 registry 자체 손상 시 우리도 못 막음.
582
- - KEV 는 24h 단위 update — 그 사이 새 KEV 등재 못 잡음.
583
- - transitive dep 의 vuln 검사는 ledger 폭증 가능 (수백 개 dep). 최적화 필요.
390
+ **Current limits:**
584
391
 
585
- **미래 확장**:
586
- - **plugin model** 사용자 정의 provider (회사 내부 vuln DB, private registry).
587
- - **policy file** `.safedeps.toml` \"우리 팀 정책: KEV hit 자동 block, CVSS 7+ 사용자 컨펌\" 같이 명시.
588
- - **CI mode** `safedeps check --ci` GitHub Actions / CircleCI 등에서 fail fast.
589
- - **multi-machine ledger sync** — 팀 차원의 approved spec 공유.
590
- - **deps.dev graph 활용** — transitive dep 의 \"위험 score\" 시각화.
591
- - **AI agent integration** — Claude / Codex 가 \"이 패키지 알려진 vuln 있음, 대체 모듈 X 권장\" 결로 직접 제안.
392
+ - A zero-day discovered after `approved_at` is caught only by the daily re-check.
393
+ - A compromise of the registry itself (npm/PyPI/…) is out of reach.
394
+ - KEV updates once a day; a KEV listed in between is not caught until the next refresh.
395
+ - Transitive-closure checking can grow the ledger to hundreds of entries; this needs optimization.
592
396
 
593
- ---
397
+ **Future direction** (see [`ROADMAP.md`](./ROADMAP.md)):
594
398
 
595
- *문서 history*: v1 (`npm-reorg-guard`) 2026-05-18 작성 v2 (`safedeps`) 2026-05-18 재작성. 코덱시 (surface:195) 와 클로디시 (surface:61) peer-question 합의안 기반.
399
+ - Effect-based closure enforcement for the non-npm ecosystems.
400
+ - Ledger tamper resistance (OSV-as-authority + tamper detection; no local signing).
401
+ - Plugin providers, a `.safedeps.toml` policy file, CI mode, multi-machine ledger sync, and agent-suggested safe replacements.