x-fidelity 1.4.0 → 1.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.
Files changed (60) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/README.md +178 -70
  3. package/dist/archetypes/index.js +6 -3
  4. package/dist/core/cli.js +24 -20
  5. package/dist/core/engine.js +88 -15
  6. package/dist/core/engine.test.js +21 -46
  7. package/dist/facts/openaiAnalysisFacts.js +2 -3
  8. package/dist/facts/openaiAnalysisFacts.test.js +2 -2
  9. package/dist/facts/repoDependencyFacts.js +5 -1
  10. package/dist/index.js +32 -17
  11. package/dist/operators/fileContains.test.js +37 -2
  12. package/dist/operators/openaiAnalysisHighSeverity.js +11 -7
  13. package/dist/operators/openaiAnalysisHighSeverity.test.js +41 -0
  14. package/dist/rules/index.js +10 -6
  15. package/dist/rules/index.test.js +11 -2
  16. package/dist/rules/{noDatabases-rule.json → noDatabases-iterative-rule.json} +2 -2
  17. package/dist/rules/{nonStandardDirectoryStructure-rule.json → nonStandardDirectoryStructure-global-rule.json} +3 -3
  18. package/{src/rules/openaiAnalysisA11y-rule.json → dist/rules/openaiAnalysisA11y-global-rule.json} +1 -1
  19. package/{src/rules/openaiAnalysisTop5-rule.json → dist/rules/openaiAnalysisTop5-global-rule.json} +1 -1
  20. package/dist/rules/{outdatedFramework-rule.json → outdatedFramework-global-rule.json} +4 -3
  21. package/dist/rules/{sensitiveLogging-rule.json → sensitiveLogging-iterative-rule.json} +6 -4
  22. package/dist/server/configServer.js +26 -15
  23. package/dist/server/expressLogger.js +36 -0
  24. package/dist/utils/config.js +9 -4
  25. package/dist/utils/logger.js +26 -4
  26. package/dist/utils/telemetry.js +29 -0
  27. package/dist/xfidelity +32 -17
  28. package/package.json +7 -4
  29. package/src/archetypes/index.ts +7 -4
  30. package/src/core/cli.ts +28 -25
  31. package/src/core/engine.test.ts +21 -53
  32. package/src/core/engine.ts +111 -23
  33. package/src/facts/openaiAnalysisFacts.test.ts +2 -2
  34. package/src/facts/openaiAnalysisFacts.ts +2 -3
  35. package/src/facts/repoDependencyFacts.ts +9 -2
  36. package/src/facts/repoFilesystemFacts.test.ts +1 -1
  37. package/src/facts/repoFilesystemFacts.ts +1 -1
  38. package/src/index.ts +30 -16
  39. package/src/operators/fileContains.test.ts +43 -2
  40. package/src/operators/fileContains.ts +1 -1
  41. package/src/operators/index.ts +1 -1
  42. package/src/operators/nonStandardDirectoryStructure.ts +2 -1
  43. package/src/operators/openaiAnalysisHighSeverity.test.ts +46 -0
  44. package/src/operators/openaiAnalysisHighSeverity.ts +14 -8
  45. package/src/operators/outdatedFramework.ts +1 -1
  46. package/src/rules/index.test.ts +12 -2
  47. package/src/rules/index.ts +13 -7
  48. package/src/rules/{noDatabases-rule.json → noDatabases-iterative-rule.json} +2 -2
  49. package/src/rules/{nonStandardDirectoryStructure-rule.json → nonStandardDirectoryStructure-global-rule.json} +3 -3
  50. package/{dist/rules/openaiAnalysisA11y-rule.json → src/rules/openaiAnalysisA11y-global-rule.json} +1 -1
  51. package/{dist/rules/openaiAnalysisTop5-rule.json → src/rules/openaiAnalysisTop5-global-rule.json} +1 -1
  52. package/src/rules/{outdatedFramework-rule.json → outdatedFramework-global-rule.json} +4 -3
  53. package/src/rules/{sensitiveLogging-rule.json → sensitiveLogging-iterative-rule.json} +6 -4
  54. package/src/server/configServer.ts +27 -17
  55. package/src/server/expressLogger.ts +37 -0
  56. package/src/utils/config.ts +10 -6
  57. package/src/utils/logger.ts +30 -4
  58. package/src/utils/telemetry.ts +23 -0
  59. /package/dist/{typeDefs.js → types/typeDefs.js} +0 -0
  60. /package/src/{typeDefs.ts → types/typeDefs.ts} +0 -0
