@aspect-guard/core 0.1.0 → 0.5.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/dist/index.d.ts CHANGED
@@ -72,6 +72,18 @@ interface Finding {
72
72
  remediation?: string;
73
73
  }
74
74
 
75
+ type IntegrityStatus = 'verified' | 'modified' | 'unknown' | 'skipped' | 'error';
76
+ interface IntegrityInfo {
77
+ status: IntegrityStatus;
78
+ /** Which parts were modified (if status is 'modified') */
79
+ modifications?: {
80
+ manifest: boolean;
81
+ content: boolean;
82
+ structure: boolean;
83
+ };
84
+ /** Combined hash of this extension */
85
+ hash?: string;
86
+ }
75
87
  interface ScanResult {
76
88
  extensionId: string;
77
89
  displayName: string;
@@ -82,6 +94,8 @@ interface ScanResult {
82
94
  metadata: ExtensionInfo;
83
95
  analyzedFiles: number;
84
96
  scanDurationMs: number;
97
+ /** Integrity verification result (only if --verify-integrity is used) */
98
+ integrity?: IntegrityInfo;
85
99
  }
86
100
  interface ScanSummary {
87
101
  byRiskLevel: Record<RiskLevel, number>;
@@ -129,6 +143,10 @@ interface ScanOptions {
129
143
  skipRules?: string[];
130
144
  concurrency?: number;
131
145
  timeout?: number;
146
+ /** Enable integrity verification against known-good hashes */
147
+ verifyIntegrity?: boolean;
148
+ /** Path to custom hash database */
149
+ hashDatabasePath?: string;
132
150
  }
133
151
  interface InspectOptions {
134
152
  vsixPath: string;
@@ -139,6 +157,7 @@ interface InspectOptions {
139
157
  declare class ExtensionGuardScanner {
140
158
  private options;
141
159
  private ruleEngine;
160
+ private hashDatabase;
142
161
  constructor(options?: Partial<ScanOptions>);
143
162
  scan(options?: Partial<ScanOptions>): Promise<FullScanReport>;
144
163
  private scanExtension;
@@ -147,9 +166,46 @@ declare class ExtensionGuardScanner {
147
166
  private calculateSummary;
148
167
  }
149
168
 
169
+ /**
170
+ * IDE extension paths organized by IDE name.
171
+ * Each IDE has multiple possible paths to support:
172
+ * - Different OS (Windows, macOS, Linux)
173
+ * - Different installation methods (user, system, portable)
174
+ * - Remote development scenarios (SSH, WSL, containers)
175
+ *
176
+ * Paths use these placeholders:
177
+ * - ~ : User home directory
178
+ * - %USERPROFILE% : Windows user profile
179
+ * - %APPDATA% : Windows AppData/Roaming
180
+ * - %LOCALAPPDATA% : Windows AppData/Local
181
+ *
182
+ * References:
183
+ * - https://code.visualstudio.com/docs/editor/extension-marketplace
184
+ * - https://code.visualstudio.com/docs/remote/troubleshooting
185
+ * - https://vscodium.com/
186
+ * - https://zed.dev/docs/extensions/installing-extensions
187
+ */
150
188
  declare const IDE_PATHS: Record<string, string[]>;
189
+ /**
190
+ * Expand path placeholders to actual paths
191
+ */
151
192
  declare function expandPath(inputPath: string): string;
193
+ /**
194
+ * Detect all installed IDE extension paths
195
+ */
152
196
  declare function detectIDEPaths(): DetectedIDE[];
197
+ /**
198
+ * Get list of all supported IDE names
199
+ */
200
+ declare function getSupportedIDEs(): string[];
201
+ /**
202
+ * Check if a specific IDE is installed
203
+ */
204
+ declare function isIDEInstalled(ideName: string): boolean;
205
+ /**
206
+ * Get the extension path for a specific IDE
207
+ */
208
+ declare function getIDEExtensionPath(ideName: string): string | null;
153
209
 
154
210
  declare function readExtension(extensionPath: string): Promise<ExtensionInfo | null>;
155
211
  declare function readExtensionsFromDirectory(directoryPath: string): Promise<ExtensionInfo[]>;
@@ -157,6 +213,17 @@ declare function readExtensionsFromDirectory(directoryPath: string): Promise<Ext
157
213
  declare function shouldCollectFile(filePath: string): boolean;
158
214
  declare function collectFiles(extensionPath: string): Promise<Map<string, string>>;
159
215
 
216
+ /**
217
+ * Inferred extension category used to adjust finding severity.
218
+ * Extensions in different categories have different "normal" behaviors.
219
+ */
220
+ type ExtensionCategory = 'theme' | 'language' | 'ai-assistant' | 'scm' | 'debugger' | 'linter' | 'language-support' | 'developer-tools' | 'remote-development' | 'testing' | 'notebook' | 'general';
221
+ /**
222
+ * Infer an extension's category from its manifest (package.json).
223
+ * Uses categories, contributes, keywords, displayName, and description.
224
+ */
225
+ declare function categorizeExtension(manifest: ExtensionManifest): ExtensionCategory;
226
+
160
227
  interface DetectionRule {
161
228
  id: string;
162
229
  name: string;
@@ -195,6 +262,165 @@ declare const ruleRegistry: RuleRegistry;
195
262
 
196
263
  declare function registerBuiltInRules(): void;
197
264
 
265
+ /**
266
+ * All built-in detection rules with their metadata.
267
+ * Useful for CLI commands that list rules.
268
+ */
269
+ declare const DETECTION_RULES: DetectionRule[];
270
+
271
+ /**
272
+ * Options for adjusting findings.
273
+ */
274
+ interface AdjustFindingsOptions {
275
+ /** Publisher name for soft trust check */
276
+ publisher?: string;
277
+ /** Full extension ID (publisher.name) for soft trust check */
278
+ extensionId?: string;
279
+ /** Skip soft trust adjustments (strict mode) */
280
+ strictMode?: boolean;
281
+ /** Map of file paths to file contents for bundle detection */
282
+ files?: Map<string, string>;
283
+ }
284
+ /**
285
+ * Adjust findings based on the extension's inferred category and trust status.
286
+ *
287
+ * Four layers of adjustment:
288
+ * 1. Category-based: Expected behaviors for extension type (e.g., AI tools use network)
289
+ * 2. Soft Trust: Trusted publishers get an additional severity downgrade
290
+ * 3. Verified Publisher: Verified publishers on marketplace get severity downgrade
291
+ * 4. Popularity: Extensions with 10M+ downloads get double downgrade, 1M+ get single
292
+ *
293
+ * Returns a new array with adjusted findings (original array is not mutated).
294
+ */
295
+ declare function adjustFindings(findings: Finding[], category: ExtensionCategory, options?: AdjustFindingsOptions): Finding[];
296
+
297
+ /**
298
+ * List of well-known, trusted publishers.
299
+ *
300
+ * Extensions from these publishers receive "soft trust" treatment:
301
+ * - Their findings are downgraded one additional severity level
302
+ * - They are NOT completely bypassed (supply chain attacks can hit anyone)
303
+ *
304
+ * This list is intentionally conservative and includes only:
305
+ * - Major IDE vendors (Microsoft, GitHub)
306
+ * - Well-established tool vendors with long track records
307
+ */
308
+ declare const TRUSTED_PUBLISHERS: string[];
309
+ /**
310
+ * Specific extension IDs that are trusted regardless of publisher.
311
+ * Use this for known extensions from smaller publishers.
312
+ */
313
+ declare const TRUSTED_EXTENSION_IDS: string[];
314
+ /**
315
+ * Check if an extension is from a trusted publisher.
316
+ */
317
+ declare function isTrustedPublisher(publisher: string): boolean;
318
+ /**
319
+ * Check if an extension ID is explicitly trusted.
320
+ */
321
+ declare function isTrustedExtension(extensionId: string): boolean;
322
+
323
+ /**
324
+ * List of verified publishers from VS Code Marketplace.
325
+ *
326
+ * These publishers have undergone verification by Microsoft and display
327
+ * a verified badge on the marketplace. Extensions from verified publishers
328
+ * are treated similarly to trusted publishers.
329
+ *
330
+ * Note: This list is maintained manually based on known verified publishers.
331
+ * In the future, this could be fetched from the marketplace API.
332
+ */
333
+ declare const VERIFIED_PUBLISHERS: string[];
334
+ /**
335
+ * Check if a publisher is verified on the marketplace.
336
+ */
337
+ declare function isVerifiedPublisher(publisher: string): boolean;
338
+
339
+ /**
340
+ * List of popular extensions with high download counts.
341
+ *
342
+ * Extensions with millions of downloads have been vetted by the community
343
+ * through widespread usage. Supply chain attacks on these would be extremely
344
+ * visible and risky for attackers.
345
+ *
346
+ * Threshold tiers:
347
+ * - 10M+ downloads: Highest trust (downgrade by 2 severity levels)
348
+ * - 1M+ downloads: High trust (downgrade by 1 severity level)
349
+ *
350
+ * Note: This data is manually maintained. In the future, this could be
351
+ * fetched from the marketplace API and cached locally.
352
+ *
353
+ * Last updated: 2026-02
354
+ */
355
+ interface PopularExtension {
356
+ id: string;
357
+ downloads: number;
358
+ tier: 'mega' | 'popular';
359
+ }
360
+ /**
361
+ * Extensions with 10M+ downloads (mega popular)
362
+ */
363
+ declare const MEGA_POPULAR_EXTENSIONS: PopularExtension[];
364
+ /**
365
+ * Extensions with 1M-10M downloads (popular)
366
+ */
367
+ declare const POPULAR_EXTENSIONS: PopularExtension[];
368
+ /**
369
+ * All popular extensions combined
370
+ */
371
+ declare const ALL_POPULAR_EXTENSIONS: PopularExtension[];
372
+ /**
373
+ * Get popularity tier for an extension.
374
+ * Returns null if not in the popular extensions list.
375
+ */
376
+ declare function getPopularityTier(extensionId: string): 'mega' | 'popular' | null;
377
+ /**
378
+ * Check if an extension is mega popular (10M+ downloads)
379
+ */
380
+ declare function isMegaPopular(extensionId: string): boolean;
381
+ /**
382
+ * Check if an extension is popular (1M+ downloads)
383
+ */
384
+ declare function isPopular(extensionId: string): boolean;
385
+
386
+ /**
387
+ * Bundle/Minified File Detector
388
+ *
389
+ * Detects if a JavaScript file is bundled/minified output from tools like:
390
+ * - webpack
391
+ * - esbuild
392
+ * - rollup
393
+ * - parcel
394
+ * - vite
395
+ *
396
+ * Bundled files often trigger false positives because:
397
+ * - They contain many library dependencies inlined
398
+ * - Minification creates high-entropy code patterns
399
+ * - Source maps and comments are stripped
400
+ */
401
+ interface BundleDetectionResult {
402
+ isBundled: boolean;
403
+ confidence: 'high' | 'medium' | 'low';
404
+ reasons: string[];
405
+ bundler?: string;
406
+ }
407
+ /**
408
+ * Detect if a file is a bundled/minified output
409
+ */
410
+ declare function detectBundle(filePath: string, content: string): BundleDetectionResult;
411
+ /**
412
+ * Check if a file path looks like a bundled output location
413
+ */
414
+ declare function isBundleOutputPath(filePath: string): boolean;
415
+ /**
416
+ * Determine if findings from this file should be treated with reduced severity
417
+ * because it's likely bundled code (which commonly contains many false positives)
418
+ */
419
+ declare function shouldReduceSeverityForBundle(filePath: string, content: string): {
420
+ reduce: boolean;
421
+ reason?: string;
422
+ };
423
+
198
424
  interface ReporterOptions {
199
425
  includeEvidence?: boolean;
200
426
  includeSafe?: boolean;
@@ -390,6 +616,137 @@ declare class PolicyEngine {
390
616
  private checkMaxDaysSinceUpdate;
391
617
  }
392
618
 
393
- declare const VERSION = "0.1.0";
619
+ /**
620
+ * Extension Integrity Verifier
621
+ *
622
+ * Verifies that installed extensions match their known-good hashes.
623
+ * This detects supply chain attacks where an official extension has been
624
+ * tampered with after installation or during distribution.
625
+ *
626
+ * Verification methods:
627
+ * 1. File content hash - SHA256 of all JS files concatenated
628
+ * 2. Manifest hash - SHA256 of package.json
629
+ * 3. Structure hash - Hash of file list (detects added/removed files)
630
+ */
631
+ /**
632
+ * Hash record for a specific extension version
633
+ */
634
+ interface ExtensionHash {
635
+ /** Extension ID (publisher.name) */
636
+ extensionId: string;
637
+ /** Version string */
638
+ version: string;
639
+ /** SHA256 of package.json content */
640
+ manifestHash: string;
641
+ /** SHA256 of all JS file contents concatenated (sorted by path) */
642
+ contentHash: string;
643
+ /** SHA256 of sorted file path list */
644
+ structureHash: string;
645
+ /** Combined hash for quick comparison */
646
+ combinedHash: string;
647
+ /** When this hash was recorded */
648
+ recordedAt: string;
649
+ /** Source of the hash (marketplace, manual, etc.) */
650
+ source: 'marketplace' | 'manual' | 'community';
651
+ }
652
+ /**
653
+ * Result of integrity verification
654
+ */
655
+ interface IntegrityResult {
656
+ extensionId: string;
657
+ version: string;
658
+ status: 'verified' | 'modified' | 'unknown' | 'error';
659
+ /** Which parts were modified (if status is 'modified') */
660
+ modifications?: {
661
+ manifest: boolean;
662
+ content: boolean;
663
+ structure: boolean;
664
+ };
665
+ /** The computed hashes */
666
+ computedHashes?: {
667
+ manifestHash: string;
668
+ contentHash: string;
669
+ structureHash: string;
670
+ combinedHash: string;
671
+ };
672
+ /** The expected hashes (if known) */
673
+ expectedHashes?: ExtensionHash;
674
+ /** Error message if status is 'error' */
675
+ error?: string;
676
+ }
677
+ /**
678
+ * Compute SHA256 hash of a string
679
+ */
680
+ declare function sha256(content: string): string;
681
+ /**
682
+ * Compute hashes for an extension from its files
683
+ */
684
+ declare function computeExtensionHashes(extensionId: string, version: string, files: Map<string, string>): Omit<ExtensionHash, 'recordedAt' | 'source'>;
685
+ /**
686
+ * Verify extension integrity against known hashes
687
+ */
688
+ declare function verifyIntegrity(extensionId: string, version: string, files: Map<string, string>, knownHashes: Map<string, ExtensionHash>): IntegrityResult;
689
+ /**
690
+ * Create a hash record for an extension (for adding to the database)
691
+ */
692
+ declare function createHashRecord(extensionId: string, version: string, files: Map<string, string>, source?: ExtensionHash['source']): ExtensionHash;
693
+
694
+ /**
695
+ * Known-Good Hash Database
696
+ *
697
+ * This module manages the database of known-good extension hashes.
698
+ * The database can be:
699
+ * 1. Bundled with the package (for critical extensions)
700
+ * 2. Downloaded from a remote server (for community-maintained hashes)
701
+ * 3. Locally maintained by the user
702
+ *
703
+ * IMPORTANT: This is a static snapshot. For production use, consider:
704
+ * - Fetching from VS Code Marketplace API
705
+ * - Community-maintained hash repository
706
+ * - User-generated baseline from clean install
707
+ */
708
+
709
+ /**
710
+ * Hash database structure
711
+ */
712
+ interface HashDatabase {
713
+ version: string;
714
+ updatedAt: string;
715
+ hashes: ExtensionHash[];
716
+ }
717
+ /**
718
+ * Default path for local hash database
719
+ */
720
+ declare function getDefaultDatabasePath(): string;
721
+ /**
722
+ * Load hash database from a JSON file
723
+ */
724
+ declare function loadHashDatabase(filePath?: string): Map<string, ExtensionHash>;
725
+ /**
726
+ * Save hash database to a JSON file
727
+ */
728
+ declare function saveHashDatabase(hashes: Map<string, ExtensionHash>, filePath?: string): void;
729
+ /**
730
+ * Add or update a hash in the database
731
+ */
732
+ declare function addHash(hash: ExtensionHash, filePath?: string): void;
733
+ /**
734
+ * Get a hash from the database
735
+ */
736
+ declare function getHash(extensionId: string, version: string, filePath?: string): ExtensionHash | undefined;
737
+ /**
738
+ * Clear the hash cache (useful for testing)
739
+ */
740
+ declare function clearHashCache(): void;
741
+ /**
742
+ * Generate a baseline database from currently installed extensions
743
+ * This is useful for users to create their own trusted baseline
744
+ */
745
+ declare function generateBaseline(_extensionPaths: string[], _outputPath?: string): Promise<{
746
+ generated: number;
747
+ errors: string[];
748
+ }>;
749
+
750
+ declare const VERSION = "0.5.0";
394
751
 
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 };
752
+ export { ALL_POPULAR_EXTENSIONS, type AdjustFindingsOptions, type AuditReport, type BundleDetectionResult, DETECTION_RULES, type DetectedIDE, type DetectionRule, type Evidence, type ExtensionCategory, ExtensionGuardScanner, type ExtensionHash, type ExtensionInfo, type ExtensionManifest, type Finding, type FindingCategory, type FullScanReport, type HashDatabase, IDE_PATHS, type InspectOptions, type IntegrityInfo, type IntegrityResult, type IntegrityStatus, JsonReporter, MEGA_POPULAR_EXTENSIONS, MarkdownReporter, POPULAR_EXTENSIONS, type PolicyAction, type PolicyConfig, PolicyEngine, type PolicyRules, type PolicyViolation, type PopularExtension, type Reporter, type ReporterOptions, type RiskLevel, RuleEngine, type RuleEngineOptions, SEVERITY_ORDER, SarifReporter, type ScanOptions, type ScanResult, type ScanSummary, type Severity, TRUSTED_EXTENSION_IDS, TRUSTED_PUBLISHERS, VERIFIED_PUBLISHERS, VERSION, addHash, adjustFindings, categorizeExtension, clearHashCache, collectFiles, compareSeverity, computeExtensionHashes, createHashRecord, detectBundle, detectIDEPaths, expandPath, generateBaseline, getDefaultDatabasePath, getHash, getIDEExtensionPath, getPopularityTier, getSupportedIDEs, isAtLeastSeverity, isBundleOutputPath, isIDEInstalled, isMegaPopular, isPopular, isTrustedExtension, isTrustedPublisher, isVerifiedPublisher, loadHashDatabase, loadPolicyConfig, readExtension, readExtensionsFromDirectory, registerBuiltInRules, ruleRegistry, saveHashDatabase, sha256, shouldCollectFile, shouldReduceSeverityForBundle, verifyIntegrity };