x-fidelity 2.2.0 → 2.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 +76 -0
- package/dist/core/engine/analyzer.test.js +17 -9
- package/dist/core/engine/engineRunner.test.js +1 -0
- package/dist/core/engine/engineSetup.js +8 -9
- package/dist/core/engine/engineSetup.test.js +106 -77
- package/dist/facts/openaiAnalysisFacts.test.js +1 -0
- package/dist/index.js +45 -34
- package/dist/index.test.js +160 -0
- package/dist/rules/index.js +2 -2
- package/dist/rules/index.test.js +6 -6
- package/dist/server/cacheManager.js +66 -0
- package/dist/server/configServer.js +50 -153
- package/dist/server/configServer.test.js +40 -29
- package/dist/server/middleware/checkSharedSecret.js +14 -0
- package/dist/server/middleware/validateGithubWebhook.js +23 -0
- package/dist/server/middleware/validateTelemetryData.js +10 -0
- package/dist/server/middleware/validateUrlInput.js +10 -0
- package/dist/server/routes/archetypeRoute.js +50 -0
- package/dist/server/routes/archetypeRuleRoute.js +58 -0
- package/dist/server/routes/archetypeRulesRoute.js +46 -0
- package/dist/server/routes/clearCacheRoute.js +14 -0
- package/dist/server/routes/githubWebhookRoute.js +140 -0
- package/dist/server/routes/telemetryRoute.js +15 -0
- package/dist/server/routes/viewCacheRoute.js +13 -0
- package/dist/utils/axiosClient.js +61 -0
- package/dist/utils/configManager.js +36 -7
- package/dist/utils/configManager.test.js +10 -10
- package/dist/utils/inputValidation.js +12 -0
- package/dist/utils/inputValidation.test.js +51 -0
- package/dist/utils/logger.js +1 -0
- package/dist/utils/logger.test.js +32 -0
- package/dist/utils/maskSensitiveData.test.js +40 -0
- package/dist/utils/telemetry.js +3 -6
- package/dist/xfidelity +45 -34
- package/package.json +6 -2
- package/src/core/engine/analyzer.test.ts +17 -9
- package/src/core/engine/engineRunner.test.ts +1 -0
- package/src/core/engine/engineSetup.test.ts +119 -81
- package/src/core/engine/engineSetup.ts +11 -11
- package/src/facts/openaiAnalysisFacts.test.ts +1 -0
- package/src/index.test.ts +157 -0
- package/src/index.ts +55 -45
- package/src/rules/index.test.ts +6 -6
- package/src/rules/index.ts +9 -33
- package/src/server/cacheManager.ts +65 -0
- package/src/server/configServer.test.ts +43 -32
- package/src/server/configServer.ts +61 -156
- package/src/server/middleware/checkSharedSecret.ts +14 -0
- package/src/server/middleware/validateGithubWebhook.ts +24 -0
- package/src/server/middleware/validateTelemetryData.ts +9 -0
- package/src/server/middleware/validateUrlInput.ts +9 -0
- package/src/server/routes/archetypeRoute.ts +40 -0
- package/src/server/routes/archetypeRuleRoute.ts +46 -0
- package/src/server/routes/archetypeRulesRoute.ts +35 -0
- package/src/server/routes/clearCacheRoute.ts +13 -0
- package/src/server/routes/githubWebhookRoute.ts +131 -0
- package/src/server/routes/telemetryRoute.ts +14 -0
- package/src/server/routes/viewCacheRoute.ts +15 -0
- package/src/types/typeDefs.ts +20 -0
- package/src/utils/axiosClient.ts +40 -0
- package/src/utils/configManager.test.ts +10 -10
- package/src/utils/configManager.ts +40 -8
- package/src/utils/inputValidation.test.ts +58 -0
- package/src/utils/inputValidation.ts +14 -0
- package/src/utils/logger.test.ts +34 -0
- package/src/utils/logger.ts +1 -0
- package/src/utils/maskSensitiveData.test.ts +45 -0
- package/src/utils/telemetry.ts +3 -4
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,79 @@
|
|
|
1
|
+
# [2.4.0](https://github.com/zotoio/x-fidelity/compare/v2.3.0...v2.4.0) (2024-08-21)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* add unit tests for all files except typeDefs ([b1d1fd9](https://github.com/zotoio/x-fidelity/commit/b1d1fd9d069d2bd54712ae0cf96a9e48ebec903e))
|
|
7
|
+
* **deps:** make artillery a peer dependency ([d89361f](https://github.com/zotoio/x-fidelity/commit/d89361fcc24744cfa52df6cbe52b6117b92e46d8))
|
|
8
|
+
* Handle errors during execution ([48a9488](https://github.com/zotoio/x-fidelity/commit/48a94882eff7db64e0f996a6b55d3dde9eca080b))
|
|
9
|
+
* Improve error handling and execution flow in index.ts ([0b8ca73](https://github.com/zotoio/x-fidelity/commit/0b8ca73d3cc4b0b498ab9a8cf93d9d67965243af))
|
|
10
|
+
* Increase timeout for test case to prevent "force exited" issue ([ab3d0b3](https://github.com/zotoio/x-fidelity/commit/ab3d0b30696f6056df8a386b5eb366f4c545dbfa))
|
|
11
|
+
* **logging:** silence in logs and increase unit test coverage ([5017a12](https://github.com/zotoio/x-fidelity/commit/5017a1216c5dedc443d40787aa70ea40814de49c))
|
|
12
|
+
* Mock axiosClient instead of axios in rules/index.test.ts ([40e7410](https://github.com/zotoio/x-fidelity/commit/40e74108b45813244fa3810649d1b681a1e85af5))
|
|
13
|
+
* Pass executionLogPrefix to startServer and analyzeCodebase ([99a6692](https://github.com/zotoio/x-fidelity/commit/99a669232d77a8bfaeca22590efcdc9fd9ecb80a))
|
|
14
|
+
* Prevent unnecessary process exit in test environment ([aab777f](https://github.com/zotoio/x-fidelity/commit/aab777f76f4ab3c98322c93250bbfa5d35f2812a))
|
|
15
|
+
* Remove setTimeout and directly call process.exit(1) in error handling function ([8a7587e](https://github.com/zotoio/x-fidelity/commit/8a7587ea169ff8313d187f4ea71487eb8273623f))
|
|
16
|
+
* resolve TypeScript errors in telemetry utility ([3c68aa1](https://github.com/zotoio/x-fidelity/commit/3c68aa1d4d3b2594dd05fa120233a56ff06d5206))
|
|
17
|
+
* Update import and call of main function in index.test.ts ([70e11b1](https://github.com/zotoio/x-fidelity/commit/70e11b18dfbf272035e96a004b6f7b889644c229))
|
|
18
|
+
* Update import and export in index.test.ts and index.ts ([b15203d](https://github.com/zotoio/x-fidelity/commit/b15203d8aa3b37b211c5a57edd8dd0ea58c9d93f))
|
|
19
|
+
* Update index.test.ts ([b3d1799](https://github.com/zotoio/x-fidelity/commit/b3d1799153de1f502f5b897d268c30999189f1ca))
|
|
20
|
+
* Update process.exit usage in src/index.ts ([ac398c3](https://github.com/zotoio/x-fidelity/commit/ac398c31cd944e2c062db5d7b57254f026a89f8c))
|
|
21
|
+
* Update startServer function call and process exit handling ([7be6c28](https://github.com/zotoio/x-fidelity/commit/7be6c280dda46f49a8c1c45149b93fcadd261ccb))
|
|
22
|
+
* update test expectations ([d24279e](https://github.com/zotoio/x-fidelity/commit/d24279e8520f882260299190b9562831b7c79528))
|
|
23
|
+
* Update test expectations to match actual error messages ([454aea6](https://github.com/zotoio/x-fidelity/commit/454aea6a8cf38cfdd1b9ed31288c119f7f37dbbf))
|
|
24
|
+
* update type of `code` parameter in `mockImplementation` function ([f7aab15](https://github.com/zotoio/x-fidelity/commit/f7aab15c67e155da2fedb29a704633629561964a))
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
### Features
|
|
28
|
+
|
|
29
|
+
* centralise the axios client usage in one file and implement exponential backoff ([9a6d000](https://github.com/zotoio/x-fidelity/commit/9a6d00051c92cbe498c429503356f445d64d1685))
|
|
30
|
+
|
|
31
|
+
# [2.3.0](https://github.com/zotoio/x-fidelity/compare/v2.2.0...v2.3.0) (2024-08-20)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
### Bug Fixes
|
|
35
|
+
|
|
36
|
+
* Add clearCache import and ConfigManager import to configServer.ts ([4212096](https://github.com/zotoio/x-fidelity/commit/4212096ea2459e4c55a7c6b396755d72f440ecb6))
|
|
37
|
+
* address SSRF risks in `githubWebhookRoute` ([9b6d64a](https://github.com/zotoio/x-fidelity/commit/9b6d64acf7e49604815b606292890a4b50a11ab8))
|
|
38
|
+
* Clear rule list cache correctly ([3cb17c7](https://github.com/zotoio/x-fidelity/commit/3cb17c7e54e9c8be19b03405a3b13eeaf21bf16c))
|
|
39
|
+
* import missing middleware functions ([fd00a4f](https://github.com/zotoio/x-fidelity/commit/fd00a4f9b4b2dac3ef41782f517186a07ce1c53c))
|
|
40
|
+
* Improve security and mitigate potential SSRF risks in configManager and configServer ([f87ccab](https://github.com/zotoio/x-fidelity/commit/f87ccab24c465d374ef191973d4f3f500ebcca00))
|
|
41
|
+
* move the github webhook route and related update code to separate route file ([4deb57e](https://github.com/zotoio/x-fidelity/commit/4deb57e57f4b95cda757aaa84e8c3f89485e24cd))
|
|
42
|
+
* Properly handle asynchronous operations in configServer.test.ts ([2de6174](https://github.com/zotoio/x-fidelity/commit/2de6174330e518a49c0530455f9bfd4118f648d2))
|
|
43
|
+
* Refactor ConfigManager class ([7f1c2fe](https://github.com/zotoio/x-fidelity/commit/7f1c2fe2e895684145c843615876e3118be095a9))
|
|
44
|
+
* Update configServer to use RuleConfig from ConfigManager ([100c0b3](https://github.com/zotoio/x-fidelity/commit/100c0b301423ca111aa8e452073d3c190a317fbc))
|
|
45
|
+
* Update engineSetup.test.ts to use ConfigManager and setLogPrefix ([c36c64d](https://github.com/zotoio/x-fidelity/commit/c36c64de689a952a500a360dffe8e57605d2dbac))
|
|
46
|
+
* Update error message and fix warning detection test ([9f37bf5](https://github.com/zotoio/x-fidelity/commit/9f37bf502407404ddad355a5ac7d4d8710153b80))
|
|
47
|
+
* Update mock configuration in engineSetup.test.ts ([fd3d7db](https://github.com/zotoio/x-fidelity/commit/fd3d7dbaab3ae51b5c6cbc6d0970f3bf2b2db32c))
|
|
48
|
+
* Update mockParams object to include archetypeConfig property ([b0c9628](https://github.com/zotoio/x-fidelity/commit/b0c9628050643fbc508a087f2387144961a74264))
|
|
49
|
+
* Update rule schema definition ([ed5d87a](https://github.com/zotoio/x-fidelity/commit/ed5d87a3579cd2f6d7eb414207a3cfb9bd571d70))
|
|
50
|
+
* Update ruleSchema to match RuleProperties type ([0f09992](https://github.com/zotoio/x-fidelity/commit/0f099925b14d32d044e5c8fb3583cfec4bb39ae7))
|
|
51
|
+
* Update test configuration for analyzer ([f0b139d](https://github.com/zotoio/x-fidelity/commit/f0b139d7b208553d131d682e19a7b0ccebd5febf))
|
|
52
|
+
* Update test expectation for loadFacts ([ee04ee0](https://github.com/zotoio/x-fidelity/commit/ee04ee0c38883e5c073e6360fe6febed45e42cc6))
|
|
53
|
+
* Update test expectations for loadFacts ([4c57421](https://github.com/zotoio/x-fidelity/commit/4c57421de624622404e6232f450057f200781a2b))
|
|
54
|
+
* Validate and sanitize archetype input in configManager ([3a92119](https://github.com/zotoio/x-fidelity/commit/3a921195beb1ac0da0421aafb443adbf77d83eb2))
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
### Features
|
|
58
|
+
|
|
59
|
+
* add clearcache route ([89e9633](https://github.com/zotoio/x-fidelity/commit/89e96333ae1bb36b4673c09ddc8b69f6b1ed9740))
|
|
60
|
+
* Add file watcher for local config path ([43da2f3](https://github.com/zotoio/x-fidelity/commit/43da2f3b84f2c852426813068487702c4745d549))
|
|
61
|
+
* Add GitHub webhook route ([cab04ae](https://github.com/zotoio/x-fidelity/commit/cab04ae5c7fbba954e9b85c8182ec3595215a8f9))
|
|
62
|
+
* Add GitHub webhook route to handle archetype or rule config updates ([5af3d63](https://github.com/zotoio/x-fidelity/commit/5af3d63d4d9ef6f3f48a5be4001d3f28f1522d6c))
|
|
63
|
+
* Add high-value unit tests for utility functions ([f90d5e2](https://github.com/zotoio/x-fidelity/commit/f90d5e218cc8c5743515744fc9584801c3003398))
|
|
64
|
+
* Add input validation for URL parameters and telemetry data ([77bdfaa](https://github.com/zotoio/x-fidelity/commit/77bdfaa4e35c34e62c341fca6f87db46726db993))
|
|
65
|
+
* Add support for additional properties in rule schema ([98826e5](https://github.com/zotoio/x-fidelity/commit/98826e5edad1a443d6299a1ad3b970517c384783))
|
|
66
|
+
* add viewcache route ([1fa105c](https://github.com/zotoio/x-fidelity/commit/1fa105c6c29ef05b8eb5312c638785dd5d56af07))
|
|
67
|
+
* Create comprehensive unit test file for engineSetup.ts ([50556ce](https://github.com/zotoio/x-fidelity/commit/50556ce257cb579ef856b74a012b986b81490f2b))
|
|
68
|
+
* Implement GitHub webhook to update local config ([351fbf0](https://github.com/zotoio/x-fidelity/commit/351fbf022100f8e9acc3734b291afdac9057e386))
|
|
69
|
+
* Implement server routes and middleware ([3de18a6](https://github.com/zotoio/x-fidelity/commit/3de18a6cab08a26ecd51f7dc9148da5fee93aeba))
|
|
70
|
+
* load all RuleConfig for a given archetype into the ExecutionConfig ([a122c52](https://github.com/zotoio/x-fidelity/commit/a122c52986adeadeec9085b5c94bfd5e142e80d8))
|
|
71
|
+
* move the configServer features related to caching into a new file ([95a9908](https://github.com/zotoio/x-fidelity/commit/95a9908c97878b062337e100b37ae1d4919b53e5))
|
|
72
|
+
* **rules:** github hook to refresh config ([2485fbe](https://github.com/zotoio/x-fidelity/commit/2485fbe36a9f5102fe815209e0961f604b0e6f30))
|
|
73
|
+
* **rules:** optimise loading of rules, and filesystem watcher for server ([6e6c5ac](https://github.com/zotoio/x-fidelity/commit/6e6c5ac0a784ab76b9d3ec476de580225932b443))
|
|
74
|
+
* update configserver to use new route files ([eda8240](https://github.com/zotoio/x-fidelity/commit/eda8240a09073612f060d65494d4973b1b170c94))
|
|
75
|
+
* Update rule schema to improve flexibility and compatibility ([989bdf6](https://github.com/zotoio/x-fidelity/commit/989bdf64ead3148a366c046f6c0e883d6b1b1109))
|
|
76
|
+
|
|
1
77
|
# [2.2.0](https://github.com/zotoio/x-fidelity/compare/v2.1.0...v2.2.0) (2024-08-20)
|
|
2
78
|
|
|
3
79
|
|
|
@@ -17,7 +17,6 @@ const openaiAnalysisFacts_1 = require("../../facts/openaiAnalysisFacts");
|
|
|
17
17
|
const rules_1 = require("../../rules");
|
|
18
18
|
const operators_1 = require("../../operators");
|
|
19
19
|
const facts_1 = require("../../facts");
|
|
20
|
-
const archetypes_1 = require("../../archetypes");
|
|
21
20
|
const configManager_1 = require("../../utils/configManager");
|
|
22
21
|
const telemetry_1 = require("../../utils/telemetry");
|
|
23
22
|
const openaiUtils_1 = require("../../utils/openaiUtils");
|
|
@@ -64,8 +63,19 @@ describe('analyzeCodebase', () => {
|
|
|
64
63
|
beforeEach(() => {
|
|
65
64
|
jest.clearAllMocks();
|
|
66
65
|
configManager_1.ConfigManager.getConfig.mockResolvedValue({
|
|
67
|
-
archetype:
|
|
68
|
-
|
|
66
|
+
archetype: {
|
|
67
|
+
name: 'test-archetype',
|
|
68
|
+
rules: ['rule1'],
|
|
69
|
+
operators: ['operator1'],
|
|
70
|
+
facts: ['fact1'],
|
|
71
|
+
config: {
|
|
72
|
+
minimumDependencyVersions: {},
|
|
73
|
+
standardStructure: {},
|
|
74
|
+
blacklistPatterns: [],
|
|
75
|
+
whitelistPatterns: []
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
rules: [{ name: 'rule1', conditions: { all: [] }, event: { type: 'test', params: {} } }],
|
|
69
79
|
cliOptions: {}
|
|
70
80
|
});
|
|
71
81
|
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
@@ -104,9 +114,8 @@ describe('analyzeCodebase', () => {
|
|
|
104
114
|
});
|
|
105
115
|
expect(repoFilesystemFacts_1.collectRepoFileData).toHaveBeenCalledWith('mockRepoPath', expect.any(Object));
|
|
106
116
|
expect(repoDependencyFacts_1.getDependencyVersionFacts).toHaveBeenCalledWith(expect.any(Object));
|
|
107
|
-
expect(
|
|
108
|
-
expect(
|
|
109
|
-
expect(facts_1.loadFacts).toHaveBeenCalledWith(['mockFact']);
|
|
117
|
+
expect(operators_1.loadOperators).toHaveBeenCalledWith(['operator1']);
|
|
118
|
+
expect(facts_1.loadFacts).toHaveBeenCalledWith(['fact1']);
|
|
110
119
|
expect(engineRunMock).toHaveBeenCalledTimes(mockFileData.length);
|
|
111
120
|
expect(results).toEqual({
|
|
112
121
|
XFI_RESULT: expect.objectContaining({
|
|
@@ -157,9 +166,8 @@ describe('analyzeCodebase', () => {
|
|
|
157
166
|
});
|
|
158
167
|
expect(repoFilesystemFacts_1.collectRepoFileData).toHaveBeenCalledWith('mockRepoPath', expect.any(Object));
|
|
159
168
|
expect(repoDependencyFacts_1.getDependencyVersionFacts).toHaveBeenCalled();
|
|
160
|
-
expect(
|
|
161
|
-
expect(
|
|
162
|
-
expect(facts_1.loadFacts).toHaveBeenCalledWith(['mockFact']);
|
|
169
|
+
expect(operators_1.loadOperators).toHaveBeenCalledWith(['operator1']);
|
|
170
|
+
expect(facts_1.loadFacts).toHaveBeenCalledWith(['fact1']);
|
|
163
171
|
expect(engineRunMock).toHaveBeenCalledTimes(mockFileData.length);
|
|
164
172
|
expect(results).toEqual({
|
|
165
173
|
XFI_RESULT: expect.objectContaining({
|
|
@@ -14,12 +14,11 @@ const json_rules_engine_1 = require("json-rules-engine");
|
|
|
14
14
|
const logger_1 = require("../../utils/logger");
|
|
15
15
|
const operators_1 = require("../../operators");
|
|
16
16
|
const facts_1 = require("../../facts");
|
|
17
|
-
const rules_1 = require("../../rules");
|
|
18
|
-
const cli_1 = require("../../core/cli");
|
|
19
17
|
const telemetry_1 = require("../../utils/telemetry");
|
|
18
|
+
const configManager_1 = require("../../utils/configManager");
|
|
20
19
|
function setupEngine(params) {
|
|
21
20
|
return __awaiter(this, void 0, void 0, function* () {
|
|
22
|
-
const { archetypeConfig, archetype, executionLogPrefix
|
|
21
|
+
const { archetypeConfig, archetype, executionLogPrefix } = params;
|
|
23
22
|
const engine = new json_rules_engine_1.Engine([], { replaceFactsInEventParams: true, allowUndefinedFacts: true });
|
|
24
23
|
// Add operators to engine
|
|
25
24
|
logger_1.logger.info(`=== loading custom operators..`);
|
|
@@ -33,21 +32,21 @@ function setupEngine(params) {
|
|
|
33
32
|
});
|
|
34
33
|
// Add rules to engine
|
|
35
34
|
logger_1.logger.info(`=== loading json rules..`);
|
|
36
|
-
const
|
|
37
|
-
logger_1.logger.debug(rules);
|
|
38
|
-
rules.forEach((rule) => {
|
|
35
|
+
const config = yield configManager_1.ConfigManager.getConfig({ archetype, logPrefix: executionLogPrefix });
|
|
36
|
+
logger_1.logger.debug(config.rules);
|
|
37
|
+
config.rules.forEach((rule) => {
|
|
39
38
|
try {
|
|
40
39
|
logger_1.logger.info(`adding rule: ${rule === null || rule === void 0 ? void 0 : rule.name}`);
|
|
41
40
|
engine.addRule(rule);
|
|
42
41
|
}
|
|
43
42
|
catch (e) {
|
|
44
|
-
|
|
43
|
+
logger_1.logger.error(`Error loading rule: ${rule === null || rule === void 0 ? void 0 : rule.name}`);
|
|
45
44
|
logger_1.logger.error(e.message);
|
|
46
45
|
}
|
|
47
46
|
});
|
|
48
47
|
engine.on('success', (_a) => __awaiter(this, [_a], void 0, function* ({ type, params }) {
|
|
49
48
|
if (type === 'warning') {
|
|
50
|
-
logger_1.logger.warn(`warning detected: ${JSON.stringify(params)}
|
|
49
|
+
logger_1.logger.warn(`warning detected: ${JSON.stringify(params)}`);
|
|
51
50
|
yield (0, telemetry_1.sendTelemetry)({
|
|
52
51
|
eventType: 'warning',
|
|
53
52
|
metadata: Object.assign({ archetype, repoPath: '' }, params),
|
|
@@ -55,7 +54,7 @@ function setupEngine(params) {
|
|
|
55
54
|
}, executionLogPrefix);
|
|
56
55
|
}
|
|
57
56
|
if (type === 'fatality') {
|
|
58
|
-
logger_1.logger.error(`fatality detected: ${JSON.stringify(params)}
|
|
57
|
+
logger_1.logger.error(`fatality detected: ${JSON.stringify(params)}`);
|
|
59
58
|
yield (0, telemetry_1.sendTelemetry)({
|
|
60
59
|
eventType: 'fatality',
|
|
61
60
|
metadata: Object.assign({ archetype, repoPath: '' }, params),
|
|
@@ -13,127 +13,156 @@ const engineSetup_1 = require("./engineSetup");
|
|
|
13
13
|
const json_rules_engine_1 = require("json-rules-engine");
|
|
14
14
|
const operators_1 = require("../../operators");
|
|
15
15
|
const facts_1 = require("../../facts");
|
|
16
|
-
const rules_1 = require("../../rules");
|
|
17
16
|
const telemetry_1 = require("../../utils/telemetry");
|
|
18
|
-
const
|
|
19
|
-
const
|
|
17
|
+
const configManager_1 = require("../../utils/configManager");
|
|
18
|
+
const logger_1 = require("../../utils/logger");
|
|
20
19
|
jest.mock('json-rules-engine');
|
|
21
20
|
jest.mock('../../operators');
|
|
22
21
|
jest.mock('../../facts');
|
|
23
|
-
jest.mock('../../rules');
|
|
24
22
|
jest.mock('../../utils/telemetry');
|
|
25
|
-
jest.mock('../../utils/
|
|
26
|
-
jest.mock('../../utils/logger'
|
|
27
|
-
logger: {
|
|
28
|
-
info: jest.fn(),
|
|
29
|
-
debug: jest.fn(),
|
|
30
|
-
error: jest.fn(),
|
|
31
|
-
warn: jest.fn(),
|
|
32
|
-
},
|
|
33
|
-
}));
|
|
23
|
+
jest.mock('../../utils/configManager');
|
|
24
|
+
jest.mock('../../utils/logger');
|
|
34
25
|
describe('setupEngine', () => {
|
|
35
26
|
const mockArchetypeConfig = {
|
|
36
27
|
name: 'test-archetype',
|
|
37
|
-
rules: ['rule1'],
|
|
38
|
-
operators: ['operator1'],
|
|
39
|
-
facts: ['fact1'],
|
|
28
|
+
rules: ['rule1', 'rule2'],
|
|
29
|
+
operators: ['operator1', 'operator2'],
|
|
30
|
+
facts: ['fact1', 'fact2'],
|
|
40
31
|
config: {
|
|
41
32
|
minimumDependencyVersions: {},
|
|
42
33
|
standardStructure: {},
|
|
43
34
|
blacklistPatterns: [],
|
|
44
35
|
whitelistPatterns: []
|
|
45
|
-
}
|
|
36
|
+
}
|
|
46
37
|
};
|
|
47
38
|
const mockParams = {
|
|
48
39
|
archetypeConfig: mockArchetypeConfig,
|
|
49
40
|
archetype: 'test-archetype',
|
|
50
|
-
configManager:
|
|
41
|
+
configManager: configManager_1.ConfigManager,
|
|
51
42
|
executionLogPrefix: 'test-prefix',
|
|
52
|
-
localConfigPath: '/test/path'
|
|
43
|
+
localConfigPath: '/test/path'
|
|
53
44
|
};
|
|
54
45
|
beforeEach(() => {
|
|
55
46
|
jest.clearAllMocks();
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
};
|
|
65
|
-
json_rules_engine_1.Engine.mockImplementation(() => mockEngine);
|
|
66
|
-
operators_1.loadOperators.mockResolvedValue([{ name: 'operator1', fn: jest.fn() }]);
|
|
67
|
-
facts_1.loadFacts.mockResolvedValue([{ name: 'fact1', fn: jest.fn() }]);
|
|
68
|
-
rules_1.loadRules.mockResolvedValue([{ name: 'rule1' }]);
|
|
69
|
-
openaiUtils_1.isOpenAIEnabled.mockReturnValue(true);
|
|
70
|
-
yield (0, engineSetup_1.setupEngine)(mockParams);
|
|
71
|
-
expect(json_rules_engine_1.Engine).toHaveBeenCalled();
|
|
72
|
-
expect(operators_1.loadOperators).toHaveBeenCalledWith(['operator1']);
|
|
73
|
-
expect(facts_1.loadFacts).toHaveBeenCalledWith(['fact1']);
|
|
74
|
-
expect(rules_1.loadRules).toHaveBeenCalledWith(expect.objectContaining({
|
|
75
|
-
archetype: 'test-archetype',
|
|
76
|
-
ruleNames: ['rule1'],
|
|
77
|
-
}));
|
|
78
|
-
expect(mockEngine.addOperator).toHaveBeenCalled();
|
|
79
|
-
expect(mockEngine.addRule).toHaveBeenCalled();
|
|
80
|
-
expect(mockEngine.addFact).toHaveBeenCalled();
|
|
81
|
-
expect(mockEngine.on).toHaveBeenCalledWith('success', expect.any(Function));
|
|
82
|
-
}));
|
|
83
|
-
it('should not add OpenAI-related operators and facts when OpenAI is disabled', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
84
|
-
cli_1.options.openai = false;
|
|
85
|
-
process.env.OPENAI_API_KEY = '';
|
|
86
|
-
const mockEngine = {
|
|
87
|
-
addOperator: jest.fn(),
|
|
88
|
-
addRule: jest.fn(),
|
|
89
|
-
addFact: jest.fn(),
|
|
90
|
-
on: jest.fn(),
|
|
91
|
-
};
|
|
92
|
-
json_rules_engine_1.Engine.mockImplementation(() => mockEngine);
|
|
47
|
+
configManager_1.ConfigManager.getConfig.mockResolvedValue({
|
|
48
|
+
archetype: mockArchetypeConfig,
|
|
49
|
+
rules: [
|
|
50
|
+
{ name: 'rule1', conditions: { all: [] }, event: { type: 'test', params: {} } },
|
|
51
|
+
{ name: 'rule2', conditions: { all: [] }, event: { type: 'test', params: {} } }
|
|
52
|
+
],
|
|
53
|
+
cliOptions: {}
|
|
54
|
+
});
|
|
93
55
|
operators_1.loadOperators.mockResolvedValue([
|
|
94
56
|
{ name: 'operator1', fn: jest.fn() },
|
|
95
|
-
{ name: '
|
|
57
|
+
{ name: 'operator2', fn: jest.fn() }
|
|
96
58
|
]);
|
|
97
59
|
facts_1.loadFacts.mockResolvedValue([
|
|
98
60
|
{ name: 'fact1', fn: jest.fn() },
|
|
99
|
-
{ name: '
|
|
61
|
+
{ name: 'fact2', fn: jest.fn() }
|
|
100
62
|
]);
|
|
101
|
-
|
|
102
|
-
|
|
63
|
+
});
|
|
64
|
+
it('should create and configure an engine instance', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
65
|
+
const mockAddOperator = jest.fn();
|
|
66
|
+
const mockAddRule = jest.fn();
|
|
67
|
+
const mockAddFact = jest.fn();
|
|
68
|
+
const mockOn = jest.fn();
|
|
69
|
+
json_rules_engine_1.Engine.mockImplementation(() => ({
|
|
70
|
+
addOperator: mockAddOperator,
|
|
71
|
+
addRule: mockAddRule,
|
|
72
|
+
addFact: mockAddFact,
|
|
73
|
+
on: mockOn
|
|
74
|
+
}));
|
|
75
|
+
const engine = yield (0, engineSetup_1.setupEngine)(mockParams);
|
|
76
|
+
expect(json_rules_engine_1.Engine).toHaveBeenCalledWith([], { replaceFactsInEventParams: true, allowUndefinedFacts: true });
|
|
77
|
+
expect(operators_1.loadOperators).toHaveBeenCalledWith(['operator1', 'operator2']);
|
|
78
|
+
expect(facts_1.loadFacts).toHaveBeenCalledWith(['fact1', 'fact2']);
|
|
79
|
+
expect(configManager_1.ConfigManager.getConfig).toHaveBeenCalledWith({ archetype: 'test-archetype', logPrefix: 'test-prefix' });
|
|
80
|
+
expect(mockAddOperator).toHaveBeenCalledTimes(2);
|
|
81
|
+
expect(mockAddRule).toHaveBeenCalledTimes(2);
|
|
82
|
+
expect(mockAddFact).toHaveBeenCalledTimes(2);
|
|
83
|
+
expect(mockOn).toHaveBeenCalledTimes(1);
|
|
84
|
+
expect(engine).toBeDefined();
|
|
85
|
+
}));
|
|
86
|
+
it('should handle errors when loading rules', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
87
|
+
const mockAddRule = jest.fn().mockImplementationOnce(() => {
|
|
88
|
+
throw new Error('Rule loading error');
|
|
89
|
+
});
|
|
90
|
+
json_rules_engine_1.Engine.mockImplementation(() => ({
|
|
91
|
+
addOperator: jest.fn(),
|
|
92
|
+
addRule: mockAddRule,
|
|
93
|
+
addFact: jest.fn(),
|
|
94
|
+
on: jest.fn()
|
|
95
|
+
}));
|
|
103
96
|
yield (0, engineSetup_1.setupEngine)(mockParams);
|
|
104
|
-
expect(
|
|
105
|
-
expect(
|
|
106
|
-
expect(mockEngine.addOperator).not.toHaveBeenCalledWith('openaiOperator', expect.any(Function));
|
|
107
|
-
expect(mockEngine.addFact).not.toHaveBeenCalledWith('openaiAnalysis', expect.any(Function));
|
|
97
|
+
expect(mockAddRule).toHaveBeenCalledTimes(2);
|
|
98
|
+
expect(logger_1.logger.error).toHaveBeenCalledWith('Rule loading error');
|
|
108
99
|
}));
|
|
109
|
-
it('should
|
|
110
|
-
const
|
|
100
|
+
it('should set up event listeners for success events', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
101
|
+
const mockOn = jest.fn();
|
|
102
|
+
json_rules_engine_1.Engine.mockImplementation(() => ({
|
|
111
103
|
addOperator: jest.fn(),
|
|
112
104
|
addRule: jest.fn(),
|
|
113
105
|
addFact: jest.fn(),
|
|
114
|
-
on:
|
|
115
|
-
};
|
|
116
|
-
json_rules_engine_1.Engine.mockImplementation(() => mockEngine);
|
|
117
|
-
operators_1.loadOperators.mockResolvedValue([{ name: 'operator1', fn: jest.fn() }]);
|
|
118
|
-
facts_1.loadFacts.mockResolvedValue([{ name: 'fact1', fn: jest.fn() }]);
|
|
119
|
-
rules_1.loadRules.mockResolvedValue([{ name: 'rule1' }]);
|
|
106
|
+
on: mockOn
|
|
107
|
+
}));
|
|
120
108
|
yield (0, engineSetup_1.setupEngine)(mockParams);
|
|
121
|
-
|
|
109
|
+
expect(mockOn).toHaveBeenCalledWith('success', expect.any(Function));
|
|
122
110
|
// Test warning event
|
|
123
|
-
|
|
111
|
+
const warningCallback = mockOn.mock.calls[0][1];
|
|
112
|
+
yield warningCallback({ type: 'warning', params: { message: 'Test warning' } });
|
|
113
|
+
expect(logger_1.logger.warn).toHaveBeenCalledWith('warning detected: {"message":"Test warning"}');
|
|
124
114
|
expect(telemetry_1.sendTelemetry).toHaveBeenCalledWith(expect.objectContaining({
|
|
125
115
|
eventType: 'warning',
|
|
126
116
|
metadata: expect.objectContaining({
|
|
127
117
|
archetype: 'test-archetype',
|
|
128
|
-
|
|
118
|
+
message: 'Test warning'
|
|
119
|
+
})
|
|
129
120
|
}), 'test-prefix');
|
|
130
121
|
// Test fatality event
|
|
131
|
-
yield
|
|
122
|
+
yield warningCallback({ type: 'fatality', params: { message: 'Test fatality' } });
|
|
123
|
+
expect(logger_1.logger.error).toHaveBeenCalledWith('fatality detected: {"message":"Test fatality"}');
|
|
132
124
|
expect(telemetry_1.sendTelemetry).toHaveBeenCalledWith(expect.objectContaining({
|
|
133
125
|
eventType: 'fatality',
|
|
134
126
|
metadata: expect.objectContaining({
|
|
135
127
|
archetype: 'test-archetype',
|
|
136
|
-
|
|
128
|
+
message: 'Test fatality'
|
|
129
|
+
})
|
|
137
130
|
}), 'test-prefix');
|
|
138
131
|
}));
|
|
132
|
+
it('should not add OpenAI-related facts when OpenAI is not enabled', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
133
|
+
process.env.OPENAI_API_KEY = '';
|
|
134
|
+
const mockAddFact = jest.fn();
|
|
135
|
+
json_rules_engine_1.Engine.mockImplementation(() => ({
|
|
136
|
+
addOperator: jest.fn(),
|
|
137
|
+
addRule: jest.fn(),
|
|
138
|
+
addFact: mockAddFact,
|
|
139
|
+
on: jest.fn()
|
|
140
|
+
}));
|
|
141
|
+
facts_1.loadFacts.mockResolvedValue([
|
|
142
|
+
{ name: 'fact1', fn: jest.fn() },
|
|
143
|
+
{ name: 'openaiAnalysis', fn: jest.fn() }
|
|
144
|
+
]);
|
|
145
|
+
yield (0, engineSetup_1.setupEngine)(mockParams);
|
|
146
|
+
expect(mockAddFact).toHaveBeenCalledTimes(1);
|
|
147
|
+
expect(mockAddFact).toHaveBeenCalledWith('fact1', expect.any(Function));
|
|
148
|
+
expect(mockAddFact).not.toHaveBeenCalledWith('openaiAnalysis', expect.any(Function));
|
|
149
|
+
}));
|
|
150
|
+
it('should add OpenAI-related facts when OpenAI is enabled', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
151
|
+
process.env.OPENAI_API_KEY = 'test-key';
|
|
152
|
+
const mockAddFact = jest.fn();
|
|
153
|
+
json_rules_engine_1.Engine.mockImplementation(() => ({
|
|
154
|
+
addOperator: jest.fn(),
|
|
155
|
+
addRule: jest.fn(),
|
|
156
|
+
addFact: mockAddFact,
|
|
157
|
+
on: jest.fn()
|
|
158
|
+
}));
|
|
159
|
+
facts_1.loadFacts.mockResolvedValue([
|
|
160
|
+
{ name: 'fact1', fn: jest.fn() },
|
|
161
|
+
{ name: 'openaiAnalysis', fn: jest.fn() }
|
|
162
|
+
]);
|
|
163
|
+
yield (0, engineSetup_1.setupEngine)(mockParams);
|
|
164
|
+
expect(mockAddFact).toHaveBeenCalledTimes(2);
|
|
165
|
+
expect(mockAddFact).toHaveBeenCalledWith('fact1', expect.any(Function));
|
|
166
|
+
expect(mockAddFact).toHaveBeenCalledWith('openaiAnalysis', expect.any(Function));
|
|
167
|
+
}));
|
|
139
168
|
});
|
package/dist/index.js
CHANGED
|
@@ -13,6 +13,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
13
13
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
14
14
|
};
|
|
15
15
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
16
|
+
exports.main = main;
|
|
16
17
|
const logger_1 = require("./utils/logger");
|
|
17
18
|
const prettyjson_1 = __importDefault(require("prettyjson"));
|
|
18
19
|
const cli_1 = require("./core/cli");
|
|
@@ -21,18 +22,32 @@ const configServer_1 = require("./server/configServer");
|
|
|
21
22
|
const telemetry_1 = require("./utils/telemetry");
|
|
22
23
|
const executionLogPrefix = (0, logger_1.generateLogPrefix)();
|
|
23
24
|
(0, logger_1.setLogPrefix)(executionLogPrefix);
|
|
25
|
+
// Function to handle errors and send telemetry
|
|
26
|
+
const handleError = (error) => __awaiter(void 0, void 0, void 0, function* () {
|
|
27
|
+
yield (0, telemetry_1.sendTelemetry)({
|
|
28
|
+
eventType: 'execution failure',
|
|
29
|
+
metadata: {
|
|
30
|
+
archetype: cli_1.options.archetype,
|
|
31
|
+
repoPath: cli_1.options.dir,
|
|
32
|
+
options: cli_1.options,
|
|
33
|
+
errorMessage: error.message
|
|
34
|
+
},
|
|
35
|
+
timestamp: new Date().toISOString()
|
|
36
|
+
}, executionLogPrefix);
|
|
37
|
+
logger_1.logger.error(JSON.stringify(error));
|
|
38
|
+
});
|
|
24
39
|
const outcomeMessage = (message) => `\n
|
|
25
40
|
==========================================================================
|
|
26
41
|
${message}
|
|
27
42
|
==========================================================================`;
|
|
28
|
-
logger_1.logger.debug(`startup options: ${cli_1.options}`);
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
43
|
+
logger_1.logger.debug(`startup options: ${JSON.stringify(cli_1.options)}`);
|
|
44
|
+
function main() {
|
|
45
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
46
|
+
try {
|
|
47
|
+
if (cli_1.options.mode === 'server') {
|
|
48
|
+
yield (0, configServer_1.startServer)({ customPort: cli_1.options.port, executionLogPrefix });
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
36
51
|
const resultMetadata = yield (0, analyzer_1.analyzeCodebase)({
|
|
37
52
|
repoPath: cli_1.options.dir,
|
|
38
53
|
archetype: cli_1.options.archetype,
|
|
@@ -43,40 +58,36 @@ logger_1.logger.debug(`startup options: ${cli_1.options}`);
|
|
|
43
58
|
// if results are found, there were issues found in the codebase
|
|
44
59
|
if (resultMetadata.XFI_RESULT.totalIssues > 0) {
|
|
45
60
|
logger_1.logger.warn(`WARNING: lo-fi attributes detected in codebase. ${resultMetadata.XFI_RESULT.warningCount} are warnings, ${resultMetadata.XFI_RESULT.fatalityCount} are fatal.`);
|
|
46
|
-
logger_1.logger.warn(JSON.stringify(
|
|
61
|
+
logger_1.logger.warn(JSON.stringify(resultMetadata));
|
|
62
|
+
logger_1.logger.warn(`\n${prettyjson_1.default.render(resultMetadata)}\n\n`);
|
|
47
63
|
if (resultMetadata.XFI_RESULT.fatalityCount > 0) {
|
|
48
64
|
logger_1.logger.error(outcomeMessage(`THERE WERE ${resultMetadata.XFI_RESULT.fatalityCount} FATAL ERRORS DETECTED TO BE IMMEDIATELY ADDRESSED!`));
|
|
49
|
-
|
|
65
|
+
logger_1.logger.on('finish', function () {
|
|
66
|
+
process.exit(1);
|
|
67
|
+
});
|
|
68
|
+
logger_1.logger.error(`\n${prettyjson_1.default.render(resultMetadata.XFI_RESULT.issueDetails)}\n\n`);
|
|
69
|
+
logger_1.logger.error(outcomeMessage(`THERE WERE ${resultMetadata.XFI_RESULT.fatalityCount} FATAL ERRORS DETECTED TO BE IMMEDIATELY ADDRESSED!`));
|
|
70
|
+
logger_1.logger.end();
|
|
50
71
|
}
|
|
51
72
|
else {
|
|
52
73
|
logger_1.logger.warn(outcomeMessage('No fatal errors were found, however please review the following warnings.'));
|
|
74
|
+
logger_1.logger.warn(`\n${prettyjson_1.default.render(resultMetadata.XFI_RESULT.issueDetails)}\n\n`);
|
|
75
|
+
logger_1.logger.warn(outcomeMessage('No fatal errors were found, however please review the above warnings.'));
|
|
53
76
|
}
|
|
54
|
-
console.log(`\n${prettyjson_1.default.render(resultMetadata.XFI_RESULT.issueDetails)}\n\n`);
|
|
55
77
|
}
|
|
56
78
|
else {
|
|
57
79
|
logger_1.logger.info(outcomeMessage('SUCCESS! hi-fi codebase detected.'));
|
|
80
|
+
logger_1.logger.info(JSON.stringify(resultMetadata));
|
|
81
|
+
logger_1.logger.info(`\n${prettyjson_1.default.render(resultMetadata)}\n\n`);
|
|
82
|
+
logger_1.logger.info(outcomeMessage('SUCCESS! hi-fi codebase detected.'));
|
|
58
83
|
}
|
|
59
|
-
}
|
|
60
|
-
// analyzeCodebase failed
|
|
61
|
-
logger_1.logger.error(outcomeMessage('FATAL: execution failed!'));
|
|
62
|
-
logger_1.logger.error(e.message);
|
|
63
|
-
logger_1.logger.error(`\n${prettyjson_1.default.render(JSON.parse(e.message))}`);
|
|
64
|
-
setTimeout(() => process.exit(1), 1000);
|
|
65
|
-
});
|
|
84
|
+
}
|
|
66
85
|
}
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
errorMessage: e.message
|
|
76
|
-
},
|
|
77
|
-
timestamp: new Date().toISOString()
|
|
78
|
-
}, executionLogPrefix);
|
|
79
|
-
logger_1.logger.error(JSON.stringify(e));
|
|
80
|
-
setTimeout(() => process.exit(1), 1000);
|
|
81
|
-
}
|
|
82
|
-
}))();
|
|
86
|
+
catch (e) {
|
|
87
|
+
yield handleError(e);
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
if (require.main === module) {
|
|
92
|
+
main();
|
|
93
|
+
}
|