x-fidelity 1.4.1 → 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 +15 -0
  2. package/README.md +117 -121
  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} +4 -2
  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} +4 -2
  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,18 @@
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
+
1
16
  ## [1.4.1](https://github.com/zotoio/x-fidelity/compare/v1.4.0...v1.4.1) (2024-07-14)
2
17
 
3
18
 
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,107 +16,131 @@ 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
69
- ```
94
+ # Use remote config server
95
+ xfidelity --configServer https://localhost:8888
70
96
 
71
- ### Configuration Server
97
+ # Analyze parent directory with java-microservice archetype
98
+ xfidelity -d .. -a java-microservice -c https://localhost:8888
72
99
 
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.
100
+ # Run in server mode with custom port
101
+ xfidelity --mode server --port 9999
74
102
 
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.
103
+ ```
76
104
 
77
- **To start the server:**
105
+ ### Configuration Server
78
106
 
79
- 1. Navigate to the x-fidelity directory.
80
- 2. Run the following command:
107
+ Start the built-in configuration server:
81
108
 
82
109
  ```sh
83
- yarn start-config-server
110
+ yarn start-server
84
111
  ```
85
112
 
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.
113
+ Or use the CLI:
114
+
87
115
  ```sh
88
- export XFI_SERVER_PORT=8888
116
+ xfidelity --mode server
89
117
  ```
90
118
 
91
- ## OpenAI Integration
92
-
93
- To enable OpenAI features for experimental LLM-based codebase analysis:
94
-
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:
119
+ Set a custom port:
98
120
 
99
121
  ```sh
100
- export OPENAI_API_KEY=your_openai_api_key
122
+ xfidelity --mode server --port 9999
101
123
  ```
102
- 4. Optionally set the OPENAI_MODEL environment var (default is gpt-4o):
124
+
125
+ You can also set the port using an environment variable:
126
+
103
127
  ```sh
104
- export OPENAI_MODEL=gpt-4
128
+ export XFI_SERVER_PORT=8888
129
+ xfidelity --mode server
105
130
  ```
106
- Note that not all models consistently return parseable JSON results, so some experimentation is required.
107
-
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.
112
131
 
113
132
  ## Configuration
114
133
 
115
- The configuration for x-fidelity is based on archetypes, which define the rules, operators, facts, and other settings for a specific type of project. You can find example configuration files in the `src/archetypes` directory of the repository.
134
+ x-fidelity uses archetypes to define project-specific configurations. Archetypes specify:
116
135
 
117
- ### Archetype Schema
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
118
142
 
119
- An archetype is defined with the following structure:
143
+ Example archetype structure:
120
144
 
121
145
  ```typescript
122
146
  interface ArchetypeConfig {
@@ -132,54 +156,19 @@ interface ArchetypeConfig {
132
156
  }
133
157
  ```
134
158
 
135
- - `rules`: An array of rule names to be applied for this archetype.
136
- - `operators`: An array of operator names used in the rules.
137
- - `facts`: An array of fact provider names used to gather information about the codebase.
138
- - `config`: Additional configuration specific to the archetype:
139
- - `minimumDependencyVersions`: Minimum required versions for dependencies.
140
- - `standardStructure`: Expected directory structure for the project.
141
- - `blacklistPatterns`: Patterns for files/directories to be ignored.
142
- - `whitelistPatterns`: Patterns for files/directories to be included.
143
-
144
- ### Rule Structure
145
-
146
- Each rule is defined in a JSON file with the following structure:
147
-
148
- ```json
149
- {
150
- "name": "ruleName",
151
- "conditions": {
152
- "all": [
153
- {
154
- "fact": "factName",
155
- "operator": "operatorName",
156
- "value": "expectedValue"
157
- }
158
- ]
159
- },
160
- "event": {
161
- "type": "violation",
162
- "params": {
163
- "message": "Error message when the rule fails"
164
- }
165
- }
166
- }
167
- ```
168
-
169
- ## Creating New Archetypes
159
+ ## Extending x-fidelity
170
160
 
171
- To create a new archetype:
161
+ x-fidelity is designed to be highly extensible:
172
162
 
