@bloodhound-rs/core 0.1.2 → 0.2.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/CHANGELOG.md +19 -1
- package/README.md +93 -134
- package/dist/index.d.ts +33 -44
- package/dist/index.js +39 -733
- package/dist/native.d.ts +24 -0
- package/dist/native.js +725 -0
- package/dist/types.d.ts +172 -194
- package/dist/types.js +8 -0
- package/package.json +29 -19
- package/docs/support.md +0 -57
- package/schemas/index.schema.json +0 -464
- package/schemas/report.schema.json +0 -542
package/dist/types.d.ts
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Public types of `@bloodhound-rs/core`.
|
|
3
|
+
*
|
|
4
|
+
* These mirror the Rust data model in `native/src/model.rs`. The Rust side is
|
|
5
|
+
* the source of truth; keep field names and enum values in sync.
|
|
6
|
+
*/
|
|
7
|
+
/** Where a resource's bytes come from. */
|
|
5
8
|
export type Source = {
|
|
6
9
|
type: 'file';
|
|
7
10
|
path: string;
|
|
@@ -11,234 +14,209 @@ export type Source = {
|
|
|
11
14
|
} | {
|
|
12
15
|
type: 'content';
|
|
13
16
|
content: string;
|
|
14
|
-
|
|
17
|
+
/** Logical URL used to resolve relative dependencies and to label the resource. */
|
|
18
|
+
resourceUrl?: string;
|
|
15
19
|
};
|
|
16
|
-
export
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
20
|
+
export type ResourceKind = 'js' | 'html' | 'css';
|
|
21
|
+
/**
|
|
22
|
+
* How a JavaScript resource executes. Top-level `var`/`function` in a classic
|
|
23
|
+
* script become `window` properties; in a module they stay module-local.
|
|
24
|
+
*/
|
|
25
|
+
export type ScriptMode = 'classic' | 'module';
|
|
26
|
+
export type DependencyMode = 'single' | 'recursive';
|
|
27
|
+
export interface ScanEntry {
|
|
28
|
+
kind: ResourceKind;
|
|
29
|
+
source: Source;
|
|
30
|
+
/** Overrides the logical URL of the source. */
|
|
31
|
+
resourceUrl?: string;
|
|
32
|
+
/** Script mode for JS entries. Defaults to `ScanOptions.scriptMode`. */
|
|
33
|
+
scriptMode?: ScriptMode;
|
|
29
34
|
}
|
|
30
35
|
export interface Budgets {
|
|
36
|
+
/** Maximum in-flight load-and-analysis jobs. Default 8, at most 256. */
|
|
31
37
|
concurrency: number;
|
|
38
|
+
/** Worker count, capped by concurrency. Default: CPU count, at most 256. */
|
|
32
39
|
analysisConcurrency: number;
|
|
40
|
+
/** Wall clock limit for the whole scan. Default 120 000. */
|
|
33
41
|
timeoutMs: number;
|
|
42
|
+
/** Per-request network timeout. Default 30 000. */
|
|
34
43
|
resourceTimeoutMs: number;
|
|
44
|
+
/** Maximum resources loaded. Default 500. */
|
|
35
45
|
maxResources: number;
|
|
36
|
-
|
|
46
|
+
/** Maximum size of one resource. Default 16 MiB. */
|
|
37
47
|
maxResourceBytes: number;
|
|
38
|
-
|
|
39
|
-
|
|
48
|
+
/** Maximum total bytes loaded. Default 256 MiB. */
|
|
49
|
+
maxBytes: number;
|
|
50
|
+
/** Maximum dependency depth from an entry. Default 16. */
|
|
40
51
|
maxDepth: number;
|
|
52
|
+
/** Maximum AST nodes visited per JavaScript resource. Default 2 000 000. */
|
|
41
53
|
maxSteps: number;
|
|
54
|
+
/** Maximum string candidates tracked per value. Default 32. */
|
|
42
55
|
maxCandidates: number;
|
|
43
|
-
|
|
56
|
+
/** HTTP redirects followed per request. Default 5. */
|
|
44
57
|
maxRedirects: number;
|
|
58
|
+
/** HTTP retries on transport failure. Default 1. */
|
|
45
59
|
retries: number;
|
|
46
60
|
}
|
|
61
|
+
export interface Access {
|
|
62
|
+
/** Allowed URL schemes with trailing colon, e.g. `['https:']`. Default: file, http, https. */
|
|
63
|
+
protocols?: string[];
|
|
64
|
+
/** Allowed `host[:port]` values for network requests. */
|
|
65
|
+
hosts?: string[];
|
|
66
|
+
/** Directories that `file:` URLs must live inside. */
|
|
67
|
+
fileRoots?: string[];
|
|
68
|
+
}
|
|
69
|
+
export interface ImportMap {
|
|
70
|
+
imports?: Record<string, string | null>;
|
|
71
|
+
scopes?: Record<string, Record<string, string | null>>;
|
|
72
|
+
}
|
|
73
|
+
export interface ScanOptions {
|
|
74
|
+
/** Script mode for JS entries and for scripts whose mode is unknown. Default `classic`. */
|
|
75
|
+
scriptMode?: ScriptMode;
|
|
76
|
+
/** `single` analyzes only the entries; `recursive` follows dependencies. Default `recursive`. */
|
|
77
|
+
dependencyMode?: DependencyMode;
|
|
78
|
+
/** Logical URL for a string or content input (used by `scanHtml`/`scanJs`). */
|
|
79
|
+
resourceUrl?: string;
|
|
80
|
+
/** Document base when a resource has no usable URL of its own. */
|
|
81
|
+
baseUrl?: string;
|
|
82
|
+
/** Import map applied to standalone JS entries. HTML entries read their own. */
|
|
83
|
+
importMap?: ImportMap;
|
|
84
|
+
budgets?: Partial<Budgets>;
|
|
85
|
+
access?: Access;
|
|
86
|
+
/**
|
|
87
|
+
* Regex source strings (Rust regex syntax: no lookaround or backreferences) matched against
|
|
88
|
+
* the resolved logical URL of recursively discovered dependencies, e.g. `'/vendor/'` or
|
|
89
|
+
* `'\\.min\\.js($|\\?)'`. Matching dependencies are not loaded or analyzed and appear in
|
|
90
|
+
* `dependencies` as `not-followed` with `reason: 'excluded'`. Inline scripts are not matched.
|
|
91
|
+
* A matching entry, or an invalid pattern, rejects the scan (throws).
|
|
92
|
+
*/
|
|
93
|
+
excludeUrls?: string[];
|
|
94
|
+
/** Substitute sources for resolved URLs (offline scanning of bundler output). */
|
|
95
|
+
resourceMappings?: Record<string, Source>;
|
|
96
|
+
/** Extra request headers keyed by `host[:port]`. */
|
|
97
|
+
requestHeaders?: Record<string, Record<string, string>>;
|
|
98
|
+
proxy?: string;
|
|
99
|
+
/** Decode `sourceMappingURL` comments and attach original locations. */
|
|
100
|
+
sourceMaps?: boolean;
|
|
101
|
+
/** Cancels a running scan. The result is a manifest with `status: 'cancelled'`. */
|
|
102
|
+
signal?: AbortSignal;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Pollution categories reported by the scanner.
|
|
106
|
+
*
|
|
107
|
+
* | rule | meaning |
|
|
108
|
+
* |------------------------|---------------------------------------------------------------------|
|
|
109
|
+
* | `global-write` | `window.x = …`, top-level `var`/`function` in classic scripts |
|
|
110
|
+
* | `document-write` | `document.body.className = …`, `document.body.setAttribute(…)` |
|
|
111
|
+
* | `builtin-mutation` | `Array.prototype.x = …`, `Promise.allSettled = …` |
|
|
112
|
+
* | `host-api-override` | `window.fetch = …`, `XMLHttpRequest.prototype.open = …` |
|
|
113
|
+
* | `dom-insertion` | `document.body.appendChild(…)`, `document.write(…)` |
|
|
114
|
+
* | `style-injection` | `<style>`/`<link>` inserted by script without removal |
|
|
115
|
+
* | `document-style-write` | `document.body.style.x = …`, `documentElement.style.setProperty(…)` |
|
|
116
|
+
* | `global-listener` | `window.addEventListener(…)` without `removeEventListener` |
|
|
117
|
+
* | `html-global-style` | `style=` attribute on `<html>`/`<body>` |
|
|
118
|
+
*/
|
|
119
|
+
export type Rule = 'global-write' | 'document-write' | 'builtin-mutation' | 'host-api-override' | 'dom-insertion' | 'style-injection' | 'document-style-write' | 'global-listener' | 'html-global-style';
|
|
120
|
+
export type Severity = 'info' | 'warning' | 'error';
|
|
121
|
+
/**
|
|
122
|
+
* `high`: the receiver is provably the global object, `document`, or a builtin.
|
|
123
|
+
* `medium`: the receiver was tracked through a reassignable alias or a branch.
|
|
124
|
+
*/
|
|
125
|
+
export type Confidence = 'high' | 'medium';
|
|
126
|
+
export type ScanStatus = 'completed' | 'partial' | 'failed' | 'cancelled';
|
|
127
|
+
export type SourceStatus = 'completed' | 'partial' | 'failed';
|
|
128
|
+
export type DependencyStatus = 'resolved' | 'not-followed' | 'unresolved';
|
|
129
|
+
export type DependencyKind = 'script' | 'inline-script' | 'style' | 'module-preload' | 'iframe' | 'import' | 'dynamic-import' | 'worker' | 'dynamic-script' | 'dynamic-style';
|
|
130
|
+
/** Lines are 1-based; columns are 0-based UTF-16 code units. */
|
|
47
131
|
export interface Location {
|
|
48
|
-
start: number;
|
|
49
|
-
end: number;
|
|
50
132
|
line: number;
|
|
51
133
|
column: number;
|
|
52
134
|
endLine: number;
|
|
53
135
|
endColumn: number;
|
|
54
|
-
|
|
136
|
+
/** Original position from a source map when `sourceMaps` was enabled. */
|
|
55
137
|
original?: {
|
|
56
138
|
source: string;
|
|
57
139
|
line: number;
|
|
58
140
|
column: number;
|
|
59
141
|
name?: string;
|
|
60
142
|
};
|
|
61
|
-
container?: {
|
|
62
|
-
resourceUrl: string;
|
|
63
|
-
offset: number;
|
|
64
|
-
line: number;
|
|
65
|
-
column: number;
|
|
66
|
-
approximate?: boolean;
|
|
67
|
-
};
|
|
68
143
|
}
|
|
69
|
-
export interface
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
finalUrl: string;
|
|
73
|
-
contentHash: string;
|
|
144
|
+
export interface ManifestSource {
|
|
145
|
+
/** Manifest-local id such as `s1`. */
|
|
146
|
+
id: string;
|
|
74
147
|
kind: ResourceKind;
|
|
75
|
-
|
|
76
|
-
|
|
148
|
+
/** Logical URL. Absent for anonymous inline content. */
|
|
149
|
+
url?: string;
|
|
150
|
+
/** Present for inline scripts extracted from an HTML parent. */
|
|
77
151
|
inline?: {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
152
|
+
parent: string;
|
|
153
|
+
line: number;
|
|
154
|
+
column: number;
|
|
81
155
|
};
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
resolution: 'resolved' | 'candidate' | 'unresolved' | 'not-followed';
|
|
100
|
-
location: Location;
|
|
101
|
-
condition?: string;
|
|
102
|
-
attributes?: Record<string, string>;
|
|
103
|
-
reason?: string;
|
|
104
|
-
}
|
|
105
|
-
export interface Target {
|
|
106
|
-
targetId: string;
|
|
107
|
-
scopeKey: string;
|
|
108
|
-
namespace: string;
|
|
109
|
-
pathSegments: string[];
|
|
110
|
-
keyKind: string;
|
|
111
|
-
}
|
|
112
|
-
export interface GlobalAccess {
|
|
113
|
-
accessId: string;
|
|
114
|
-
analysisId: string;
|
|
115
|
-
targetRefs: string[];
|
|
156
|
+
scriptMode?: ScriptMode;
|
|
157
|
+
status: SourceStatus;
|
|
158
|
+
bytes: number;
|
|
159
|
+
contentHash: string;
|
|
160
|
+
/** Ids of the sources that referenced this one. Empty for entries. */
|
|
161
|
+
referrers: string[];
|
|
162
|
+
/** Shortest chain of source ids from an entry to this source, inclusive. */
|
|
163
|
+
chain: string[];
|
|
164
|
+
}
|
|
165
|
+
export interface ManifestFinding {
|
|
166
|
+
/** Source id containing the pollution. */
|
|
167
|
+
source: string;
|
|
168
|
+
rule: Rule;
|
|
169
|
+
severity: Severity;
|
|
170
|
+
/** Dotted path of the polluted target, e.g. `window.sharedConfig`. */
|
|
171
|
+
target: string;
|
|
172
|
+
/** `write` | `update` | `define` | `delete` | `declare` | `insert` | `listen` | `style`. */
|
|
116
173
|
operation: string;
|
|
117
|
-
|
|
174
|
+
confidence: Confidence;
|
|
118
175
|
location: Location;
|
|
119
|
-
|
|
120
|
-
|
|
176
|
+
/** Trimmed excerpt of the offending expression. */
|
|
177
|
+
snippet: string;
|
|
178
|
+
detail?: string;
|
|
121
179
|
}
|
|
122
|
-
export interface
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
180
|
+
export interface ManifestDependency {
|
|
181
|
+
from: string;
|
|
182
|
+
/** Set when the dependency was resolved and analyzed. */
|
|
183
|
+
to?: string;
|
|
184
|
+
kind: DependencyKind;
|
|
185
|
+
specifier?: string;
|
|
186
|
+
url?: string;
|
|
187
|
+
status: DependencyStatus;
|
|
188
|
+
reason?: string;
|
|
128
189
|
location: Location;
|
|
129
|
-
details: Record<string, unknown>;
|
|
130
|
-
fingerprint: string;
|
|
131
190
|
}
|
|
132
|
-
export interface
|
|
133
|
-
|
|
134
|
-
referenceId?: string;
|
|
135
|
-
location?: Location;
|
|
191
|
+
export interface ManifestGap {
|
|
192
|
+
source?: string;
|
|
136
193
|
reason: string;
|
|
137
|
-
|
|
194
|
+
count: number;
|
|
138
195
|
detail?: string;
|
|
196
|
+
location?: Location;
|
|
139
197
|
}
|
|
140
|
-
export interface
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
parentContent: string;
|
|
151
|
-
};
|
|
152
|
-
}
|
|
153
|
-
export interface Checkpoint {
|
|
154
|
-
checkpointVersion: 1;
|
|
155
|
-
configHash: string;
|
|
156
|
-
entries: ScanEntry[];
|
|
157
|
-
pending: PendingResource[];
|
|
158
|
-
report: Report;
|
|
159
|
-
options?: Pick<ScanOptions, 'access' | 'resourceMappings' | 'sourceMaps'>;
|
|
160
|
-
}
|
|
161
|
-
export interface ScanEntry {
|
|
162
|
-
kind: ResourceKind;
|
|
163
|
-
source: Source;
|
|
164
|
-
resourceUrl?: string;
|
|
198
|
+
export interface Summary {
|
|
199
|
+
sources: number;
|
|
200
|
+
findings: number;
|
|
201
|
+
errors: number;
|
|
202
|
+
warnings: number;
|
|
203
|
+
dependencies: number;
|
|
204
|
+
unresolved: number;
|
|
205
|
+
gaps: number;
|
|
206
|
+
bytes: number;
|
|
207
|
+
elapsedMs: number;
|
|
165
208
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
209
|
+
/** The scan result. */
|
|
210
|
+
export interface Manifest {
|
|
211
|
+
schemaVersion: 2;
|
|
169
212
|
scannerVersion: string;
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
dependencyMode: 'single' | 'recursive';
|
|
180
|
-
};
|
|
181
|
-
entryAnalysisIds: string[];
|
|
182
|
-
resources: Resource[];
|
|
183
|
-
analysisInstances: AnalysisInstance[];
|
|
184
|
-
references: Reference[];
|
|
185
|
-
globalTargets: Target[];
|
|
186
|
-
globalAccesses: GlobalAccess[];
|
|
187
|
-
findings: Finding[];
|
|
188
|
-
unresolved: Unresolved[];
|
|
189
|
-
coverage: {
|
|
190
|
-
analyzed: number;
|
|
191
|
-
failed: number;
|
|
192
|
-
unresolved: number;
|
|
193
|
-
bytes: number;
|
|
194
|
-
dependencyMode: 'single' | 'recursive';
|
|
195
|
-
sourceMapped: number;
|
|
196
|
-
elapsedMs: number;
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
export interface ScanOptions {
|
|
200
|
-
scriptMode?: ScriptMode;
|
|
201
|
-
executionEnvironment?: Environment;
|
|
202
|
-
/** 离线资源的逻辑地址;直接扫描 URL 时无需重复设置。 */
|
|
203
|
-
resourceUrl?: string;
|
|
204
|
-
/** 补充文档基准;HTML 中的有效 base 标签会被自动读取。 */
|
|
205
|
-
baseUrl?: string;
|
|
206
|
-
/** 补充页面上下文,供单独扫描 JS 等场景使用;HTML 内的 Import Map 自动读取。 */
|
|
207
|
-
importMap?: ImportMap;
|
|
208
|
-
/** 外部传入 importMap 中相对地址的解析基准。 */
|
|
209
|
-
importMapBaseUrl?: string;
|
|
210
|
-
publicPath?: string;
|
|
211
|
-
scopeKey?: string;
|
|
212
|
-
scope?: Record<string, unknown>;
|
|
213
|
-
versions?: Record<string, string>;
|
|
214
|
-
dependencyMode?: 'single' | 'recursive';
|
|
215
|
-
budgets?: Partial<Budgets>;
|
|
216
|
-
signal?: AbortSignal;
|
|
217
|
-
access?: {
|
|
218
|
-
protocols?: string[];
|
|
219
|
-
hosts?: string[];
|
|
220
|
-
fileRoots?: string[];
|
|
221
|
-
};
|
|
222
|
-
/** 用本地文件或源码替代已解析的资源 URL;不是 HTML Import Map,普通页面扫描无需设置。 */
|
|
223
|
-
resourceMappings?: Record<string, Source>;
|
|
224
|
-
requestHeaders?: Record<string, Record<string, string>>;
|
|
225
|
-
proxy?: string;
|
|
226
|
-
jsonlPath?: string;
|
|
227
|
-
reportPath?: string;
|
|
228
|
-
checkpointPath?: string;
|
|
229
|
-
resumePath?: string;
|
|
230
|
-
sourceMaps?: boolean;
|
|
231
|
-
resume?: Checkpoint;
|
|
213
|
+
status: ScanStatus;
|
|
214
|
+
dependencyMode: DependencyMode;
|
|
215
|
+
summary: Summary;
|
|
216
|
+
/** Source ids of the entries, in request order. */
|
|
217
|
+
entries: string[];
|
|
218
|
+
sources: ManifestSource[];
|
|
219
|
+
findings: ManifestFinding[];
|
|
220
|
+
dependencies: ManifestDependency[];
|
|
221
|
+
gaps: ManifestGap[];
|
|
232
222
|
}
|
|
233
|
-
export type StreamRecord = {
|
|
234
|
-
type: 'resetAnalysis';
|
|
235
|
-
value: {
|
|
236
|
-
analysisId: string;
|
|
237
|
-
};
|
|
238
|
-
} | {
|
|
239
|
-
type: keyof Pick<Report, 'resources' | 'analysisInstances' | 'references' | 'globalTargets' | 'globalAccesses' | 'findings' | 'unresolved'>;
|
|
240
|
-
value: unknown;
|
|
241
|
-
} | {
|
|
242
|
-
type: 'summary';
|
|
243
|
-
value: Omit<Report, 'resources' | 'analysisInstances' | 'references' | 'globalTargets' | 'globalAccesses' | 'findings' | 'unresolved'>;
|
|
244
|
-
};
|
package/dist/types.js
ADDED
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@bloodhound-rs/core",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"description": "Rust static
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"description": "Rust static scanner that finds global-environment pollution in JavaScript and HTML",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"engines": {
|
|
@@ -13,16 +13,12 @@
|
|
|
13
13
|
".": {
|
|
14
14
|
"types": "./dist/index.d.ts",
|
|
15
15
|
"import": "./dist/index.js"
|
|
16
|
-
}
|
|
17
|
-
"./schema": "./schemas/report.schema.json",
|
|
18
|
-
"./index-schema": "./schemas/index.schema.json"
|
|
16
|
+
}
|
|
19
17
|
},
|
|
20
18
|
"files": [
|
|
21
19
|
"dist/*.js",
|
|
22
20
|
"dist/*.d.ts",
|
|
23
|
-
"schemas",
|
|
24
21
|
"README.md",
|
|
25
|
-
"docs/support.md",
|
|
26
22
|
"CHANGELOG.md"
|
|
27
23
|
],
|
|
28
24
|
"devDependencies": {
|
|
@@ -30,7 +26,10 @@
|
|
|
30
26
|
"@napi-rs/cli": "3.10.8",
|
|
31
27
|
"@types/node": "^22.19.0",
|
|
32
28
|
"prettier": "3.6.2",
|
|
33
|
-
"
|
|
29
|
+
"rolldown": "1.2.14",
|
|
30
|
+
"rollup": "^4.64.12",
|
|
31
|
+
"typescript": "^5.9.3",
|
|
32
|
+
"@bloodhound-rs/rollup-plugin": "0.2.0"
|
|
34
33
|
},
|
|
35
34
|
"napi": {
|
|
36
35
|
"binaryName": "bloodhound",
|
|
@@ -52,25 +51,36 @@
|
|
|
52
51
|
"url": "git+https://github.com/Justinidlerz/bloodhound.git"
|
|
53
52
|
},
|
|
54
53
|
"optionalDependencies": {
|
|
55
|
-
"@bloodhound-rs/core-
|
|
56
|
-
"@bloodhound-rs/core-
|
|
57
|
-
"@bloodhound-rs/core-
|
|
58
|
-
"@bloodhound-rs/core-
|
|
59
|
-
"@bloodhound-rs/core-darwin-x64": "0.
|
|
54
|
+
"@bloodhound-rs/core-darwin-arm64": "0.2.0",
|
|
55
|
+
"@bloodhound-rs/core-linux-arm64-gnu": "0.2.0",
|
|
56
|
+
"@bloodhound-rs/core-linux-x64-gnu": "0.2.0",
|
|
57
|
+
"@bloodhound-rs/core-win32-x64-msvc": "0.2.0",
|
|
58
|
+
"@bloodhound-rs/core-darwin-x64": "0.2.0"
|
|
60
59
|
},
|
|
61
60
|
"scripts": {
|
|
62
61
|
"build:native": "node scripts/build-native.mjs",
|
|
63
|
-
"build:ts": "tsc
|
|
64
|
-
"build": "
|
|
65
|
-
"
|
|
62
|
+
"build:ts": "tsc -p tsconfig.json",
|
|
63
|
+
"build:plugin": "pnpm --filter @bloodhound-rs/rollup-plugin build",
|
|
64
|
+
"build": "node scripts/clean-dist.mjs && pnpm build:native && pnpm build:ts && pnpm build:plugin",
|
|
65
|
+
"typecheck": "tsc --noEmit -p tsconfig.json && tsc --noEmit --strict --skipLibCheck --module NodeNext --target ES2023 tests/types.test.ts && pnpm --filter @bloodhound-rs/rollup-plugin typecheck && pnpm typecheck:playground",
|
|
66
66
|
"example": "node examples/scan.mjs",
|
|
67
67
|
"example:html": "node examples/scan-html.mjs",
|
|
68
|
-
"
|
|
69
|
-
"
|
|
68
|
+
"example:rollup": "rollup -c examples/rollup/rollup.config.mjs",
|
|
69
|
+
"example:rolldown": "rolldown -c examples/rollup/rolldown.config.mjs",
|
|
70
|
+
"playground": "node playground/scripts/dev.mjs",
|
|
71
|
+
"build:playground": "node playground/scripts/build.mjs",
|
|
72
|
+
"typecheck:playground": "tsc --noEmit -p playground/tsconfig.json",
|
|
73
|
+
"format": "prettier --write src scripts tests examples packages playground README.md docs .github .changeset package.json tsconfig.json npm pnpm-workspace.yaml",
|
|
74
|
+
"format:check": "prettier --check src scripts tests examples packages playground README.md docs .github .changeset package.json tsconfig.json npm pnpm-workspace.yaml",
|
|
70
75
|
"changeset": "changeset",
|
|
71
76
|
"changeset:status": "changeset status",
|
|
72
77
|
"version:packages": "changeset version && node scripts/sync-native-version.mjs && node scripts/sync-platform-packages.mjs",
|
|
73
78
|
"platforms:sync": "node scripts/sync-platform-packages.mjs",
|
|
74
|
-
"pack:release": "node scripts/pack-ci.mjs"
|
|
79
|
+
"pack:release": "node scripts/pack-ci.mjs",
|
|
80
|
+
"test": "pnpm test:rust && pnpm test:scripts && pnpm build && pnpm typecheck && pnpm test:sdk && pnpm test:plugin",
|
|
81
|
+
"test:rust": "cargo test --locked --lib",
|
|
82
|
+
"test:scripts": "node --test tests/scripts.test.mjs tests/release.test.mjs",
|
|
83
|
+
"test:sdk": "node --test tests/sdk.test.mjs",
|
|
84
|
+
"test:plugin": "pnpm --filter @bloodhound-rs/rollup-plugin test"
|
|
75
85
|
}
|
|
76
86
|
}
|
package/docs/support.md
DELETED
|
@@ -1,57 +0,0 @@
|
|
|
1
|
-
# Supported capabilities
|
|
2
|
-
|
|
3
|
-
Use this reference to identify supported syntax, analysis limits, and report semantics.
|
|
4
|
-
|
|
5
|
-
| Area | Implementation | Coverage gaps |
|
|
6
|
-
| -------------------- | ------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------- |
|
|
7
|
-
| JavaScript input | Files, URLs, source text, and classic / module / unknown modes | Syntax errors and missing script mode or environment |
|
|
8
|
-
| Bindings and targets | Oxc scopes, local shadowing, separate global lexical bindings and object properties, and unbound references | Dynamic scopes introduced by `with` |
|
|
9
|
-
| Global operations | Declarations, reads, assignments, compound assignments, updates, delete, Object / Reflect APIs, and prototypes | Unknown property keys remain separate accesses without a shared placeholder target |
|
|
10
|
-
| Aliases | Sequential assignments, invalidation, bounded branch merging, direct IIFEs, and wrapper parameters with known bindings | Complex destructuring, exception and switch value propagation, and general function side effects |
|
|
11
|
-
| Bounded evaluation | Literals, concatenation, templates, bounded conditions, constant array and object keys, and restricted return expressions | Getters, proxies, general calls, and expansion beyond budgets |
|
|
12
|
-
| ESM | Imports, exports, dynamic import candidates, cross-module primitive summaries, and bounded iteration | Unbounded dynamic dependencies and unknown bare-specifier mappings |
|
|
13
|
-
| webpack | Runtime object properties, pure chunk mapping functions, script `src` expressions, and bounded ID tables | Automatic publicPath, complex runtime functions, and unknown addresses |
|
|
14
|
-
| Vite | Dynamic imports, preload wrappers with link creation and callback invocation, and bounded dependency arrays | General caching mapDeps wrappers and unbounded arrays |
|
|
15
|
-
| DOM | Candidate operations on document / body / head and aliases, and recoverable node resource addresses | Unknown node identity, runtime insertion, and teardown residue |
|
|
16
|
-
| Workers / iframes | Separate scopes for resolvable entry points, with reference edges preserved | Unknown document bases and dynamic child-environment addresses |
|
|
17
|
-
| HTML | HTML5 tokenization, raw text, base URLs, import map snapshots, scripts, styles, iframes, and inline offsets | Foreign-content tree contexts, noscript environments, token recovery, and event-handler scopes |
|
|
18
|
-
| CSS | CSS Syntax parsing, @import, url, global selectors, resets, custom properties, and animations | Parser recovery and unknown resource values. Candidates do not prove actual matching or pollution |
|
|
19
|
-
| Source maps | Rust sourcemap support for external maps and data URLs | Missing or unavailable maps affect only optional original-source locations |
|
|
20
|
-
|
|
21
|
-
HTML processing uses tokenization with source locations, without constructing a complete browser DOM tree. Template contents remain inert, and special tree contexts explicitly reduce coverage. For entity-decoded content such as `srcdoc`, the host location identifies the tag containing the attribute. Child-resource locations remain independent.
|
|
22
|
-
|
|
23
|
-
The webpack adapter matches syntax structures and Oxc bindings rather than fixed minified variable names. Chunk mappings produce bounded candidates without proving that every chunk loads. ESM analysis handles ordinary Vite dynamic imports, while preload analysis adds resource edges.
|
|
24
|
-
|
|
25
|
-
# Status
|
|
26
|
-
|
|
27
|
-
| Status | Meaning |
|
|
28
|
-
| --------- | ------------------------------------------------------------------------ |
|
|
29
|
-
| completed | No required coverage gaps were recorded within the declared scope |
|
|
30
|
-
| partial | Results exist, with gaps in dependencies, context, semantics, or budgets |
|
|
31
|
-
| failed | No valid analysis result was established |
|
|
32
|
-
| cancelled | A `runStatus` value, independent of the scan statuses |
|
|
33
|
-
|
|
34
|
-
`single` excludes the dependency closure and marks reference edges as `not-followed`. `completed` does not mean that the program has no dynamic behavior or that candidate issues occurred at runtime.
|
|
35
|
-
|
|
36
|
-
# Indexes and locations
|
|
37
|
-
|
|
38
|
-
- Target IDs use scope, namespace, path segments, and key type. Local Symbols also include the analysis instance and do not merge across resources.
|
|
39
|
-
- Identical contents with different URLs or contexts retain separate instances. Cycles prevent repeated analysis while preserving reference edges.
|
|
40
|
-
- Unbound bare references retain candidate relationships. They are not automatically classified as implicit global properties.
|
|
41
|
-
- Artifact locations use UTF-16 offsets, one-based lines, and zero-based columns. Rust converts its internal UTF-8 offsets when emitting results.
|
|
42
|
-
- Multiple writes, prototype changes, and DOM/CSS operations remain `static-candidate` findings.
|
|
43
|
-
- Version diffs match resources, scopes, modes, environments, targets, and operation features. Ambiguous matches become additions and removals. Changes between arbitrary values of the same type are not guaranteed to be detected.
|
|
44
|
-
|
|
45
|
-
# Runtime budgets
|
|
46
|
-
|
|
47
|
-
Limits apply to resource counts, total bytes, bytes per resource, download buffers, concurrency, depth, time, AST visits, bounded evaluation, candidate counts, summary rounds, and record counts. ASTs are released after each resource analysis, and caches have byte limits.
|
|
48
|
-
|
|
49
|
-
These limits bound input, work, and result sizes. They are not operating-system RSS limits. A host process can impose additional memory limits for large or untrusted inputs. Request timeouts bound network waits, while parsing does not guarantee immediate preemption.
|
|
50
|
-
|
|
51
|
-
JSONL supports consumer backpressure through the filesystem. Standard reports and in-memory indexes use memory proportional to their record counts. Recovery rebuilds the graph from saved entries and reads resources again, including remote content validation.
|
|
52
|
-
|
|
53
|
-
Checkpoints preserve access restrictions, resource mappings, and source map settings. Supply authentication headers and proxy settings again when resuming.
|
|
54
|
-
|
|
55
|
-
# Delivery scope
|
|
56
|
-
|
|
57
|
-
The SDK excludes platform databases, release gates, browser probes, and production deployment. No unit test suite was added. Scans of real artifacts and build evidence do not replace precision and recall evaluation against a fully labeled application dataset.
|