@aspect-guard/core 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Aspect Guard
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,395 @@
1
+ type Severity = 'critical' | 'high' | 'medium' | 'low' | 'info';
2
+ type RiskLevel = 'critical' | 'high' | 'medium' | 'low' | 'safe';
3
+ declare const SEVERITY_ORDER: Record<Severity, number>;
4
+ declare function compareSeverity(a: Severity, b: Severity): number;
5
+ declare function isAtLeastSeverity(severity: Severity, minimum: Severity): boolean;
6
+
7
+ interface ExtensionInfo {
8
+ id: string;
9
+ displayName: string;
10
+ version: string;
11
+ publisher: {
12
+ name: string;
13
+ verified: boolean;
14
+ };
15
+ description: string;
16
+ categories: string[];
17
+ activationEvents: string[];
18
+ extensionDependencies: string[];
19
+ installPath: string;
20
+ engines: {
21
+ vscode: string;
22
+ };
23
+ repository?: string;
24
+ license?: string;
25
+ fileCount: number;
26
+ totalSize: number;
27
+ }
28
+ interface ExtensionManifest {
29
+ name: string;
30
+ publisher: string;
31
+ version: string;
32
+ displayName?: string;
33
+ description?: string;
34
+ categories?: string[];
35
+ activationEvents?: string[];
36
+ contributes?: Record<string, unknown>;
37
+ dependencies?: Record<string, string>;
38
+ devDependencies?: Record<string, string>;
39
+ extensionDependencies?: string[];
40
+ main?: string;
41
+ browser?: string;
42
+ engines?: {
43
+ vscode?: string;
44
+ };
45
+ repository?: string | {
46
+ url: string;
47
+ };
48
+ license?: string;
49
+ [key: string]: unknown;
50
+ }
51
+
52
+ type FindingCategory = 'data-exfiltration' | 'remote-code-execution' | 'credential-theft' | 'keylogger' | 'code-obfuscation' | 'suspicious-network' | 'excessive-permission' | 'known-malicious' | 'hardcoded-secret' | 'vulnerable-dependency' | 'persistence' | 'supply-chain' | 'crypto-mining';
53
+ interface Evidence {
54
+ filePath: string;
55
+ lineNumber?: number;
56
+ columnNumber?: number;
57
+ lineContent?: string;
58
+ contextBefore?: string[];
59
+ contextAfter?: string[];
60
+ matchedPattern?: string;
61
+ snippet?: string;
62
+ }
63
+ interface Finding {
64
+ id: string;
65
+ ruleId: string;
66
+ severity: Severity;
67
+ category: FindingCategory;
68
+ title: string;
69
+ description: string;
70
+ evidence: Evidence;
71
+ mitreAttackId?: string;
72
+ remediation?: string;
73
+ }
74
+
75
+ interface ScanResult {
76
+ extensionId: string;
77
+ displayName: string;
78
+ version: string;
79
+ trustScore: number;
80
+ riskLevel: RiskLevel;
81
+ findings: Finding[];
82
+ metadata: ExtensionInfo;
83
+ analyzedFiles: number;
84
+ scanDurationMs: number;
85
+ }
86
+ interface ScanSummary {
87
+ byRiskLevel: Record<RiskLevel, number>;
88
+ bySeverity: Record<Severity, number>;
89
+ byCategory: Partial<Record<FindingCategory, number>>;
90
+ topFindings: Finding[];
91
+ overallHealthScore: number;
92
+ }
93
+ interface DetectedIDE {
94
+ name: string;
95
+ path: string;
96
+ extensionCount: number;
97
+ }
98
+ interface FullScanReport {
99
+ scanId: string;
100
+ version: string;
101
+ timestamp: string;
102
+ environment: {
103
+ os: string;
104
+ ides: DetectedIDE[];
105
+ };
106
+ totalExtensions: number;
107
+ uniqueExtensions: number;
108
+ results: ScanResult[];
109
+ summary: ScanSummary;
110
+ scanDurationMs: number;
111
+ }
112
+ interface PolicyViolation {
113
+ extensionId: string;
114
+ rule: string;
115
+ message: string;
116
+ action: 'block' | 'warn' | 'info';
117
+ }
118
+ interface AuditReport extends FullScanReport {
119
+ policyPath: string;
120
+ policyViolations: PolicyViolation[];
121
+ auditPassed: boolean;
122
+ }
123
+
124
+ interface ScanOptions {
125
+ idePaths?: string[];
126
+ autoDetect?: boolean;
127
+ severity?: Severity;
128
+ rules?: string[];
129
+ skipRules?: string[];
130
+ concurrency?: number;
131
+ timeout?: number;
132
+ }
133
+ interface InspectOptions {
134
+ vsixPath: string;
135
+ severity?: Severity;
136
+ rules?: string[];
137
+ }
138
+
139
+ declare class ExtensionGuardScanner {
140
+ private options;
141
+ private ruleEngine;
142
+ constructor(options?: Partial<ScanOptions>);
143
+ scan(options?: Partial<ScanOptions>): Promise<FullScanReport>;
144
+ private scanExtension;
145
+ private calculateTrustScore;
146
+ private calculateRiskLevel;
147
+ private calculateSummary;
148
+ }
149
+
150
+ declare const IDE_PATHS: Record<string, string[]>;
151
+ declare function expandPath(inputPath: string): string;
152
+ declare function detectIDEPaths(): DetectedIDE[];
153
+
154
+ declare function readExtension(extensionPath: string): Promise<ExtensionInfo | null>;
155
+ declare function readExtensionsFromDirectory(directoryPath: string): Promise<ExtensionInfo[]>;
156
+
157
+ declare function shouldCollectFile(filePath: string): boolean;
158
+ declare function collectFiles(extensionPath: string): Promise<Map<string, string>>;
159
+
160
+ interface DetectionRule {
161
+ id: string;
162
+ name: string;
163
+ description: string;
164
+ severity: Severity;
165
+ category: FindingCategory;
166
+ mitreAttackId?: string;
167
+ enabled: boolean;
168
+ detect(files: Map<string, string>, manifest: ExtensionManifest): Evidence[];
169
+ }
170
+
171
+ interface RuleEngineOptions {
172
+ rules?: string[];
173
+ skipRules?: string[];
174
+ minSeverity?: Severity;
175
+ }
176
+ declare class RuleEngine {
177
+ private options;
178
+ constructor(options?: RuleEngineOptions);
179
+ run(files: Map<string, string>, manifest: ExtensionManifest): Finding[];
180
+ private getApplicableRules;
181
+ private createFinding;
182
+ }
183
+
184
+ declare class RuleRegistry {
185
+ private rules;
186
+ register(rule: DetectionRule): void;
187
+ get(id: string): DetectionRule | undefined;
188
+ getAll(): DetectionRule[];
189
+ getEnabled(): DetectionRule[];
190
+ getByCategory(category: string): DetectionRule[];
191
+ getBySeverity(severity: string): DetectionRule[];
192
+ clear(): void;
193
+ }
194
+ declare const ruleRegistry: RuleRegistry;
195
+
196
+ declare function registerBuiltInRules(): void;
197
+
198
+ interface ReporterOptions {
199
+ includeEvidence?: boolean;
200
+ includeSafe?: boolean;
201
+ minSeverity?: Severity;
202
+ }
203
+ interface Reporter {
204
+ readonly format: string;
205
+ generate(report: FullScanReport, options?: ReporterOptions): string;
206
+ }
207
+
208
+ declare class JsonReporter implements Reporter {
209
+ readonly format = "json";
210
+ generate(report: FullScanReport, options?: ReporterOptions): string;
211
+ private filterResults;
212
+ }
213
+
214
+ declare class SarifReporter implements Reporter {
215
+ readonly format = "sarif";
216
+ generate(report: FullScanReport, _options?: ReporterOptions): string;
217
+ private extractRules;
218
+ private extractResults;
219
+ }
220
+
221
+ declare class MarkdownReporter implements Reporter {
222
+ readonly format = "markdown";
223
+ generate(report: FullScanReport, options?: ReporterOptions): string;
224
+ private formatExtensionResult;
225
+ private formatFinding;
226
+ }
227
+
228
+ /**
229
+ * Policy Engine Types
230
+ *
231
+ * Defines the structure for Extension Guard policy configurations.
232
+ * Policies allow organizations to enforce security standards for VSCode extensions.
233
+ */
234
+
235
+ /**
236
+ * Root policy configuration structure.
237
+ * Supports both scanning configuration and policy enforcement rules.
238
+ */
239
+ interface PolicyConfig {
240
+ /** Schema version for the policy file (e.g., "1") */
241
+ version: string;
242
+ /** Scanning behavior configuration */
243
+ scanning?: {
244
+ /** Minimum severity level to report (findings below this are ignored) */
245
+ minSeverity?: Severity;
246
+ /** Rule IDs to skip during scanning */
247
+ skipRules?: string[];
248
+ /** Scan timeout in milliseconds */
249
+ timeout?: number;
250
+ };
251
+ /** Policy enforcement configuration */
252
+ policy?: {
253
+ /** Extension IDs that are always allowed (bypass policy checks) */
254
+ allowlist?: string[];
255
+ /** Extension IDs that are always blocked */
256
+ blocklist?: string[];
257
+ /** Configurable policy rules */
258
+ rules?: PolicyRules;
259
+ };
260
+ }
261
+ /**
262
+ * Configurable policy rules for extension evaluation.
263
+ * Each rule can specify its own action when violated.
264
+ */
265
+ interface PolicyRules {
266
+ /** Minimum trust score requirement */
267
+ minTrustScore?: {
268
+ /** Score threshold (0-100) */
269
+ threshold: number;
270
+ /** Action to take when score is below threshold */
271
+ action: PolicyAction;
272
+ };
273
+ /** Require extensions to have a verified publisher */
274
+ requireVerifiedPublisher?: {
275
+ /** Whether this rule is enabled */
276
+ enabled: boolean;
277
+ /** Action to take when publisher is not verified */
278
+ action: PolicyAction;
279
+ /** Extension IDs exempt from this rule */
280
+ exceptions?: string[];
281
+ };
282
+ /** Maximum days since last extension update */
283
+ maxDaysSinceUpdate?: {
284
+ /** Maximum allowed days since last update */
285
+ days: number;
286
+ /** Action to take when extension is too old */
287
+ action: PolicyAction;
288
+ };
289
+ /** Block extensions with obfuscated code */
290
+ blockObfuscated?: {
291
+ /** Whether this rule is enabled */
292
+ enabled: boolean;
293
+ /** Action to take when obfuscated code is detected */
294
+ action: PolicyAction;
295
+ };
296
+ }
297
+ /**
298
+ * Action to take when a policy rule is violated.
299
+ * - 'block': Prevent extension usage (fail the check)
300
+ * - 'warn': Allow but generate a warning
301
+ * - 'info': Log for informational purposes only
302
+ */
303
+ type PolicyAction = 'block' | 'warn' | 'info';
304
+
305
+ /**
306
+ * Policy Loader
307
+ *
308
+ * Loads and validates Extension Guard policy configuration files.
309
+ */
310
+
311
+ /**
312
+ * Load and validate a policy configuration file.
313
+ *
314
+ * @param configPath - Optional path to the config file. If not provided,
315
+ * searches for .extension-guard.json in the current directory.
316
+ * @returns The parsed PolicyConfig or null if not found.
317
+ * @throws Error if the file exists but is invalid JSON or fails validation.
318
+ */
319
+ declare function loadPolicyConfig(configPath?: string): Promise<PolicyConfig | null>;
320
+
321
+ /**
322
+ * Policy Engine
323
+ *
324
+ * Evaluates extension scan results against policy rules to determine compliance.
325
+ */
326
+
327
+ /**
328
+ * PolicyEngine evaluates scan results against configured policy rules.
329
+ *
330
+ * @example
331
+ * ```typescript
332
+ * const config = await loadPolicyConfig();
333
+ * const engine = new PolicyEngine(config);
334
+ * const violations = engine.evaluate(scanResults);
335
+ *
336
+ * if (engine.hasBlockingViolations()) {
337
+ * console.error('Policy check failed');
338
+ * process.exit(1);
339
+ * }
340
+ * ```
341
+ */
342
+ declare class PolicyEngine {
343
+ private config;
344
+ private violations;
345
+ /**
346
+ * Create a new PolicyEngine instance.
347
+ *
348
+ * @param config - The policy configuration to evaluate against
349
+ */
350
+ constructor(config: PolicyConfig);
351
+ /**
352
+ * Evaluate scan results against the configured policy.
353
+ *
354
+ * Checks are applied in this order for each extension:
355
+ * 1. Blocklist - if matched, block immediately and skip other checks
356
+ * 2. Allowlist - if matched, skip all other checks
357
+ * 3. Individual rules (minTrustScore, blockObfuscated, etc.)
358
+ *
359
+ * @param results - Array of scan results to evaluate
360
+ * @returns Array of policy violations found
361
+ */
362
+ evaluate(results: ScanResult[]): PolicyViolation[];
363
+ /**
364
+ * Check if there are any violations with 'block' action.
365
+ *
366
+ * @returns true if any blocking violations exist
367
+ */
368
+ hasBlockingViolations(): boolean;
369
+ /**
370
+ * Get all violations from the last evaluation.
371
+ *
372
+ * @returns Array of all policy violations
373
+ */
374
+ getViolations(): PolicyViolation[];
375
+ /**
376
+ * Check minTrustScore rule.
377
+ */
378
+ private checkMinTrustScore;
379
+ /**
380
+ * Check blockObfuscated rule.
381
+ */
382
+ private checkBlockObfuscated;
383
+ /**
384
+ * Check requireVerifiedPublisher rule.
385
+ */
386
+ private checkRequireVerifiedPublisher;
387
+ /**
388
+ * Check maxDaysSinceUpdate rule.
389
+ */
390
+ private checkMaxDaysSinceUpdate;
391
+ }
392
+
393
+ declare const VERSION = "0.1.0";
394
+
395
+ export { type AuditReport, type DetectedIDE, type DetectionRule, type Evidence, ExtensionGuardScanner, type ExtensionInfo, type ExtensionManifest, type Finding, type FindingCategory, type FullScanReport, IDE_PATHS, type InspectOptions, JsonReporter, MarkdownReporter, type PolicyAction, type PolicyConfig, PolicyEngine, type PolicyRules, type PolicyViolation, type Reporter, type ReporterOptions, type RiskLevel, RuleEngine, type RuleEngineOptions, SEVERITY_ORDER, SarifReporter, type ScanOptions, type ScanResult, type ScanSummary, type Severity, VERSION, collectFiles, compareSeverity, detectIDEPaths, expandPath, isAtLeastSeverity, loadPolicyConfig, readExtension, readExtensionsFromDirectory, registerBuiltInRules, ruleRegistry, shouldCollectFile };