@aldegad/safedeps 2.5.0 → 2.5.1

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/README.ko.md CHANGED
@@ -1,18 +1,28 @@
1
- # Safedeps
1
+ # safedeps
2
2
 
3
- > **모든 install 미확정 블록으로 본다 `safedeps` 안전한 것만 승인하고, 그렇지 않으면 reorg 한다.**
3
+ > **AI 코딩 에이전트가 취약하거나 미승인된 의존성을 설치하지 못하게 막고, 빠져나간 롤백한다.**
4
4
  >
5
- > OSV / CISA KEV / GitHub Advisory 의존성 spec사전 승인하고, Claude Code Codex CLI hook 에서 실제 설치 closure 를 강제하며, 승인과 어긋난 install 자동으로 마지막 안전 snapshot 으로 롤백한다.
5
+ > `safedeps` Claude Code·Codex CLI 에이전트가 실행하는 모든 의존성 install게이트한다. 패키지를 OSV / CISA KEV / GitHub Advisory 사전 승인하고, 실제로 lockfile 에 깔린 closure 를 다시 검증하며, 어긋난 자동으로 롤백한다. 전부 로컬에서 돌고 런타임 의존성은 0.
6
6
 
7
- *Detailed reference [README.md](./README.md) (영문, SSoT)*
7
+ - **사전 승인** — 모든 `pkg@version` 과 (npm 은) 그 전체 transitive closure 를 설치 *전에* OSV(정본)·CISA KEV·GitHub Advisory 로 검사한다.
8
+ - **실제 effect 강제** — 설치 후 실제 `package-lock.json` closure 를 다시 확인하므로, 래핑·난독화된 명령도 게이트를 못 빠져나간다.
9
+ - **롤백** — 미승인·신규 취약 패키지는 마지막 확정 안전 snapshot 으로 되돌린다. Claude Code 에서는 install 이 inert(`--ignore-scripts`)로 돌아 거부된 패키지의 lifecycle script 가 아예 실행되지 않는다.
8
10
 
9
- ---
11
+ ## Quickstart
10
12
 
