x-fidelity 3.17.1 → 3.19.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/.xfi-config.json +4 -1
- package/CHANGELOG.md +55 -0
- package/dist/core/engine/engineRunner.js +20 -11
- package/dist/core/engine/engineSetup.js +36 -3
- package/dist/facts/repoDependencyFacts.test.js +33 -4
- package/dist/index.test.js +15 -1
- package/dist/plugins/xfiPluginAst/facts/codeRhythmFact.d.ts +5 -0
- package/dist/plugins/xfiPluginAst/facts/codeRhythmFact.js +1 -5
- package/dist/plugins/xfiPluginAst/facts/codeRhythmFact.test.js +8 -8
- package/dist/types/typeDefs.d.ts +6 -1
- package/dist/utils/logger.js +1 -5
- package/dist/utils/repoXFIConfigLoader.d.ts +1 -0
- package/dist/utils/repoXFIConfigLoader.js +202 -24
- package/dist/utils/repoXFIConfigLoader.test.d.ts +1 -0
- package/dist/utils/repoXFIConfigLoader.test.js +88 -0
- package/package.json +2 -1
- package/src/core/engine/engineRunner.ts +18 -8
- package/src/core/engine/engineSetup.ts +41 -3
- package/src/facts/repoDependencyFacts.test.ts +38 -5
- package/src/index.test.ts +15 -1
- package/src/plugins/xfiPluginAst/facts/codeRhythmFact.test.ts +11 -11
- package/src/plugins/xfiPluginAst/facts/codeRhythmFact.ts +3 -7
- package/src/types/typeDefs.ts +7 -1
- package/src/utils/logger.ts +1 -5
- package/src/utils/repoXFIConfigLoader.test.ts +98 -0
- package/src/utils/repoXFIConfigLoader.ts +175 -25
- package/website/docs/local-configuration.md +153 -23
package/.xfi-config.json
CHANGED
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,58 @@
|
|
|
1
|
+
# [3.19.0](https://github.com/zotoio/x-fidelity/compare/v3.18.0...v3.19.0) (2025-03-25)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* add non-null assertion for additionalRules array access ([9e7ee91](https://github.com/zotoio/x-fidelity/commit/9e7ee9117bd336c016bdeb5c1c429d6c59388fa1))
|
|
7
|
+
* correct try-catch block structure in config loader ([dc6fd2c](https://github.com/zotoio/x-fidelity/commit/dc6fd2c7683c2694381020e9ac9ffd6032dbb2da))
|
|
8
|
+
* correct try/catch block structure in repoXFIConfigLoader ([82ddb04](https://github.com/zotoio/x-fidelity/commit/82ddb04f4f9efa915386a213fad61dd55c923553))
|
|
9
|
+
* correct TypeScript type errors in repoXFIConfigLoader tests ([4100e06](https://github.com/zotoio/x-fidelity/commit/4100e067e71b4154b14da299c4760950e7ebaa8b))
|
|
10
|
+
* ensure inline rules are properly processed and assigned ([7ea7661](https://github.com/zotoio/x-fidelity/commit/7ea7661a962af83423f20270c1f27bb859573ef4))
|
|
11
|
+
* handle undefined sensitiveFileFalsePositives in config loader ([4f940cf](https://github.com/zotoio/x-fidelity/commit/4f940cf7677a29b5e1c611531b0294f1970a15d3))
|
|
12
|
+
* improve error message for missing rule files ([c271700](https://github.com/zotoio/x-fidelity/commit/c271700fa35bd9c43a68f996a7c1f29790bbab53))
|
|
13
|
+
* improve file path handling in repoXFIConfigLoader tests ([93a0289](https://github.com/zotoio/x-fidelity/commit/93a02891528852192d0d7c1b86f9b441f1c66c75))
|
|
14
|
+
* improve file system mocking in config loader test ([f0cfc25](https://github.com/zotoio/x-fidelity/commit/f0cfc25d1a3cfc9207b65078c2bc26b8c95cf0a0))
|
|
15
|
+
* improve inline rule validation and logging in config loader ([625a4aa](https://github.com/zotoio/x-fidelity/commit/625a4aae86220f6ed856f8ea3679b17e48f75cfc))
|
|
16
|
+
* improve test mocks for fs.promises and jsonSchemas validation ([8b1def8](https://github.com/zotoio/x-fidelity/commit/8b1def8bf577a7ad1d4314fe4787b8e7b6570264))
|
|
17
|
+
* prevent duplicate rule registration in engine setup ([a9e2956](https://github.com/zotoio/x-fidelity/commit/a9e295666dc41079f31074164a6c60babae4cc96))
|
|
18
|
+
* remove duplicate code blocks and fix return statements in config loader ([414e500](https://github.com/zotoio/x-fidelity/commit/414e5001b2a0329ce88f519a2d5563f815772154))
|
|
19
|
+
* Replace continue with return in rule registration loop ([44ef9fd](https://github.com/zotoio/x-fidelity/commit/44ef9fd92be577043d1cf04585841e3ded5bf42f))
|
|
20
|
+
* restructure rule loading logic and improve error handling ([ff8b6e6](https://github.com/zotoio/x-fidelity/commit/ff8b6e698d89b7adb99b294eec048c340d4976ac))
|
|
21
|
+
* restructure try/catch blocks and improve error handling in config loader ([a0f76bb](https://github.com/zotoio/x-fidelity/commit/a0f76bbabfc29c172fecf7d1d0691358ff44226b))
|
|
22
|
+
* simplify pino file transport configuration ([c99bf26](https://github.com/zotoio/x-fidelity/commit/c99bf2671abd96bf5b77d09ce3941852609dfaac))
|
|
23
|
+
* **tests:** update docs and tests for .xfi-config.json ([cc6e11e](https://github.com/zotoio/x-fidelity/commit/cc6e11e24fbb94c8cca34147026c2072db918ba3))
|
|
24
|
+
* update fs mock to include promises property in test ([1a50355](https://github.com/zotoio/x-fidelity/commit/1a50355aec723fa4cfd0ee4403b07fccd218303b))
|
|
25
|
+
* update glob import to use dynamic import pattern ([2677260](https://github.com/zotoio/x-fidelity/commit/2677260d854728195559798d66ccd1a94ca8a476))
|
|
26
|
+
* update glob import to use named import syntax ([c290016](https://github.com/zotoio/x-fidelity/commit/c2900168c270edd38bea766baa440baab8a16959))
|
|
27
|
+
* update test mocks to handle file paths correctly ([4407c1e](https://github.com/zotoio/x-fidelity/commit/4407c1e39a433f8c9e7bc1b7cab1d3781447acc3))
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
### Features
|
|
31
|
+
|
|
32
|
+
* Add CLI options import to repo config loader ([26b97bc](https://github.com/zotoio/x-fidelity/commit/26b97bcbe80438debd1a07f3b22076ff9398f933))
|
|
33
|
+
* add deduplication for rules and failure results ([169c035](https://github.com/zotoio/x-fidelity/commit/169c0351de2390bb9f22823c6a64110306caf32e))
|
|
34
|
+
* add reference to sensitiveLogging-iterative rule ([fea3d28](https://github.com/zotoio/x-fidelity/commit/fea3d2817018c0b7e328cec539a1ac00a1cd48b6))
|
|
35
|
+
* add support for loading additional rules from repo config ([7abac68](https://github.com/zotoio/x-fidelity/commit/7abac6891076f2eb0d47b3e2a08470241ac0b3fe))
|
|
36
|
+
* add wildcard support and flexible rule loading patterns ([a2d19c2](https://github.com/zotoio/x-fidelity/commit/a2d19c2bb5ba38026ba3dce6ba0be17039b9387f))
|
|
37
|
+
|
|
38
|
+
# [3.18.0](https://github.com/zotoio/x-fidelity/compare/v3.17.1...v3.18.0) (2025-03-25)
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
### Bug Fixes
|
|
42
|
+
|
|
43
|
+
* add missing execSync import in repoDependencyFacts test ([b06abdd](https://github.com/zotoio/x-fidelity/commit/b06abdd9007f3631f7586aac86bf3b160810c217))
|
|
44
|
+
* handle type safety and increase test timeout for exemption utils ([02939c2](https://github.com/zotoio/x-fidelity/commit/02939c2c55e0a592a5a019130310a563ca54e486))
|
|
45
|
+
* resolve TypeScript errors in config loader and tests ([f91a7d8](https://github.com/zotoio/x-fidelity/commit/f91a7d8d2c6f4fded75dd50e696cd7cfaab40caf))
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
### Features
|
|
49
|
+
|
|
50
|
+
* add additionalRules field to default XFI config ([ce6d787](https://github.com/zotoio/x-fidelity/commit/ce6d78706ac368bec79f7ae0da6bf07baebe47f1))
|
|
51
|
+
* add missing fields to default XFI config ([f9841fb](https://github.com/zotoio/x-fidelity/commit/f9841fbf551e6615a58f7e04b52cac6ea1c4facb))
|
|
52
|
+
* add support for external rule references in xfi config ([9dc47a1](https://github.com/zotoio/x-fidelity/commit/9dc47a161c19078de56ece1d4ed0938350dee2e9))
|
|
53
|
+
* add support for loading rules from URLs and multiple paths ([2704fd8](https://github.com/zotoio/x-fidelity/commit/2704fd85cae845f49abf07ec537a2640005a5ea7))
|
|
54
|
+
* **xfi-config:** support for file references in repo config for additional rules ([706febc](https://github.com/zotoio/x-fidelity/commit/706febc866ee3c0dce413920247d8d1d534d0c94))
|
|
55
|
+
|
|
1
56
|
## [3.17.1](https://github.com/zotoio/x-fidelity/compare/v3.17.0...v3.17.1) (2025-03-20)
|
|
2
57
|
|
|
3
58
|
|
|
@@ -15,7 +15,7 @@ const configManager_1 = require("../configManager");
|
|
|
15
15
|
const errorActionExecutor_1 = require("./errorActionExecutor");
|
|
16
16
|
function runEngineOnFiles(params) {
|
|
17
17
|
return __awaiter(this, void 0, void 0, function* () {
|
|
18
|
-
var _a, _b, _c, _d, _e, _f, _g, _h, _j;
|
|
18
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m;
|
|
19
19
|
const { engine, fileData, installedDependencyVersions, minimumDependencyVersions, standardStructure } = params;
|
|
20
20
|
const msg = `\n==========================\nRUNNING FILE CHECKS..\n==========================`;
|
|
21
21
|
logger_1.logger.info(msg);
|
|
@@ -42,20 +42,29 @@ function runEngineOnFiles(params) {
|
|
|
42
42
|
const fileFailures = [];
|
|
43
43
|
try {
|
|
44
44
|
const { results } = yield engine.run(facts);
|
|
45
|
+
const seenFailures = new Set();
|
|
45
46
|
for (const result of results) {
|
|
46
47
|
logger_1.logger.trace(JSON.stringify(result));
|
|
47
48
|
if (result.result) {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
49
|
+
// Create unique key for deduplication
|
|
50
|
+
const failureKey = `${result.name}:${(_a = result.event) === null || _a === void 0 ? void 0 : _a.type}:${(_c = (_b = result.event) === null || _b === void 0 ? void 0 : _b.params) === null || _c === void 0 ? void 0 : _c.message}`;
|
|
51
|
+
if (!seenFailures.has(failureKey)) {
|
|
52
|
+
fileFailures.push({
|
|
53
|
+
ruleFailure: result.name,
|
|
54
|
+
level: (_d = result.event) === null || _d === void 0 ? void 0 : _d.type,
|
|
55
|
+
details: Object.assign({ message: ((_f = (_e = result.event) === null || _e === void 0 ? void 0 : _e.params) === null || _f === void 0 ? void 0 : _f.message) || 'Rule failure detected' }, (_g = result.event) === null || _g === void 0 ? void 0 : _g.params)
|
|
56
|
+
});
|
|
57
|
+
seenFailures.add(failureKey);
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
logger_1.logger.debug(`Skipping duplicate failure: ${failureKey}`);
|
|
61
|
+
}
|
|
53
62
|
}
|
|
54
63
|
}
|
|
55
64
|
}
|
|
56
65
|
catch (e) {
|
|
57
66
|
const error = e;
|
|
58
|
-
const failedRuleName = (
|
|
67
|
+
const failedRuleName = (_h = error === null || error === void 0 ? void 0 : error.rule) === null || _h === void 0 ? void 0 : _h.name;
|
|
59
68
|
const rule = failedRuleName ? engine.rules.find((r) => r.name === failedRuleName) : null;
|
|
60
69
|
// Determine error source and level
|
|
61
70
|
let errorSource = 'unknown';
|
|
@@ -80,7 +89,7 @@ function runEngineOnFiles(params) {
|
|
|
80
89
|
}
|
|
81
90
|
else if (failedRuleName) {
|
|
82
91
|
errorSource = 'rule';
|
|
83
|
-
errorLevel = (rule === null || rule === void 0 ? void 0 : rule.errorBehavior) === 'fatal' || ((
|
|
92
|
+
errorLevel = (rule === null || rule === void 0 ? void 0 : rule.errorBehavior) === 'fatal' || ((_j = rule === null || rule === void 0 ? void 0 : rule.event) === null || _j === void 0 ? void 0 : _j.type) === 'fatality' ? 'fatality' : 'error';
|
|
84
93
|
}
|
|
85
94
|
logger_1.logger.error({
|
|
86
95
|
index: i,
|
|
@@ -90,10 +99,10 @@ function runEngineOnFiles(params) {
|
|
|
90
99
|
source: errorSource,
|
|
91
100
|
type: errorLevel,
|
|
92
101
|
stack: (handledError || error).stack,
|
|
93
|
-
details: ((
|
|
102
|
+
details: ((_k = error === null || error === void 0 ? void 0 : error.pluginError) === null || _k === void 0 ? void 0 : _k.details) || error.message
|
|
94
103
|
}, `Execution error occurred at file ${file.filePath} (${i + 1} of ${fileCount})`);
|
|
95
104
|
// Execute error action if specified
|
|
96
|
-
if ((
|
|
105
|
+
if ((_l = rule === null || rule === void 0 ? void 0 : rule.onError) === null || _l === void 0 ? void 0 : _l.action) {
|
|
97
106
|
try {
|
|
98
107
|
const actionResult = yield (0, errorActionExecutor_1.executeErrorAction)(rule.onError.action, {
|
|
99
108
|
error: error,
|
|
@@ -124,7 +133,7 @@ function runEngineOnFiles(params) {
|
|
|
124
133
|
message: `${errorSource} execution failed: ${(handledError || error).message}`,
|
|
125
134
|
source: errorSource,
|
|
126
135
|
stack: (handledError || error).stack,
|
|
127
|
-
details: (
|
|
136
|
+
details: (_m = error === null || error === void 0 ? void 0 : error.pluginError) === null || _m === void 0 ? void 0 : _m.details
|
|
128
137
|
}
|
|
129
138
|
});
|
|
130
139
|
}
|
|
@@ -17,9 +17,11 @@ const facts_1 = require("../../facts");
|
|
|
17
17
|
const telemetry_1 = require("../../utils/telemetry");
|
|
18
18
|
const exemptionUtils_1 = require("../../utils/exemptionUtils");
|
|
19
19
|
const configManager_1 = require("../configManager");
|
|
20
|
+
const repoXFIConfigLoader_1 = require("../../utils/repoXFIConfigLoader");
|
|
20
21
|
function setupEngine(params) {
|
|
21
22
|
return __awaiter(this, void 0, void 0, function* () {
|
|
22
|
-
|
|
23
|
+
var _a;
|
|
24
|
+
const { archetypeConfig, archetype, executionLogPrefix, repoUrl, localConfigPath } = params;
|
|
23
25
|
const engine = new json_rules_engine_1.Engine([], { replaceFactsInEventParams: true, allowUndefinedFacts: true });
|
|
24
26
|
// Add operators to engine
|
|
25
27
|
logger_1.logger.info(`=== loading custom operators..`);
|
|
@@ -34,12 +36,21 @@ function setupEngine(params) {
|
|
|
34
36
|
// Add rules to engine
|
|
35
37
|
logger_1.logger.info(`=== loading json rules..`);
|
|
36
38
|
const config = yield configManager_1.ConfigManager.getConfig({ archetype, logPrefix: executionLogPrefix });
|
|
39
|
+
// Load repo config to get additional rules
|
|
40
|
+
const repoConfig = yield (0, repoXFIConfigLoader_1.loadRepoXFIConfig)(localConfigPath);
|
|
37
41
|
logger_1.logger.debug(`rules loaded: ${config.rules}`);
|
|
38
42
|
const addedRules = new Set();
|
|
43
|
+
// First add archetype rules
|
|
39
44
|
config.rules.forEach((rule) => {
|
|
40
45
|
try {
|
|
41
46
|
if (rule && rule.name) {
|
|
42
|
-
|
|
47
|
+
// Check if rule is already registered
|
|
48
|
+
if (addedRules.has(rule.name)) {
|
|
49
|
+
logger_1.logger.warn(`Skipping duplicate rule: ${rule.name}`);
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
logger_1.logger.info(`adding archetype rule: ${rule.name}`);
|
|
53
|
+
// Check for exemption
|
|
43
54
|
if ((0, exemptionUtils_1.isExempt)({ exemptions: config.exemptions, repoUrl, ruleName: rule.name, logPrefix: executionLogPrefix })) {
|
|
44
55
|
// clone the rule to avoid modifying the original rule
|
|
45
56
|
const exemptRule = JSON.parse(JSON.stringify(rule));
|
|
@@ -50,6 +61,7 @@ function setupEngine(params) {
|
|
|
50
61
|
else {
|
|
51
62
|
engine.addRule(rule);
|
|
52
63
|
}
|
|
64
|
+
// Track added rule
|
|
53
65
|
addedRules.add(rule.name);
|
|
54
66
|
}
|
|
55
67
|
else {
|
|
@@ -57,10 +69,31 @@ function setupEngine(params) {
|
|
|
57
69
|
}
|
|
58
70
|
}
|
|
59
71
|
catch (e) {
|
|
60
|
-
logger_1.logger.error(`Error loading rule: ${(rule === null || rule === void 0 ? void 0 : rule.name) || 'unknown'}`);
|
|
72
|
+
logger_1.logger.error(`Error loading archetype rule: ${(rule === null || rule === void 0 ? void 0 : rule.name) || 'unknown'}`);
|
|
61
73
|
logger_1.logger.error(e.message);
|
|
62
74
|
}
|
|
63
75
|
});
|
|
76
|
+
// Then add additional rules from repo config
|
|
77
|
+
if ((_a = repoConfig.additionalRules) === null || _a === void 0 ? void 0 : _a.length) {
|
|
78
|
+
repoConfig.additionalRules.forEach((rule) => {
|
|
79
|
+
try {
|
|
80
|
+
if (rule && rule.name) {
|
|
81
|
+
// Check if rule is already registered
|
|
82
|
+
if (addedRules.has(rule.name)) {
|
|
83
|
+
logger_1.logger.warn(`Skipping duplicate additional rule: ${rule.name}`);
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
logger_1.logger.info(`adding additional rule: ${rule.name}`);
|
|
87
|
+
engine.addRule(rule);
|
|
88
|
+
addedRules.add(rule.name);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
catch (e) {
|
|
92
|
+
logger_1.logger.error(`Error loading additional rule: ${(rule === null || rule === void 0 ? void 0 : rule.name) || 'unknown'}`);
|
|
93
|
+
logger_1.logger.error(e.message);
|
|
94
|
+
}
|
|
95
|
+
});
|
|
96
|
+
}
|
|
64
97
|
engine.on('success', (_a) => __awaiter(this, [_a], void 0, function* ({ type, params }) {
|
|
65
98
|
if (type === 'warning') {
|
|
66
99
|
logger_1.logger.warn(`warning detected: ${JSON.stringify(params)}`);
|
|
@@ -47,6 +47,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
47
47
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
48
|
const repoDependencyFacts = __importStar(require("./repoDependencyFacts"));
|
|
49
49
|
const fs_1 = __importDefault(require("fs"));
|
|
50
|
+
const child_process_1 = require("child_process");
|
|
50
51
|
const repoDependencyFacts_1 = require("./repoDependencyFacts");
|
|
51
52
|
const logger_1 = require("../utils/logger");
|
|
52
53
|
// Mock child_process.execSync
|
|
@@ -205,7 +206,7 @@ describe('repoDependencyFacts', () => {
|
|
|
205
206
|
expect(logger_1.logger.error).toHaveBeenCalled();
|
|
206
207
|
}));
|
|
207
208
|
});
|
|
208
|
-
|
|
209
|
+
describe('getDependencyVersionFacts', () => {
|
|
209
210
|
beforeEach(() => {
|
|
210
211
|
// Reset the mock implementation for collectLocalDependencies
|
|
211
212
|
jest.spyOn(repoDependencyFacts, 'collectLocalDependencies')
|
|
@@ -219,6 +220,7 @@ describe('repoDependencyFacts', () => {
|
|
|
219
220
|
}));
|
|
220
221
|
});
|
|
221
222
|
it('should return dependency version facts', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
223
|
+
// Mock successful dependency collection
|
|
222
224
|
const mockArchetypeConfig = {
|
|
223
225
|
facts: ['repoDependencyFacts'],
|
|
224
226
|
config: {
|
|
@@ -227,6 +229,22 @@ describe('repoDependencyFacts', () => {
|
|
|
227
229
|
}
|
|
228
230
|
}
|
|
229
231
|
};
|
|
232
|
+
// Mock fs.existsSync to return true for yarn.lock
|
|
233
|
+
fs_1.default.existsSync.mockImplementation((path) => {
|
|
234
|
+
return path.includes('yarn.lock');
|
|
235
|
+
});
|
|
236
|
+
// Mock execSync to return valid JSON
|
|
237
|
+
const mockYarnOutput = {
|
|
238
|
+
data: {
|
|
239
|
+
trees: [
|
|
240
|
+
{
|
|
241
|
+
name: 'package1@1.0.0',
|
|
242
|
+
children: []
|
|
243
|
+
}
|
|
244
|
+
]
|
|
245
|
+
}
|
|
246
|
+
};
|
|
247
|
+
child_process_1.execSync.mockReturnValue(Buffer.from(JSON.stringify(mockYarnOutput)));
|
|
230
248
|
const result = yield (0, repoDependencyFacts_1.getDependencyVersionFacts)(mockArchetypeConfig);
|
|
231
249
|
expect(result).toEqual([
|
|
232
250
|
{ dep: 'package1', ver: '1.0.0', min: '^1.0.0' }
|
|
@@ -244,15 +262,26 @@ describe('repoDependencyFacts', () => {
|
|
|
244
262
|
expect(logger_1.logger.warn).toHaveBeenCalled();
|
|
245
263
|
}));
|
|
246
264
|
it('should return empty array when no local dependencies are found', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
265
|
+
// Mock empty dependency collection
|
|
266
|
+
jest.spyOn(repoDependencyFacts, 'collectLocalDependencies')
|
|
267
|
+
.mockImplementation(() => __awaiter(void 0, void 0, void 0, function* () { return []; }));
|
|
247
268
|
const mockArchetypeConfig = {
|
|
248
269
|
facts: ['repoDependencyFacts'],
|
|
249
270
|
config: {
|
|
250
271
|
minimumDependencyVersions: {}
|
|
251
272
|
}
|
|
252
273
|
};
|
|
253
|
-
//
|
|
254
|
-
|
|
255
|
-
.
|
|
274
|
+
// Mock fs.existsSync to return true for yarn.lock
|
|
275
|
+
fs_1.default.existsSync.mockImplementation((path) => {
|
|
276
|
+
return path.includes('yarn.lock');
|
|
277
|
+
});
|
|
278
|
+
// Mock execSync to return valid JSON with no dependencies
|
|
279
|
+
const mockYarnOutput = {
|
|
280
|
+
data: {
|
|
281
|
+
trees: []
|
|
282
|
+
}
|
|
283
|
+
};
|
|
284
|
+
child_process_1.execSync.mockReturnValue(Buffer.from(JSON.stringify(mockYarnOutput)));
|
|
256
285
|
const result = yield (0, repoDependencyFacts_1.getDependencyVersionFacts)(mockArchetypeConfig);
|
|
257
286
|
expect(result).toEqual([]);
|
|
258
287
|
expect(logger_1.logger.warn).toHaveBeenCalled();
|
package/dist/index.test.js
CHANGED
|
@@ -105,10 +105,24 @@ describe('index', () => {
|
|
|
105
105
|
const mockAnalyzeCodebase = analyzer_1.analyzeCodebase;
|
|
106
106
|
mockAnalyzeCodebase.mockResolvedValue({
|
|
107
107
|
XFI_RESULT: {
|
|
108
|
+
archetype: 'test-archetype',
|
|
109
|
+
repoPath: 'mockRepoPath',
|
|
110
|
+
fileCount: 1,
|
|
108
111
|
totalIssues: 0,
|
|
109
112
|
warningCount: 0,
|
|
110
113
|
fatalityCount: 0,
|
|
111
|
-
|
|
114
|
+
errorCount: 0,
|
|
115
|
+
exemptCount: 0,
|
|
116
|
+
issueDetails: [],
|
|
117
|
+
startTime: expect.any(Number),
|
|
118
|
+
finishTime: expect.any(Number),
|
|
119
|
+
durationSeconds: expect.any(Number),
|
|
120
|
+
telemetryData: expect.any(Object),
|
|
121
|
+
options: expect.any(Object),
|
|
122
|
+
repoXFIConfig: expect.any(Object),
|
|
123
|
+
memoryUsage: expect.any(Object),
|
|
124
|
+
repoUrl: expect.any(String),
|
|
125
|
+
xfiVersion: expect.any(String)
|
|
112
126
|
}
|
|
113
127
|
});
|
|
114
128
|
const { main } = yield Promise.resolve().then(() => __importStar(require('./index')));
|
|
@@ -64,7 +64,7 @@ function calculateConsistency(nodeTypes, total) {
|
|
|
64
64
|
variance += Math.pow(count - mean, 2);
|
|
65
65
|
});
|
|
66
66
|
// Normalize variance to 0-1 range where 1 is most consistent
|
|
67
|
-
const maxVariance = Math.pow(mean * (nodeTypes.size - 1), 2);
|
|
67
|
+
const maxVariance = Math.pow(mean * (nodeTypes.size - 1), 2) / 2;
|
|
68
68
|
return maxVariance > 0 ? 1 - (Math.sqrt(variance) / Math.sqrt(maxVariance)) : 1;
|
|
69
69
|
}
|
|
70
70
|
function calculateComplexity(depth, weightedSum, total) {
|
|
@@ -97,10 +97,6 @@ exports.codeRhythmFact = {
|
|
|
97
97
|
consistency: roundToTwo(baseMetrics.consistency),
|
|
98
98
|
complexity: roundToTwo(baseMetrics.complexity),
|
|
99
99
|
readability: roundToTwo(baseMetrics.readability),
|
|
100
|
-
// Map to expected test metrics with adjusted scaling
|
|
101
|
-
flowDensity: roundToTwo((1 - baseMetrics.consistency) * 2.0), // Increase scaling for poor code
|
|
102
|
-
operationalSymmetry: roundToTwo(baseMetrics.consistency * 0.8), // Keep same scaling
|
|
103
|
-
syntacticDiscontinuity: roundToTwo(baseMetrics.complexity * 0.45) // Reduce scaling to stay under 0.5 for good code
|
|
104
100
|
};
|
|
105
101
|
logger_1.logger.debug({
|
|
106
102
|
fileName: fileData.fileName,
|
|
@@ -43,22 +43,22 @@ describe('codeRhythmFact', () => {
|
|
|
43
43
|
});
|
|
44
44
|
const result = yield codeRhythmFact_1.codeRhythmFact.fn({ resultFact: 'rhythmResult' }, mockAlmanac);
|
|
45
45
|
expect(result.metrics).toBeDefined();
|
|
46
|
-
expect(result.metrics.
|
|
47
|
-
expect(result.metrics.
|
|
48
|
-
expect(result.metrics.
|
|
46
|
+
expect(result.metrics.consistency).toBeGreaterThan(0.5);
|
|
47
|
+
expect(result.metrics.complexity).toBeGreaterThan(0.5);
|
|
48
|
+
expect(result.metrics.readability).toBeGreaterThan(0.5);
|
|
49
49
|
expect(mockAlmanac.addRuntimeFact).toHaveBeenCalledWith('rhythmResult', result.metrics);
|
|
50
50
|
}));
|
|
51
|
-
|
|
51
|
+
it('should identify poor code rhythm', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
52
52
|
mockAlmanac.factValue.mockResolvedValue({
|
|
53
53
|
fileName: 'poorCodeRhythm.ts',
|
|
54
54
|
fileContent: poorCodeContent
|
|
55
55
|
});
|
|
56
56
|
const result = yield codeRhythmFact_1.codeRhythmFact.fn({ resultFact: 'rhythmResult' }, mockAlmanac);
|
|
57
57
|
expect(result.metrics).toBeDefined();
|
|
58
|
-
expect(result.metrics.
|
|
59
|
-
expect(result.metrics.
|
|
60
|
-
expect(result.metrics.
|
|
61
|
-
expect(mockAlmanac.addRuntimeFact).toHaveBeenCalledWith('rhythmResult', result.metrics);
|
|
58
|
+
expect(result.metrics.consistency).toBeLessThanOrEqual(0.76);
|
|
59
|
+
expect(result.metrics.complexity).toBeLessThanOrEqual(0.76);
|
|
60
|
+
expect(result.metrics.readability).toBeLessThanOrEqual(0.76);
|
|
61
|
+
expect(mockAlmanac.addRuntimeFact).toHaveBeenCalledWith('rhythmResult', Object.assign({}, result.metrics));
|
|
62
62
|
}));
|
|
63
63
|
it('should handle missing AST gracefully', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
64
64
|
mockAlmanac.factValue.mockResolvedValue({
|
package/dist/types/typeDefs.d.ts
CHANGED
|
@@ -241,9 +241,14 @@ export interface ValidationResult {
|
|
|
241
241
|
isValid: boolean;
|
|
242
242
|
error?: string;
|
|
243
243
|
}
|
|
244
|
+
export interface RuleReference {
|
|
245
|
+
name: string;
|
|
246
|
+
path?: string;
|
|
247
|
+
url?: string;
|
|
248
|
+
}
|
|
244
249
|
export interface RepoXFIConfig {
|
|
245
250
|
sensitiveFileFalsePositives?: string[];
|
|
246
|
-
additionalRules?: RuleConfig[];
|
|
251
|
+
additionalRules?: (RuleConfig | RuleReference)[];
|
|
247
252
|
additionalFacts?: string[];
|
|
248
253
|
additionalOperators?: string[];
|
|
249
254
|
additionalPlugins?: string[];
|
package/dist/utils/logger.js
CHANGED
|
@@ -41,11 +41,7 @@ function getLogger(force) {
|
|
|
41
41
|
// Determine if color should be enabled based on environment variable only
|
|
42
42
|
const useColor = process.env.XFI_LOG_COLOR !== 'false';
|
|
43
43
|
if (!loggerInstance || force) {
|
|
44
|
-
const fileTransport = pino_1.default.destination(
|
|
45
|
-
dest: 'x-fidelity.log',
|
|
46
|
-
sync: false,
|
|
47
|
-
mkdir: true
|
|
48
|
-
});
|
|
44
|
+
const fileTransport = pino_1.default.destination('x-fidelity.log');
|
|
49
45
|
const prettyTransport = pino_1.default.transport({
|
|
50
46
|
target: 'pino-pretty',
|
|
51
47
|
options: {
|