@npm-safe/core-dsh 1.0.5

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.
Files changed (86) hide show
  1. package/LICENSE +204 -0
  2. package/dist/index.d.ts +513 -0
  3. package/dist/index.d.ts.map +1 -0
  4. package/dist/index.js +711 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/llm/anthropic.d.ts +47 -0
  7. package/dist/llm/anthropic.d.ts.map +1 -0
  8. package/dist/llm/anthropic.js +161 -0
  9. package/dist/llm/anthropic.js.map +1 -0
  10. package/dist/llm/gemini.d.ts +47 -0
  11. package/dist/llm/gemini.d.ts.map +1 -0
  12. package/dist/llm/gemini.js +165 -0
  13. package/dist/llm/gemini.js.map +1 -0
  14. package/dist/llm/llm-config.d.ts +97 -0
  15. package/dist/llm/llm-config.d.ts.map +1 -0
  16. package/dist/llm/llm-config.js +188 -0
  17. package/dist/llm/llm-config.js.map +1 -0
  18. package/dist/llm/parse.d.ts +95 -0
  19. package/dist/llm/parse.d.ts.map +1 -0
  20. package/dist/llm/parse.js +158 -0
  21. package/dist/llm/parse.js.map +1 -0
  22. package/dist/llm/provider.d.ts +122 -0
  23. package/dist/llm/provider.d.ts.map +1 -0
  24. package/dist/llm/provider.js +206 -0
  25. package/dist/llm/provider.js.map +1 -0
  26. package/dist/registry/client.d.ts +164 -0
  27. package/dist/registry/client.d.ts.map +1 -0
  28. package/dist/registry/client.js +378 -0
  29. package/dist/registry/client.js.map +1 -0
  30. package/dist/registry/types.d.ts +226 -0
  31. package/dist/registry/types.d.ts.map +1 -0
  32. package/dist/registry/types.js +32 -0
  33. package/dist/registry/types.js.map +1 -0
  34. package/dist/registry/validator.d.ts +87 -0
  35. package/dist/registry/validator.d.ts.map +1 -0
  36. package/dist/registry/validator.js +214 -0
  37. package/dist/registry/validator.js.map +1 -0
  38. package/dist/scanner/ci-scan.d.ts +82 -0
  39. package/dist/scanner/ci-scan.d.ts.map +1 -0
  40. package/dist/scanner/ci-scan.js +130 -0
  41. package/dist/scanner/ci-scan.js.map +1 -0
  42. package/dist/scanner/rule-config.d.ts +61 -0
  43. package/dist/scanner/rule-config.d.ts.map +1 -0
  44. package/dist/scanner/rule-config.js +103 -0
  45. package/dist/scanner/rule-config.js.map +1 -0
  46. package/dist/scanner/rule-loader.d.ts +28 -0
  47. package/dist/scanner/rule-loader.d.ts.map +1 -0
  48. package/dist/scanner/rule-loader.js +67 -0
  49. package/dist/scanner/rule-loader.js.map +1 -0
  50. package/dist/scanner/static-rules.d.ts +88 -0
  51. package/dist/scanner/static-rules.d.ts.map +1 -0
  52. package/dist/scanner/static-rules.js +723 -0
  53. package/dist/scanner/static-rules.js.map +1 -0
  54. package/dist/scanner/types.d.ts +177 -0
  55. package/dist/scanner/types.d.ts.map +1 -0
  56. package/dist/scanner/types.js +53 -0
  57. package/dist/scanner/types.js.map +1 -0
  58. package/dist/scheduler/rate-limiter.d.ts +74 -0
  59. package/dist/scheduler/rate-limiter.d.ts.map +1 -0
  60. package/dist/scheduler/rate-limiter.js +182 -0
  61. package/dist/scheduler/rate-limiter.js.map +1 -0
  62. package/dist/scheduler/refresh-scheduler.d.ts +201 -0
  63. package/dist/scheduler/refresh-scheduler.d.ts.map +1 -0
  64. package/dist/scheduler/refresh-scheduler.js +295 -0
  65. package/dist/scheduler/refresh-scheduler.js.map +1 -0
  66. package/dist/store/cache-manager.d.ts +166 -0
  67. package/dist/store/cache-manager.d.ts.map +1 -0
  68. package/dist/store/cache-manager.js +356 -0
  69. package/dist/store/cache-manager.js.map +1 -0
  70. package/dist/store/database.d.ts +81 -0
  71. package/dist/store/database.d.ts.map +1 -0
  72. package/dist/store/database.js +182 -0
  73. package/dist/store/database.js.map +1 -0
  74. package/dist/store/schema.d.ts +42 -0
  75. package/dist/store/schema.d.ts.map +1 -0
  76. package/dist/store/schema.js +126 -0
  77. package/dist/store/schema.js.map +1 -0
  78. package/dist/translator/provider.d.ts +152 -0
  79. package/dist/translator/provider.d.ts.map +1 -0
  80. package/dist/translator/provider.js +159 -0
  81. package/dist/translator/provider.js.map +1 -0
  82. package/dist/translator/types.d.ts +83 -0
  83. package/dist/translator/types.d.ts.map +1 -0
  84. package/dist/translator/types.js +58 -0
  85. package/dist/translator/types.js.map +1 -0
  86. package/package.json +42 -0
