@aldegad/safedeps 2.1.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 +595 -0
- package/LICENSE +190 -0
- package/README.md +311 -0
- package/ROADMAP.md +131 -0
- package/SKILL.md +200 -0
- package/agents/openai.yaml +4 -0
- package/bin/safedeps +842 -0
- package/lib/ledger/ledger.sh +346 -0
- package/lib/providers/providers.sh +479 -0
- package/package.json +41 -0
- package/scripts/install/install-safedeps-hooks.mjs +209 -0
- package/scripts/install/install-safedeps-recheck-agent.mjs +203 -0
- package/scripts/install/migrate-safedeps-state.mjs +91 -0
- package/scripts/safedeps-post-verify.sh +584 -0
- package/scripts/safedeps-pre-guard.sh +427 -0
- package/scripts/safedeps-recheck-alert.sh +115 -0
- package/scripts/test/e2e.sh +107 -0
- package/scripts/test/fixture-provider.mjs +104 -0
- package/scripts/test/smoke.sh +89 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to the Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by the Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding any notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
Copyright 2026 soohongkim
|
|
179
|
+
|
|
180
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
181
|
+
you may not use this file except in compliance with the License.
|
|
182
|
+
You may obtain a copy of the License at
|
|
183
|
+
|
|
184
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
185
|
+
|
|
186
|
+
Unless required by applicable law or agreed to in writing, software
|
|
187
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
188
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
189
|
+
See the License for the specific language governing permissions and
|
|
190
|
+
limitations under the License.
|
package/README.md
ADDED
|
@@ -0,0 +1,311 @@
|
|
|
1
|
+
# Safedeps
|
|
2
|
+
|
|
3
|
+
> Dependency install safety gate -- advisory checks, approved spec enforcement, and auto-rollback suspicious package installs in Claude Code and Codex CLI.
|
|
4
|
+
|
|
5
|
+
## Why "reorg"?
|
|
6
|
+
|
|
7
|
+
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.
|
|
8
|
+
|
|
9
|
+
No manual review. No leftover malicious code. Fully automatic.
|
|
10
|
+
|
|
11
|
+
## Distribution Model
|
|
12
|
+
|
|
13
|
+
Safedeps has two distribution surfaces:
|
|
14
|
+
|
|
15
|
+
1. **Agent skill + hooks (canonical)** -- the repo itself is the skill folder. `SKILL.md`, hook scripts, provider/ledger libraries, and install helpers stay together in one directory.
|
|
16
|
+
2. **npm package (CLI convenience)** -- `@aldegad/safedeps` installs the `safedeps` command. npm does **not** make Claude Code or Codex automatically discover the skill; after npm installation, users still need to run the hook/skill installer or manually register the skill folder.
|
|
17
|
+
|
|
18
|
+
Use the GitHub release when you want the full skill/hook source tree as the canonical artifact. Use npm when you mainly want a versioned global CLI.
|
|
19
|
+
|
|
20
|
+
## How It Works
|
|
21
|
+
|
|
22
|
+
`safedeps` plugs into Claude Code and Codex CLI hooks as a pair of **PreToolUse** and **PostToolUse** hooks that wrap package install commands. The CLI owns provider lookups and the approved-spec ledger; hooks enforce that ledger and run post-install rollback checks.
|
|
23
|
+
|
|
24
|
+
```
|
|
25
|
+
PreToolUse PostToolUse
|
|
26
|
+
(safedeps-pre-guard.sh) (safedeps-post-verify.sh)
|
|
27
|
+
| |
|
|
28
|
+
install cmd ──> [ Advisory/ledger gate ] ──> [ Execute ] ──> [ Verify ]
|
|
29
|
+
| | | |
|
|
30
|
+
Block if Snapshot Clean? Suspicious?
|
|
31
|
+
unapproved lock/manifest files, | |
|
|
32
|
+
or risky package listings Confirm REORG
|
|
33
|
+
| |
|
|
34
|
+
| v v
|
|
35
|
+
+--- parent_snapshot_id ──> confirmed
|
|
36
|
+
|
|
|
37
|
+
Rollback to last
|
|
38
|
+
confirmed snapshot
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
### Phase 1: Advisory Gate + Pre-flight (PreToolUse)
|
|
42
|
+
|
|
43
|
+
Before an agent installs a dependency, it should run:
|
|
44
|
+
|
|
45
|
+
```bash
|
|
46
|
+
safedeps check <ecosystem> <pkg>@<version|range> --json
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
That command queries OSV (canonical), CISA KEV (hard-risk overlay), and GitHub Advisory (enrichment). Clean or safely narrowed specs are written to `~/.safedeps/approved-specs/`.
|
|
50
|
+
|
|
51
|
+
When Claude Code or Codex CLI is about to run `npm install`, `pip install`, `cargo add`, `go get`, `gem install`, or similar commands, the guard hook:
|
|
52
|
+
|
|
53
|
+
1. **Snapshots** the current `package-lock.json`, `pnpm-lock.yaml`, `yarn.lock`, and `package.json` into `~/.safedeps/snapshots/`.
|
|
54
|
+
2. **Records metadata** including a `parent_snapshot_id` linking to the previous confirmed snapshot (forming a chain, just like blocks).
|
|
55
|
+
3. **Captures pre-install state** of `node_modules` (package listings and binary listings) for diff-based detection later.
|
|
56
|
+
4. **Enforces the approved-spec ledger** for explicit `pkg@version` install commands.
|
|
57
|
+
5. **Runs pre-flight checks** and **blocks** the command entirely if it detects:
|
|
58
|
+
- Typosquatting package names (`lod_sh`, `reacct`, `axois`, etc.)
|
|
59
|
+
- Non-standard `--registry` URLs (anything outside `registry.npmjs.org` and `registry.yarnpkg.com`)
|
|
60
|
+
- Piped remote execution patterns (`curl ... | bash`)
|
|
61
|
+
- Explicit disabling of install script safety (`npm config set ignore-scripts false`)
|
|
62
|
+
|
|
63
|
+
If the ledger gate or a pre-flight check fails, the command is **blocked before execution** -- nothing is installed.
|
|
64
|
+
|
|
65
|
+
### Phase 2: Post-install verification (`safedeps-post-verify.sh` -- PostToolUse)
|
|
66
|
+
|
|
67
|
+
After the install command completes, the verify hook analyzes what changed:
|
|
68
|
+
|
|
69
|
+
1. **Install script analysis** -- Scans newly added packages for `preinstall`, `install`, and `postinstall` scripts containing:
|
|
70
|
+
- Network access (`curl`, `wget`, `fetch`, `http`, `socket`, `dns`)
|
|
71
|
+
- Dynamic code execution (`eval`, `exec`, `spawn`, `child_process`, `Function()`)
|
|
72
|
+
- Sensitive path access (`~/.ssh`, `.env`, `.aws`, `credentials`)
|
|
73
|
+
- Obfuscated content (`base64`, `atob`, `Buffer.from`, hex/unicode escapes)
|
|
74
|
+
|
|
75
|
+
2. **Lock file diff analysis** -- Compares the snapshotted lock file content against the post-install version:
|
|
76
|
+
- Resolved URLs pointing to non-standard registries
|
|
77
|
+
- Insecure protocols (`http://`, `git://`) in resolved URLs
|
|
78
|
+
- Unusually large dependency additions (>50 new resolved entries, indicating potential dependency confusion)
|
|
79
|
+
|
|
80
|
+
3. **Binary inspection** -- Checks `node_modules/.bin/` for newly added native binaries (ELF, Mach-O, shared objects) that should not appear in a JavaScript project.
|
|
81
|
+
|
|
82
|
+
### Phase 3: Confirm or Reorg
|
|
83
|
+
|
|
84
|
+
- **All checks pass** -- The snapshot is marked as **confirmed** in `~/.safedeps/confirmed`. This becomes the new safe baseline.
|
|
85
|
+
- **Any check fails** -- A **reorg** is triggered:
|
|
86
|
+
1. Lock files are restored from the last confirmed snapshot.
|
|
87
|
+
2. `package.json` is restored if it was modified.
|
|
88
|
+
3. `node_modules` is rebuilt via `npm ci` (or `npm install` as fallback) to purge any malicious artifacts.
|
|
89
|
+
4. The event is logged to `~/.safedeps/reorg.log`.
|
|
90
|
+
5. Claude Code receives a system message detailing the detected threats and rollback actions.
|
|
91
|
+
|
|
92
|
+
## The Blockchain Analogy
|
|
93
|
+
|
|
94
|
+
| Blockchain Concept | Safedeps Equivalent |
|
|
95
|
+
|---|---|
|
|
96
|
+
| **Block candidate** | Snapshot taken before `npm install` |
|
|
97
|
+
| **Block validation** | Post-install security checks (scripts, lock diff, binaries) |
|
|
98
|
+
| **Finality / confirmation** | Snapshot ID written to `~/.safedeps/confirmed` |
|
|
99
|
+
| **Chain reorganization** | Rollback to last confirmed snapshot + `node_modules` rebuild |
|
|
100
|
+
| **Parent hash linking** | `parent_snapshot_id` in each snapshot's `_meta.json` |
|
|
101
|
+
| **Chain pruning** | Old unconfirmed snapshots cleaned up, confirmed chain preserved |
|
|
102
|
+
|
|
103
|
+
## Detection Rules
|
|
104
|
+
|
|
105
|
+
| Category | What it catches | Phase | Action |
|
|
106
|
+
|---|---|---|---|
|
|
107
|
+
| Typosquatting | Known misspelling patterns of popular packages | Pre-flight | **Block** |
|
|
108
|
+
| Pipe execution | `curl \| bash`, `wget \| sh` | Pre-flight | **Block** |
|
|
109
|
+
| Registry hijack | `--registry` pointing to unofficial sources | Pre-flight | **Block** |
|
|
110
|
+
| Script safety bypass | `npm config set ignore-scripts false` | Pre-flight | **Block** |
|
|
111
|
+
| Command indirection | `eval "npm install ..."`, subshell expansion, variable indirection | Pre-flight | **Guard** |
|
|
112
|
+
| npx/dlx execution | `npx`, `pnpm dlx`, `yarn dlx` package execution | Pre-flight | **Guard** |
|
|
113
|
+
| Malicious install scripts | Network calls, `eval`/`exec`, sensitive path access in hooks | Post-install | **Reorg** |
|
|
114
|
+
| Obfuscated code | Base64, hex encoding, `Buffer.from` in install scripts | Post-install | **Reorg** |
|
|
115
|
+
| Lock file tampering | Resolved URLs from non-standard registries | Post-install | **Reorg** |
|
|
116
|
+
| Insecure protocols | `http://` or `git://` resolved URLs | Post-install | **Reorg** |
|
|
117
|
+
| Dependency confusion | >50 new dependencies in a single install | Post-install | **Reorg** |
|
|
118
|
+
| Native binaries | Compiled executables in `node_modules/.bin/` | Post-install | **Reorg** |
|
|
119
|
+
|
|
120
|
+
## Installation
|
|
121
|
+
|
|
122
|
+
### Prerequisites
|
|
123
|
+
|
|
124
|
+
- [Claude Code](https://docs.anthropic.com/en/docs/claude-code) with hook support
|
|
125
|
+
- `jq` -- JSON parsing (hooks exit gracefully if missing)
|
|
126
|
+
- `shasum` or `sha256sum` -- hash computation
|
|
127
|
+
- `file` (optional) -- binary detection
|
|
128
|
+
|
|
129
|
+
```bash
|
|
130
|
+
# macOS
|
|
131
|
+
brew install jq
|
|
132
|
+
|
|
133
|
+
# Ubuntu / Debian
|
|
134
|
+
sudo apt-get install jq
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### Setup From GitHub (Skill + Hooks)
|
|
138
|
+
|
|
139
|
+
**1. Clone the repository:**
|
|
140
|
+
|
|
141
|
+
```bash
|
|
142
|
+
git clone https://github.com/aldegad/safedeps.git
|
|
143
|
+
cd safedeps
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
**2. Install the skill + hooks:**
|
|
147
|
+
|
|
148
|
+
```bash
|
|
149
|
+
node scripts/install/install-safedeps-hooks.mjs
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
The installer is idempotent. It symlinks the skill into `~/.claude/skills/safedeps` and `~/.codex/skills/safedeps` when those roots exist, patches the matching hook config, and can also place `safedeps` on PATH through `~/.local/bin`.
|
|
153
|
+
|
|
154
|
+
**3. Manual hook registration, if needed:**
|
|
155
|
+
|
|
156
|
+
Edit `.claude/settings.json` (project-level) or `~/.claude/settings.json` (global):
|
|
157
|
+
|
|
158
|
+
```json
|
|
159
|
+
{
|
|
160
|
+
"hooks": {
|
|
161
|
+
"PreToolUse": [
|
|
162
|
+
{
|
|
163
|
+
"matcher": "Bash",
|
|
164
|
+
"hooks": [
|
|
165
|
+
{
|
|
166
|
+
"type": "command",
|
|
167
|
+
"command": "~/.claude/skills/safedeps/scripts/safedeps-pre-guard.sh"
|
|
168
|
+
}
|
|
169
|
+
]
|
|
170
|
+
}
|
|
171
|
+
],
|
|
172
|
+
"PostToolUse": [
|
|
173
|
+
{
|
|
174
|
+
"matcher": "Bash",
|
|
175
|
+
"hooks": [
|
|
176
|
+
{
|
|
177
|
+
"type": "command",
|
|
178
|
+
"command": "~/.claude/skills/safedeps/scripts/safedeps-post-verify.sh"
|
|
179
|
+
}
|
|
180
|
+
]
|
|
181
|
+
}
|
|
182
|
+
]
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
**4. Verify permissions:**
|
|
188
|
+
|
|
189
|
+
```bash
|
|
190
|
+
chmod +x ~/.claude/skills/safedeps/scripts/safedeps-pre-guard.sh
|
|
191
|
+
chmod +x ~/.claude/skills/safedeps/scripts/safedeps-post-verify.sh
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
That's it. The guard activates automatically whenever Claude Code or Codex CLI runs a package install command.
|
|
195
|
+
|
|
196
|
+
### Setup From npm (CLI First)
|
|
197
|
+
|
|
198
|
+
```bash
|
|
199
|
+
npm install -g @aldegad/safedeps
|
|
200
|
+
safedeps version
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
npm puts `safedeps` on PATH through its standard `bin` entry. It does **not** register the agent skill or hooks for Claude Code / Codex. To enable the hooks from the npm-installed copy, run the installer from the installed package root:
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
cd "$(npm root -g)/@aldegad/safedeps"
|
|
207
|
+
node scripts/install/install-safedeps-hooks.mjs
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
The installer is idempotent and only adds symlinks/hook entries. The `--link-bin` flag is **only useful when you installed via GitHub clone instead of npm** — npm already places the CLI on PATH, so the flag is redundant in this path.
|
|
211
|
+
|
|
212
|
+
If you want the skill folder itself to be the canonical local source, prefer the GitHub setup above.
|
|
213
|
+
|
|
214
|
+
### Daily Re-check With macOS Alerts
|
|
215
|
+
|
|
216
|
+
Install a per-user LaunchAgent to re-check the approved-spec ledger once per day:
|
|
217
|
+
|
|
218
|
+
```bash
|
|
219
|
+
node scripts/install/install-safedeps-recheck-agent.mjs install --hour 9 --minute 0
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
This runs `safedeps re-check --json` against `~/.safedeps/approved-specs/`. It does not use LLM tokens; it only calls the advisory providers used by safedeps. If a new CVE/KEV is found, a spec is revoked, or a provider check is skipped, the wrapper writes `~/.safedeps/recheck-alerts.jsonl` and raises a macOS notification.
|
|
223
|
+
|
|
224
|
+
Useful commands:
|
|
225
|
+
|
|
226
|
+
```bash
|
|
227
|
+
node scripts/install/install-safedeps-recheck-agent.mjs status
|
|
228
|
+
node scripts/install/install-safedeps-recheck-agent.mjs uninstall
|
|
229
|
+
tail -f ~/.safedeps/recheck.log
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
### Legacy State Migration
|
|
233
|
+
|
|
234
|
+
If you used the old `npm-reorg-guard` state directory, migrate it once:
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
safedeps migrate
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
This copies missing state from `~/.npm-reorg-guard` into `~/.safedeps` and archives the legacy directory so there is no second active state root.
|
|
241
|
+
|
|
242
|
+
## Real-World Attack Coverage
|
|
243
|
+
|
|
244
|
+
`safedeps` is designed to catch the patterns behind real supply-chain incidents:
|
|
245
|
+
|
|
246
|
+
- **`event-stream` (2018)** -- Malicious `postinstall` script with obfuscated code that exfiltrated cryptocurrency wallet keys. Caught by: install script analysis (obfuscation + network access detection).
|
|
247
|
+
- **`ua-parser-js` hijack (2021)** -- Compromised package added a `preinstall` script that downloaded and executed cryptominers. Caught by: install script analysis (network access + code execution).
|
|
248
|
+
- **`colors` / `faker` sabotage (2022)** -- While these were author-initiated, the abnormal dependency behavior would trigger the dependency explosion check.
|
|
249
|
+
- **Typosquatting campaigns** -- Ongoing campaigns publishing packages like `crossenv` (instead of `cross-env`) or `babelcli` (instead of `babel-cli`). Caught by: pre-flight typosquatting pattern matching.
|
|
250
|
+
- **Dependency confusion attacks** -- Internal package names published to the public registry with higher version numbers. Caught by: non-standard registry detection + large dependency count changes.
|
|
251
|
+
|
|
252
|
+
## Logs and Snapshots
|
|
253
|
+
|
|
254
|
+
| Path | Description |
|
|
255
|
+
|---|---|
|
|
256
|
+
| `~/.safedeps/reorg.log` | Full reorg event history with timestamps, reasons, and rolled-back files |
|
|
257
|
+
| `~/.safedeps/confirmed` | Current confirmed (safe) snapshot ID |
|
|
258
|
+
| `~/.safedeps/snapshots/` | All snapshot files (lock files, package.json copies, metadata) |
|
|
259
|
+
|
|
260
|
+
```bash
|
|
261
|
+
# View reorg history
|
|
262
|
+
cat ~/.safedeps/reorg.log
|
|
263
|
+
|
|
264
|
+
# Check current confirmed snapshot
|
|
265
|
+
cat ~/.safedeps/confirmed
|
|
266
|
+
|
|
267
|
+
# List all snapshots
|
|
268
|
+
ls -la ~/.safedeps/snapshots/
|
|
269
|
+
```
|
|
270
|
+
|
|
271
|
+
Old unconfirmed snapshots are automatically pruned (keeping the 10 most recent), while the confirmed snapshot chain is always preserved.
|
|
272
|
+
|
|
273
|
+
## Security Hardening
|
|
274
|
+
|
|
275
|
+
`safedeps` includes multiple layers of defense against attacks targeting the guard itself:
|
|
276
|
+
|
|
277
|
+
| Measure | What it prevents |
|
|
278
|
+
|---|---|
|
|
279
|
+
| **JSON-safe metadata** | `project_dir` is escaped via `jq -Rs` to prevent JSON injection in snapshot metadata |
|
|
280
|
+
| **Path canonicalization** | `realpath`/`readlink -f` resolves symlinks and `..` traversal in `cwd` before use |
|
|
281
|
+
| **Atomic state files** | Snapshot ID and project directory are written as a single JSON file, preventing TOCTOU races |
|
|
282
|
+
| **Stale lock recovery** | Locks older than 60 seconds are automatically removed, preventing permanent DoS from `SIGKILL`/OOM |
|
|
283
|
+
| **Project-scoped state** | Each project gets its own confirmed snapshot chain (`confirmed_${dir_hash}`), preventing cross-project interference |
|
|
284
|
+
| **Restrictive permissions** | `umask 077` ensures `~/.safedeps/` is readable only by the owner |
|
|
285
|
+
| **Indirection detection** | Commands using `eval`, `$()`, or backticks with package manager keywords are treated as install candidates |
|
|
286
|
+
|
|
287
|
+
## Project Structure
|
|
288
|
+
|
|
289
|
+
```
|
|
290
|
+
safedeps/
|
|
291
|
+
bin/
|
|
292
|
+
safedeps # CLI -- advisory gate, ledger, revoke, re-check
|
|
293
|
+
lib/
|
|
294
|
+
providers/ # OSV / CISA KEV / GHSA adapters
|
|
295
|
+
ledger/ # approved-spec ledger
|
|
296
|
+
scripts/
|
|
297
|
+
safedeps-pre-guard.sh # PreToolUse hook -- snapshot + ledger enforcement
|
|
298
|
+
safedeps-post-verify.sh # PostToolUse hook -- post-install verification + reorg
|
|
299
|
+
install/install-safedeps-hooks.mjs
|
|
300
|
+
install/install-safedeps-recheck-agent.mjs
|
|
301
|
+
install/migrate-safedeps-state.mjs
|
|
302
|
+
safedeps-recheck-alert.sh
|
|
303
|
+
test/
|
|
304
|
+
package.json
|
|
305
|
+
SKILL.md # Claude Code / Codex skill manifest
|
|
306
|
+
LICENSE # Apache-2.0
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
## License
|
|
310
|
+
|
|
311
|
+
[Apache License 2.0](LICENSE)
|
package/ROADMAP.md
ADDED
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
# Safedeps Roadmap
|
|
2
|
+
|
|
3
|
+
> 시간축 + 우선순위. **왜·어떻게** 는 `ARCHITECTURE.md`, **언제·뭐 먼저** 는 이 파일.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 결정 SSoT
|
|
8
|
+
|
|
9
|
+
**스코프 = 개발 의존성만** (npm / pip / cargo / go / gem / maven / nuget).
|
|
10
|
+
OS-level (nginx / apt / brew / system binary) 은 **별도 도구로 분리**. SRP 측면 더 깔끔.
|
|
11
|
+
|
|
12
|
+
근거: dev 의존성과 OS 패키지는 운영 결이 다름.
|
|
13
|
+
- dev = "새 기능 → install 명령 → 매번 새 패키지 진입" (install 순간 게이트가 의미 큼).
|
|
14
|
+
- OS = "기존 패키지 security update" (cron 주기 audit + RSS 알람이 더 맞음).
|
|
15
|
+
|
|
16
|
+
→ safedeps = dev 의존성 install 단계 결.
|
|
17
|
+
→ OS-level 은 별도 (가칭 `infra-cve-monitor` — 미래 v3+).
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## v1 (출시 완료)
|
|
22
|
+
|
|
23
|
+
**이름**: `npm-reorg-guard`
|
|
24
|
+
**Status**: shipped as v1. GitHub repo has since been renamed to `aldegad/safedeps`.
|
|
25
|
+
|
|
26
|
+
- npm ecosystem 전용.
|
|
27
|
+
- PreToolUse hook (guard.sh): typosquat / curl|bash / 비표준 registry 등 **hardcoded pattern** 차단.
|
|
28
|
+
- PostToolUse hook (verify.sh): lockfile diff + install script 검사 → 의심 시 **reorg** (rollback).
|
|
29
|
+
- 외부 vuln DB 조회 0. self-contained.
|
|
30
|
+
|
|
31
|
+
**한계**:
|
|
32
|
+
- npm 만.
|
|
33
|
+
- 알려진 CVE 검사 X (pattern matching 위주).
|
|
34
|
+
- adversarial 회피 가능.
|
|
35
|
+
|
|
36
|
+
---
|
|
37
|
+
|
|
38
|
+
## v2 — Safedeps (현재 작업 중)
|
|
39
|
+
|
|
40
|
+
**이름**: `safedeps`, 내부 engine = `reorg-guard` (v1 자산 보존).
|
|
41
|
+
**Status**: `ARCHITECTURE.md` v2 작성 완료, v2.1 provider/ledger 구현 시작.
|
|
42
|
+
|
|
43
|
+
### 핵심 변화
|
|
44
|
+
- ecosystem 통합: npm / yarn / pnpm / pip (poetry, uv, pipenv) / cargo / go / gem / maven / nuget.
|
|
45
|
+
- **외부 vuln DB 결합**: OSV.dev (primary) + CISA KEV (hard-risk overlay) + GHSA (cross-check). NVD / deps.dev / Snyk = enrichment.
|
|
46
|
+
- **3-phase defense**:
|
|
47
|
+
1. Advisory Gate (`safedeps check`) — install 명령 *작성 전* vuln DB 조회 → 안전 spec 결정 → `~/.safedeps/approved-specs/<hash>.json` ledger 기록.
|
|
48
|
+
2. Hook Enforcement (`safedeps-pre-guard.sh`) — ledger 일치 검증.
|
|
49
|
+
3. Post-Install Reorg (`safedeps-post-verify.sh`) — v1 engine 그대로 (rollback fallback).
|
|
50
|
+
- Approved spec **TTL** (30일) + **daily re-check** cron (새 CVE 발견 시 revoke + 알람).
|
|
51
|
+
- **No silent fallback**: provider fail = fail-closed + `--allow-unverified` explicit override (observable).
|
|
52
|
+
|
|
53
|
+
### 구현 마일스톤
|
|
54
|
+
|
|
55
|
+
| 마일스톤 | 산출물 | 의존 |
|
|
56
|
+
|---|---|---|
|
|
57
|
+
| **v2.0-doc** ✅ | `ARCHITECTURE.md` v2 작성·push | — |
|
|
58
|
+
| **v2.0-roadmap** ✅ | 이 문서 | — |
|
|
59
|
+
| **v2.1-rename** ✅ | GitHub repo rename `aldegad/npm-reorg-guard` → `aldegad/safedeps` ✅. 로컬 repo/skill id/path `safedeps` ✅. `safedeps migrate` 로 legacy `~/.npm-reorg-guard` → `~/.safedeps` 이전 + legacy hook cleanup. | v2.0-doc |
|
|
60
|
+
| **v2.1-providers** ✅ | `lib/providers/` 신규 — OSV / KEV / GHSA adapter. 단일 query interface. 응답 cache (TTL 24h). | — |
|
|
61
|
+
| **v2.1-ledger** ✅ | `lib/ledger/` 신규 — approved spec JSON I/O (atomic write, hash 계산, TTL 검사). | v2.1-providers |
|
|
62
|
+
| **v2.1-cli** ✅ | `bin/safedeps` 신규 — `check`, `ledger`, `revoke`, `re-check`, `migrate`, `version` 서브커맨드. | v2.1-providers, v2.1-ledger |
|
|
63
|
+
| **v2.1-guard-patch** ✅ | `scripts/safedeps-pre-guard.sh` 갱신 — ledger 일치 검증 추가 + v1 pattern 유지. | v2.1-ledger |
|
|
64
|
+
| **v2.1-verify-patch** ✅ | `scripts/safedeps-post-verify.sh` 갱신 — approved spec 과 lockfile diff 비교 추가 + v1 reorg 유지. | v2.1-ledger |
|
|
65
|
+
| **v2.1-multi-ecosystem** ✅ | pip / cargo / go / gem / maven / nuget 명령 파싱 + lockfile snapshot. `safedeps-pre-guard.sh` 는 install 분류와 typosquat pattern 을 확장했고, `safedeps-post-verify.sh` 는 monitored dependency files 기준으로 rollback truth 를 공유한다. | v2.1-guard-patch |
|
|
66
|
+
| **v2.1-hook-rename** ✅ | hook 파일 namespacing (`guard.sh` → `safedeps-pre-guard.sh`, `verify.sh` → `safedeps-post-verify.sh`) + cross-engine installer (`scripts/install/install-safedeps-hooks.mjs`, ~/.claude + ~/.codex 자동 등록, idempotent, --uninstall). | v2.1-cli |
|
|
67
|
+
| **v2.1-recheck-cron** ✅ | daily re-check launchd — 전체 approved spec 재 query → 새 CVE/KEV/provider-skip 시 revoke + macOS 알림. | v2.1-providers, v2.1-ledger |
|
|
68
|
+
| **v2.1-tests** ✅ | end-to-end 테스트 — fixture provider 응답 → 명령 시뮬레이션 → ledger / hook / re-check / migration 동작 검증. | 모든 v2.1 |
|
|
69
|
+
| **v2.1-release** | npm package publish (`@aldegad/safedeps`) + GitHub release v2.1.0. | 모든 v2.1 |
|
|
70
|
+
|
|
71
|
+
### 2026-05-18 릴리즈 전 정리 메모
|
|
72
|
+
|
|
73
|
+
- npm package metadata 는 v2.1.0 기준으로 정합화한다 (`package.json` version + `bin.safedeps`).
|
|
74
|
+
- `npm test` 는 release smoke suite 를 실행한다. full fixture E2E 는 `v2.1-tests` 후속으로 남긴다.
|
|
75
|
+
- daily re-check 는 토큰을 쓰지 않는다. 알렉스가 opt-in 하면 macOS `launchd` user agent 로 `safedeps re-check --json` 을 매일 실행하는 구조가 기본이다. 네트워크는 OSV/CISA/GHSA provider query 에만 사용된다.
|
|
76
|
+
- 실제 local background job 은 `scripts/install/install-safedeps-recheck-agent.mjs` 로 atomic install 한다. wrapper 는 `~/.safedeps/recheck.log` 와 `~/.safedeps/recheck-alerts.jsonl` 를 쓰고, 새 CVE/KEV/revoke/provider-skip 이 있으면 macOS notification 을 띄운다.
|
|
77
|
+
|
|
78
|
+
### 후속 로드맵 — 전체 workspace inventory audit
|
|
79
|
+
|
|
80
|
+
전체 repo/lockfile inventory scan 은 safedeps v2.1 daily re-check 와 분리한다. 후보 설계는 최초 one-shot inventory scan 으로 workspace 의 manifest/lockfile 을 발견하고, 사용자가 채택한 spec 만 approved ledger 또는 별도 inventory ledger 에 넣은 뒤 주기 re-check 대상으로 삼는 방식이다. 이렇게 해야 safedeps 의 현재 책임인 install approval gate 와 이미 디스크에 존재하는 dependency audit 의 책임 소재가 섞이지 않는다.
|
|
81
|
+
|
|
82
|
+
### 우선순위
|
|
83
|
+
|
|
84
|
+
1. v2.1-release: commit / tag / GitHub release / npm publish.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## v3 (미래 — 알렉스 결정 시점)
|
|
89
|
+
|
|
90
|
+
- **plugin model** — 사용자 정의 provider (회사 내부 vuln DB, private registry).
|
|
91
|
+
- **policy file** — `.safedeps.toml` 로 \"우리 팀 정책: KEV hit 자동 block, CVSS 7+ 사용자 컨펌, 특정 패키지 allowlist\" 명시.
|
|
92
|
+
- **CI mode** — `safedeps check --ci` 로 GitHub Actions / CircleCI fail-fast.
|
|
93
|
+
- **transitive risk score** — deps.dev graph 통합. 직접 dep 만 아니라 transitive dep 의 \"위험 점수\" 시각화.
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## v4+ (장기)
|
|
98
|
+
|
|
99
|
+
- **team-shared ledger** — multi-machine approved spec sync (회사 dev 모두가 같은 ledger 공유).
|
|
100
|
+
- **AI agent integration** — Claude / Codex 가 vuln 발견 시 \"대체 모듈 X 권장\" 직접 제안 (LLM-as-judge).
|
|
101
|
+
- **diff visualization UI** — 두 approved spec snapshot 사이의 dep tree diff 시각화.
|
|
102
|
+
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
## 명시적 NON-GOAL (이 도구는 하지 않는다)
|
|
106
|
+
|
|
107
|
+
- **OS-level CVE 감시** (nginx, apt 패키지, system binary). → 별도 도구 `infra-cve-monitor` 결로 분리.
|
|
108
|
+
- **컨테이너 이미지 스캔**. → Trivy / Grype.
|
|
109
|
+
- **runtime 권한 sandbox**. → lavamoat / firejail.
|
|
110
|
+
- **registry 자체의 손상 감지**. → registry 운영사 책임.
|
|
111
|
+
- **사용자 평판 분석 (behavioral)**. → socket.dev.
|
|
112
|
+
|
|
113
|
+
safedeps 의 결 = **\"개발 의존성 install 단계의 advisory + spec gate + rollback\"** 한 줄. 다른 결로 확장하지 않는다 — SRP 측면 다른 도구로 분리.
|
|
114
|
+
|
|
115
|
+
---
|
|
116
|
+
|
|
117
|
+
## 관련 미래 도구 (분리 권장)
|
|
118
|
+
|
|
119
|
+
| 도구 | 결 | 관계 |
|
|
120
|
+
|---|---|---|
|
|
121
|
+
| `safedeps` (이것) | dev 의존성 (npm/pip/cargo/...) install 단계 | 현재 작업 |
|
|
122
|
+
| `infra-cve-monitor` (가칭) | nginx / apt / OS package 주기적 audit + RSS 알람 | 미래 별 도구 |
|
|
123
|
+
| `container-scan-bridge` (가칭) | Trivy / Grype wrapper, 컨테이너 이미지 결 | 미래 별 도구 |
|
|
124
|
+
|
|
125
|
+
세 도구가 같은 결 (\"보안\") 의 다른 layer. 한 skill 에 통합하지 않고 분리.
|
|
126
|
+
|
|
127
|
+
---
|
|
128
|
+
|
|
129
|
+
## 변경 history
|
|
130
|
+
|
|
131
|
+
- 2026-05-18: ROADMAP.md 최초 작성. v1 → v2 결정 + v3 / v4 / NON-GOAL 명시. (코덱시 surface:195 합의 + 클로디시 surface:61 작성.)
|