package/CHANGELOG.md CHANGED
@@ -1,3 +1,25 @@
1
+ # [1.5.0](https://github.com/zotoio/x-fidelity/compare/v1.4.1...v1.5.0) (2024-07-24)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * **logger:** console transport ([69c62b1](https://github.com/zotoio/x-fidelity/commit/69c62b1b9859bc71801c576b969e9698ecc53a61))
7
+ * **log:** remove console and add process exit codes ([3ec801f](https://github.com/zotoio/x-fidelity/commit/3ec801fe3f913452d1f6ef14723fd0f8cb3a8439))
8
+
9
+
10
+ ### Features
11
+
12
+ * **telemetry:** basic start ([47faf3b](https://github.com/zotoio/x-fidelity/commit/47faf3b5f7a88afc07be1b256a611ce46ef64872))
13
+ * **telemetry:** basics including tracing ([f07f6b4](https://github.com/zotoio/x-fidelity/commit/f07f6b4d7ad886008cd20d3ccfa80e0e980bfd34))
14
+ * **telemetry:** request ids ([e19489e](https://github.com/zotoio/x-fidelity/commit/e19489eadd08b06119244a8e1798c2f22bac898b))
15
+
16
+ ## [1.4.1](https://github.com/zotoio/x-fidelity/compare/v1.4.0...v1.4.1) (2024-07-14)
17
+
18
+
19
+ ### Bug Fixes
20
+
21
+ * **rules:** change default sensitive strings rule ([3e14e24](https://github.com/zotoio/x-fidelity/commit/3e14e248cc8ae95a6a79a7f3d5f75b3db6f9d35f))
22
+
1
23
  # [1.4.0](https://github.com/zotoio/x-fidelity/compare/v1.3.0...v1.4.0) (2024-07-14)
2
24
 
3
25
 
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # x-fidelity
2
2
 
3
- CLI for opinionated framework adherence checks
3
+ x-fidelity is an advanced CLI tool designed to enforce opinionated framework adherence checks within a codebase. It provides a flexible and extensible way to ensure your projects follow specific standards and best practices.
4
4
 
5
5
  ```
6
6
  =====================================
@@ -16,130 +16,238 @@ CLI for opinionated framework adherence checks
16
16
  -------------------------------------
17
17
  ```
18
18
 
19
- ## What is x-fidelity?
19
+ ## Table of Contents
20
20
 
21
- x-fidelity is a CLI tool designed to enforce adherence to a set of opinionated framework rules within a codebase. It checks for various conditions such as directory structure, dependency versions, and the presence of certain strings in files.
21
+ 1. [Intent and Purpose](#intent-and-purpose)
22
+ 2. [Key Features](#key-features)
23
+ 3. [Installation](#installation)
24
+ 4. [Usage](#usage)
25
+ 5. [Configuration](#configuration)
26
+ 6. [Extending x-fidelity](#extending-x-fidelity)
27
+ 7. [OpenAI Integration](#openai-integration)
28
+ 8. [Hosting Config Servers](#hosting-config-servers)
29
+ 9. [Best Practices](#best-practices)
30
+ 10. [Contributing](#contributing)
31
+ 11. [License](#license)
22
32
 
23
- ## Features
33
+ ## Intent and Purpose
24
34
 
25
- - Ensures the directory structure matches a predefined standard.
26
- - Verifies that dependencies are up-to-date according to a specified minimum version.
27
- - Checks for the presence or absence of specific strings in files.
28
- - Configurable via a remote JSON configuration file.
29
- - Integrates with OpenAI for advanced code analysis.
35
+ x-fidelity aims to streamline the process of maintaining code quality and consistency across projects. By providing a flexible, rule-based system, it allows teams to:
36
+
37
+ - Enforce coding standards and best practices
38
+ - Ensure consistent project structures
39
+ - Maintain up-to-date dependencies
40
+ - Catch potential issues early in the development process
41
+ - Integrate advanced code analysis using AI (via OpenAI)
42
+
43
+ The tool is designed to be highly customizable, allowing teams to define their own archetypes, rules, and checks tailored to their specific needs and tech stacks.
44
+
45
+ ## Key Features
46
+
47
+ - **Flexible Archetype System**: Define custom project archetypes with specific rules and configurations.
48
+ - **Customizable Rules**: Create and apply rules for various aspects of your codebase.
49
+ - **Directory Structure Validation**: Ensure your project follows a predefined directory structure.
50
+ - **Dependency Version Checking**: Verify that your project uses up-to-date dependencies.
51
+ - **Content Analysis**: Search for specific patterns or strings within your codebase.
52
+ - **Remote Configuration**: Fetch configurations from a remote server for centralized management.
53
+ - **OpenAI Integration**: Leverage AI for advanced code analysis and suggestions.
54
+ - **Extensible Architecture**: Easily add new operators, facts, and rules to suit your needs.
30
55
 
31
56
  ## Installation
32
57
 
33
- Install x-fidelity with Node.js 18+ and Yarn:
58
+ Install x-fidelity using Node.js 18+ and Yarn:
34
59
 
35
60
  ```sh
36
61
  yarn global add x-fidelity
37
62
  export PATH="$PATH:$(yarn global bin)"
38
63
  ```
39
64
 
40
- You may want to add the path line to your `~/.bashrc` or `~/.zshrc` file for persistence of the binary in your path.
65
+ For persistent access, add the PATH line to your `~/.bashrc` or `~/.zshrc` file.
41
66
 
42
67
  ## Usage
43
68
 
44
- ### CLI
69
+ ### Basic Usage
45
70
 
46
- To run x-fidelity, use the following command:
71
+ Run x-fidelity in your project directory:
47
72
 
48
73
  ```sh
49
74
  xfidelity
50
-
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>]
53
75
  ```
54
76
 
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)
77
+ ### Advanced Usage
58
78
 
59
- **Example for node-fullstack archetype in current dir with remove config server:**
79
+ Use command-line options for more control:
60
80
 
61
81
  ```sh
62
- xfidelity --configUrl https://localhost:8888
82
+ xfidelity [-d --dir <directory>] [-c --configServer <url>] [-a --archetype <archetype>] [-m --mode <mode>] [-p --port <port>]
63
83
  ```
64
84
 
65
- **Example for java-microservice archetype in parent dir with remote config server (in this example running locally on port 8888):**
85
+ - `-d --dir <directory>`: Specify the root directory to analyze (default: current directory)
86
+ - `-c --configServer <url>`: URL to fetch the configuration from
87
+ - `-a --archetype <archetype>`: Archetype to use for analysis (default: 'node-fullstack')
88
+ - `-m --mode <mode>`: Run mode: 'cli' or 'server' (default: 'cli')
89
+ - `-p --port <port>`: Port number for server mode (default: 8888)
90
+
91
+ Examples:
66
92
 
67
93
  ```sh
68
- xfidelity -d .. -a java-microservice --c https://localhost:8888
94
+ # Use remote config server
95
+ xfidelity --configServer https://localhost:8888
96
+
97
+ # Analyze parent directory with java-microservice archetype
98
+ xfidelity -d .. -a java-microservice -c https://localhost:8888
99
+
100
+ # Run in server mode with custom port
101
+ xfidelity --mode server --port 9999
102
+
69
103
  ```
70
104
 
71
105
  ### Configuration Server
72
106
 
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.
107
+ Start the built-in configuration server:
74
108
 
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.
109
+ ```sh
110
+ yarn start-server
111
+ ```
76
112
 
77
- **To start the server:**
113
+ Or use the CLI:
78
114
 
79
- 1. Navigate to the x-fidelity directory.
80
- 2. Run the following command:
115
+ ```sh
116
+ xfidelity --mode server
117
+ ```
118
+
119
+ Set a custom port:
81
120
 
82
121
  ```sh
83
- yarn start-config-server
122
+ xfidelity --mode server --port 9999
84
123
  ```
85
124
 
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.
125
+ You can also set the port using an environment variable:
126
+
87
127
  ```sh
88
128
  export XFI_SERVER_PORT=8888
129
+ xfidelity --mode server
130
+ ```
131
+
132
+ ## Configuration
133
+
134
+ x-fidelity uses archetypes to define project-specific configurations. Archetypes specify:
135
+
136
+ - Rules to apply
137
+ - Operators to use
138
+ - Facts to gather
139
+ - Dependency version requirements
140
+ - Standard directory structure
141
+ - File patterns to include or exclude
142
+
143
+ Example archetype structure:
144
+
145
+ ```typescript
146
+ interface ArchetypeConfig {
147
+ rules: string[];
148
+ operators: string[];
149
+ facts: string[];
150
+ config: {
151
+ minimumDependencyVersions: Record<string, string>;
152
+ standardStructure: Record<string, any>;
153
+ blacklistPatterns: string[];
154
+ whitelistPatterns: string[];
155
+ };
156
+ }
157
+ ```
158
+
159
+ ## Extending x-fidelity
160
+
161
+ x-fidelity is designed to be highly extensible:
162
+
163
+ 1. **Custom Rules**: Add new JSON rule files in `src/rules`.
164
+ 2. **Custom Operators**: Implement new operators in `src/operators` and add them to `src/operators/index.ts`.
165
+ 3. **Custom Facts**: Create new fact providers in `src/facts` and add them to `src/facts/index.ts`.
166
+ 4. **New Archetypes**: Define new archetypes in `src/archetypes` and include them in `src/archetypes/index.ts`.
167
+
168
+ Example of creating a new archetype:
169
+
170
+ ```typescript
171
+ // src/archetypes/myNewArchetype.ts
172
+ export const myNewArchetype: ArchetypeConfig = {
173
+ rules: ['myCustomRule', 'standardRule1', 'standardRule2'],
174
+ operators: ['myCustomOperator', 'standardOperator1'],
175
+ facts: ['myCustomFact', 'standardFact1'],
176
+ config: {
177
+ minimumDependencyVersions: {
178
+ 'my-framework': '^2.0.0'
179
+ },
180
+ standardStructure: {
181
+ src: {
182
+ components: null,
183
+ utils: null
184
+ },
185
+ tests: null
186
+ },
187
+ blacklistPatterns: ['.*\\/\\..*', '.*\\/(dist|build)(\\/.*|$)'],
188
+ whitelistPatterns: ['.*\\.(ts|tsx|js|jsx)$']
189
+ }
190
+ };
89
191
  ```
90
192
 
91
193
  ## OpenAI Integration
92
194
 
93
- To enable OpenAI features for experimental LLM-based codebase analysis:
195
+ To enable AI-powered code analysis:
94
196
 
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:
197
+ 1. Sign up for an [OpenAI API key](https://platform.openai.com).
198
+ 2. Set environment variables:
98
199
 
99
200
  ```sh
100
201
  export OPENAI_API_KEY=your_openai_api_key
202
+ export OPENAI_MODEL=gpt-4 # Optional, default is gpt-4o
101
203
  ```
102
- 4. Optionally set the OPENAI_MODEL environment var (default is gpt-4o):
103
- ```sh
104
- export OPENAI_MODEL=gpt-4
105
- ```
106
- Note that not all models consistently return parseable JSON results, so some experimentation is required.
107
204
 
108
205
  > [!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.
206
+ > Be aware of potential costs and data privacy concerns when using OpenAI's API.
112
207
 
113
- ## Configuration
208
+ ## Hosting Config Servers
114
209
 
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.
116
-
117
- ### Rule Structure
118
-
119
- Each rule is defined in a JSON file with the following structure:
120
-
121
- ```json
122
- {
123
- "name": "ruleName",
124
- "description": "A brief description of the rule",
125
- "conditions": {
126
- "all": [
127
- {
128
- "fact": "factName",
129
- "operator": "operatorName",
130
- "value": "expectedValue"
131
- }
132
- ]
133
- },
134
- "event": {
135
- "type": "ruleFailure",
136
- "params": {
137
- "message": "Error message when the rule fails"
138
- }
139
- }
140
- }
210
+ To host a config server for x-fidelity:
211
+
212
+ 1. Set up a Node.js server (e.g., Express.js)
213
+ 2. Implement endpoints for archetype configurations and rules
214
+ 3. Ensure security, scalability, and performance
215
+ 4. Use HTTPS and implement proper authentication
216
+ 5. Consider using a CDN for global distribution
217
+
218
+ Example server setup:
219
+
220
+ ```javascript
221
+ const express = require('express');
222
+ const app = express();
223
+
224
+ app.get('/archetypes/:archetype', (req, res) => {
225
+ // Fetch and return archetype configuration
226
+ });
227
+
228
+ app.get('/archetypes/:archetype/rules/:rule', (req, res) => {
229
+ // Fetch and return specific rule
230
+ });
231
+
232
+ app.listen(8888, () => {
233
+ console.log('Config server running on port 8888');
234
+ });
141
235
  ```
142
236
 
237
+ ## Best Practices
238
+
239
+ 1. **Version Control**: Keep your x-fidelity configurations in version control.
240
+ 2. **Continuous Integration**: Integrate x-fidelity checks into your CI/CD pipeline.
241
+ 3. **Regular Updates**: Keep your archetypes, rules, and dependencies up to date.
242
+ 4. **Documentation**: Document custom rules, operators, and archetypes for your team.
243
+ 5. **Gradual Implementation**: When introducing x-fidelity to an existing project, start with basic checks and gradually increase strictness.
244
+ 6. **Team Alignment**: Ensure your team understands and agrees on the rules being enforced.
245
+ 7. **Performance**: Be mindful of the performance impact, especially for large codebases.
246
+
247
+ ## Contributing
248
+
249
+ Contributions to x-fidelity are welcome! Please refer to the `CONTRIBUTING.md` file for guidelines on how to contribute to this project.
250
+
143
251
  ## License
144
252
 
145
- This project is licensed under the MIT License.
253
+ This project is licensed under the MIT License. See the `LICENSE` file for details.
@@ -3,7 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.archetypes = void 0;
4
4
  exports.archetypes = {
5
5
  'node-fullstack': {
6
- rules: ['sensitiveLogging', 'outdatedFramework', 'noDatabases', 'nonStandardDirectoryStructure', 'openaiAnalysisTop5', 'openaiAnalysisA11y'],
6
+ rules: ['sensitiveLogging-iterative', 'outdatedFramework-global', 'noDatabases-iterative', 'nonStandardDirectoryStructure-global', 'openaiAnalysisTop5-global', 'openaiAnalysisA11y-global'],
7
7
  operators: ['fileContains', 'outdatedFramework', 'nonStandardDirectoryStructure', 'openaiAnalysisHighSeverity'],
8
8
  facts: ['repoFilesystemFacts', 'repoDependencyFacts', 'openaiAnalysisFacts'],
9
9
  config: {
@@ -14,9 +14,12 @@ exports.archetypes = {
14
14
  standardStructure: {
15
15
  app: {
16
16
  frontend: null,
17
- common: null,
18
17
  server: null
19
18
  }
19
+ // app: {
20
+ // frontend: 'required',
21
+ // server: 'required'
22
+ // }
20
23
  },
21
24
  blacklistPatterns: [
22
25
  '.*\\/\\..*', // dot files
@@ -29,7 +32,7 @@ exports.archetypes = {
29
32
  }
30
33
  },
31
34
  'java-microservice': {
32
- rules: ['sensitiveLogging', 'outdatedFramework', 'noDatabases', 'nonStandardDirectoryStructure'],
35
+ rules: ['sensitiveLogging-iterative', 'outdatedFramework-global', 'noDatabases-iterative', 'nonStandardDirectoryStructure-global'],
33
36
  operators: ['fileContains', 'outdatedFramework', 'nonStandardDirectoryStructure'],
34
37
  facts: ['repoFilesystemFacts', 'repoDependencyFacts'],
35
38
  config: {
package/dist/core/cli.js CHANGED
@@ -3,6 +3,20 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.options = void 0;
4
4
  const logger_1 = require("../utils/logger");
5
5
  const commander_1 = require("commander");
6
+ // Ensure logger is initialized
7
+ if (!logger_1.logger || typeof logger_1.logger.info !== 'function') {
8
+ console.error('Logger is not properly initialized');
9
+ process.exit(1);
10
+ }
11
+ commander_1.program
12
+ .option("-d, --dir <directory>", "The checkout directory to analyze", ".")
13
+ .option("-a, --archetype <archetype>", "The archetype to use for analysis", "node-fullstack")
14
+ .option("-c, --configServer <configServer>", "The config server URL for fetching remote archetype configurations and rules")
15
+ .option("-m, --mode <mode>", "Run mode: 'cli' or 'server'", "cli")
16
+ .option("-p, --port <port>", "Port number for server mode", "8888");
17
+ commander_1.program.parse();
18
+ const options = commander_1.program.opts();
19
+ exports.options = options;
6
20
  const banner = (`
7
21
  =====================================
8
22
  __ __ ________ ______
@@ -14,26 +28,16 @@ const banner = (`
14
28
  | ## | ## | ## | ## \\
15
29
  \\## \\## \\## \\######
16
30
 
17
- -------------------------------------
18
- ${new Date().toString()}`);
19
- console.log(banner);
20
- logger_1.logger.info([banner]);
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")
24
- .option("-c, --configServer <configServer>", "The config server URL for fetching remote archetype configurations and rules");
25
- commander_1.program.parse();
26
- const options = commander_1.program.opts();
27
- exports.options = options;
31
+ --------------------
32
+ ${new Date().toString().slice(0, 24)}
33
+ archetype: ${options.archetype}
34
+ directory: ${process.env.PWD}/${options.dir}
35
+ configServer: ${options.configServer ? options.configServer : 'none'}
36
+ mode: ${options.mode}
37
+ port: ${options.mode === 'server' ? options.port : 'N/A'}
38
+ for available options run: xfidelity --help
39
+ =====================================`);
40
+ logger_1.logger.info(banner);
28
41
  // print help if no arguments are passed
29
42
  if (commander_1.program.options.length === 0)
30
43
  commander_1.program.help();
31
- if (!options.dir) {
32
- console.error("Checkout directory not provided. Defaulting to current directory.");
33
- }
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);
@@ -19,6 +19,7 @@ const operators_1 = require("../operators");
19
19
  const facts_1 = require("../facts");
20
20
  const rules_1 = require("../rules");
21
21
  const config_1 = require("../utils/config");
22
+ const telemetry_1 = require("../utils/telemetry");
22
23
  function analyzeCodebase(repoPath_1) {
23
24
  return __awaiter(this, arguments, void 0, function* (repoPath, archetype = 'node-fullstack', configServer = '') {
24
25
  const configManager = config_1.ConfigManager.getInstance();
@@ -35,23 +36,34 @@ function analyzeCodebase(repoPath_1) {
35
36
  const { minimumDependencyVersions, standardStructure } = archetypeConfig.config;
36
37
  const openaiSystemPrompt = yield (0, openaiAnalysisFacts_1.collectOpenaiAnalysisFacts)(fileData);
37
38
  const engine = new json_rules_engine_1.Engine([], { replaceFactsInEventParams: true, allowUndefinedFacts: true });
39
+ // Send telemetry for analysis start
40
+ yield (0, telemetry_1.sendTelemetry)({
41
+ eventType: 'analysisStart',
42
+ metadata: {
43
+ archetype,
44
+ repoPath,
45
+ fileCount: fileData.length,
46
+ configServer: configServer || 'none'
47
+ },
48
+ timestamp: new Date().toISOString()
49
+ });
38
50
  // Add operators to engine
39
- console.log(`### loading custom operators..`);
51
+ logger_1.logger.info(`### loading custom operators..`);
40
52
  const operators = yield (0, operators_1.loadOperators)(archetypeConfig.operators);
41
53
  operators.forEach((operator) => {
42
54
  var _a, _b;
43
55
  if (!((_a = operator === null || operator === void 0 ? void 0 : operator.name) === null || _a === void 0 ? void 0 : _a.includes('openai')) || (process.env.OPENAI_API_KEY && ((_b = operator === null || operator === void 0 ? void 0 : operator.name) === null || _b === void 0 ? void 0 : _b.includes('openai')))) {
44
- console.log(`adding custom operator: ${operator.name}`);
56
+ logger_1.logger.info(`adding custom operator: ${operator.name}`);
45
57
  engine.addOperator(operator.name, operator.fn);
46
58
  }
47
59
  });
48
60
  // Add rules to engine
49
- console.log(`### loading json rules..`);
50
- const rules = yield (0, rules_1.loadRules)(archetype, archetypeConfig.rules, configManager.configServer);
61
+ logger_1.logger.info(`### loading json rules..`);
62
+ const rules = yield (0, rules_1.loadRules)(archetype, archetypeConfig.rules, configManager.configServer, logger_1.logPrefix);
51
63
  logger_1.logger.debug(rules);
52
64
  rules.forEach((rule) => {
53
65
  try {
54
- console.log(`adding rule: ${rule === null || rule === void 0 ? void 0 : rule.name}`);
66
+ logger_1.logger.info(`adding rule: ${rule === null || rule === void 0 ? void 0 : rule.name}`);
55
67
  engine.addRule(rule);
56
68
  }
57
69
  catch (e) {
@@ -61,38 +73,52 @@ function analyzeCodebase(repoPath_1) {
61
73
  });
62
74
  engine.on('success', (_a, almanac_1) => __awaiter(this, [_a, almanac_1], void 0, function* ({ type, params }, almanac) {
63
75
  if (type === 'violation') {
64
- //console.log(await almanac.factValue('dependencyData'));
65
- console.log(`Rule violation: ${JSON.stringify(params)}}`);
76
+ logger_1.logger.warn(`violation detected: ${JSON.stringify(params)}}`);
77
+ yield (0, telemetry_1.sendTelemetry)({
78
+ eventType: 'violation',
79
+ metadata: Object.assign({ archetype,
80
+ repoPath }, params),
81
+ timestamp: new Date().toISOString()
82
+ });
83
+ }
84
+ if (type === 'fatality') {
85
+ logger_1.logger.error(`fatality detected: ${JSON.stringify(params)}}`);
86
+ yield (0, telemetry_1.sendTelemetry)({
87
+ eventType: 'fatality',
88
+ metadata: Object.assign({ archetype,
89
+ repoPath }, params),
90
+ timestamp: new Date().toISOString()
91
+ });
66
92
  }
67
93
  }));
68
94
  // Add facts to engine
69
- console.log(`### loading facts..`);
95
+ logger_1.logger.info(`### loading facts..`);
70
96
  const facts = yield (0, facts_1.loadFacts)(archetypeConfig.facts);
71
97
  facts.forEach((fact) => {
72
98
  var _a, _b;
73
99
  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}`);
100
+ logger_1.logger.info(`adding fact: ${fact.name}`);
75
101
  engine.addFact(fact.name, fact.fn);
76
102
  }
77
103
  });
78
104
  if (process.env.OPENAI_API_KEY && archetypeConfig.facts.includes('openaiAnalysisFacts')) {
79
- console.log(`adding additional openai facts to engine..`);
105
+ logger_1.logger.info(`adding additional openai facts to engine..`);
80
106
  engine.addFact('openaiAnalysis', openaiAnalysisFacts_1.openaiAnalysis);
81
107
  engine.addFact('openaiSystemPrompt', openaiSystemPrompt);
82
108
  }
83
109
  // add output facts
84
110
  engine.addFact('repoDependencyAnalysis', repoDependencyFacts_1.repoDependencyAnalysis);
85
111
  // Run the engine for each file's data
86
- console.log(`### Executing rules..`);
112
+ logger_1.logger.info(`### Executing rules..`);
87
113
  let failures = [];
88
114
  for (const file of fileData) {
89
- if (file.fileName === 'REPO_GLOBAL_CHECK') {
115
+ if (file.fileName === config_1.REPO_GLOBAL_CHECK) {
90
116
  let msg = `\n==========================\nSTARTING GLOBAL REPO CHECKS..\n==========================`;
91
- logger_1.logger.info(msg) && console.log(msg);
117
+ logger_1.logger.info(msg);
92
118
  }
93
119
  else {
94
120
  let msg = `running engine for ${file.filePath}`;
95
- logger_1.logger.info(msg) && console.log(msg);
121
+ logger_1.logger.info(msg);
96
122
  }
97
123
  const facts = {
98
124
  fileData: file,
@@ -105,7 +131,6 @@ function analyzeCodebase(repoPath_1) {
105
131
  let fileFailures = [];
106
132
  yield engine.run(facts)
107
133
  .then(({ results }) => {
108
- //console.log(events);
109
134
  results.map((result) => {
110
135
  var _a;
111
136
  logger_1.logger.debug(result);
@@ -122,6 +147,54 @@ function analyzeCodebase(repoPath_1) {
122
147
  }
123
148
  }
124
149
  logger_1.logger.info(`${fileData.length} files analyzed. ${failures.length} files with errors.`);
150
+ const fatalities = findKeyValuePair(failures, 'level', 'fatality');
151
+ // Send telemetry for analysis end
152
+ yield (0, telemetry_1.sendTelemetry)({
153
+ eventType: 'analysisEnd',
154
+ metadata: {
155
+ archetype,
156
+ repoPath,
157
+ fileCount: fileData.length,
158
+ failureCount: failures.length,
159
+ fatalityCount: fatalities.length
160
+ },
161
+ timestamp: new Date().toISOString()
162
+ });
163
+ if (fatalities.length > 0) {
164
+ throw new Error(JSON.stringify(fatalities));
165
+ }
125
166
  return failures;
126
167
  });
127
168
  }
169
+ const findKeyValuePair = (data, targetKey, targetValue) => {
170
+ let results = [];
171
+ const recursiveSearch = (obj) => {
172
+ if (typeof obj === 'object' && obj !== null) {
173
+ for (let key in obj) {
174
+ if (obj.hasOwnProperty(key)) {
175
+ if (key === targetKey && obj[key] === targetValue) {
176
+ results.push(obj);
177
+ return; // Stop searching this branch as we've found the target in this object
178
+ }
179
+ if (typeof obj[key] === 'object' || Array.isArray(obj[key])) {
180
+ recursiveSearch(obj[key]);
181
+ }
182
+ }
183
+ }
184
+ }
185
+ else if (Array.isArray(obj)) {
186
+ obj.forEach((item) => {
187
+ recursiveSearch(item);
188
+ });
189
+ }
190
+ };
191
+ if (Array.isArray(data)) {
192
+ data.forEach((item) => {
193
+ recursiveSearch(item);
194
+ });
195
+ }
196
+ else {
197
+ recursiveSearch(data);
198
+ }
199
+ return results;
200
+ };