dw-kit 1.3.5 → 1.3.6
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/.claude/hooks/supply-chain-scan.sh +16 -14
- package/.dw/security/advisory-snapshot.json +157 -0
- package/.dw/security/ioc-namespaces.json +20 -8
- package/CLAUDE.md +1 -1
- package/README.md +14 -2
- package/package.json +1 -1
- package/src/cli.mjs +5 -2
- package/src/commands/init.mjs +45 -1
- package/src/commands/security-scan.mjs +367 -52
- package/src/lib/gitignore.mjs +5 -1
- package/src/lib/npm-registry.mjs +159 -0
- package/src/lib/sc-heuristic.mjs +263 -0
- package/src/lib/sc-scanner.mjs +60 -11
- package/src/lib/sc-sync.mjs +98 -8
- package/src/lib/telemetry.mjs +20 -0
|
@@ -60,9 +60,12 @@ fi
|
|
|
60
60
|
|
|
61
61
|
START_TS=$(date +%s%N 2>/dev/null || date +%s)
|
|
62
62
|
|
|
63
|
-
#
|
|
63
|
+
# Pillar 3 (ADR-0006): heuristic-only mode probes ONLY the NEW/bumped packages
|
|
64
|
+
# from the lockfile diff against npm registry metadata. Cached 1h per package
|
|
65
|
+
# so repeat edits hit cache. This is the AI-Native moat — catches zero-day-ish
|
|
66
|
+
# at the edit boundary, before OSV indexes and before any TL fixture bump.
|
|
64
67
|
set +e
|
|
65
|
-
SCAN_OUTPUT=$(cd "$LOCKFILE_DIR" && $DW_BIN security-scan --
|
|
68
|
+
SCAN_OUTPUT=$(cd "$LOCKFILE_DIR" && $DW_BIN security-scan --heuristic-only 2>&1)
|
|
66
69
|
SCAN_EXIT=$?
|
|
67
70
|
set -e
|
|
68
71
|
|
|
@@ -73,28 +76,27 @@ case "$SCAN_EXIT" in
|
|
|
73
76
|
0)
|
|
74
77
|
# Clean — silent unless verbose
|
|
75
78
|
if [ "${DW_SC_GUARD_VERBOSE:-}" = "1" ]; then
|
|
76
|
-
echo "✓ supply-chain-scan: clean (no
|
|
79
|
+
echo "✓ supply-chain-scan: clean (no heuristic flags on NEW/bumped packages in $BASENAME)" >&2
|
|
77
80
|
fi
|
|
78
81
|
;;
|
|
79
82
|
1)
|
|
80
|
-
#
|
|
83
|
+
# Mid-risk heuristic flags — warn, do not block
|
|
81
84
|
echo "" >&2
|
|
82
|
-
echo "⚠ supply-chain-scan:
|
|
83
|
-
echo "$SCAN_OUTPUT" | tail -
|
|
84
|
-
echo " (advisory — not blocking; run \`dw security-scan\` for full report)" >&2
|
|
85
|
+
echo "⚠ supply-chain-scan: heuristic flags on NEW/bumped packages in $BASENAME" >&2
|
|
86
|
+
echo "$SCAN_OUTPUT" | tail -30 >&2
|
|
87
|
+
echo " (advisory — not blocking; run \`dw security-scan\` for full pillar 1+2+3 report)" >&2
|
|
85
88
|
;;
|
|
86
89
|
2)
|
|
87
|
-
# HIGH
|
|
90
|
+
# HIGH-risk heuristic flag (score ≥80) — loud warning, still non-blocking
|
|
88
91
|
echo "" >&2
|
|
89
|
-
echo "⚠ supply-chain-scan: HIGH
|
|
90
|
-
echo "$SCAN_OUTPUT" | tail -
|
|
91
|
-
echo " ADVISORY ONLY —
|
|
92
|
-
echo " Run \`dw security-scan\` for full report. Public sunset review 2026-08-12 (ADR-0005)." >&2
|
|
92
|
+
echo "⚠ supply-chain-scan: HIGH-RISK heuristic flag on NEW/bumped package in $BASENAME" >&2
|
|
93
|
+
echo "$SCAN_OUTPUT" | tail -40 >&2
|
|
94
|
+
echo " ADVISORY ONLY — review before commit. Public sunset review 2026-08-12 (ADR-0005)." >&2
|
|
93
95
|
;;
|
|
94
96
|
*)
|
|
95
|
-
# Setup error (no
|
|
97
|
+
# Setup error (no lockfile, network failure) — quiet hint
|
|
96
98
|
if [ "${DW_SC_GUARD_VERBOSE:-}" = "1" ]; then
|
|
97
|
-
echo "supply-chain-scan:
|
|
99
|
+
echo "supply-chain-scan: heuristic check skipped or errored — run \`dw security-scan\` manually" >&2
|
|
98
100
|
fi
|
|
99
101
|
;;
|
|
100
102
|
esac
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": "1.0",
|
|
3
|
+
"fetched_at": "2026-05-12T09:57:47.323Z",
|
|
4
|
+
"source": "osv.dev",
|
|
5
|
+
"ecosystem": "npm",
|
|
6
|
+
"package_count": 13,
|
|
7
|
+
"advisory_count": 2,
|
|
8
|
+
"advisories": [
|
|
9
|
+
{
|
|
10
|
+
"id": "GHSA-q3j6-qgpj-74h6",
|
|
11
|
+
"summary": "fast-uri vulnerable to path traversal via percent-encoded dot segments",
|
|
12
|
+
"details": "### Impact\n\n`fast-uri` v3.1.0 and earlier decodes percent-encoded path separators (`%2F`) and dot segments (`%2E`) before applying dot-segment removal in `normalize()` and `equal()`. This makes encoded path data behave like real `/` and `..`, so distinct URIs collapse onto the same normalized path.\n\nFor example, `http://example.com/public/%2e%2e/admin` normalizes to `http://example.com/admin`, and `equal()` considers them the same URI.\n\nApplications that normalize or compare attacker-controlled URLs to enforce path-based policy can be bypassed. A path that looks confined under an allowed prefix can normalize to a different location.\n\n### Patches\n\nUpgrade to `fast-uri` >= 3.1.1.\n\n### Workarounds\n\nNone. Upgrade to the patched version.",
|
|
13
|
+
"aliases": [
|
|
14
|
+
"CVE-2026-6321"
|
|
15
|
+
],
|
|
16
|
+
"modified": "2026-05-09T16:44:22.524341929Z",
|
|
17
|
+
"published": "2026-05-08T17:15:09Z",
|
|
18
|
+
"related": [
|
|
19
|
+
"CGA-9j5f-2hwm-8hfc"
|
|
20
|
+
],
|
|
21
|
+
"database_specific": {
|
|
22
|
+
"cwe_ids": [
|
|
23
|
+
"CWE-22"
|
|
24
|
+
],
|
|
25
|
+
"github_reviewed": true,
|
|
26
|
+
"github_reviewed_at": "2026-05-08T17:15:09Z",
|
|
27
|
+
"severity": "HIGH",
|
|
28
|
+
"nvd_published_at": "2026-05-04T20:16:20Z"
|
|
29
|
+
},
|
|
30
|
+
"references": [
|
|
31
|
+
{
|
|
32
|
+
"type": "WEB",
|
|
33
|
+
"url": "https://github.com/fastify/fast-uri/security/advisories/GHSA-q3j6-qgpj-74h6"
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"type": "ADVISORY",
|
|
37
|
+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-6321"
|
|
38
|
+
},
|
|
39
|
+
{
|
|
40
|
+
"type": "WEB",
|
|
41
|
+
"url": "https://cna.openjsf.org/security-advisories.html"
|
|
42
|
+
},
|
|
43
|
+
{
|
|
44
|
+
"type": "PACKAGE",
|
|
45
|
+
"url": "https://github.com/fastify/fast-uri"
|
|
46
|
+
}
|
|
47
|
+
],
|
|
48
|
+
"affected": [
|
|
49
|
+
{
|
|
50
|
+
"package": {
|
|
51
|
+
"name": "fast-uri",
|
|
52
|
+
"ecosystem": "npm",
|
|
53
|
+
"purl": "pkg:npm/fast-uri"
|
|
54
|
+
},
|
|
55
|
+
"ranges": [
|
|
56
|
+
{
|
|
57
|
+
"type": "SEMVER",
|
|
58
|
+
"events": [
|
|
59
|
+
{
|
|
60
|
+
"introduced": "0"
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"fixed": "3.1.1"
|
|
64
|
+
}
|
|
65
|
+
]
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
"database_specific": {
|
|
69
|
+
"source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-q3j6-qgpj-74h6/GHSA-q3j6-qgpj-74h6.json",
|
|
70
|
+
"last_known_affected_version_range": "<= 3.1.0"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
],
|
|
74
|
+
"schema_version": "1.7.5",
|
|
75
|
+
"severity": [
|
|
76
|
+
{
|
|
77
|
+
"type": "CVSS_V3",
|
|
78
|
+
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N"
|
|
79
|
+
}
|
|
80
|
+
]
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
"id": "GHSA-v39h-62p7-jpjc",
|
|
84
|
+
"summary": "fast-uri vulnerable to host confusion via percent-encoded authority delimiters",
|
|
85
|
+
"details": "### Impact\n\n`fast-uri` v3.1.1 and earlier decodes percent-encoded authority delimiters (`%40` as `@`, `%3A` as `:`) inside the host component and serializes them back as raw characters. This changes the URI structure, turning a hostname into userinfo plus a different host.\n\nFor example, `http://trusted.com%40evil.com/` normalizes to `http://trusted.com@evil.com/`, which reparses as host `evil.com` with userinfo `trusted.com`.\n\nApplications that normalize untrusted URLs before host allowlist checks, redirect validation, or outbound request routing can be steered to a different authority than the original URL appeared to contain.\n\n### Patches\n\nUpgrade to `fast-uri` >= 3.1.2.\n\n### Workarounds\n\nNone. Upgrade to the patched version.",
|
|
86
|
+
"aliases": [
|
|
87
|
+
"CVE-2026-6322"
|
|
88
|
+
],
|
|
89
|
+
"modified": "2026-05-10T04:44:28.903255090Z",
|
|
90
|
+
"published": "2026-05-08T19:13:01Z",
|
|
91
|
+
"related": [
|
|
92
|
+
"CGA-5vr9-c8qr-fqvg"
|
|
93
|
+
],
|
|
94
|
+
"database_specific": {
|
|
95
|
+
"cwe_ids": [
|
|
96
|
+
"CWE-436"
|
|
97
|
+
],
|
|
98
|
+
"github_reviewed": true,
|
|
99
|
+
"github_reviewed_at": "2026-05-08T19:13:01Z",
|
|
100
|
+
"severity": "HIGH",
|
|
101
|
+
"nvd_published_at": "2026-05-05T11:16:33Z"
|
|
102
|
+
},
|
|
103
|
+
"references": [
|
|
104
|
+
{
|
|
105
|
+
"type": "WEB",
|
|
106
|
+
"url": "https://github.com/fastify/fast-uri/security/advisories/GHSA-v39h-62p7-jpjc"
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
"type": "ADVISORY",
|
|
110
|
+
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-6322"
|
|
111
|
+
},
|
|
112
|
+
{
|
|
113
|
+
"type": "WEB",
|
|
114
|
+
"url": "https://cna.openjsf.org/security-advisories.html"
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"type": "PACKAGE",
|
|
118
|
+
"url": "https://github.com/fastify/fast-uri"
|
|
119
|
+
}
|
|
120
|
+
],
|
|
121
|
+
"affected": [
|
|
122
|
+
{
|
|
123
|
+
"package": {
|
|
124
|
+
"name": "fast-uri",
|
|
125
|
+
"ecosystem": "npm",
|
|
126
|
+
"purl": "pkg:npm/fast-uri"
|
|
127
|
+
},
|
|
128
|
+
"ranges": [
|
|
129
|
+
{
|
|
130
|
+
"type": "SEMVER",
|
|
131
|
+
"events": [
|
|
132
|
+
{
|
|
133
|
+
"introduced": "0"
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
"fixed": "3.1.2"
|
|
137
|
+
}
|
|
138
|
+
]
|
|
139
|
+
}
|
|
140
|
+
],
|
|
141
|
+
"database_specific": {
|
|
142
|
+
"source": "https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/05/GHSA-v39h-62p7-jpjc/GHSA-v39h-62p7-jpjc.json",
|
|
143
|
+
"last_known_affected_version_range": "<= 3.1.1"
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
],
|
|
147
|
+
"schema_version": "1.7.5",
|
|
148
|
+
"severity": [
|
|
149
|
+
{
|
|
150
|
+
"type": "CVSS_V3",
|
|
151
|
+
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:H/A:N"
|
|
152
|
+
}
|
|
153
|
+
]
|
|
154
|
+
}
|
|
155
|
+
],
|
|
156
|
+
"snapshot_sha": "sha256:0b6ca61019fb234c"
|
|
157
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
"schema_version": "1.
|
|
3
|
-
"updated": "2026-05-
|
|
4
|
-
"purpose": "Curated namespace patterns under ACTIVE incident —
|
|
2
|
+
"schema_version": "1.1",
|
|
3
|
+
"updated": "2026-05-14",
|
|
4
|
+
"purpose": "Curated namespace patterns under ACTIVE incident — wired into default scan (v1.3.6+) AND pre-install scan. Auto-expires per active_until. TL updates when new incident requires fixture-level warning before OSV propagation. Per ADR-0006: pillar 2 of the 3-pillar guard architecture; pillar 3 (NEW-package heuristic) catches incidents BEFORE TL bump.",
|
|
5
5
|
"namespaces": [
|
|
6
6
|
{
|
|
7
7
|
"pattern": "@tanstack/",
|
|
@@ -9,7 +9,11 @@
|
|
|
9
9
|
"advisory": "https://github.com/advisories/GHSA-g7cv-rxg3-hmpx",
|
|
10
10
|
"active_until": "2026-11-11",
|
|
11
11
|
"severity": "critical",
|
|
12
|
-
"
|
|
12
|
+
"affected_range": {
|
|
13
|
+
"type": "SEMVER",
|
|
14
|
+
"events": [{ "introduced": "1.169.5" }, { "fixed": "1.169.9" }]
|
|
15
|
+
},
|
|
16
|
+
"guidance": "Affected: 1.169.5-1.169.8. Safe: 1.169.9+. Verify SLSA provenance attestation matches expected publisher. If lockfile already pins affected range: rotate ALL credentials (npm tokens, GitHub PATs, SSH keys, cloud keys, Claude/AI configs) before continuing."
|
|
13
17
|
},
|
|
14
18
|
{
|
|
15
19
|
"pattern": "@uipath/",
|
|
@@ -17,7 +21,7 @@
|
|
|
17
21
|
"advisory": "https://github.com/advisories/GHSA-g7cv-rxg3-hmpx",
|
|
18
22
|
"active_until": "2026-11-11",
|
|
19
23
|
"severity": "critical",
|
|
20
|
-
"guidance": "Verify each @uipath/* install against official UiPath release notes. Worm SLSA attestations are VALID — provenance check alone is insufficient. Cross-reference with UiPath security bulletin."
|
|
24
|
+
"guidance": "Verify each @uipath/* install against official UiPath release notes. Worm SLSA attestations are VALID — provenance check alone is insufficient. Cross-reference with UiPath security bulletin. (No affected_range — range still under investigation; treat all recent versions as suspect.)"
|
|
21
25
|
},
|
|
22
26
|
{
|
|
23
27
|
"pattern": "@mistralai/",
|
|
@@ -25,7 +29,11 @@
|
|
|
25
29
|
"advisory": "https://github.com/advisories/GHSA-g7cv-rxg3-hmpx",
|
|
26
30
|
"active_until": "2026-11-11",
|
|
27
31
|
"severity": "critical",
|
|
28
|
-
"
|
|
32
|
+
"affected_range": {
|
|
33
|
+
"type": "SEMVER",
|
|
34
|
+
"events": [{ "introduced": "2.2.3" }, { "fixed": "2.2.5" }]
|
|
35
|
+
},
|
|
36
|
+
"guidance": "Affected: 2.2.3-2.2.4. Pin to 2.2.2 or 2.2.5+."
|
|
29
37
|
},
|
|
30
38
|
{
|
|
31
39
|
"pattern": "@opensearch-project/opensearch",
|
|
@@ -33,8 +41,12 @@
|
|
|
33
41
|
"advisory": "https://github.com/advisories/GHSA-g7cv-rxg3-hmpx",
|
|
34
42
|
"active_until": "2026-11-11",
|
|
35
43
|
"severity": "critical",
|
|
36
|
-
"
|
|
44
|
+
"affected_range": {
|
|
45
|
+
"type": "SEMVER",
|
|
46
|
+
"events": [{ "introduced": "3.6.2" }, { "fixed": "3.6.3" }]
|
|
47
|
+
},
|
|
48
|
+
"guidance": "Affected: 3.6.2 only. Pin to 3.6.1 or 3.6.3+."
|
|
37
49
|
}
|
|
38
50
|
],
|
|
39
|
-
"maintenance_note": "
|
|
51
|
+
"maintenance_note": "Per ADR-0005 + ADR-0006: this fixture handles the 'TL knows about incident' window (post-incident, pre-OSV-propagation). Pillar 3 (NEW-package heuristic, ADR-0006) handles the 'nobody knows yet' window. TL prunes entries past active_until on regular release cycles."
|
|
40
52
|
}
|
package/CLAUDE.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
Workflow toolkit codebase. Rules live in `.claude/rules/` (auto-loaded).
|
|
4
4
|
|
|
5
5
|
**v2.0 direction:** Context-First SDLC Governance Layer (5 pillars — see `.dw/core/PILLARS.md`)
|
|
6
|
-
**Current:** v1.3.
|
|
6
|
+
**Current:** v1.3.6 (released 2026-05-14) · ADR-0001 active · ADR-0005 + ADR-0006 Accepted (Supply-Chain Guard 3-pillar AI-Native; sunset review 2026-08-12 per pillar) · v1.4 cuts pending telemetry
|
|
7
7
|
|
|
8
8
|
---
|
|
9
9
|
|
package/README.md
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
> An AI development workflow toolkit for teams using agentic IDEs (Claude Code, Cursor) — from idea to review-ready commits.
|
|
4
4
|
|
|
5
|
-
**v1.3.
|
|
5
|
+
**v1.3.6** · `npm install -g dw-kit` · [Docs](docs/README.md) · [Get started](docs/get-started.md) · [Cheatsheet](docs/cheatsheet.md) · [Migration v1.3](MIGRATION-v1.3.md) · [Changelog](CHANGELOG.md)
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
|
|
@@ -36,7 +36,8 @@ It’s designed for collaboration (Dev / Tech Lead / QA / PM) and keeps work aud
|
|
|
36
36
|
|
|
37
37
|
## Release notes
|
|
38
38
|
|
|
39
|
-
- **v1.3.
|
|
39
|
+
- **v1.3.6** (2026-05-14) — Supply-Chain Guard upgraded to 3-pillar architecture: OSV snapshot + curated IoC fixture (version-aware, wired into default scan) + **AI-Native NEW-package heuristic** that catches zero-day-ish risk at the AI-edit boundary. See [`CHANGELOG.md#v136--2026-05-14`](CHANGELOG.md#v136--2026-05-14) and [ADR-0006](.dw/decisions/0006-supply-chain-guard-heuristic.md).
|
|
40
|
+
- v1.3.5 (2026-05-12) — AI-Native Supply-Chain Guard: `dw security-scan` CLI + OSV.dev auto-sync + Edit-lockfile hook + scoped `.gitignore` for end-user projects. See [ADR-0005](.dw/decisions/0005-supply-chain-guard.md). Public 90-day sunset review committed for 2026-08-12.
|
|
40
41
|
- v1.3.4 (2026-04-21) — `/dw:plan` Quick Debate (red/blue self-critique), depth-driven activation
|
|
41
42
|
- v1.3.3 (2026-04-21) — Writer skills v1/v2 compatibility fix
|
|
42
43
|
- v1.3.0 (2026-04-21) — 5-pillar governance layer + telemetry foundation + ADRs + v2 task docs ([ADR-0001](.dw/decisions/0001-v2-pragmatic-lean.md))
|
|
@@ -44,6 +45,17 @@ It’s designed for collaboration (Dev / Tech Lead / QA / PM) and keeps work aud
|
|
|
44
45
|
- Full changelog: `CHANGELOG.md`
|
|
45
46
|
- Latest release notes: [GitHub Releases](https://github.com/dv-workflow/dv-workflow/releases)
|
|
46
47
|
|
|
48
|
+
### What's in v1.3.6 for your team
|
|
49
|
+
|
|
50
|
+
Reaction time when a supply-chain incident drops goes from 24-72 hours (wait for OSV index + npm publish cycle) to **~1 hour** (AI edits lockfile → hook fires → heuristic flags BEFORE anyone knows).
|
|
51
|
+
|
|
52
|
+
- **3-pillar default scan** — `dw security-scan` now runs OSV snapshot + curated IoC fixture + AI-Native heuristic in one go. Heuristic only probes NEW/bumped packages from `git show HEAD:package-lock.json` diff — typical edit = 1-5 packages probed, not 1000+.
|
|
53
|
+
- **npm registry metadata heuristic** — composite scoring on `recent_publish` (<72h), `popular_package` (≥10k weekly DL), `maintainer_change_recent`, `major_version_jump`, `typo_squat`. Per-package metadata cached 1h. Tunable threshold via `.dw/config/dw.config.yml`.
|
|
54
|
+
- **Version-aware IoC fixture** — `affected_range` per entry. Concrete versions out-of-range are skipped (no false positives). Range specs (`^1.169.0`) emit ambiguity warnings with severity downgrade.
|
|
55
|
+
- **Hook fires `dw security-scan --heuristic-only`** on Claude Code lockfile edit — fast diff-only check.
|
|
56
|
+
- **Telemetry per pillar** — `source: 'osv' | 'fixture' | 'heuristic'` tracked separately so the 2026-08-12 sunset review attributes catches to the right pillar.
|
|
57
|
+
- **`>1000 packages`** crash bug from v1.3.5 fixed (chunked OSV batches).
|
|
58
|
+
|
|
47
59
|
### What's in v1.3.5 for your team
|
|
48
60
|
|
|
49
61
|
- **`dw security-scan`** — scan for known supply-chain advisories against your project's `package-lock.json` (full match) or `package.json` (pre-install approximate). Uses [OSV.dev](https://osv.dev/) as data source (multi-maintainer upstream feed; no solo-curated bundle to go stale).
|
package/package.json
CHANGED
package/src/cli.mjs
CHANGED
|
@@ -103,11 +103,14 @@ export function run(argv) {
|
|
|
103
103
|
|
|
104
104
|
program
|
|
105
105
|
.command('security-scan')
|
|
106
|
-
.
|
|
106
|
+
.alias('scan')
|
|
107
|
+
.description('Scan project: 3-pillar supply-chain guard (OSV + fixture + AI-Native heuristic). Auto-syncs OSV snapshot if missing or stale.')
|
|
107
108
|
.option('--quick', 'Offline mode — use existing snapshot only (default behavior)')
|
|
108
109
|
.option('--update-db', 'Fetch fresh advisory snapshot from OSV.dev before scanning')
|
|
109
110
|
.option('--pre-install', 'Scan package.json without lockfile (OSV name-only + namespace fixture)')
|
|
110
|
-
.option('--offline', 'Skip network in --pre-install mode
|
|
111
|
+
.option('--offline', 'Skip network in --pre-install mode + skip pillar 3 heuristic')
|
|
112
|
+
.option('--no-heuristic', 'Skip pillar 3 (AI-Native NEW-package heuristic). Default: enabled on lockfile diff.')
|
|
113
|
+
.option('--heuristic-only', 'Run ONLY pillar 3 (used by hook). Skips OSV + fixture pillars.')
|
|
111
114
|
.option('--json', 'Output machine-readable JSON')
|
|
112
115
|
.option('--install-hook', 'Wire supply-chain-scan.sh into .claude/settings.json PostToolUse (idempotent)')
|
|
113
116
|
.option('--uninstall-hook', 'Remove supply-chain-scan.sh entry from .claude/settings.json')
|
package/src/commands/init.mjs
CHANGED
|
@@ -193,7 +193,51 @@ async function maybeInstallSupplyChainHook(projectDir, presetKey) {
|
|
|
193
193
|
}
|
|
194
194
|
if (result.action === 'added') {
|
|
195
195
|
ok('Supply-chain guard hook wired (ADR-0005 — opt-in flag enabled)');
|
|
196
|
-
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// UX: offer one-time OSV snapshot sync so end-user doesn't need to know
|
|
199
|
+
// `--update-db` exists. Lazy auto-refresh in `dw scan` covers the case
|
|
200
|
+
// when user declines, but offering during init gets snapshot ready upfront.
|
|
201
|
+
await maybeBootstrapOsvSnapshot(projectDir);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async function maybeBootstrapOsvSnapshot(projectDir) {
|
|
205
|
+
// Non-TTY (CI / scripted): default yes so the snapshot exists for next scan.
|
|
206
|
+
// TTY: prompt user, default yes.
|
|
207
|
+
let shouldSync = true;
|
|
208
|
+
if (process.stdin.isTTY && !process.env.DW_INIT_NO_PROMPT) {
|
|
209
|
+
try {
|
|
210
|
+
const { prompt } = await import('enquirer');
|
|
211
|
+
const answer = await prompt({
|
|
212
|
+
type: 'confirm',
|
|
213
|
+
name: 'syncNow',
|
|
214
|
+
message: 'Sync OSV advisory snapshot now? (recommended first-time; ~10-30s)',
|
|
215
|
+
initial: true,
|
|
216
|
+
});
|
|
217
|
+
shouldSync = !!answer.syncNow;
|
|
218
|
+
} catch {
|
|
219
|
+
shouldSync = true;
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
if (!shouldSync) {
|
|
223
|
+
log(' Skipped. First `dw scan` will auto-sync if needed.');
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const { findLockfile } = await import('../lib/sc-scanner.mjs');
|
|
228
|
+
if (!findLockfile(projectDir)) {
|
|
229
|
+
log(' No lockfile yet — first `dw scan` will sync after `npm install` runs.');
|
|
230
|
+
return;
|
|
231
|
+
}
|
|
232
|
+
log(' Syncing OSV snapshot...');
|
|
233
|
+
try {
|
|
234
|
+
const { syncSnapshotForProject } = await import('../lib/sc-sync.mjs');
|
|
235
|
+
const start = Date.now();
|
|
236
|
+
const res = await syncSnapshotForProject(projectDir);
|
|
237
|
+
const partialNote = res.partial ? ` (PARTIAL ${res.chunks.failed}/${res.chunks.total})` : '';
|
|
238
|
+
ok(`OSV snapshot ready — ${res.advisoryCount} advisories for ${res.packageCount} packages (${Date.now() - start}ms)${partialNote}`);
|
|
239
|
+
} catch (e) {
|
|
240
|
+
warn(`OSV sync skipped: ${e.message}. Will retry on first \`dw scan\`.`);
|
|
197
241
|
}
|
|
198
242
|
}
|
|
199
243
|
|