x-fidelity 1.2.0 → 1.4.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 +25 -0
- package/README.md +54 -226
- package/dist/archetypes/index.js +13 -16
- package/dist/core/cli.js +9 -6
- package/dist/core/engine.js +41 -31
- package/dist/core/engine.test.js +140 -7
- package/dist/facts/openaiAnalysisFacts.js +23 -20
- package/dist/facts/openaiAnalysisFacts.test.js +34 -26
- package/dist/facts/repoDependencyFacts.js +50 -1
- package/dist/facts/repoDependencyFacts.test.js +72 -0
- package/dist/facts/repoFilesystemFacts.js +2 -2
- package/dist/facts/repoFilesystemFacts.test.js +2 -2
- package/dist/index.js +2 -2
- package/dist/operators/fileContains.js +1 -0
- package/dist/operators/index.test.js +52 -0
- package/dist/operators/openaiAnalysisHighSeverity.js +3 -5
- package/dist/operators/openaiAnalysisHighSeverity.test.js +6 -6
- package/dist/operators/outdatedFramework.js +8 -43
- package/dist/operators/outdatedFramework.test.js +12 -33
- package/dist/rules/index.js +49 -15
- package/dist/rules/index.test.js +113 -0
- package/dist/rules/noDatabases-rule.json +5 -1
- package/dist/rules/openaiAnalysisA11y-rule.json +1 -1
- package/dist/rules/openaiAnalysisTop5-rule.json +1 -1
- package/dist/rules/outdatedFramework-rule.json +13 -11
- package/dist/rules/sensitiveLogging-rule.json +5 -1
- package/dist/server/configServer.js +70 -0
- package/dist/utils/config.js +10 -15
- package/dist/utils/config.test.js +62 -0
- package/dist/xfidelity +2 -2
- package/package.json +8 -4
- package/src/archetypes/index.ts +13 -16
- package/src/core/cli.ts +9 -6
- package/src/core/engine.test.ts +160 -7
- package/src/core/engine.ts +48 -37
- package/src/facts/index.ts +1 -1
- package/src/facts/openaiAnalysisFacts.test.ts +40 -31
- package/src/facts/openaiAnalysisFacts.ts +26 -22
- package/src/facts/repoDependencyFacts.test.ts +85 -0
- package/src/facts/repoDependencyFacts.ts +32 -1
- package/src/facts/repoFilesystemFacts.test.ts +2 -2
- package/src/facts/repoFilesystemFacts.ts +4 -4
- package/src/index.ts +2 -2
- package/src/operators/fileContains.ts +2 -1
- package/src/operators/index.test.ts +51 -0
- package/src/operators/openaiAnalysisHighSeverity.test.ts +6 -6
- package/src/operators/openaiAnalysisHighSeverity.ts +3 -6
- package/src/operators/outdatedFramework.test.ts +12 -32
- package/src/operators/outdatedFramework.ts +8 -22
- package/src/rules/index.test.ts +94 -0
- package/src/rules/index.ts +48 -17
- package/src/rules/noDatabases-rule.json +5 -1
- package/src/rules/openaiAnalysisA11y-rule.json +1 -1
- package/src/rules/openaiAnalysisTop5-rule.json +1 -1
- package/src/rules/outdatedFramework-rule.json +13 -11
- package/src/rules/sensitiveLogging-rule.json +5 -1
- package/src/server/configServer.ts +62 -0
- package/src/typeDefs.ts +8 -3
- package/src/utils/config.test.ts +64 -0
- package/src/utils/config.ts +14 -22
- package/webpack.config.js +0 -26
- /package/dist/rules/{standardDirectoryStructure-rule.json → nonStandardDirectoryStructure-rule.json} +0 -0
- /package/src/rules/{standardDirectoryStructure-rule.json → nonStandardDirectoryStructure-rule.json} +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,28 @@
|
|
|
1
|
+
# [1.4.0](https://github.com/zotoio/x-fidelity/compare/v1.3.0...v1.4.0) (2024-07-14)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* **rule:** report specific dependency issues ([2ccaf6c](https://github.com/zotoio/x-fidelity/commit/2ccaf6cfe9d6cf8a73de5413fffee40dbb0f236d))
|
|
7
|
+
|
|
8
|
+
# [1.3.0](https://github.com/zotoio/x-fidelity/compare/v1.2.0...v1.3.0) (2024-07-11)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* **ai:** fix ([8f94cee](https://github.com/zotoio/x-fidelity/commit/8f94cee6ef990a39db3bc4c61f16b3c56bdb10dd))
|
|
14
|
+
* **ai:** fix ([f5ba9f5](https://github.com/zotoio/x-fidelity/commit/f5ba9f5319e02788f3c6a1f0b70b1fa2638e719d))
|
|
15
|
+
* Initialized OpenAI client before using it to prevent "Cannot read properties of undefined (reading 'chat')" error ([a112b43](https://github.com/zotoio/x-fidelity/commit/a112b4372ff7eef5c00cb4c3fede13eeb932b2a2))
|
|
16
|
+
* **refactor:** logic issues and async issue ([2ad8cdd](https://github.com/zotoio/x-fidelity/commit/2ad8cdd7becbd80217dd0115be266cdf753a8470))
|
|
17
|
+
* **sec:** prevent error reflection ([93eca93](https://github.com/zotoio/x-fidelity/commit/93eca93e4737f01977f27dacf8cabbd5adf1ab2b))
|
|
18
|
+
* **sec:** santize input ([6f78c39](https://github.com/zotoio/x-fidelity/commit/6f78c396a6d83189d3985a0c826f5967e1e6eee4))
|
|
19
|
+
* **server:** fix ai error ([20341fa](https://github.com/zotoio/x-fidelity/commit/20341fa0df7a34791f2a4f34a89ee1cf7e5014ef))
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Features
|
|
23
|
+
|
|
24
|
+
* **server:** remote config server ([f027ed2](https://github.com/zotoio/x-fidelity/commit/f027ed200d94e0bc16c000a8a677da819a8695cf))
|
|
25
|
+
|
|
1
26
|
# [1.2.0](https://github.com/zotoio/x-fidelity/compare/v1.1.0...v1.2.0) (2024-07-10)
|
|
2
27
|
|
|
3
28
|
|
package/README.md
CHANGED
|
@@ -26,287 +26,115 @@ x-fidelity is a CLI tool designed to enforce adherence to a set of opinionated f
|
|
|
26
26
|
- Verifies that dependencies are up-to-date according to a specified minimum version.
|
|
27
27
|
- Checks for the presence or absence of specific strings in files.
|
|
28
28
|
- Configurable via a remote JSON configuration file.
|
|
29
|
+
- Integrates with OpenAI for advanced code analysis.
|
|
29
30
|
|
|
30
31
|
## Installation
|
|
31
32
|
|
|
32
|
-
Install x-fidelity with
|
|
33
|
+
Install x-fidelity with Node.js 18+ and Yarn:
|
|
33
34
|
|
|
34
35
|
```sh
|
|
35
|
-
corepack enable
|
|
36
36
|
yarn global add x-fidelity
|
|
37
37
|
export PATH="$PATH:$(yarn global bin)"
|
|
38
38
|
```
|
|
39
39
|
|
|
40
|
-
You may want to add
|
|
40
|
+
You may want to add the path line to your `~/.bashrc` or `~/.zshrc` file for persistence of the binary in your path.
|
|
41
41
|
|
|
42
42
|
## Usage
|
|
43
43
|
|
|
44
|
+
### CLI
|
|
45
|
+
|
|
44
46
|
To run x-fidelity, use the following command:
|
|
45
47
|
|
|
46
48
|
```sh
|
|
47
|
-
xfidelity
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
- `--dir <directory>`: The directory of the repository to analyze.
|
|
51
|
-
- `--configUrl <url>`: (Optional) The URL to fetch the configuration from.
|
|
52
|
-
|
|
53
|
-
Example:
|
|
49
|
+
xfidelity
|
|
54
50
|
|
|
55
|
-
|
|
56
|
-
xfidelity --dir
|
|
51
|
+
# you can use the following options for more advanced setups such as the remote config server
|
|
52
|
+
xfidelity [-d --dir <directory>] [-c --configUrl <url>] [-a --archtype <archetype>]
|
|
57
53
|
```
|
|
58
54
|
|
|
59
|
-
|
|
55
|
+
- `-d --dir <directory>`: (Optional) The root directory of the local repo dir to analyze. Default is current dir.
|
|
56
|
+
- `-c --configUrl <url>`: (Optional) The URL to fetch the configuration from.
|
|
57
|
+
- `-a --archetype <archetype>`: (Optional) The archetype to use for analysis. 'node-fullstack' is the default, or 'java-microservice' and these are extensible)
|
|
60
58
|
|
|
61
|
-
|
|
59
|
+
**Example for node-fullstack archetype in current dir with remove config server:**
|
|
62
60
|
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
"minimumDependencyVersions": {
|
|
66
|
-
"commander": "^2.0.0",
|
|
67
|
-
"nodemon": "^3.9.0"
|
|
68
|
-
},
|
|
69
|
-
"standardStructure": {
|
|
70
|
-
"src": {
|
|
71
|
-
"core": null,
|
|
72
|
-
"utils": null,
|
|
73
|
-
"operators": null,
|
|
74
|
-
"rules": null,
|
|
75
|
-
"facts": null
|
|
76
|
-
}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
61
|
+
```sh
|
|
62
|
+
xfidelity --configUrl https://localhost:8888
|
|
79
63
|
```
|
|
80
64
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
x-fidelity can integrate with OpenAI to provide advanced code analysis. To enable OpenAI features, you need to set the `OPENAI_API_KEY` environment variable with your OpenAI API key.
|
|
84
|
-
|
|
85
|
-
### Getting an OpenAI API Key
|
|
86
|
-
|
|
87
|
-
1. Sign up for an account at [OpenAI](https://www.openai.com/).
|
|
88
|
-
2. Navigate to the API section and generate a new API key.
|
|
89
|
-
3. Set the `OPENAI_API_KEY` environment variable in your terminal or CI/CD pipeline.
|
|
65
|
+
**Example for java-microservice archetype in parent dir with remote config server (in this example running locally on port 8888):**
|
|
90
66
|
|
|
91
67
|
```sh
|
|
92
|
-
|
|
68
|
+
xfidelity -d .. -a java-microservice --c https://localhost:8888
|
|
93
69
|
```
|
|
94
70
|
|
|
95
|
-
###
|
|
71
|
+
### Configuration Server
|
|
96
72
|
|
|
97
|
-
|
|
73
|
+
x-fidelity includes an optional configuration server that can be used to serve configuration per archetype. This includes config for fact provders and custom operators, and also the rule json to use per archetype.
|
|
98
74
|
|
|
99
|
-
|
|
75
|
+
This is of most use when you need to be able to globally rollout config updates for minor/patch releases without relying cli users run to upgrade x-fidelity.
|
|
100
76
|
|
|
101
|
-
|
|
77
|
+
**To start the server:**
|
|
102
78
|
|
|
103
|
-
|
|
79
|
+
1. Navigate to the x-fidelity directory.
|
|
80
|
+
2. Run the following command:
|
|
104
81
|
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
"name": "sensitiveLogging",
|
|
108
|
-
"conditions": {
|
|
109
|
-
"any": [
|
|
110
|
-
{
|
|
111
|
-
"fact": "fileData",
|
|
112
|
-
"path": "$.fileContent",
|
|
113
|
-
"operator": "fileContains",
|
|
114
|
-
"value": "token"
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
"fact": "fileData",
|
|
118
|
-
"path": "$.fileContent",
|
|
119
|
-
"operator": "fileContains",
|
|
120
|
-
"value": "secret"
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
"fact": "fileData",
|
|
124
|
-
"path": "$.fileContent",
|
|
125
|
-
"operator": "fileContains",
|
|
126
|
-
"value": "todo: expand with regex operator for more sensitive data patterns"
|
|
127
|
-
}
|
|
128
|
-
]
|
|
129
|
-
},
|
|
130
|
-
"event": {
|
|
131
|
-
"type": "violation",
|
|
132
|
-
"params": {
|
|
133
|
-
"message": "Sensitive data must not be logged."
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
}
|
|
82
|
+
```sh
|
|
83
|
+
yarn start-config-server
|
|
137
84
|
```
|
|
138
85
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
```json
|
|
144
|
-
{
|
|
145
|
-
"name": "outdatedFramework",
|
|
146
|
-
"conditions": {
|
|
147
|
-
"all": [
|
|
148
|
-
{
|
|
149
|
-
"fact": "fileData",
|
|
150
|
-
"path": "$.fileName",
|
|
151
|
-
"operator": "outdatedFramework",
|
|
152
|
-
"value": {
|
|
153
|
-
"fact": "dependencyData"
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
]
|
|
157
|
-
},
|
|
158
|
-
"event": {
|
|
159
|
-
"type": "violation",
|
|
160
|
-
"params": {
|
|
161
|
-
"message": "Some core framework dependencies have expired!",
|
|
162
|
-
"filePath": {
|
|
163
|
-
"fact": "fileData",
|
|
164
|
-
"path": "$.filePath"
|
|
165
|
-
},
|
|
166
|
-
"minimumDependencyVersions": {
|
|
167
|
-
"fact": "dependencyData",
|
|
168
|
-
"path": "$.minimumDependencyVersions"
|
|
169
|
-
}
|
|
170
|
-
}
|
|
171
|
-
}
|
|
172
|
-
}
|
|
86
|
+
> **By default, the server will start on port 8888**. You can override this using the `XFI_SERVER_PORT` environment variable You can then use the server URL as the `--configUrl` parameter when running the CLI.
|
|
87
|
+
```sh
|
|
88
|
+
export XFI_SERVER_PORT=8888
|
|
173
89
|
```
|
|
174
90
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
This rule ensures that code does not directly call databases.
|
|
178
|
-
|
|
179
|
-
```json
|
|
180
|
-
{
|
|
181
|
-
"name": "noDatabases",
|
|
182
|
-
"conditions": {
|
|
183
|
-
"any": [
|
|
184
|
-
{
|
|
185
|
-
"fact": "fileData",
|
|
186
|
-
"path": "$.fileContent",
|
|
187
|
-
"operator": "fileContains",
|
|
188
|
-
"value": "oracle"
|
|
189
|
-
}
|
|
190
|
-
]
|
|
191
|
-
},
|
|
192
|
-
"event": {
|
|
193
|
-
"type": "violation",
|
|
194
|
-
"params": {
|
|
195
|
-
"message": "Code must not directly call databases."
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
```
|
|
91
|
+
## OpenAI Integration
|
|
200
92
|
|
|
201
|
-
|
|
93
|
+
To enable OpenAI features for experimental LLM-based codebase analysis:
|
|
202
94
|
|
|
203
|
-
|
|
95
|
+
1. Sign up for a developer account at [OpenAI](https://platform.openai.com).
|
|
96
|
+
2. Navigate to the API section and generate a new API key.
|
|
97
|
+
3. Set the `OPENAI_API_KEY` environment variable:
|
|
204
98
|
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
"fact": "fileData",
|
|
212
|
-
"path": "$.fileName",
|
|
213
|
-
"operator": "equal",
|
|
214
|
-
"value": "REPO_GLOBAL_CHECK"
|
|
215
|
-
},
|
|
216
|
-
{
|
|
217
|
-
"fact": "fileData",
|
|
218
|
-
"path": "$.filePath",
|
|
219
|
-
"operator": "nonStandardDirectoryStructure",
|
|
220
|
-
"value": {
|
|
221
|
-
"fact": "standardStructure"
|
|
222
|
-
}
|
|
223
|
-
}
|
|
224
|
-
]
|
|
225
|
-
},
|
|
226
|
-
"event": {
|
|
227
|
-
"type": "violation",
|
|
228
|
-
"params": {
|
|
229
|
-
"message": "Directory structure does not match the standard.",
|
|
230
|
-
"details": {
|
|
231
|
-
"fact": "fileData",
|
|
232
|
-
"path": "$.filePath"
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
}
|
|
236
|
-
}
|
|
99
|
+
```sh
|
|
100
|
+
export OPENAI_API_KEY=your_openai_api_key
|
|
101
|
+
```
|
|
102
|
+
4. Optionally set the OPENAI_MODEL environment var (default is gpt-4o):
|
|
103
|
+
```sh
|
|
104
|
+
export OPENAI_MODEL=gpt-4
|
|
237
105
|
```
|
|
106
|
+
Note that not all models consistently return parseable JSON results, so some experimentation is required.
|
|
238
107
|
|
|
239
|
-
|
|
108
|
+
> [!IMPORTANT]
|
|
109
|
+
> Using OpenAI's API may incur costs. Please refer to OpenAI's pricing page for more details.
|
|
110
|
+
>
|
|
111
|
+
>The 'collectOpenaiAnalysisFacts' function will concatenate all files that are not blacklisted but are included in the whitelist and send this to OpenAI. Ensure you consider any sensitive data that may be sent, and the cost based on the token count this will be per rule check that is executed.
|
|
240
112
|
|
|
241
|
-
|
|
113
|
+
## Configuration
|
|
242
114
|
|
|
243
|
-
|
|
115
|
+
The configuration file should be a JSON file containing rules, operators, facts, and other settings. You can find example configuration files in the `src/rules` directory of the repository.
|
|
244
116
|
|
|
245
|
-
|
|
246
|
-
{
|
|
247
|
-
"name": "openaiAnalysisTop5Rule",
|
|
248
|
-
"conditions": {
|
|
249
|
-
"all": [
|
|
250
|
-
{
|
|
251
|
-
"fact": "fileData",
|
|
252
|
-
"path": "$.fileName",
|
|
253
|
-
"operator": "equal",
|
|
254
|
-
"value": "REPO_GLOBAL_CHECK"
|
|
255
|
-
},
|
|
256
|
-
{
|
|
257
|
-
"fact": "openaiAnalysis",
|
|
258
|
-
"params": {
|
|
259
|
-
"prompt": "What are the most important 5 things to fix?",
|
|
260
|
-
"resultFact": "openaiAnalysisTop5"
|
|
261
|
-
},
|
|
262
|
-
"operator": "openaiAnalysisHighSeverity",
|
|
263
|
-
"value": 8
|
|
264
|
-
}
|
|
265
|
-
]
|
|
266
|
-
},
|
|
267
|
-
"event": {
|
|
268
|
-
"type": "violation",
|
|
269
|
-
"params": {
|
|
270
|
-
"message": "OpenAI analysis failed for the provided prompt.",
|
|
271
|
-
"results": {
|
|
272
|
-
"fact": "openaiAnalysisTop5"
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
}
|
|
276
|
-
}
|
|
277
|
-
```
|
|
117
|
+
### Rule Structure
|
|
278
118
|
|
|
279
|
-
|
|
119
|
+
Each rule is defined in a JSON file with the following structure:
|
|
280
120
|
|
|
281
121
|
```json
|
|
282
122
|
{
|
|
283
|
-
"name": "
|
|
123
|
+
"name": "ruleName",
|
|
124
|
+
"description": "A brief description of the rule",
|
|
284
125
|
"conditions": {
|
|
285
126
|
"all": [
|
|
286
127
|
{
|
|
287
|
-
"fact": "
|
|
288
|
-
"
|
|
289
|
-
"
|
|
290
|
-
"value": "REPO_GLOBAL_CHECK"
|
|
291
|
-
},
|
|
292
|
-
{
|
|
293
|
-
"fact": "openaiAnalysis",
|
|
294
|
-
"params": {
|
|
295
|
-
"prompt": "Identify any accessibility (a11y) issues in the codebase.",
|
|
296
|
-
"resultFact": "openaiAnalysisA11y"
|
|
297
|
-
},
|
|
298
|
-
"operator": "openaiAnalysisHighSeverity",
|
|
299
|
-
"value": 8
|
|
128
|
+
"fact": "factName",
|
|
129
|
+
"operator": "operatorName",
|
|
130
|
+
"value": "expectedValue"
|
|
300
131
|
}
|
|
301
132
|
]
|
|
302
133
|
},
|
|
303
134
|
"event": {
|
|
304
|
-
"type": "
|
|
135
|
+
"type": "ruleFailure",
|
|
305
136
|
"params": {
|
|
306
|
-
"message": "
|
|
307
|
-
"results": {
|
|
308
|
-
"fact": "openaiAnalysisA11y"
|
|
309
|
-
}
|
|
137
|
+
"message": "Error message when the rule fails"
|
|
310
138
|
}
|
|
311
139
|
}
|
|
312
140
|
}
|
package/dist/archetypes/index.js
CHANGED
|
@@ -12,22 +12,19 @@ exports.archetypes = {
|
|
|
12
12
|
nodemon: '^3.9.0'
|
|
13
13
|
},
|
|
14
14
|
standardStructure: {
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
rules: null,
|
|
20
|
-
facts: null
|
|
15
|
+
app: {
|
|
16
|
+
frontend: null,
|
|
17
|
+
common: null,
|
|
18
|
+
server: null
|
|
21
19
|
}
|
|
22
20
|
},
|
|
23
21
|
blacklistPatterns: [
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
'.*\\/\\..*', // dot files
|
|
23
|
+
'.*\\.(log|lock)$', // file extensions blacklisted
|
|
24
|
+
'.*\\/(dist|coverage|build|node_modules)(\\/.*|$)' // directory names blacklisted
|
|
27
25
|
],
|
|
28
26
|
whitelistPatterns: [
|
|
29
|
-
|
|
30
|
-
/.*\/(package|tsconfig)\.json$/
|
|
27
|
+
'.*\\.(ts|tsx|js|jsx|md)$' // file extensions whitelisted
|
|
31
28
|
]
|
|
32
29
|
}
|
|
33
30
|
},
|
|
@@ -53,13 +50,13 @@ exports.archetypes = {
|
|
|
53
50
|
}
|
|
54
51
|
},
|
|
55
52
|
blacklistPatterns: [
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
53
|
+
'.*\\/\\..*', // dot files
|
|
54
|
+
'.*\\.(log|lock)$', // file extensions blacklisted
|
|
55
|
+
'.*\\/(target|build|out|dist|coverage|build|node_modules)(\\/.*|$)' // directory names blacklisted
|
|
59
56
|
],
|
|
60
57
|
whitelistPatterns: [
|
|
61
|
-
|
|
62
|
-
|
|
58
|
+
'.*\\.(java|xml|properties|yml)$',
|
|
59
|
+
'.*\\/pom\\.xml$'
|
|
63
60
|
]
|
|
64
61
|
}
|
|
65
62
|
}
|
package/dist/core/cli.js
CHANGED
|
@@ -19,8 +19,9 @@ ${new Date().toString()}`);
|
|
|
19
19
|
console.log(banner);
|
|
20
20
|
logger_1.logger.info([banner]);
|
|
21
21
|
commander_1.program
|
|
22
|
-
.option("-d, --dir <directory>", "The checkout directory to analyse")
|
|
23
|
-
.option("-a, --archetype <archetype>", "The archetype to use for analysis", "node-fullstack")
|
|
22
|
+
.option("-d, --dir <directory>", "The checkout directory to analyse", ".")
|
|
23
|
+
.option("-a, --archetype <archetype>", "The archetype to use for analysis", "node-fullstack")
|
|
24
|
+
.option("-c, --configServer <configServer>", "The config server URL for fetching remote archetype configurations and rules");
|
|
24
25
|
commander_1.program.parse();
|
|
25
26
|
const options = commander_1.program.opts();
|
|
26
27
|
exports.options = options;
|
|
@@ -30,7 +31,9 @@ if (commander_1.program.options.length === 0)
|
|
|
30
31
|
if (!options.dir) {
|
|
31
32
|
console.error("Checkout directory not provided. Defaulting to current directory.");
|
|
32
33
|
}
|
|
33
|
-
|
|
34
|
-
logger_1.logger.info(
|
|
35
|
-
|
|
36
|
-
logger_1.logger.info(
|
|
34
|
+
let msg = `Archetype ${options.archetype}: analysis of: ${process.env.PWD}/${options.dir}`;
|
|
35
|
+
logger_1.logger.info(msg) && console.log(msg);
|
|
36
|
+
msg = `configServer: ${options.configServer ? options.configServer : 'local'}`;
|
|
37
|
+
logger_1.logger.info(msg) && console.log(msg);
|
|
38
|
+
msg = '=====================================';
|
|
39
|
+
logger_1.logger.info(msg) && console.log(msg);
|
package/dist/core/engine.js
CHANGED
|
@@ -8,9 +8,6 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
-
};
|
|
14
11
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
12
|
exports.analyzeCodebase = analyzeCodebase;
|
|
16
13
|
const logger_1 = require("../utils/logger");
|
|
@@ -18,29 +15,28 @@ const json_rules_engine_1 = require("json-rules-engine");
|
|
|
18
15
|
const repoFilesystemFacts_1 = require("../facts/repoFilesystemFacts");
|
|
19
16
|
const repoDependencyFacts_1 = require("../facts/repoDependencyFacts");
|
|
20
17
|
const openaiAnalysisFacts_1 = require("../facts/openaiAnalysisFacts");
|
|
21
|
-
const axios_1 = __importDefault(require("axios"));
|
|
22
|
-
const archetypes_1 = require("../archetypes");
|
|
23
|
-
const rules_1 = require("../rules");
|
|
24
18
|
const operators_1 = require("../operators");
|
|
25
19
|
const facts_1 = require("../facts");
|
|
20
|
+
const rules_1 = require("../rules");
|
|
21
|
+
const config_1 = require("../utils/config");
|
|
26
22
|
function analyzeCodebase(repoPath_1) {
|
|
27
|
-
return __awaiter(this, arguments, void 0, function* (repoPath, archetype = 'node-fullstack') {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const response = yield axios_1.default.get(archetypeConfig.configUrl);
|
|
32
|
-
archetypeConfig = Object.assign(Object.assign({}, archetypeConfig), { config: Object.assign(Object.assign({}, archetypeConfig.config), response.data) });
|
|
33
|
-
}
|
|
34
|
-
catch (error) {
|
|
35
|
-
logger_1.logger.error(`Error fetching remote config: ${error}`);
|
|
36
|
-
}
|
|
37
|
-
}
|
|
23
|
+
return __awaiter(this, arguments, void 0, function* (repoPath, archetype = 'node-fullstack', configServer = '') {
|
|
24
|
+
const configManager = config_1.ConfigManager.getInstance();
|
|
25
|
+
yield configManager.initialize(archetype, configServer);
|
|
26
|
+
const archetypeConfig = configManager.getConfig();
|
|
38
27
|
const installedDependencyVersions = yield (0, repoDependencyFacts_1.getDependencyVersionFacts)(archetypeConfig);
|
|
39
28
|
const fileData = yield (0, repoFilesystemFacts_1.collectRepoFileData)(repoPath, archetypeConfig);
|
|
29
|
+
// add REPO_GLOBAL_CHECK to fileData, which is the trigger for global checks
|
|
30
|
+
fileData.push({
|
|
31
|
+
fileName: config_1.REPO_GLOBAL_CHECK,
|
|
32
|
+
filePath: config_1.REPO_GLOBAL_CHECK,
|
|
33
|
+
fileContent: config_1.REPO_GLOBAL_CHECK
|
|
34
|
+
});
|
|
40
35
|
const { minimumDependencyVersions, standardStructure } = archetypeConfig.config;
|
|
41
36
|
const openaiSystemPrompt = yield (0, openaiAnalysisFacts_1.collectOpenaiAnalysisFacts)(fileData);
|
|
42
37
|
const engine = new json_rules_engine_1.Engine([], { replaceFactsInEventParams: true, allowUndefinedFacts: true });
|
|
43
38
|
// Add operators to engine
|
|
39
|
+
console.log(`### loading custom operators..`);
|
|
44
40
|
const operators = yield (0, operators_1.loadOperators)(archetypeConfig.operators);
|
|
45
41
|
operators.forEach((operator) => {
|
|
46
42
|
var _a, _b;
|
|
@@ -50,39 +46,54 @@ function analyzeCodebase(repoPath_1) {
|
|
|
50
46
|
}
|
|
51
47
|
});
|
|
52
48
|
// Add rules to engine
|
|
53
|
-
|
|
49
|
+
console.log(`### loading json rules..`);
|
|
50
|
+
const rules = yield (0, rules_1.loadRules)(archetype, archetypeConfig.rules, configManager.configServer);
|
|
51
|
+
logger_1.logger.debug(rules);
|
|
54
52
|
rules.forEach((rule) => {
|
|
55
|
-
var _a, _b;
|
|
56
53
|
try {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
engine.addRule(rule);
|
|
60
|
-
}
|
|
54
|
+
console.log(`adding rule: ${rule === null || rule === void 0 ? void 0 : rule.name}`);
|
|
55
|
+
engine.addRule(rule);
|
|
61
56
|
}
|
|
62
57
|
catch (e) {
|
|
63
58
|
console.error(`Error loading rule: ${rule === null || rule === void 0 ? void 0 : rule.name}`);
|
|
64
59
|
logger_1.logger.error(e.message);
|
|
65
60
|
}
|
|
66
61
|
});
|
|
67
|
-
engine.on('success', ({ type, params })
|
|
62
|
+
engine.on('success', (_a, almanac_1) => __awaiter(this, [_a, almanac_1], void 0, function* ({ type, params }, almanac) {
|
|
68
63
|
if (type === 'violation') {
|
|
69
|
-
//console.log(
|
|
64
|
+
//console.log(await almanac.factValue('dependencyData'));
|
|
65
|
+
console.log(`Rule violation: ${JSON.stringify(params)}}`);
|
|
70
66
|
}
|
|
71
|
-
});
|
|
67
|
+
}));
|
|
72
68
|
// Add facts to engine
|
|
69
|
+
console.log(`### loading facts..`);
|
|
73
70
|
const facts = yield (0, facts_1.loadFacts)(archetypeConfig.facts);
|
|
74
71
|
facts.forEach((fact) => {
|
|
75
|
-
|
|
72
|
+
var _a, _b;
|
|
73
|
+
if (!((_a = fact === null || fact === void 0 ? void 0 : fact.name) === null || _a === void 0 ? void 0 : _a.includes('openai')) || (process.env.OPENAI_API_KEY && ((_b = fact === null || fact === void 0 ? void 0 : fact.name) === null || _b === void 0 ? void 0 : _b.includes('openai')))) {
|
|
74
|
+
console.log(`adding fact: ${fact.name}`);
|
|
75
|
+
engine.addFact(fact.name, fact.fn);
|
|
76
|
+
}
|
|
76
77
|
});
|
|
77
78
|
if (process.env.OPENAI_API_KEY && archetypeConfig.facts.includes('openaiAnalysisFacts')) {
|
|
78
|
-
console.log(`adding openai facts to engine..`);
|
|
79
|
+
console.log(`adding additional openai facts to engine..`);
|
|
79
80
|
engine.addFact('openaiAnalysis', openaiAnalysisFacts_1.openaiAnalysis);
|
|
80
81
|
engine.addFact('openaiSystemPrompt', openaiSystemPrompt);
|
|
81
82
|
}
|
|
82
|
-
//
|
|
83
|
+
// add output facts
|
|
84
|
+
engine.addFact('repoDependencyAnalysis', repoDependencyFacts_1.repoDependencyAnalysis);
|
|
85
|
+
// Run the engine for each file's data
|
|
86
|
+
console.log(`### Executing rules..`);
|
|
83
87
|
let failures = [];
|
|
84
88
|
for (const file of fileData) {
|
|
85
|
-
|
|
89
|
+
if (file.fileName === 'REPO_GLOBAL_CHECK') {
|
|
90
|
+
let msg = `\n==========================\nSTARTING GLOBAL REPO CHECKS..\n==========================`;
|
|
91
|
+
logger_1.logger.info(msg) && console.log(msg);
|
|
92
|
+
}
|
|
93
|
+
else {
|
|
94
|
+
let msg = `running engine for ${file.filePath}`;
|
|
95
|
+
logger_1.logger.info(msg) && console.log(msg);
|
|
96
|
+
}
|
|
86
97
|
const facts = {
|
|
87
98
|
fileData: file,
|
|
88
99
|
dependencyData: {
|
|
@@ -92,7 +103,6 @@ function analyzeCodebase(repoPath_1) {
|
|
|
92
103
|
standardStructure
|
|
93
104
|
};
|
|
94
105
|
let fileFailures = [];
|
|
95
|
-
console.log(`running engine for ${file.filePath} ..`);
|
|
96
106
|
yield engine.run(facts)
|
|
97
107
|
.then(({ results }) => {
|
|
98
108
|
//console.log(events);
|