aegis-ast 1.0.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/README.md +138 -0
- package/dist/core/comparator.d.ts +32 -0
- package/dist/core/comparator.d.ts.map +1 -0
- package/dist/core/comparator.js +57 -0
- package/dist/core/comparator.js.map +1 -0
- package/dist/core/fetcher.d.ts +37 -0
- package/dist/core/fetcher.d.ts.map +1 -0
- package/dist/core/fetcher.js +144 -0
- package/dist/core/fetcher.js.map +1 -0
- package/dist/core/imports.d.ts +27 -0
- package/dist/core/imports.d.ts.map +1 -0
- package/dist/core/imports.js +200 -0
- package/dist/core/imports.js.map +1 -0
- package/dist/core/index.d.ts +23 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +54 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/policy.d.ts +40 -0
- package/dist/core/policy.d.ts.map +1 -0
- package/dist/core/policy.js +166 -0
- package/dist/core/policy.js.map +1 -0
- package/dist/core/risk_engine.d.ts +164 -0
- package/dist/core/risk_engine.d.ts.map +1 -0
- package/dist/core/risk_engine.js +234 -0
- package/dist/core/risk_engine.js.map +1 -0
- package/dist/main.d.ts +3 -0
- package/dist/main.d.ts.map +1 -0
- package/dist/main.js +524 -0
- package/dist/main.js.map +1 -0
- package/dist/scanner/entropy.d.ts +26 -0
- package/dist/scanner/entropy.d.ts.map +1 -0
- package/dist/scanner/entropy.js +172 -0
- package/dist/scanner/entropy.js.map +1 -0
- package/dist/scanner/eval.d.ts +21 -0
- package/dist/scanner/eval.d.ts.map +1 -0
- package/dist/scanner/eval.js +151 -0
- package/dist/scanner/eval.js.map +1 -0
- package/dist/scanner/exec.d.ts +20 -0
- package/dist/scanner/exec.d.ts.map +1 -0
- package/dist/scanner/exec.js +166 -0
- package/dist/scanner/exec.js.map +1 -0
- package/dist/scanner/fs_access.d.ts +20 -0
- package/dist/scanner/fs_access.d.ts.map +1 -0
- package/dist/scanner/fs_access.js +164 -0
- package/dist/scanner/fs_access.js.map +1 -0
- package/dist/scanner/gemini.d.ts +45 -0
- package/dist/scanner/gemini.d.ts.map +1 -0
- package/dist/scanner/gemini.js +323 -0
- package/dist/scanner/gemini.js.map +1 -0
- package/dist/scanner/index.d.ts +15 -0
- package/dist/scanner/index.d.ts.map +1 -0
- package/dist/scanner/index.js +24 -0
- package/dist/scanner/index.js.map +1 -0
- package/dist/scanner/network.d.ts +20 -0
- package/dist/scanner/network.d.ts.map +1 -0
- package/dist/scanner/network.js +163 -0
- package/dist/scanner/network.js.map +1 -0
- package/dist/scanner/scripts.d.ts +20 -0
- package/dist/scanner/scripts.d.ts.map +1 -0
- package/dist/scanner/scripts.js +157 -0
- package/dist/scanner/scripts.js.map +1 -0
- package/dist/types/index.d.ts +149 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +10 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/file_walker.d.ts +71 -0
- package/dist/utils/file_walker.d.ts.map +1 -0
- package/dist/utils/file_walker.js +194 -0
- package/dist/utils/file_walker.js.map +1 -0
- package/dist/utils/index.d.ts +9 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +19 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +57 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +176 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +52 -0
package/README.md
ADDED
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
# 🛡️ Aegis
|
|
2
|
+
|
|
3
|
+
### Secure Package Installation via Static Code Verification
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## One-Line Pitch
|
|
8
|
+
|
|
9
|
+
> **Aegis-AST verifies code truth before execution, stopping supply-chain attacks at install time.**
|
|
10
|
+
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 🚀 Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
# 1. Install dependencies
|
|
17
|
+
npm install
|
|
18
|
+
|
|
19
|
+
# 2. Build
|
|
20
|
+
npm run build
|
|
21
|
+
|
|
22
|
+
# 3. Run in development mode
|
|
23
|
+
npm run dev
|
|
24
|
+
|
|
25
|
+
# 4. Or run the CLI directly
|
|
26
|
+
npx ts-node src/main.ts install axios
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
---
|
|
30
|
+
|
|
31
|
+
## 📁 Project Structure
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
aegis/
|
|
35
|
+
├── src/
|
|
36
|
+
│ ├── main.ts # CLI entry point (Person 4)
|
|
37
|
+
│ ├── types/
|
|
38
|
+
│ │ └── index.ts # 🔒 Shared type contracts (DO NOT modify alone)
|
|
39
|
+
│ ├── core/
|
|
40
|
+
│ │ ├── index.ts # Barrel export
|
|
41
|
+
│ │ ├── fetcher.ts # Package fetcher (Person 1)
|
|
42
|
+
│ │ ├── imports.ts # Import extractor (Person 1)
|
|
43
|
+
│ │ ├── comparator.ts # Dependency comparator (Person 1)
|
|
44
|
+
│ │ ├── risk_engine.ts # Risk scoring (Person 3)
|
|
45
|
+
│ │ └── policy.ts # Decision engine (Person 3)
|
|
46
|
+
│ ├── scanner/
|
|
47
|
+
│ │ ├── index.ts # Barrel export
|
|
48
|
+
│ │ ├── scripts.ts # Script scanner (Person 2)
|
|
49
|
+
│ │ ├── network.ts # Network detection (Person 2)
|
|
50
|
+
│ │ ├── entropy.ts # Entropy detection (Person 2)
|
|
51
|
+
│ │ ├── fs_access.ts # FS access detection (Person 2)
|
|
52
|
+
│ │ ├── exec.ts # Exec detection (Person 2)
|
|
53
|
+
│ │ └── eval.ts # Eval detection (Person 2)
|
|
54
|
+
│ └── utils/
|
|
55
|
+
│ ├── index.ts # Barrel export
|
|
56
|
+
│ ├── logger.ts # MongoDB logger (Person 3)
|
|
57
|
+
│ └── file_walker.ts # 🔧 Shared file walker (IMPLEMENTED)
|
|
58
|
+
├── tests/
|
|
59
|
+
│ └── comparator.test.ts # Example test
|
|
60
|
+
├── package.json
|
|
61
|
+
├── tsconfig.json
|
|
62
|
+
├── jest.config.js
|
|
63
|
+
├── .env.example
|
|
64
|
+
├── .gitignore
|
|
65
|
+
└── README.md
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## 👥 Team Ownership
|
|
71
|
+
|
|
72
|
+
| Person | Role | Files |
|
|
73
|
+
|--------|------|-------|
|
|
74
|
+
| **P1** | Core Engine | `fetcher.ts`, `imports.ts`, `comparator.ts` |
|
|
75
|
+
| **P2** | Security Detection | `scripts.ts`, `network.ts`, `entropy.ts`, `fs_access.ts`, `exec.ts`, `eval.ts` |
|
|
76
|
+
| **P3** | Risk Engine + Backend | `risk_engine.ts`, `policy.ts`, `logger.ts` |
|
|
77
|
+
| **P4** | CLI + Demo + UX | `main.ts`, demo setup, dashboard |
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
## 🔗 Integration Contract
|
|
82
|
+
|
|
83
|
+
### Input to Risk Engine (all signals merged)
|
|
84
|
+
|
|
85
|
+
```json
|
|
86
|
+
{
|
|
87
|
+
"phantom": [],
|
|
88
|
+
"scripts": [],
|
|
89
|
+
"network": [],
|
|
90
|
+
"entropy": [],
|
|
91
|
+
"fs": [],
|
|
92
|
+
"exec": [],
|
|
93
|
+
"eval": []
|
|
94
|
+
}
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Output from Policy Engine
|
|
98
|
+
|
|
99
|
+
```json
|
|
100
|
+
{
|
|
101
|
+
"score": 85,
|
|
102
|
+
"decision": "BLOCK",
|
|
103
|
+
"reasons": ["Phantom dependencies detected: evil-pkg"]
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## ⚙️ Environment Variables
|
|
110
|
+
|
|
111
|
+
Copy `.env.example` to `.env` and configure:
|
|
112
|
+
|
|
113
|
+
```bash
|
|
114
|
+
cp .env.example .env
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
| Variable | Description |
|
|
118
|
+
|----------|-------------|
|
|
119
|
+
| `MONGODB_URI` | MongoDB Atlas connection string |
|
|
120
|
+
| `GEMINI_API_KEY` | (Optional) Gemini API key |
|
|
121
|
+
| `NPM_REGISTRY_URL` | npm registry URL (default: registry.npmjs.org) |
|
|
122
|
+
|
|
123
|
+
---
|
|
124
|
+
|
|
125
|
+
## 🧪 Testing
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
npm test
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## 🎤 Demo Flow
|
|
134
|
+
|
|
135
|
+
1. `npm install axios` → compromised package gets through
|
|
136
|
+
2. `aegis install axios` → **BLOCKED** by Aegis
|
|
137
|
+
3. Show scan reasons and risk breakdown
|
|
138
|
+
4. (Optional) View dashboard
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ═══════════════════════════════════════════════════════════
|
|
3
|
+
* AEGIS-AST — Dependency Comparator
|
|
4
|
+
* Owner: Person 1 (Core Engine)
|
|
5
|
+
*
|
|
6
|
+
* Responsibilities:
|
|
7
|
+
* - Compare declared dependencies (package.json) vs used (imports)
|
|
8
|
+
* - Identify PHANTOM dependencies (declared but NOT used)
|
|
9
|
+
* - Identify MISSING dependencies (used but NOT declared)
|
|
10
|
+
*
|
|
11
|
+
* ⚠️ PHANTOM DEPENDENCIES = MALICIOUS SIGNAL
|
|
12
|
+
* Declared ≠ Used → suspicious
|
|
13
|
+
* ═══════════════════════════════════════════════════════════
|
|
14
|
+
*/
|
|
15
|
+
import { ComparatorResult, PackageMetadata, ImportScanResult } from '../types';
|
|
16
|
+
/**
|
|
17
|
+
* Compares declared dependencies against actually used imports.
|
|
18
|
+
*
|
|
19
|
+
* @param metadata - Parsed package.json with declared dependencies
|
|
20
|
+
* @param imports - Extracted imports from source code
|
|
21
|
+
* @returns ComparatorResult with phantom, used, and missing deps
|
|
22
|
+
*
|
|
23
|
+
* @example
|
|
24
|
+
* ```ts
|
|
25
|
+
* const result = compareDependencies(metadata, imports);
|
|
26
|
+
* if (result.phantom.length > 0) {
|
|
27
|
+
* console.warn('🚨 PHANTOM DEPENDENCIES DETECTED:', result.phantom);
|
|
28
|
+
* }
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare function compareDependencies(metadata: PackageMetadata, imports: ImportScanResult): ComparatorResult;
|
|
32
|
+
//# sourceMappingURL=comparator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comparator.d.ts","sourceRoot":"","sources":["../../src/core/comparator.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAE/E;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,eAAe,EACzB,OAAO,EAAE,gBAAgB,GACxB,gBAAgB,CA6BlB"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* ═══════════════════════════════════════════════════════════
|
|
4
|
+
* AEGIS-AST — Dependency Comparator
|
|
5
|
+
* Owner: Person 1 (Core Engine)
|
|
6
|
+
*
|
|
7
|
+
* Responsibilities:
|
|
8
|
+
* - Compare declared dependencies (package.json) vs used (imports)
|
|
9
|
+
* - Identify PHANTOM dependencies (declared but NOT used)
|
|
10
|
+
* - Identify MISSING dependencies (used but NOT declared)
|
|
11
|
+
*
|
|
12
|
+
* ⚠️ PHANTOM DEPENDENCIES = MALICIOUS SIGNAL
|
|
13
|
+
* Declared ≠ Used → suspicious
|
|
14
|
+
* ═══════════════════════════════════════════════════════════
|
|
15
|
+
*/
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.compareDependencies = compareDependencies;
|
|
18
|
+
/**
|
|
19
|
+
* Compares declared dependencies against actually used imports.
|
|
20
|
+
*
|
|
21
|
+
* @param metadata - Parsed package.json with declared dependencies
|
|
22
|
+
* @param imports - Extracted imports from source code
|
|
23
|
+
* @returns ComparatorResult with phantom, used, and missing deps
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```ts
|
|
27
|
+
* const result = compareDependencies(metadata, imports);
|
|
28
|
+
* if (result.phantom.length > 0) {
|
|
29
|
+
* console.warn('🚨 PHANTOM DEPENDENCIES DETECTED:', result.phantom);
|
|
30
|
+
* }
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
function compareDependencies(metadata, imports) {
|
|
34
|
+
// 1. Get all declared deps from metadata.dependencies
|
|
35
|
+
const declaredDeps = Object.keys(metadata.dependencies || {});
|
|
36
|
+
// 2. Get all used deps from imports.usedDependencies
|
|
37
|
+
const usedDeps = imports.usedDependencies || [];
|
|
38
|
+
// 3. Collect optional & peer deps — these are NOT phantoms.
|
|
39
|
+
// They are dynamically loaded at runtime by design (e.g. vite uses picomatch, postcss).
|
|
40
|
+
const optionalDeps = new Set([
|
|
41
|
+
...Object.keys(metadata.optionalDependencies || {}),
|
|
42
|
+
...Object.keys(metadata.peerDependencies || {}),
|
|
43
|
+
]);
|
|
44
|
+
// Convert arrays to Sets for O(1) lookup efficiency
|
|
45
|
+
const declaredSet = new Set(declaredDeps);
|
|
46
|
+
const usedSet = new Set(usedDeps);
|
|
47
|
+
// 4. phantom = declared - used - optional/peer - @types/* (TS type packages, never require()'d)
|
|
48
|
+
const phantom = declaredDeps.filter(dep => !usedSet.has(dep) &&
|
|
49
|
+
!optionalDeps.has(dep) &&
|
|
50
|
+
!dep.startsWith('@types/'));
|
|
51
|
+
// 5. missing = used - declared
|
|
52
|
+
const missing = usedDeps.filter(dep => !declaredSet.has(dep));
|
|
53
|
+
// 6. usedDependencies = declared ∩ used
|
|
54
|
+
const usedDependencies = declaredDeps.filter(dep => usedSet.has(dep));
|
|
55
|
+
return { usedDependencies, phantom, missing };
|
|
56
|
+
}
|
|
57
|
+
//# sourceMappingURL=comparator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comparator.js","sourceRoot":"","sources":["../../src/core/comparator.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;GAaG;;AAmBH,kDAgCC;AA/CD;;;;;;;;;;;;;;GAcG;AACH,SAAgB,mBAAmB,CACjC,QAAyB,EACzB,OAAyB;IAEzB,sDAAsD;IACtD,MAAM,YAAY,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;IAC9D,qDAAqD;IACrD,MAAM,QAAQ,GAAG,OAAO,CAAC,gBAAgB,IAAI,EAAE,CAAC;IAEhD,4DAA4D;IAC5D,2FAA2F;IAC3F,MAAM,YAAY,GAAG,IAAI,GAAG,CAAC;QAC3B,GAAG,MAAM,CAAC,IAAI,CAAE,QAAgB,CAAC,oBAAoB,IAAI,EAAE,CAAC;QAC5D,GAAG,MAAM,CAAC,IAAI,CAAE,QAAgB,CAAC,gBAAgB,IAAI,EAAE,CAAC;KACzD,CAAC,CAAC;IAEH,oDAAoD;IACpD,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;IAC1C,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC;IAElC,gGAAgG;IAChG,MAAM,OAAO,GAAG,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CACxC,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC;QACjB,CAAC,YAAY,CAAC,GAAG,CAAC,GAAG,CAAC;QACtB,CAAC,GAAG,CAAC,UAAU,CAAC,SAAS,CAAC,CAC3B,CAAC;IACF,+BAA+B;IAC/B,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC,WAAW,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9D,wCAAwC;IACxC,MAAM,gBAAgB,GAAG,YAAY,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;IAEtE,OAAO,EAAE,gBAAgB,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ═══════════════════════════════════════════════════════════
|
|
3
|
+
* AEGIS-AST — Package Fetcher
|
|
4
|
+
* Owner: Person 1 (Core Engine)
|
|
5
|
+
*
|
|
6
|
+
* Responsibilities:
|
|
7
|
+
* - Download package tarball from npm registry
|
|
8
|
+
* - Extract to /tmp/aegis/<package-name>
|
|
9
|
+
* - Parse and return package.json metadata
|
|
10
|
+
* ═══════════════════════════════════════════════════════════
|
|
11
|
+
*/
|
|
12
|
+
import { FetchResult, PackageMetadata } from '../types';
|
|
13
|
+
/**
|
|
14
|
+
* Fetches a package from the npm registry, downloads the tarball,
|
|
15
|
+
* and extracts it to a temporary directory.
|
|
16
|
+
*
|
|
17
|
+
* @param packageName - Name of the npm package (e.g., "axios")
|
|
18
|
+
* @param version - Specific version or "latest"
|
|
19
|
+
* @returns FetchResult with extractedPath and metadata
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```ts
|
|
23
|
+
* const result = await fetchPackage("axios", "latest");
|
|
24
|
+
* console.log(result.extractedPath); // /tmp/aegis/axios
|
|
25
|
+
* console.log(result.metadata.dependencies);
|
|
26
|
+
* ```
|
|
27
|
+
*/
|
|
28
|
+
export declare function fetchPackage(packageName: string, version?: string): Promise<FetchResult>;
|
|
29
|
+
/**
|
|
30
|
+
* Parses package.json from an extracted package directory.
|
|
31
|
+
*/
|
|
32
|
+
export declare function parsePackageJson(extractedPath: string): PackageMetadata;
|
|
33
|
+
/**
|
|
34
|
+
* Cleans up the temporary extraction directory.
|
|
35
|
+
*/
|
|
36
|
+
export declare function cleanup(extractedPath: string): Promise<void>;
|
|
37
|
+
//# sourceMappingURL=fetcher.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetcher.d.ts","sourceRoot":"","sources":["../../src/core/fetcher.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAUxD;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,MAAM,EACnB,OAAO,GAAE,MAAiB,GACzB,OAAO,CAAC,WAAW,CAAC,CAoDtB;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,aAAa,EAAE,MAAM,GAAG,eAAe,CAcvE;AAED;;GAEG;AACH,wBAAsB,OAAO,CAAC,aAAa,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAMlE"}
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* ═══════════════════════════════════════════════════════════
|
|
4
|
+
* AEGIS-AST — Package Fetcher
|
|
5
|
+
* Owner: Person 1 (Core Engine)
|
|
6
|
+
*
|
|
7
|
+
* Responsibilities:
|
|
8
|
+
* - Download package tarball from npm registry
|
|
9
|
+
* - Extract to /tmp/aegis/<package-name>
|
|
10
|
+
* - Parse and return package.json metadata
|
|
11
|
+
* ═══════════════════════════════════════════════════════════
|
|
12
|
+
*/
|
|
13
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
16
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
17
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
18
|
+
}
|
|
19
|
+
Object.defineProperty(o, k2, desc);
|
|
20
|
+
}) : (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
o[k2] = m[k];
|
|
23
|
+
}));
|
|
24
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
25
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
26
|
+
}) : function(o, v) {
|
|
27
|
+
o["default"] = v;
|
|
28
|
+
});
|
|
29
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
30
|
+
var ownKeys = function(o) {
|
|
31
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
32
|
+
var ar = [];
|
|
33
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
34
|
+
return ar;
|
|
35
|
+
};
|
|
36
|
+
return ownKeys(o);
|
|
37
|
+
};
|
|
38
|
+
return function (mod) {
|
|
39
|
+
if (mod && mod.__esModule) return mod;
|
|
40
|
+
var result = {};
|
|
41
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
42
|
+
__setModuleDefault(result, mod);
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
45
|
+
})();
|
|
46
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
47
|
+
exports.fetchPackage = fetchPackage;
|
|
48
|
+
exports.parsePackageJson = parsePackageJson;
|
|
49
|
+
exports.cleanup = cleanup;
|
|
50
|
+
const fs = __importStar(require("fs"));
|
|
51
|
+
const fsp = __importStar(require("fs/promises"));
|
|
52
|
+
const path = __importStar(require("path"));
|
|
53
|
+
const os = __importStar(require("os"));
|
|
54
|
+
const child_process_1 = require("child_process");
|
|
55
|
+
const util_1 = require("util");
|
|
56
|
+
const execAsync = (0, util_1.promisify)(child_process_1.exec);
|
|
57
|
+
/**
|
|
58
|
+
* Fetches a package from the npm registry, downloads the tarball,
|
|
59
|
+
* and extracts it to a temporary directory.
|
|
60
|
+
*
|
|
61
|
+
* @param packageName - Name of the npm package (e.g., "axios")
|
|
62
|
+
* @param version - Specific version or "latest"
|
|
63
|
+
* @returns FetchResult with extractedPath and metadata
|
|
64
|
+
*
|
|
65
|
+
* @example
|
|
66
|
+
* ```ts
|
|
67
|
+
* const result = await fetchPackage("axios", "latest");
|
|
68
|
+
* console.log(result.extractedPath); // /tmp/aegis/axios
|
|
69
|
+
* console.log(result.metadata.dependencies);
|
|
70
|
+
* ```
|
|
71
|
+
*/
|
|
72
|
+
async function fetchPackage(packageName, version = 'latest') {
|
|
73
|
+
const registryUrl = process.env.NPM_REGISTRY_URL || 'https://registry.npmjs.org';
|
|
74
|
+
const packageUrl = `${registryUrl}/${packageName}/${version}`;
|
|
75
|
+
try {
|
|
76
|
+
// 1. GET package metadata from registry
|
|
77
|
+
const res = await fetch(packageUrl);
|
|
78
|
+
if (!res.ok) {
|
|
79
|
+
throw new Error(`Failed to fetch metadata for ${packageName}@${version}: ${res.statusText}`);
|
|
80
|
+
}
|
|
81
|
+
const data = (await res.json());
|
|
82
|
+
// 2. Extract tarball URL
|
|
83
|
+
const tarballUrl = data.dist?.tarball;
|
|
84
|
+
if (!tarballUrl) {
|
|
85
|
+
throw new Error(`No tarball URL found for ${packageName}@${version}`);
|
|
86
|
+
}
|
|
87
|
+
// Prepare temp directories
|
|
88
|
+
const tmpBase = path.join(os.tmpdir(), 'aegis');
|
|
89
|
+
const extractPath = path.join(tmpBase, packageName);
|
|
90
|
+
const tarballPath = path.join(tmpBase, `${packageName.replace(/\//g, '-')}.tgz`);
|
|
91
|
+
await fsp.mkdir(extractPath, { recursive: true });
|
|
92
|
+
// 3. Download tarball
|
|
93
|
+
const tarRes = await fetch(tarballUrl);
|
|
94
|
+
if (!tarRes.ok) {
|
|
95
|
+
throw new Error(`Failed to download tarball: ${tarRes.statusText}`);
|
|
96
|
+
}
|
|
97
|
+
const arrayBuffer = await tarRes.arrayBuffer();
|
|
98
|
+
await fsp.writeFile(tarballPath, Buffer.from(arrayBuffer));
|
|
99
|
+
// 4. Extract tarball
|
|
100
|
+
// Note: NPM tarballs always wrap their contents in a 'package/' directory.
|
|
101
|
+
// We use --strip-components=1 to dump the files directly into our target folder.
|
|
102
|
+
await execAsync(`tar -xzf ${tarballPath} -C ${extractPath} --strip-components=1`);
|
|
103
|
+
// Clean up the raw .tgz file now that we've extracted it
|
|
104
|
+
await fsp.rm(tarballPath, { force: true });
|
|
105
|
+
// 5. Parse package.json
|
|
106
|
+
const metadata = parsePackageJson(extractPath);
|
|
107
|
+
// 6. Return FetchResult
|
|
108
|
+
return {
|
|
109
|
+
extractedPath: extractPath,
|
|
110
|
+
metadata
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
catch (error) {
|
|
114
|
+
throw new Error(`Fetcher Error [${packageName}]: ${error.message}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Parses package.json from an extracted package directory.
|
|
119
|
+
*/
|
|
120
|
+
function parsePackageJson(extractedPath) {
|
|
121
|
+
const pkgPath = path.join(extractedPath, 'package.json');
|
|
122
|
+
if (!fs.existsSync(pkgPath)) {
|
|
123
|
+
throw new Error(`package.json not found at ${pkgPath}`);
|
|
124
|
+
}
|
|
125
|
+
const fileContent = fs.readFileSync(pkgPath, 'utf-8');
|
|
126
|
+
try {
|
|
127
|
+
return JSON.parse(fileContent);
|
|
128
|
+
}
|
|
129
|
+
catch (error) {
|
|
130
|
+
throw new Error(`Failed to parse package.json at ${pkgPath}`);
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
/**
|
|
134
|
+
* Cleans up the temporary extraction directory.
|
|
135
|
+
*/
|
|
136
|
+
async function cleanup(extractedPath) {
|
|
137
|
+
try {
|
|
138
|
+
await fsp.rm(extractedPath, { recursive: true, force: true });
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
console.error(`Cleanup failed for ${extractedPath}:`, error);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
//# sourceMappingURL=fetcher.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fetcher.js","sourceRoot":"","sources":["../../src/core/fetcher.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ═══════════════════════════════════════════════════════════
|
|
3
|
+
* AEGIS-AST — Import Extractor
|
|
4
|
+
* Owner: Person 1 (Core Engine)
|
|
5
|
+
* * Responsibilities:
|
|
6
|
+
* - Walk all .js/.ts files in extracted package
|
|
7
|
+
* - Extract require() and import statements via AST (Primary)
|
|
8
|
+
* - Fallback to regex extraction if AST parsing fails
|
|
9
|
+
* - Return deduplicated list of used dependencies
|
|
10
|
+
* ═══════════════════════════════════════════════════════════
|
|
11
|
+
*/
|
|
12
|
+
import { ImportScanResult } from '../types';
|
|
13
|
+
/**
|
|
14
|
+
* Regex patterns for extracting imports from JavaScript/TypeScript files.
|
|
15
|
+
* Used strictly as a fallback if AST parsing fails.
|
|
16
|
+
*/
|
|
17
|
+
export declare const IMPORT_PATTERNS: {
|
|
18
|
+
REQUIRE: RegExp;
|
|
19
|
+
ES_IMPORT: RegExp;
|
|
20
|
+
DYNAMIC_IMPORT: RegExp;
|
|
21
|
+
};
|
|
22
|
+
export declare function extractImports(extractedPath: string): Promise<ImportScanResult>;
|
|
23
|
+
/**
|
|
24
|
+
* Normalizes a raw import string to a package name.
|
|
25
|
+
*/
|
|
26
|
+
export declare function normalizeImport(rawImport: string): string | null;
|
|
27
|
+
//# sourceMappingURL=imports.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"imports.d.ts","sourceRoot":"","sources":["../../src/core/imports.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAC;AAa5C;;;GAGG;AACH,eAAO,MAAM,eAAe;;;;CAI3B,CAAC;AAEF,wBAAsB,cAAc,CAClC,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC,gBAAgB,CAAC,CA0H3B;AAED;;GAEG;AACH,wBAAgB,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAgBhE"}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* ═══════════════════════════════════════════════════════════
|
|
4
|
+
* AEGIS-AST — Import Extractor
|
|
5
|
+
* Owner: Person 1 (Core Engine)
|
|
6
|
+
* * Responsibilities:
|
|
7
|
+
* - Walk all .js/.ts files in extracted package
|
|
8
|
+
* - Extract require() and import statements via AST (Primary)
|
|
9
|
+
* - Fallback to regex extraction if AST parsing fails
|
|
10
|
+
* - Return deduplicated list of used dependencies
|
|
11
|
+
* ═══════════════════════════════════════════════════════════
|
|
12
|
+
*/
|
|
13
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
14
|
+
if (k2 === undefined) k2 = k;
|
|
15
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
16
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
17
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
18
|
+
}
|
|
19
|
+
Object.defineProperty(o, k2, desc);
|
|
20
|
+
}) : (function(o, m, k, k2) {
|
|
21
|
+
if (k2 === undefined) k2 = k;
|
|
22
|
+
o[k2] = m[k];
|
|
23
|
+
}));
|
|
24
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
25
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
26
|
+
}) : function(o, v) {
|
|
27
|
+
o["default"] = v;
|
|
28
|
+
});
|
|
29
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
30
|
+
var ownKeys = function(o) {
|
|
31
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
32
|
+
var ar = [];
|
|
33
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
34
|
+
return ar;
|
|
35
|
+
};
|
|
36
|
+
return ownKeys(o);
|
|
37
|
+
};
|
|
38
|
+
return function (mod) {
|
|
39
|
+
if (mod && mod.__esModule) return mod;
|
|
40
|
+
var result = {};
|
|
41
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
42
|
+
__setModuleDefault(result, mod);
|
|
43
|
+
return result;
|
|
44
|
+
};
|
|
45
|
+
})();
|
|
46
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
47
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
48
|
+
};
|
|
49
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
50
|
+
exports.IMPORT_PATTERNS = void 0;
|
|
51
|
+
exports.extractImports = extractImports;
|
|
52
|
+
exports.normalizeImport = normalizeImport;
|
|
53
|
+
const file_walker_1 = require("../utils/file_walker");
|
|
54
|
+
const module_1 = require("module");
|
|
55
|
+
const path = __importStar(require("path"));
|
|
56
|
+
const parser = __importStar(require("@babel/parser"));
|
|
57
|
+
const DEBUG = process.env.AEGIS_DEBUG === 'true';
|
|
58
|
+
// Safely import Babel traverse for TypeScript environments
|
|
59
|
+
const traverse_1 = __importDefault(require("@babel/traverse"));
|
|
60
|
+
const traverse = typeof traverse_1.default === 'function' ? traverse_1.default : traverse_1.default.default;
|
|
61
|
+
/**
|
|
62
|
+
* Regex patterns for extracting imports from JavaScript/TypeScript files.
|
|
63
|
+
* Used strictly as a fallback if AST parsing fails.
|
|
64
|
+
*/
|
|
65
|
+
exports.IMPORT_PATTERNS = {
|
|
66
|
+
REQUIRE: /require\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
67
|
+
ES_IMPORT: /import\s+(?:(?:[\w*{}\s,]+)\s+from\s+)?['"]([^'"]+)['"]/g,
|
|
68
|
+
DYNAMIC_IMPORT: /import\s*\(\s*['"]([^'"]+)['"]\s*\)/g,
|
|
69
|
+
};
|
|
70
|
+
async function extractImports(extractedPath) {
|
|
71
|
+
const usedDependencies = new Set();
|
|
72
|
+
const rawImports = [];
|
|
73
|
+
// Helper to process, normalize, and store a found import (used by both AST and Regex)
|
|
74
|
+
function processImportRecord(rawImport, line, file) {
|
|
75
|
+
rawImports.push({
|
|
76
|
+
filePath: file,
|
|
77
|
+
importName: rawImport,
|
|
78
|
+
line: line,
|
|
79
|
+
});
|
|
80
|
+
const normalized = normalizeImport(rawImport);
|
|
81
|
+
if (normalized) {
|
|
82
|
+
usedDependencies.add(normalized);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
// Helper to calculate the line number of a regex match
|
|
86
|
+
function getLineNumber(content, matchIndex) {
|
|
87
|
+
return content.substring(0, matchIndex).split('\n').length;
|
|
88
|
+
}
|
|
89
|
+
try {
|
|
90
|
+
// Uses your existing utils/file_walker.ts implementation
|
|
91
|
+
const files = (0, file_walker_1.walkSourceFiles)(extractedPath);
|
|
92
|
+
for (const sourceFile of files) {
|
|
93
|
+
const file = sourceFile.absolutePath;
|
|
94
|
+
const content = sourceFile.content;
|
|
95
|
+
try {
|
|
96
|
+
// ==========================================
|
|
97
|
+
// PRIMARY ENGINE: Babel AST Parsing
|
|
98
|
+
// ==========================================
|
|
99
|
+
const ast = parser.parse(content, {
|
|
100
|
+
sourceType: 'unambiguous', // Auto-detects ESM vs CommonJS
|
|
101
|
+
plugins: [
|
|
102
|
+
'typescript',
|
|
103
|
+
'jsx',
|
|
104
|
+
['decorators', { decoratorsBeforeExport: true }] // Prevents crashes on NestJS/Angular files
|
|
105
|
+
],
|
|
106
|
+
});
|
|
107
|
+
if (DEBUG)
|
|
108
|
+
console.log(`🟢 [AST] Successfully parsed: ${path.basename(file)}`);
|
|
109
|
+
traverse(ast, {
|
|
110
|
+
// Catch: import { x } from 'y'
|
|
111
|
+
ImportDeclaration(astPath) {
|
|
112
|
+
if (astPath.node.source && astPath.node.source.value) {
|
|
113
|
+
const line = astPath.node.loc?.start.line || 1;
|
|
114
|
+
processImportRecord(astPath.node.source.value, line, file);
|
|
115
|
+
}
|
|
116
|
+
},
|
|
117
|
+
// Catch: export { x } from 'y'
|
|
118
|
+
ExportNamedDeclaration(astPath) {
|
|
119
|
+
if (astPath.node.source && astPath.node.source.value) {
|
|
120
|
+
const line = astPath.node.loc?.start.line || 1;
|
|
121
|
+
processImportRecord(astPath.node.source.value, line, file);
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
// Catch: export * from 'y'
|
|
125
|
+
ExportAllDeclaration(astPath) {
|
|
126
|
+
if (astPath.node.source && astPath.node.source.value) {
|
|
127
|
+
const line = astPath.node.loc?.start.line || 1;
|
|
128
|
+
processImportRecord(astPath.node.source.value, line, file);
|
|
129
|
+
}
|
|
130
|
+
},
|
|
131
|
+
// Catch: require('y') and import('y')
|
|
132
|
+
CallExpression(astPath) {
|
|
133
|
+
const callee = astPath.node.callee;
|
|
134
|
+
const args = astPath.node.arguments;
|
|
135
|
+
if (args.length > 0 && args[0].type === 'StringLiteral') {
|
|
136
|
+
// Handle require()
|
|
137
|
+
if (callee.type === 'Identifier' && callee.name === 'require') {
|
|
138
|
+
const line = astPath.node.loc?.start.line || 1;
|
|
139
|
+
processImportRecord(args[0].value, line, file);
|
|
140
|
+
}
|
|
141
|
+
// Handle dynamic import()
|
|
142
|
+
else if (callee.type === 'Import') {
|
|
143
|
+
const line = astPath.node.loc?.start.line || 1;
|
|
144
|
+
processImportRecord(args[0].value, line, file);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
catch (astError) {
|
|
151
|
+
// ==========================================
|
|
152
|
+
// BACKUP ENGINE: Regex Parsing
|
|
153
|
+
// Executes if file contains syntax errors / heavily obfuscated code
|
|
154
|
+
// ==========================================
|
|
155
|
+
const extractWithRegex = (pattern) => {
|
|
156
|
+
let match;
|
|
157
|
+
pattern.lastIndex = 0; // Reset global regex state
|
|
158
|
+
while ((match = pattern.exec(content)) !== null) {
|
|
159
|
+
const rawImport = match[1];
|
|
160
|
+
const lineNumber = getLineNumber(content, match.index);
|
|
161
|
+
processImportRecord(rawImport, lineNumber, file);
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
if (DEBUG)
|
|
165
|
+
console.log(`🟠 [REGEX] AST failed. Regex fallback triggered for: ${path.basename(file)}`);
|
|
166
|
+
extractWithRegex(exports.IMPORT_PATTERNS.REQUIRE);
|
|
167
|
+
extractWithRegex(exports.IMPORT_PATTERNS.ES_IMPORT);
|
|
168
|
+
extractWithRegex(exports.IMPORT_PATTERNS.DYNAMIC_IMPORT);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
return {
|
|
172
|
+
usedDependencies: Array.from(usedDependencies),
|
|
173
|
+
rawImports,
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
throw new Error(`Failed to extract imports from ${extractedPath}: ${error.message}`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
/**
|
|
181
|
+
* Normalizes a raw import string to a package name.
|
|
182
|
+
*/
|
|
183
|
+
function normalizeImport(rawImport) {
|
|
184
|
+
if (rawImport.startsWith('.') || rawImport.startsWith('/')) {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
187
|
+
const cleanImport = rawImport.startsWith('node:') ? rawImport.substring(5) : rawImport;
|
|
188
|
+
if (module_1.builtinModules.includes(cleanImport)) {
|
|
189
|
+
return null;
|
|
190
|
+
}
|
|
191
|
+
if (cleanImport.startsWith('@')) {
|
|
192
|
+
const parts = cleanImport.split('/');
|
|
193
|
+
if (parts.length >= 2) {
|
|
194
|
+
return `${parts[0]}/${parts[1]}`;
|
|
195
|
+
}
|
|
196
|
+
return cleanImport;
|
|
197
|
+
}
|
|
198
|
+
return cleanImport.split('/')[0];
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=imports.js.map
|