@@ -0,0 +1,87 @@
1
+ /**
2
+ * Pure string-parsing validators for npm package names, semver versions,
3
+ * and registry/repository domains.
4
+ *
5
+ * This module contains no network calls and no side effects — every
6
+ * function is a pure transformation of its string input into a typed
7
+ * validation result. Inputs are treated as untrusted: empty strings,
8
+ * non-string values (rejected by the type system at compile time, but
9
+ * defended against at runtime via narrowing), and Unicode homograph
10
+ * attacks are all handled explicitly.
11
+ *
12
+ * @module registry/validator
13
+ */
14
+ import type { ValidationResult } from './types.js';
15
+ /**
16
+ * Validate an npm package name according to the public registry's naming
17
+ * rules. Accepts both unscoped (`lodash`) and scoped (`@babel/core`)
18
+ * names.
19
+ *
20
+ * Rules enforced:
21
+ * - Must be a non-empty string.
22
+ * - Maximum length of 214 characters.
23
+ * - Must be entirely lowercase (no uppercase letters).
24
+ * - Must not contain spaces.
25
+ * - Must not begin with a dot (`.`) or underscore (`_`).
26
+ * - Scoped names use the `@scope/name` syntax; both `scope` and `name`
27
+ * segments must independently satisfy the segment naming rules.
28
+ * - Rejects Unicode homograph look-alikes by restricting to ASCII
29
+ * lowercase letters, digits, hyphen, underscore, and dot.
30
+ *
31
+ * @param name - Candidate package name to validate.
32
+ * @returns A {@link ValidationResult} indicating validity and, when
33
+ * invalid, a human-readable reason.
34
+ */
35
+ export declare function validatePackageName(name: string): ValidationResult;
36
+ /**
37
+ * Validate that a string is a compliant semantic version (semver 2.0.0).
38
+ *
39
+ * Accepts strings of the form `MAJOR.MINOR.PATCH` with optional pre-release
40
+ * (`-prerelease`) and build metadata (`+build`) identifiers. Numeric
41
+ * components with leading zeros (e.g. `01.2.3`) are rejected, matching the
42
+ * semver specification.
43
+ *
44
+ * @param version - Candidate version string to validate.
45
+ * @returns `true` when the string is a valid semver version, `false`
46
+ * otherwise.
47
+ */
48
+ export declare function validateVersion(version: string): boolean;
49
+ /**
50
+ * Result of {@link validateDomain}. The `domain` field is always present
51
+ * (empty string when parsing fails) so callers can destructure safely.
52
+ */
53
+ export interface DomainValidationResult {
54
+ /** `true` when the input parsed into a URL with a usable hostname. */
55
+ readonly valid: boolean;
56
+ /** Lowercased hostname extracted from the URL, or empty string on failure. */
57
+ readonly domain: string;
58
+ }
59
+ /**
60
+ * Validate a URL string and extract its hostname.
61
+ *
62
+ * Handles edge cases including:
63
+ * - Missing protocol (defaults to `https://`).
64
+ * - Relative URLs (rejected — no hostname).
65
+ * - Invalid URL syntax (rejected).
66
+ * - Unicode hostnames (returned as-is, lowercased; punycode conversion is
67
+ * the caller's responsibility).
68
+ *
69
+ * @param url - Candidate URL string to parse.
70
+ * @returns A {@link DomainValidationResult} with the parsed hostname
71
+ * (lowercased) when valid, or an empty domain when parsing fails.
72
+ */
73
+ export declare function validateDomain(url: string): DomainValidationResult;
74
+ /**
75
+ * Check whether a domain is a known npm registry or source-control host.
76
+ *
77
+ * The whitelist includes `npmjs.com`, `registry.npmjs.org`, `github.com`,
78
+ * `bitbucket.org`, and `gitlab.com`. Comparison is case-insensitive and
79
+ * exact — subdomains are not automatically trusted (callers must normalise
80
+ * or extend the check if wildcard matching is desired).
81
+ *
82
+ * @param domain - Hostname to check against the known-domain whitelist.
83
+ * @returns `true` when the domain (case-insensitively) matches a known
84
+ * registry/repository host, `false` otherwise.
85
+ */
86
+ export declare function isKnownRegistryDomain(domain: string): boolean;
87
+ //# sourceMappingURL=validator.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.d.ts","sourceRoot":"","sources":["../../src/registry/validator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AA6CnD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,gBAAgB,CA6ElE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAKxD;AAED;;;GAGG;AACH,MAAM,WAAW,sBAAsB;IACrC,sEAAsE;IACtE,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB,8EAA8E;IAC9E,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,sBAAsB,CA0BlE;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAK7D"}
@@ -0,0 +1,214 @@
1
+ /**
2
+ * Pure string-parsing validators for npm package names, semver versions,
3
+ * and registry/repository domains.
4
+ *
5
+ * This module contains no network calls and no side effects — every
6
+ * function is a pure transformation of its string input into a typed
7
+ * validation result. Inputs are treated as untrusted: empty strings,
8
+ * non-string values (rejected by the type system at compile time, but
9
+ * defended against at runtime via narrowing), and Unicode homograph
10
+ * attacks are all handled explicitly.
11
+ *
12
+ * @module registry/validator
13
+ */
14
+ /**
15
+ * Maximum length of an npm package name, enforced by the public registry.
16
+ *
17
+ * @see https://github.com/npm/validate-npm-package-name#naming-rules
18
+ */
19
+ const MAX_PACKAGE_NAME_LENGTH = 214;
20
+ /**
21
+ * Regular expression matching a single path segment of an npm package name
22
+ * (the part after an optional `@scope/` prefix). Per the registry naming
23
+ * rules, segments must be lowercase, must not contain leading dots or
24
+ * underscores, and may contain ASCII letters, digits, hyphens, underscores,
25
+ * and dots — but no spaces or other special characters.
26
+ */
27
+ const PACKAGE_NAME_SEGMENT_PATTERN = /^[a-z0-9]([a-z0-9._-]*[a-z0-9])?$/;
28
+ /**
29
+ * Regular expression matching a semver version string with optional
30
+ * pre-release and build-metadata identifiers, per the semver 2.0.0 spec.
31
+ *
32
+ * - Major.minor.patch: three dot-separated non-negative integer groups.
33
+ * - Pre-release: hyphen followed by dot-separated alphanumeric identifiers.
34
+ * - Build metadata: plus sign followed by dot-separated alphanumeric
35
+ * identifiers.
36
+ *
37
+ * @see https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
38
+ */
39
+ const SEMVER_PATTERN = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/;
40
+ /**
41
+ * Immutable whitelist of registry/repository domains recognised by the
42
+ * tool. Used by {@link isKnownRegistryDomain} to gate trust decisions
43
+ * without performing any network lookups.
44
+ */
45
+ const KNOWN_REGISTRY_DOMAINS = new Set([
46
+ 'npmjs.com',
47
+ 'registry.npmjs.org',
48
+ 'github.com',
49
+ 'bitbucket.org',
50
+ 'gitlab.com',
51
+ ]);
52
+ /**
53
+ * Validate an npm package name according to the public registry's naming
54
+ * rules. Accepts both unscoped (`lodash`) and scoped (`@babel/core`)
55
+ * names.
56
+ *
57
+ * Rules enforced:
58
+ * - Must be a non-empty string.
59
+ * - Maximum length of 214 characters.
60
+ * - Must be entirely lowercase (no uppercase letters).
61
+ * - Must not contain spaces.
62
+ * - Must not begin with a dot (`.`) or underscore (`_`).
63
+ * - Scoped names use the `@scope/name` syntax; both `scope` and `name`
64
+ * segments must independently satisfy the segment naming rules.
65
+ * - Rejects Unicode homograph look-alikes by restricting to ASCII
66
+ * lowercase letters, digits, hyphen, underscore, and dot.
67
+ *
68
+ * @param name - Candidate package name to validate.
69
+ * @returns A {@link ValidationResult} indicating validity and, when
70
+ * invalid, a human-readable reason.
71
+ */
72
+ export function validatePackageName(name) {
73
+ if (typeof name !== 'string' || name.length === 0) {
74
+ return { valid: false, reason: 'Package name must be a non-empty string.' };
75
+ }
76
+ if (name.length > MAX_PACKAGE_NAME_LENGTH) {
77
+ return {
78
+ valid: false,
79
+ reason: `Package name must not exceed ${MAX_PACKAGE_NAME_LENGTH} characters.`,
80
+ };
81
+ }
82
+ // Reject any uppercase letters outright — npm names are case-sensitive
83
+ // and the registry only permits lowercase.
84
+ if (name !== name.toLowerCase()) {
85
+ return { valid: false, reason: 'Package name must be lowercase.' };
86
+ }
87
+ if (name.includes(' ')) {
88
+ return { valid: false, reason: 'Package name must not contain spaces.' };
89
+ }
90
+ // Scoped package: @scope/name
91
+ if (name.startsWith('@')) {
92
+ const slashIndex = name.indexOf('/');
93
+ if (slashIndex === -1) {
94
+ return {
95
+ valid: false,
96
+ reason: 'Scoped package name must contain a "/" separator.',
97
+ };
98
+ }
99
+ const scope = name.slice(1, slashIndex);
100
+ const rest = name.slice(slashIndex + 1);
101
+ if (scope.length === 0) {
102
+ return { valid: false, reason: 'Package scope must not be empty.' };
103
+ }
104
+ if (rest.length === 0) {
105
+ return { valid: false, reason: 'Package name segment must not be empty.' };
106
+ }
107
+ // Scope must not itself be scoped (no nested @s).
108
+ if (scope.startsWith('@')) {
109
+ return { valid: false, reason: 'Package scope must not be nested.' };
110
+ }
111
+ if (!PACKAGE_NAME_SEGMENT_PATTERN.test(scope)) {
112
+ return {
113
+ valid: false,
114
+ reason: `Package scope "${scope}" contains invalid characters or a leading dot/underscore.`,
115
+ };
116
+ }
117
+ if (!PACKAGE_NAME_SEGMENT_PATTERN.test(rest)) {
118
+ return {
119
+ valid: false,
120
+ reason: `Package name segment "${rest}" contains invalid characters or a leading dot/underscore.`,
121
+ };
122
+ }
123
+ return { valid: true };
124
+ }
125
+ // Unscoped package.
126
+ if (name.startsWith('.') || name.startsWith('_')) {
127
+ return {
128
+ valid: false,
129
+ reason: 'Package name must not begin with a dot or underscore.',
130
+ };
131
+ }
132
+ if (!PACKAGE_NAME_SEGMENT_PATTERN.test(name)) {
133
+ return {
134
+ valid: false,
135
+ reason: `Package name "${name}" contains invalid characters.`,
136
+ };
137
+ }
138
+ return { valid: true };
139
+ }
140
+ /**
141
+ * Validate that a string is a compliant semantic version (semver 2.0.0).
142
+ *
143
+ * Accepts strings of the form `MAJOR.MINOR.PATCH` with optional pre-release
144
+ * (`-prerelease`) and build metadata (`+build`) identifiers. Numeric
145
+ * components with leading zeros (e.g. `01.2.3`) are rejected, matching the
146
+ * semver specification.
147
+ *
148
+ * @param version - Candidate version string to validate.
149
+ * @returns `true` when the string is a valid semver version, `false`
150
+ * otherwise.
151
+ */
152
+ export function validateVersion(version) {
153
+ if (typeof version !== 'string' || version.length === 0) {
154
+ return false;
155
+ }
156
+ return SEMVER_PATTERN.test(version);
157
+ }
158
+ /**
159
+ * Validate a URL string and extract its hostname.
160
+ *
161
+ * Handles edge cases including:
162
+ * - Missing protocol (defaults to `https://`).
163
+ * - Relative URLs (rejected — no hostname).
164
+ * - Invalid URL syntax (rejected).
165
+ * - Unicode hostnames (returned as-is, lowercased; punycode conversion is
166
+ * the caller's responsibility).
167
+ *
168
+ * @param url - Candidate URL string to parse.
169
+ * @returns A {@link DomainValidationResult} with the parsed hostname
170
+ * (lowercased) when valid, or an empty domain when parsing fails.
171
+ */
172
+ export function validateDomain(url) {
173
+ if (typeof url !== 'string' || url.length === 0) {
174
+ return { valid: false, domain: '' };
175
+ }
176
+ // Reject relative URLs early: a usable registry/repository URL must have
177
+ // a scheme. If none is present, prepend `https://` as a convenience for
178
+ // inputs like `github.com/user/repo`.
179
+ let candidate = url;
180
+ if (!/^[a-z][a-z0-9+.-]*:\/\//i.test(candidate)) {
181
+ candidate = `https://${candidate}`;
182
+ }
183
+ let parsed;
184
+ try {
185
+ parsed = new URL(candidate);
186
+ }
187
+ catch {
188
+ return { valid: false, domain: '' };
189
+ }
190
+ const hostname = parsed.hostname;
191
+ if (hostname.length === 0) {
192
+ return { valid: false, domain: '' };
193
+ }
194
+ return { valid: true, domain: hostname.toLowerCase() };
195
+ }
196
+ /**
197
+ * Check whether a domain is a known npm registry or source-control host.
198
+ *
199
+ * The whitelist includes `npmjs.com`, `registry.npmjs.org`, `github.com`,
200
+ * `bitbucket.org`, and `gitlab.com`. Comparison is case-insensitive and
201
+ * exact — subdomains are not automatically trusted (callers must normalise
202
+ * or extend the check if wildcard matching is desired).
203
+ *
204
+ * @param domain - Hostname to check against the known-domain whitelist.
205
+ * @returns `true` when the domain (case-insensitively) matches a known
206
+ * registry/repository host, `false` otherwise.
207
+ */
208
+ export function isKnownRegistryDomain(domain) {
209
+ if (typeof domain !== 'string' || domain.length === 0) {
210
+ return false;
211
+ }
212
+ return KNOWN_REGISTRY_DOMAINS.has(domain.toLowerCase());
213
+ }
214
+ //# sourceMappingURL=validator.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validator.js","sourceRoot":"","sources":["../../src/registry/validator.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Pure CI dependency-scan helpers extracted from the legacy `ci` CLI command.
3
+ *
4
+ * This module is intentionally free of CLI concerns: no `commander` option
5
+ * parsing, no i18n (`t()`), no telemetry recording, and no console output.
6
+ * The {@link NpmSafeEngine.ciScan} method composes these helpers with the
7
+ * engine to produce a {@link CiReport}; rendering and exit-code mapping are
8
+ * the caller's responsibility.
9
+ *
10
+ * @module scanner/ci-scan
11
+ */
12
+ import { SecurityLevel } from './types.js';
13
+ /**
14
+ * Severity ordering used for the failure gate: lower rank = more severe.
15
+ *
16
+ * Exported so the engine's `ciScan` method can evaluate the fail gate without
17
+ * re-declaring this mapping.
18
+ */
19
+ export declare const LEVEL_RANK: Readonly<Record<string, number>>;
20
+ /**
21
+ * Display order of security levels (used for option help text in the CLI).
22
+ */
23
+ export declare const LEVEL_ORDER: readonly string[];
24
+ /** A dependency name extracted from a manifest or lockfile. */
25
+ export interface Dependency {
26
+ readonly name: string;
27
+ }
28
+ /** Per-package result within a {@link CiReport}. */
29
+ export interface PackageResult {
30
+ readonly name: string;
31
+ readonly exists: boolean;
32
+ readonly version: string;
33
+ readonly level: string;
34
+ readonly score: number;
35
+ readonly findingCount: number;
36
+ readonly error?: string;
37
+ }
38
+ /** Aggregated CI scan report for a project directory. */
39
+ export interface CiReport {
40
+ readonly dir: string;
41
+ readonly scannedAt: string;
42
+ readonly dependencyCount: number;
43
+ readonly failLevel: string;
44
+ readonly failed: boolean;
45
+ readonly summary: Readonly<Record<string, number>>;
46
+ readonly packages: readonly PackageResult[];
47
+ }
48
+ /** Options accepted by {@link NpmSafeEngine.ciScan}. */
49
+ export interface CiScanOptions {
50
+ /** Project directory containing `package.json`. @default process.cwd() */
51
+ readonly dir?: string;
52
+ /** Fail when any dependency reaches this level. @default SecurityLevel.Dangerous */
53
+ readonly failLevel?: SecurityLevel;
54
+ /** Scan every dependency in `package-lock.json` (including transitive). */
55
+ readonly lockfile?: boolean;
56
+ /** Only scan `dependencies` (skip devDependencies). */
57
+ readonly prod?: boolean;
58
+ /** Optional external abort signal for cooperative cancellation. */
59
+ readonly signal?: AbortSignal;
60
+ }
61
+ /**
62
+ * Read direct dependencies (and optionally devDependencies) from a manifest.
63
+ *
64
+ * @param dir - Project directory containing a `package.json` file.
65
+ * @param includeDev - When `true`, also include `devDependencies`.
66
+ * @returns A list of dependency names (deduplicated, insertion-ordered).
67
+ * @throws {Error} When `package.json` cannot be read or parsed.
68
+ */
69
+ export declare function readDependencies(dir: string, includeDev: boolean): Dependency[];
70
+ /**
71
+ * Read every package (including transitive dependencies) from a
72
+ * `package-lock.json` (npm lockfile v2/v3 `packages` map, with a fallback to
73
+ * the v1 `dependencies` tree). When `includeDev` is `false`, the result is
74
+ * restricted to the direct `dependencies` declared in `package.json` (`--prod`).
75
+ *
76
+ * @param dir - Project directory containing a `package-lock.json` file.
77
+ * @param includeDev - When `false`, restrict to `dependencies` from `package.json`.
78
+ * @returns A list of dependency names (deduplicated).
79
+ * @throws {Error} When `package-lock.json` cannot be read or parsed.
80
+ */
81
+ export declare function readLockfileDependencies(dir: string, includeDev: boolean): Dependency[];
82
+ //# sourceMappingURL=ci-scan.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ci-scan.d.ts","sourceRoot":"","sources":["../../src/scanner/ci-scan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAKH,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE3C;;;;;GAKG;AACH,eAAO,MAAM,UAAU,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAKvD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,WAAW,EAAE,SAAS,MAAM,EAKxC,CAAC;AAEF,+DAA+D;AAC/D,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACvB;AAED,oDAAoD;AACpD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAC;IAC9B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,yDAAyD;AACzD,MAAM,WAAW,QAAQ;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IACnD,QAAQ,CAAC,QAAQ,EAAE,SAAS,aAAa,EAAE,CAAC;CAC7C;AAED,wDAAwD;AACxD,MAAM,WAAW,aAAa;IAC5B,0EAA0E;IAC1E,QAAQ,CAAC,GAAG,CAAC,EAAE,MAAM,CAAC;IACtB,oFAAoF;IACpF,QAAQ,CAAC,SAAS,CAAC,EAAE,aAAa,CAAC;IACnC,2EAA2E;IAC3E,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,uDAAuD;IACvD,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,mEAAmE;IACnE,QAAQ,CAAC,MAAM,CAAC,EAAE,WAAW,CAAC;CAC/B;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,OAAO,GAClB,UAAU,EAAE,CAoBd;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,wBAAwB,CACtC,GAAG,EAAE,MAAM,EACX,UAAU,EAAE,OAAO,GAClB,UAAU,EAAE,CA6Dd"}
@@ -0,0 +1,130 @@
1
+ /**
2
+ * Pure CI dependency-scan helpers extracted from the legacy `ci` CLI command.
3
+ *
4
+ * This module is intentionally free of CLI concerns: no `commander` option
5
+ * parsing, no i18n (`t()`), no telemetry recording, and no console output.
6
+ * The {@link NpmSafeEngine.ciScan} method composes these helpers with the
7
+ * engine to produce a {@link CiReport}; rendering and exit-code mapping are
8
+ * the caller's responsibility.
9
+ *
10
+ * @module scanner/ci-scan
11
+ */
12
+ import fs from 'node:fs';
13
+ import path from 'node:path';
14
+ import { SecurityLevel } from './types.js';
15
+ /**
16
+ * Severity ordering used for the failure gate: lower rank = more severe.
17
+ *
18
+ * Exported so the engine's `ciScan` method can evaluate the fail gate without
19
+ * re-declaring this mapping.
20
+ */
21
+ export const LEVEL_RANK = {
22
+ [SecurityLevel.Dangerous]: 1,
23
+ [SecurityLevel.Unknown]: 2,
24
+ [SecurityLevel.Suspicious]: 3,
25
+ [SecurityLevel.Safe]: 4,
26
+ };
27
+ /**
28
+ * Display order of security levels (used for option help text in the CLI).
29
+ */
30
+ export const LEVEL_ORDER = [
31
+ SecurityLevel.Safe,
32
+ SecurityLevel.Suspicious,
33
+ SecurityLevel.Dangerous,
34
+ SecurityLevel.Unknown,
35
+ ];
36
+ /**
37
+ * Read direct dependencies (and optionally devDependencies) from a manifest.
38
+ *
39
+ * @param dir - Project directory containing a `package.json` file.
40
+ * @param includeDev - When `true`, also include `devDependencies`.
41
+ * @returns A list of dependency names (deduplicated, insertion-ordered).
42
+ * @throws {Error} When `package.json` cannot be read or parsed.
43
+ */
44
+ export function readDependencies(dir, includeDev) {
45
+ const manifestPath = path.join(dir, 'package.json');
46
+ let manifest;
47
+ try {
48
+ manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
49
+ }
50
+ catch {
51
+ throw new Error(`No package.json found in ${dir}`);
52
+ }
53
+ const names = new Set();
54
+ for (const key of ['dependencies', ...(includeDev ? ['devDependencies'] : [])]) {
55
+ const section = manifest[key];
56
+ if (section && typeof section === 'object') {
57
+ for (const name of Object.keys(section)) {
58
+ if (name !== 'optionalDependencies')
59
+ names.add(name);
60
+ }
61
+ }
62
+ }
63
+ return [...names].map((name) => ({ name }));
64
+ }
65
+ /**
66
+ * Read every package (including transitive dependencies) from a
67
+ * `package-lock.json` (npm lockfile v2/v3 `packages` map, with a fallback to
68
+ * the v1 `dependencies` tree). When `includeDev` is `false`, the result is
69
+ * restricted to the direct `dependencies` declared in `package.json` (`--prod`).
70
+ *
71
+ * @param dir - Project directory containing a `package-lock.json` file.
72
+ * @param includeDev - When `false`, restrict to `dependencies` from `package.json`.
73
+ * @returns A list of dependency names (deduplicated).
74
+ * @throws {Error} When `package-lock.json` cannot be read or parsed.
75
+ */
76
+ export function readLockfileDependencies(dir, includeDev) {
77
+ const lockPath = path.join(dir, 'package-lock.json');
78
+ let lock;
79
+ try {
80
+ lock = JSON.parse(fs.readFileSync(lockPath, 'utf8'));
81
+ }
82
+ catch {
83
+ throw new Error(`No package-lock.json found in ${dir}`);
84
+ }
85
+ const names = new Set();
86
+ const packages = lock.packages;
87
+ if (packages && typeof packages === 'object') {
88
+ for (const key of Object.keys(packages)) {
89
+ if (key === '')
90
+ continue; // root project entry
91
+ // "node_modules/a" -> "a"; "node_modules/@scope/c" -> "@scope/c";
92
+ // "node_modules/a/node_modules/d" -> "d" (the innermost package).
93
+ const stripped = key.replace(/^node_modules\//, '');
94
+ const parts = stripped.split('/node_modules/');
95
+ const name = parts[parts.length - 1];
96
+ if (name.length > 0)
97
+ names.add(name);
98
+ }
99
+ }
100
+ // npm lockfile v1 fallback: nested dependencies tree.
101
+ const collect = (section) => {
102
+ if (!section || typeof section !== 'object')
103
+ return;
104
+ for (const [name, entry] of Object.entries(section)) {
105
+ if (name === 'optionalDependencies')
106
+ continue;
107
+ names.add(name);
108
+ if (entry && typeof entry === 'object') {
109
+ collect(entry.dependencies);
110
+ }
111
+ }
112
+ };
113
+ collect(lock.dependencies);
114
+ if (!includeDev) {
115
+ // --prod: restrict to the direct dependencies declared in package.json.
116
+ const manifestPath = path.join(dir, 'package.json');
117
+ try {
118
+ const manifest = JSON.parse(fs.readFileSync(manifestPath, 'utf8'));
119
+ const prod = new Set(Object.keys(manifest.dependencies ?? {}));
120
+ return [...names]
121
+ .filter((name) => prod.has(name))
122
+ .map((name) => ({ name }));
123
+ }
124
+ catch {
125
+ // No package.json — fall through to the full lockfile set.
126
+ }
127
+ }
128
+ return [...names].map((name) => ({ name }));
129
+ }
130
+ //# sourceMappingURL=ci-scan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ci-scan.js","sourceRoot":"","sources":["../../src/scanner/ci-scan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Per-rule configuration: enable/disable, severity overrides, and free-form
3
+ * options. Configuration is persisted as JSON (default
4
+ * `~/.npm-safe/rules.json`) and can be managed at runtime through the
5
+ * {@link RuleConfigManager}.
6
+ */
7
+ import { Severity } from './types.js';
8
+ /** Free-form options passed to a rule at match time. */
9
+ export type RuleOptions = Readonly<Record<string, unknown>>;
10
+ /** Per-rule configuration overrides. */
11
+ export interface RuleConfig {
12
+ /** Whether the rule is enabled. Defaults to the rule's own default. */
13
+ readonly enabled?: boolean;
14
+ /** Severity override applied to findings produced by the rule. */
15
+ readonly severity?: Severity;
16
+ /** Free-form options made available to the rule implementation. */
17
+ readonly options?: RuleOptions;
18
+ }
19
+ /** Shape of the persisted rules configuration file. */
20
+ export interface RuleConfigFile {
21
+ /** Per-rule overrides keyed by rule id. */
22
+ readonly rules: Readonly<Record<string, RuleConfig>>;
23
+ }
24
+ /** Default location of the rules configuration file. */
25
+ export declare function getDefaultRulesConfigPath(): string;
26
+ /**
27
+ * Loads, mutates, and persists per-rule configuration. Thread-safe per
28
+ * instance; concurrent instances may race on the file, which is acceptable
29
+ * for a single-user desktop tool.
30
+ */
31
+ export declare class RuleConfigManager {
32
+ private readonly filePath;
33
+ private config;
34
+ /**
35
+ * @param filePath - Path to the JSON config file.
36
+ */
37
+ constructor(filePath?: string);
38
+ /** Load (or initialize) the config file. */
39
+ private load;
40
+ /** Persist the current configuration to disk. */
41
+ private save;
42
+ /** Get the configuration for a single rule, or `undefined` if unset. */
43
+ getRule(ruleId: string): RuleConfig | undefined;
44
+ /** Whether a rule is enabled, honoring config overrides. */
45
+ isEnabled(ruleId: string, defaultEnabled: boolean): boolean;
46
+ /** Severity override for a rule, or `undefined` if not overridden. */
47
+ getSeverityOverride(ruleId: string): Severity | undefined;
48
+ /** Options for a rule, or `{}` if none are configured. */
49
+ getOptions(ruleId: string): RuleOptions;
50
+ /** Enable or disable a rule (persisted). */
51
+ setEnabled(ruleId: string, enabled: boolean): void;
52
+ /** Override a rule's severity (persisted). `undefined` clears the override. */
53
+ setSeverity(ruleId: string, severity: Severity | undefined): void;
54
+ /** Set a rule's options (persisted). */
55
+ setOptions(ruleId: string, options: RuleOptions): void;
56
+ /** All configured rule ids. */
57
+ getConfiguredRuleIds(): string[];
58
+ /** Mutable view of the rules map for writing. */
59
+ private mutableRules;
60
+ }
61
+ //# sourceMappingURL=rule-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rule-config.d.ts","sourceRoot":"","sources":["../../src/scanner/rule-config.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC,wDAAwD;AACxD,MAAM,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAC;AAE5D,wCAAwC;AACxC,MAAM,WAAW,UAAU;IACzB,uEAAuE;IACvE,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,kEAAkE;IAClE,QAAQ,CAAC,QAAQ,CAAC,EAAE,QAAQ,CAAC;IAC7B,mEAAmE;IACnE,QAAQ,CAAC,OAAO,CAAC,EAAE,WAAW,CAAC;CAChC;AAED,uDAAuD;AACvD,MAAM,WAAW,cAAc;IAC7B,2CAA2C;IAC3C,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC,CAAC;CACtD;AAED,wDAAwD;AACxD,wBAAgB,yBAAyB,IAAI,MAAM,CAElD;AAED;;;;GAIG;AACH,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAS;IAClC,OAAO,CAAC,MAAM,CAAiB;IAE/B;;OAEG;gBACS,QAAQ,CAAC,EAAE,MAAM;IAK7B,4CAA4C;IAC5C,OAAO,CAAC,IAAI;IAUZ,iDAAiD;IACjD,OAAO,CAAC,IAAI;IASZ,wEAAwE;IACxE,OAAO,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,GAAG,SAAS;IAI/C,4DAA4D;IAC5D,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,cAAc,EAAE,OAAO,GAAG,OAAO;IAK3D,sEAAsE;IACtE,mBAAmB,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAIzD,0DAA0D;IAC1D,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,WAAW;IAIvC,4CAA4C;IAC5C,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,OAAO,GAAG,IAAI;IAOlD,+EAA+E;IAC/E,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,QAAQ,GAAG,SAAS,GAAG,IAAI;IAYjE,wCAAwC;IACxC,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,GAAG,IAAI;IAOtD,+BAA+B;IAC/B,oBAAoB,IAAI,MAAM,EAAE;IAIhC,iDAAiD;IACjD,OAAO,CAAC,YAAY;CAGrB"}