173
- 1. Create a new file in the `src/archetypes` directory, e.g., `myNewArchetype.ts`.
174
- 2. Define the archetype configuration following the `ArchetypeConfig` interface.
175
- 3. Add any necessary rules in the `src/rules` directory.
176
- 4. If needed, create custom operators in the `src/operators` directory.
177
- 5. If needed, create custom fact providers in the `src/facts` directory.
178
- 6. Update the `src/archetypes/index.ts` file to include your new archetype.
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`.
179
167
 
180
- Example of a new archetype:
168
+ Example of creating a new archetype:
181
169
 
182
170
  ```typescript
171
+ // src/archetypes/myNewArchetype.ts
183
172
  export const myNewArchetype: ArchetypeConfig = {
184
173
  rules: ['myCustomRule', 'standardRule1', 'standardRule2'],
185
174
  operators: ['myCustomOperator', 'standardOperator1'],
@@ -201,41 +190,43 @@ export const myNewArchetype: ArchetypeConfig = {
201
190
  };
202
191
  ```
203
192
 
204
- ## Extensibility
193
+ ## OpenAI Integration
194
+
195
+ To enable AI-powered code analysis:
205
196
 
206
- x-fidelity is designed to be highly extensible:
197
+ 1. Sign up for an [OpenAI API key](https://platform.openai.com).
198
+ 2. Set environment variables:
207
199
 
208
- 1. **Custom Rules**: Create new rules by adding JSON files in the `src/rules` directory.
209
- 2. **Custom Operators**: Implement new operators in the `src/operators` directory and add them to `src/operators/index.ts`.
210
- 3. **Custom Facts**: Create new fact providers in the `src/facts` directory and add them to `src/facts/index.ts`.
211
- 4. **New Archetypes**: As described above, create new archetypes to support different project types or frameworks.
200
+ ```sh
201
+ export OPENAI_API_KEY=your_openai_api_key
202
+ export OPENAI_MODEL=gpt-4 # Optional, default is gpt-4o
203
+ ```
204
+
205
+ > [!IMPORTANT]
206
+ > Be aware of potential costs and data privacy concerns when using OpenAI's API.
212
207
 
213
208
  ## Hosting Config Servers
214
209
 
215
210
  To host a config server for x-fidelity:
216
211
 
217
- 1. Set up a Node.js server environment (e.g., using Express.js).
218
- 2. Implement endpoints that serve the archetype configurations and rules.
219
- 3. Ensure the server is secure and can handle the expected load.
220
- 4. Use HTTPS for secure communication.
221
- 5. Implement caching mechanisms to improve performance.
222
- 6. Consider using a CDN for global distribution and lower latency.
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
223
217
 
224
- Example server setup (simplified):
218
+ Example server setup:
225
219
 
226
220
  ```javascript
227
221
  const express = require('express');
228
222
  const app = express();
229
223
 
230
224
  app.get('/archetypes/:archetype', (req, res) => {
231
- const archetype = req.params.archetype;
232
- // Fetch and return the archetype configuration
225
+ // Fetch and return archetype configuration
233
226
  });
234
227
 
235
228
  app.get('/archetypes/:archetype/rules/:rule', (req, res) => {
236
- const archetype = req.params.archetype;
237
- const rule = req.params.rule;
238
- // Fetch and return the specific rule for the archetype
229
+ // Fetch and return specific rule
239
230
  });
240
231
 
241
232
  app.listen(8888, () => {
@@ -243,15 +234,20 @@ app.listen(8888, () => {
243
234
  });
244
235
  ```
245
236
 
246
- Best practices for hosting:
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
247
248
 
248
- - Use environment variables for sensitive information.
249
- - Implement proper error handling and logging.
250
- - Set up monitoring and alerting for the server.
251
- - Regularly update and maintain the server and its dependencies.
252
- - Implement rate limiting to prevent abuse.
253
- - Consider using containerization (e.g., Docker) for easy deployment and scaling.
249
+ Contributions to x-fidelity are welcome! Please refer to the `CONTRIBUTING.md` file for guidelines on how to contribute to this project.
254
250
 
255
251
  ## License
256
252
 
257
- 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
+ };