depsentinel 0.1.2
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.md +55 -0
- package/dist/advisories/fixture-source.js +25 -0
- package/dist/advisories/live-source.js +83 -0
- package/dist/advisories/source.js +1 -0
- package/dist/cli.js +133 -0
- package/dist/commands/ci.js +59 -0
- package/dist/commands/doctor.js +79 -0
- package/dist/commands/fix.js +101 -0
- package/dist/commands/init.js +143 -0
- package/dist/commands/install.js +83 -0
- package/dist/commands/scan.js +39 -0
- package/dist/commands/trust.js +353 -0
- package/dist/core/detector.js +54 -0
- package/dist/core/doctor-checks.js +206 -0
- package/dist/core/evaluate.js +25 -0
- package/dist/core/install-decision.js +11 -0
- package/dist/core/overrides.js +57 -0
- package/dist/core/risk-score.js +16 -0
- package/dist/core/safe-write.js +43 -0
- package/dist/core/tool-adapters.js +87 -0
- package/dist/formatters/human.js +39 -0
- package/dist/formatters/json.js +6 -0
- package/dist/policies/catalog.v1.js +123 -0
- package/dist/types/contracts.js +1 -0
- package/docs/security-best-practices.md +202 -0
- package/package.json +55 -0
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
# depsentinel Security Best Practices Guide
|
|
2
|
+
|
|
3
|
+
This document turns npm/pnpm supply-chain best practices into practical actions with `depsentinel`.
|
|
4
|
+
|
|
5
|
+
Goal: help any JS/TS project adopt secure defaults with low friction.
|
|
6
|
+
|
|
7
|
+
## What depsentinel already enforces
|
|
8
|
+
|
|
9
|
+
- `scan`: detects package manager (`npm`, `pnpm`, `yarn`, `bun`), lockfile, workspace hint, and framework hint.
|
|
10
|
+
- `scan`: returns `risk_score`, `proposed_diff`, and `remediation_commands`.
|
|
11
|
+
- `init`: writes secure baseline files (`depsentinel.*`, `.npmrc`, `.npmignore`, CI workflow) and PM-specific configs automatically based on detection.
|
|
12
|
+
- `ci`: fails (non-zero exit code) when critical policy findings exist.
|
|
13
|
+
- `install <package>`: preflight safety check with `allow|warn|block` decision, optional tool adapters (`npq`, `sfw`, `lockfile-lint`), graceful degradation diagnostics, and `--force` for override.
|
|
14
|
+
- `doctor`: diagnoses project against 26 best practices across 4 categories with PASS/FAIL/SKIP.
|
|
15
|
+
- `fix`: applies known remediations (`.npmrc`, `.npmignore`, `lint:lockfile`, `sbom` scripts, PM configs) with dry-run by default.
|
|
16
|
+
- `override add|remove|list`: manage policy exceptions with reason and expiration date.
|
|
17
|
+
- Unknown framework: no hard-fail; falls back to universal JS/TS baseline checks.
|
|
18
|
+
|
|
19
|
+
## Secure defaults generated by `init`
|
|
20
|
+
|
|
21
|
+
### `.npmrc`
|
|
22
|
+
|
|
23
|
+
Generated baseline:
|
|
24
|
+
|
|
25
|
+
```ini
|
|
26
|
+
ignore-scripts=true
|
|
27
|
+
allow-git=none
|
|
28
|
+
min-release-age=3
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Why it matters:
|
|
32
|
+
|
|
33
|
+
- `ignore-scripts=true`: blocks lifecycle script execution by default.
|
|
34
|
+
- `allow-git=none`: blocks git-based dependency resolution.
|
|
35
|
+
- `min-release-age=3`: introduces a cooldown before fresh releases are installable.
|
|
36
|
+
|
|
37
|
+
### `pnpm-workspace.yaml` (when pnpm detected or no PM yet)
|
|
38
|
+
|
|
39
|
+
Generated baseline (universal, any JS/TS project):
|
|
40
|
+
|
|
41
|
+
```yaml
|
|
42
|
+
packages:
|
|
43
|
+
- "."
|
|
44
|
+
|
|
45
|
+
minimumReleaseAge: 43200
|
|
46
|
+
trustPolicy: no-downgrade
|
|
47
|
+
blockExoticSubdeps: true
|
|
48
|
+
strictDepBuilds: true
|
|
49
|
+
allowBuilds:
|
|
50
|
+
esbuild: true
|
|
51
|
+
rolldown: true
|
|
52
|
+
unrs-resolver: true
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Why it matters:
|
|
56
|
+
|
|
57
|
+
- `minimumReleaseAge`: cooldown window to reduce fresh-compromise risk.
|
|
58
|
+
- `trustPolicy: no-downgrade`: blocks trust-regression package versions.
|
|
59
|
+
- `blockExoticSubdeps`: blocks transitive git/tarball exotic sources.
|
|
60
|
+
- `strictDepBuilds` + `allowBuilds`: converts unreviewed build scripts into hard failures.
|
|
61
|
+
|
|
62
|
+
### PM-specific configs (auto-detected)
|
|
63
|
+
|
|
64
|
+
| Lockfile detected | Extra config generated |
|
|
65
|
+
|---|---|
|
|
66
|
+
| `pnpm-lock.yaml` or none | `pnpm-workspace.yaml` |
|
|
67
|
+
| `bun.lockb` | `bunfig.toml` with `minimumReleaseAge` |
|
|
68
|
+
| `yarn.lock` | `.yarnrc.yml` with `npmMinimalAgeGate` |
|
|
69
|
+
|
|
70
|
+
All projects get `.npmrc`, `.npmignore`, and CI workflow regardless of PM.
|
|
71
|
+
|
|
72
|
+
## Quick start
|
|
73
|
+
|
|
74
|
+
```bash
|
|
75
|
+
# 1) Diagnose
|
|
76
|
+
npx depsentinel scan
|
|
77
|
+
|
|
78
|
+
# 2) Generate secure baseline files (dry-run by default)
|
|
79
|
+
npx depsentinel init
|
|
80
|
+
|
|
81
|
+
# 3) Apply generated files
|
|
82
|
+
npx depsentinel init --write
|
|
83
|
+
|
|
84
|
+
# 4) Check a package before installing
|
|
85
|
+
npx depsentinel install express
|
|
86
|
+
|
|
87
|
+
# 5) Force-install after acknowledging risks
|
|
88
|
+
npx depsentinel install some-package --force
|
|
89
|
+
|
|
90
|
+
# 6) Enforce in CI
|
|
91
|
+
npx depsentinel ci --json
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Full Coverage Matrix: both source documents mapped to depsentinel
|
|
95
|
+
|
|
96
|
+
This matrix combines OWASP/Snyk npm best practices and Liran Tal's Awesome npm Security Best Practices into a single view.
|
|
97
|
+
|
|
98
|
+
### Automated by depsentinel
|
|
99
|
+
|
|
100
|
+
| # | Best Practice | How depsentinel helps |
|
|
101
|
+
|---|---|---|
|
|
102
|
+
| 1 | Disable post-install scripts | `init` writes `.npmrc` with `ignore-scripts=true`; pnpm projects get `strictDepBuilds` + `allowBuilds` |
|
|
103
|
+
| 2 | Block git-based dependencies | `init` writes `.npmrc` with `allow-git=none`; `scan` detects disallowed protocols (`git+`, `http:`, `file:`) |
|
|
104
|
+
| 3 | Cooldown (minimumReleaseAge) | `init` writes `.npmrc` `min-release-age=3`; pnpm projects get `pnpm-workspace.yaml` `minimumReleaseAge: 43200` |
|
|
105
|
+
| 4 | Enforce lockfile | `scan` blocks if missing lockfile (`lockfile.required` policy); `ci` returns non-zero exit code |
|
|
106
|
+
| 5 | Deterministic CI installs | `scan` suggests PM-specific frozen-lockfile command; CI workflow generated by `init` uses `--frozen-lockfile` for each PM |
|
|
107
|
+
| 6 | Audit vulnerabilities | `scan`/`ci` check critical advisory matches; `install` evaluates package safety pre-install |
|
|
108
|
+
| 7 | Hardening tools (npq / sfw / lockfile-lint) | `install` detects and uses optional adapters with `executed|skipped|failed` reporting |
|
|
109
|
+
| 8 | Typosquatting / slopsquatting detection | `install` delegates to `npq`/`sfw` adapters (when available) which detect typosquatting patterns |
|
|
110
|
+
| 9 | Package health assessment | `scan` returns `risk_score`; `install` evaluates health signals via integrated adapters |
|
|
111
|
+
| 10 | pnpm trust policy | `init` writes `trustPolicy: no-downgrade` in `pnpm-workspace.yaml` for pnpm projects |
|
|
112
|
+
| 11 | pnpm exotic subdeps blocking | `init` writes `blockExoticSubdeps: true` in `pnpm-workspace.yaml` for pnpm projects |
|
|
113
|
+
|
|
114
|
+
### Guided in documentation (manual implementation)
|
|
115
|
+
|
|
116
|
+
| # | Best Practice | User action required |
|
|
117
|
+
|---|---|---|
|
|
118
|
+
| 12 | Avoid publishing secrets to registry | Use `files` allowlist in `package.json`; add `.npmignore`; review tarball with `npm pack --dry-run` |
|
|
119
|
+
| 13 | npx hardening (offline + workspace) | Create dedicated workspace, install packages with lockfile, run `npx --offline` (see snippets below) |
|
|
120
|
+
| 14 | Lockfile injection prevention beyond baseline | Add `lockfile-lint` as pre-install gate in `package.json` scripts |
|
|
121
|
+
| 15 | Secrets hygiene (.env plaintext) | Replace plaintext secrets with 1Password/Infisical references; never commit `.env` files |
|
|
122
|
+
| 16 | Dev Containers | Create `.devcontainer/devcontainer.json`; use VS Code remote containers |
|
|
123
|
+
| 17 | Maintainer 2FA | `npm profile enable-2fa auth-and-writes` |
|
|
124
|
+
| 18 | Publishing with provenance / OIDC | Configure trusted publisher on npmjs.com; use `id-token: write` in CI |
|
|
125
|
+
| 19 | SBOM generation and artifact signing | Integrate `@cyclonedx/cyclonedx-npm` for SBOM; use `sigstore` for artifact signatures |
|
|
126
|
+
| 20 | Dependency confusion protection | Use scoped package names (`@yourorg/pkg`); configure `.npmrc` scope routing; claim names on public registry |
|
|
127
|
+
| 21 | Manage npm author tokens securely | Rotate tokens, restrict with CIDR and `--read-only`, revoke unused tokens |
|
|
128
|
+
| 22 | Use a local npm proxy (Verdaccio) | Install private registry; configure proxy cache; route internal dependencies |
|
|
129
|
+
|
|
130
|
+
### Not covered (out of tool scope)
|
|
131
|
+
|
|
132
|
+
| # | Best Practice | Reason |
|
|
133
|
+
|---|---|---|
|
|
134
|
+
| 23 | Responsible vulnerability disclosure | Process requiring human coordination and judgement |
|
|
135
|
+
| 24 | Verify documentation examples before copying | Requires manual code review |
|
|
136
|
+
| 25 | Avoid blind npm package upgrades | Manual review needed; `fix` sets up safe foundation |
|
|
137
|
+
| 26 | Reduce package dependency tree | Architectural design decision, not a tooling concern |
|
|
138
|
+
|
|
139
|
+
## Current boundaries
|
|
140
|
+
|
|
141
|
+
These are not fully implemented yet:
|
|
142
|
+
|
|
143
|
+
- Live advisory feed ingestion (uses deterministic fixture-backed provider for reliable tests).
|
|
144
|
+
- Advanced governance checks (SBOM/provenance/signature verification pipelines).
|
|
145
|
+
|
|
146
|
+
## Recommended adoption policy
|
|
147
|
+
|
|
148
|
+
1. Run `scan` on every PR.
|
|
149
|
+
2. Use `install` before adding any new dependency.
|
|
150
|
+
3. Keep `ci` as required status check.
|
|
151
|
+
4. Start with strict defaults and use explicit overrides only with reason and expiration.
|
|
152
|
+
5. Review `proposed_diff` and `remediation_commands` before applying changes.
|
|
153
|
+
|
|
154
|
+
## Guided snippets for controls not yet automated
|
|
155
|
+
|
|
156
|
+
### Harden `npx` usage for tooling
|
|
157
|
+
|
|
158
|
+
```bash
|
|
159
|
+
mkdir -p "$HOME/mcp" && cd "$HOME/mcp"
|
|
160
|
+
npm init -y
|
|
161
|
+
npm install @modelcontextprotocol/server-filesystem
|
|
162
|
+
npx --include-workspace-root --workspace "$HOME/mcp" --no --offline @modelcontextprotocol/server-filesystem /path/to/allowed/directory
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
### Add lockfile linting gate
|
|
166
|
+
|
|
167
|
+
```json
|
|
168
|
+
{
|
|
169
|
+
"scripts": {
|
|
170
|
+
"lint:lockfile": "lockfile-lint --path package-lock.json --type npm --allowed-hosts npm --validate-https"
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Deterministic install commands by package manager
|
|
176
|
+
|
|
177
|
+
```bash
|
|
178
|
+
npm ci
|
|
179
|
+
pnpm install --frozen-lockfile
|
|
180
|
+
yarn install --immutable --immutable-cache
|
|
181
|
+
bun install --frozen-lockfile
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Private scope routing to prevent dependency confusion
|
|
185
|
+
|
|
186
|
+
```ini
|
|
187
|
+
@yourcompany:registry=https://npm.yourcompany.com/
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
### Generate SBOM for supply chain governance
|
|
191
|
+
|
|
192
|
+
```bash
|
|
193
|
+
npm install @cyclonedx/cyclonedx-npm
|
|
194
|
+
npx @cyclonedx/cyclonedx-npm --validate > sbom.json
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Notes for any JS/TS project
|
|
198
|
+
|
|
199
|
+
- `init` auto-detects your package manager and generates appropriate configs.
|
|
200
|
+
- If your PM is unknown, `depsentinel` defaults to pnpm (recommended for strongest supply-chain hardening).
|
|
201
|
+
- If framework detection is unknown, `depsentinel` still applies universal checks and reports diagnostics instead of breaking.
|
|
202
|
+
- `install` works with any package manager and adapts to `npm/pnpm/yarn/bun` automatically.
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "depsentinel",
|
|
3
|
+
"version": "0.1.2",
|
|
4
|
+
"description": "JS/TS supply-chain hardening CLI — scan, secure, and enforce dependency policies",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "depsentinel contributors",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"npm",
|
|
9
|
+
"pnpm",
|
|
10
|
+
"yarn",
|
|
11
|
+
"bun",
|
|
12
|
+
"supply-chain",
|
|
13
|
+
"security",
|
|
14
|
+
"cli",
|
|
15
|
+
"hardening",
|
|
16
|
+
"lockfile",
|
|
17
|
+
"dependencies",
|
|
18
|
+
"audit"
|
|
19
|
+
],
|
|
20
|
+
"repository": {
|
|
21
|
+
"type": "git",
|
|
22
|
+
"url": "https://github.com/axelvalles/depsentinel"
|
|
23
|
+
},
|
|
24
|
+
"homepage": "https://github.com/axelvalles/depsentinel#readme",
|
|
25
|
+
"type": "module",
|
|
26
|
+
"bin": {
|
|
27
|
+
"depsentinel": "./dist/cli.js"
|
|
28
|
+
},
|
|
29
|
+
"main": "./dist/cli.js",
|
|
30
|
+
"exports": {
|
|
31
|
+
".": "./dist/cli.js"
|
|
32
|
+
},
|
|
33
|
+
"files": [
|
|
34
|
+
"dist",
|
|
35
|
+
"docs/security-best-practices.md",
|
|
36
|
+
"README.md"
|
|
37
|
+
],
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"cac": "6.7.14"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/node": "22.15.31",
|
|
43
|
+
"lockfile-lint": "4.14.1",
|
|
44
|
+
"typescript": "5.8.3",
|
|
45
|
+
"vitest": "2.1.9"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "tsc -p tsconfig.build.json",
|
|
49
|
+
"test": "vitest run",
|
|
50
|
+
"test:watch": "vitest",
|
|
51
|
+
"typecheck": "tsc --noEmit",
|
|
52
|
+
"lint:lockfile": "node scripts/lint-lockfile.mjs",
|
|
53
|
+
"sbom": "npx @cyclonedx/cyclonedx-npm --validate > sbom.json"
|
|
54
|
+
}
|
|
55
|
+
}
|