11
- ## "reorg" 는 뭐고 왜 그 비유인가
13
+ ```bash
14
+ # 1. CLI 설치 — npm 패키지는 scoped, @aldegad/ 접두사 주의
15
+ npm install -g @aldegad/safedeps
12
16
 
13
- 블록체인에서 **reorg (재편성)** 미확정 블록 시퀀스를 무효화하고 마지막 확정된 안전 상태로 체인을 되돌린다. `safedeps` 는 같은 원리를 `node_modules` 적용한다 모든 install 은 일련의 공급망 보안 검사를 통과하기 전까지는 **미확정 블록 후보** 로 취급된다. 의심스러우면 도구가 **reorg** 를 수행한다 — lock 파일, `package.json`, `node_modules` 를 마지막 확정된 안전 snapshot 으로 되돌린다.
17
+ # 2. Claude Code / Codexhook 연결 (idempotent)
18
+ cd "$(npm root -g)/@aldegad/safedeps" && node scripts/install/install-safedeps-hooks.mjs
14
19
 
15
- 빠른 advisory 피드백, 관측 가능한 rollback, silent fallback 없음. command guard best-effort UX 이고, 설치 결과 effect 가 backstop 이다.
20
+ # 3. 이제 에이전트가 실행하는 모든 의존성 install 자동으로 게이트된다.
21
+ ```
22
+
23
+ > `safedeps` 는 CLI 명령어이고, npm 패키지는 **`@aldegad/safedeps`** 다 — npm 의 unscoped `safedeps` 는 무관한 남의 패키지. 전체 skill 소스 트리를 원하면 [설치](#설치) 참고.
24
+
25
+ *Detailed reference → [README.md](./README.md) (영문, SSoT)*
16
26
 
17
27
  ---
18
28
 
@@ -193,6 +203,14 @@ node scripts/install/install-safedeps-recheck-agent.mjs install --hour 9 --minut
193
203
 
194
204
  ---
195
205
 
206
+ ## "reorg" 는 뭐고 왜 그 비유인가
207
+
208
+ 블록체인에서 **reorg (재편성)** 은 미확정 블록 시퀀스를 무효화하고 마지막 확정된 안전 상태로 체인을 되돌린다. `safedeps` 는 모든 install 을 똑같이 본다 — 일련의 공급망 보안 검사를 통과하기 전까지는 미확정 블록 후보다. 설치된 effect 가 어긋나면 도구가 **reorg** 를 수행한다 — lock 파일, `package.json`, `node_modules` 를 마지막 확정된 안전 snapshot 으로 되돌린다.
209
+
210
+ 하지만 reorg 는 **최전선이 아니라 backstop 이다.** 나쁜 install 의 대부분은 여기까지 오지도 않는다 — 사전 승인 게이트가 미승인·플래그된 패키지를 실행 전에 *거부* 하고, Claude Code 에서는 install 이 **inert (`--ignore-scripts`)** 로 돌아 closure 가 깨끗하다고 검증되기 전까지 lifecycle script 가 실행되지 않는다. reorg 가 발동하는 건 잔여 케이스뿐이다 — 승인된 직접 패키지가 미승인·취약 transitive 를 끌어오거나, 래핑된 명령이 advisory 계층을 빠져나간 경우 — 그리고 그때조차 실행되지도 못한 파일을 되돌린다.
211
+
212
+ 빠른 advisory 피드백, 관측 가능한 rollback, silent fallback 없음. command guard 는 best-effort UX 이고, 설치 결과 effect 가 backstop 이다.
213
+
196
214
  ## 다른 도구와 뭐가 다른가
197
215
 
198
216
  `safedeps` 는 **AI 에이전트가 코딩 중 install 명령을 작성하는 순간**에 끼어드는 도구다. CI 스캔, PR 권장, runtime sandbox 처럼 다른 시점에서 동작하는 도구들과 핵심 차별점이 여기 있다.
package/README.md CHANGED
@@ -1,14 +1,28 @@
1
- # Safedeps
1
+ # safedeps
2
2
 
3
- > **Treat every install as an unconfirmed block`safedeps` approves the safe ones, reorgs the rest.**
3
+ > **Stop your AI coding agent from installing vulnerable or unapproved dependencies and roll back the ones that slip through.**
4
4
  >
5
- > Pre-approve dependency installs against OSV / CISA KEV / GitHub Advisory, enforce the installed closure from Claude Code and Codex CLI hooks, and auto-rollback any install that diverges from the approved closure. *(한국어 README → [README.ko.md](./README.ko.md))*
5
+ > `safedeps` gates every dependency install your Claude Code or Codex CLI agent runs. It pre-approves packages against OSV / CISA KEV / GitHub Advisory, re-verifies the closure that actually lands in your lockfile, and auto-rolls-back anything that diverges. Local-only, with zero runtime dependencies. *(한국어 README → [README.ko.md](./README.ko.md))*
6
6
 
7
- ## Why "reorg"?
7
+ - **Pre-approve** — every `pkg@version`, plus its full transitive closure for npm, is cleared against OSV (canonical), CISA KEV, and GitHub Advisory *before* it installs.
8
+ - **Enforce the real effect** — after the install, the actual `package-lock.json` closure is re-checked, so a wrapped or obfuscated command can't sneak a package past the gate.
9
+ - **Roll back** — anything unapproved or newly-vulnerable is reverted to the last confirmed safe snapshot. On Claude Code the install runs inert (`--ignore-scripts`), so a rejected package's lifecycle scripts never run.
8
10
 
9
- In blockchain networks, a **reorganization (reorg)** invalidates a sequence of blocks and reverts the chain to a previously confirmed safe state. `safedeps` applies the same principle to your `node_modules`: every install is treated as an unconfirmed block candidate until it passes a battery of supply-chain security checks. If anything looks wrong, the tool performs a **reorg** -- rolling back lock files, `package.json`, and `node_modules` to the last confirmed safe snapshot.
11
+ ## Quickstart
10
12
 
11
- Fast advisory feedback, observable rollback, and no hidden fallback. The command guard is best-effort UX; the installed effect is the backstop.
13
+ ```bash
14
+ # 1. Install the CLI — the npm package is scoped, note the @aldegad/ prefix
15
+ npm install -g @aldegad/safedeps
16
+
17
+ # 2. Wire the hooks into Claude Code / Codex (idempotent)
18
+ cd "$(npm root -g)/@aldegad/safedeps" && node scripts/install/install-safedeps-hooks.mjs
19
+
20
+ # 3. Done — every dependency install your agent runs is now gated.
21
+ ```
22
+
23
+ > `safedeps` is the CLI command; the npm package is **`@aldegad/safedeps`** — the unscoped `safedeps` on npm is an unrelated package. Prefer the full skill source tree? See [Installation](#installation).
24
+
25
+ <!-- TODO(demo): add a 15-20s asciinema/VHS recording of safedeps catching a malicious install live (inert -> reorg). Highest-leverage conversion asset per launch review. -->
12
26
 
13
27
  ## Distribution Model
14
28
 
@@ -115,6 +129,14 @@ After the install command completes, the verify hook analyzes what changed. For
115
129
  4. The event is logged to `~/.safedeps/reorg.log`.
116
130
  5. Claude Code receives a system message detailing the detected threats and rollback actions.
117
131
 
132
+ ## Why "reorg"?
133
+
134
+ The name borrows from blockchain, where a **reorganization (reorg)** invalidates a sequence of unconfirmed blocks and reverts the chain to its last confirmed safe state. `safedeps` treats every install the same way: an unconfirmed block candidate until it passes a battery of supply-chain checks. If the installed effect diverges, the tool performs a **reorg** -- rolling the lock file, `package.json`, and `node_modules` back to the last confirmed safe snapshot.
135
+
136
+ But the reorg is the **backstop, not the front line.** Most bad installs never reach it: the pre-approval gate *denies* an unapproved or flagged package before it runs, and on Claude Code the install runs **inert** (`--ignore-scripts`) so lifecycle scripts do not execute until the closure verifies clean. The reorg fires for the residual case -- an approved direct package that pulls in an unapproved or vulnerable transitive, or a wrapped command that slips past the advisory layer -- and even then it rolls back files that never got to run.
137
+
138
+ Fast advisory feedback, observable rollback, and no hidden fallback. The command guard is best-effort UX; the installed effect is the backstop.
139
+
118
140
  ## The Blockchain Analogy
119
141
 
120
142
  | Blockchain Concept | Safedeps Equivalent |
package/bin/safedeps CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  set -euo pipefail
9
9
 
10
- SAFEDEPS_VERSION="2.5.0"
10
+ SAFEDEPS_VERSION="2.5.1"
11
11
 
12
12
  # ---- repo / lib bootstrap ----------------------------------------------------
13
13
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aldegad/safedeps",
3
- "version": "2.5.0",
3
+ "version": "2.5.1",
4
4
  "description": "Dependency install safety gate with OSV-backed advisory checks, approved-spec ledger enforcement, and reorg rollback hooks",
5
5
  "main": "bin/safedeps",
6
6
  "bin": {
@@ -190,6 +190,50 @@ EOF
190
190
  grep -qx 'rebuild' "${tmp_root}/npm-calls.log" || fail "post hook runs npm rebuild after verified injected install"
191
191
  pass "post hook rebuilds after verified inert install"
192
192
 
193
+ # Reorg must actually revert the on-disk lockfile, not just print the message. The
194
+ # missing-transitive test below proves the systemMessage; this proves the stronger
195
+ # claim — a tampered lockfile is restored byte-for-byte to the last confirmed safe
196
+ # snapshot on disk. Regression guard so a future change cannot break the rollback
197
+ # while keeping the message green. Stub npm keeps `npm ci` from rewriting the file.
198
+ revert_project="${tmp_root}/revert-project"
199
+ mkdir -p "${revert_project}"
200
+ printf '{"dependencies":{"fixture-parent":"1.0.0"}}\n' > "${revert_project}/package.json"
201
+ cat > "${revert_project}/package-lock.json" <<'EOF'
202
+ {
203
+ "name": "revert-project",
204
+ "lockfileVersion": 3,
205
+ "packages": {
206
+ "": {"dependencies": {"fixture-parent": "1.0.0"}},
207
+ "node_modules/fixture-parent": {"version": "1.0.0", "dependencies": {"fixture-child": "1.0.0"}},
208
+ "node_modules/fixture-child": {"version": "1.0.0"}
209
+ }
210
+ }
211
+ EOF
212
+ cp "${revert_project}/package-lock.json" "${tmp_root}/revert-safe-lock.json"
213
+ scripts/safedeps-pre-guard.sh > /dev/null <<EOF
214
+ {"tool_name":"Bash","tool_input":{"command":"npm install fixture-parent@1.0.0"},"cwd":"${revert_project}"}
215
+ EOF
216
+ cat > "${revert_project}/package-lock.json" <<'EOF'
217
+ {
218
+ "name": "revert-project",
219
+ "lockfileVersion": 3,
220
+ "packages": {
221
+ "": {"dependencies": {"fixture-parent": "1.0.0"}},
222
+ "node_modules/fixture-parent": {"version": "1.0.0", "dependencies": {"fixture-child": "1.0.0"}},
223
+ "node_modules/fixture-child": {"version": "1.0.0"},
224
+ "node_modules/fixture-evil": {"version": "6.6.6", "resolved": "git://evil.example.com/fixture-evil.git"}
225
+ }
226
+ }
227
+ EOF
228
+ revert_post=$(
229
+ PATH="${stub_bin}:${PATH}" scripts/safedeps-post-verify.sh <<EOF
230
+ {"tool_name":"Bash","tool_input":{"command":"npm install fixture-parent@1.0.0"},"cwd":"${revert_project}"}
231
+ EOF
232
+ )
233
+ grep -q '의심스러운 패키지 변경 감지' <<< "${revert_post}" || fail "reorg fires on a tampered lockfile"
234
+ cmp -s "${revert_project}/package-lock.json" "${tmp_root}/revert-safe-lock.json" || fail "reorg restores the exact safe lockfile content on disk"
235
+ pass "reorg reverts a tampered lockfile to safe content on disk"
236
+
193
237
  export SAFEDEPS_HOME="${tmp_root}/safe-missing-transitive"
194
238
  export SAFEDEPS_OSV_API_URL="http://127.0.0.1:${port}/osv/v1/query"
195
239
  export SAFEDEPS_OSV_BATCH_API_URL="http://127.0.0.1:${port}/osv/v1/querybatch"
@@ -225,7 +269,13 @@ EOF
225
269
  )
226
270
  grep -q '의심스러운 패키지 변경 감지' <<< "${missing_post}" || fail "post hook reorgs unapproved transitive package"
227
271
  grep -q 'fixture-child@1.0.0' <<< "${missing_post}" || fail "post hook names unapproved transitive package"
228
- pass "post hook reorgs unapproved transitive package"
272
+ # Not just the message — the unapproved transitive must be gone from the on-disk
273
+ # lockfile. (Reorg removes the tampered lockfile; a no-network reinstall may recreate
274
+ # an empty one, so assert fixture-child is absent rather than the file itself.)
275
+ if grep -q 'fixture-child' "${missing_project}/package-lock.json" 2>/dev/null; then
276
+ fail "post hook reorg leaves the unapproved transitive in the on-disk lockfile"
277
+ fi
278
+ pass "post hook reorgs unapproved transitive package (verified on disk)"
229
279
 
230
280
  export SAFEDEPS_HOME="${tmp_root}/safe"
231
281
  export SAFEDEPS_OSV_API_URL="http://127.0.0.1:${port}/osv/v1/query"