x-fidelity 3.19.1 → 3.20.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 +28 -0
- package/dist/core/engine/analyzer.js +47 -9
- package/dist/demoConfig/rules/outdatedFramework-global-rule.json +10 -4
- package/dist/facts/index.js +21 -6
- package/dist/facts/repoDependencyFacts.js +11 -3
- package/dist/notifications/reportGenerator.d.ts +25 -0
- package/dist/notifications/reportGenerator.js +402 -0
- package/dist/types/typeDefs.d.ts +9 -0
- package/dist/utils/factMetricsTracker.d.ts +13 -0
- package/dist/utils/factMetricsTracker.js +64 -0
- package/dist/utils/utils.d.ts +1 -0
- package/dist/utils/utils.js +5 -0
- package/package.json +1 -1
- package/src/core/engine/analyzer.ts +50 -3
- package/src/demoConfig/rules/outdatedFramework-global-rule.json +10 -4
- package/src/facts/index.ts +34 -6
- package/src/facts/repoDependencyFacts.ts +13 -3
- package/src/notifications/reportGenerator.ts +467 -0
- package/src/types/typeDefs.ts +10 -0
- package/src/utils/factMetricsTracker.ts +68 -0
- package/src/utils/logger.ts +2 -0
- package/src/utils/utils.ts +5 -0
- package/website/package.json +2 -2
- package/website/yarn.lock +13 -13
- package/xfi-report-2025-04-01.json +99 -0
- package/xfi-report-2025-04-01.md +90 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
# [3.20.0](https://github.com/zotoio/x-fidelity/compare/v3.19.1...v3.20.0) (2025-04-01)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* add error handling and await for markdown report generation ([c199ffe](https://github.com/zotoio/x-fidelity/commit/c199ffe7bdc2de689baf939441e0819f7637b2ea))
|
|
7
|
+
* add missing imports and convert fs operations to async ([a9185b0](https://github.com/zotoio/x-fidelity/commit/a9185b0da399ba3b5500a6a5c27415b41f220061))
|
|
8
|
+
* correct line number property reference in sensitive data report ([53c3da2](https://github.com/zotoio/x-fidelity/commit/53c3da25f4d47b008d3159de03c39fb54052731a))
|
|
9
|
+
* update execution time precision to 4 decimal places and round totals ([04ef987](https://github.com/zotoio/x-fidelity/commit/04ef9878c43cef8184f6cb26f0ec1bab1363dc5e))
|
|
10
|
+
* update getDependencyVersionFacts to use correct argument ([890f27c](https://github.com/zotoio/x-fidelity/commit/890f27c8960186ae4cbeed0589b92833cfdacb27))
|
|
11
|
+
* update property names for sensitive data table generation ([1e1bfaf](https://github.com/zotoio/x-fidelity/commit/1e1bfafc2753aca5f64819a1c82ec5e8c9dbf222))
|
|
12
|
+
* use correct property name for sensitive data match pattern ([49b3914](https://github.com/zotoio/x-fidelity/commit/49b3914ee5bfd744eb06fe62ee765622ffaab8f2))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* add average execution time per fact in pie chart labels ([4cdf959](https://github.com/zotoio/x-fidelity/commit/4cdf95916389b5b4181a502b7edcbb1ce3f9e958))
|
|
18
|
+
* add debug logging for empty report diagnosis ([ef55d2c](https://github.com/zotoio/x-fidelity/commit/ef55d2ca9570f30f0ae5f9d1c12c924bbcd5caa9))
|
|
19
|
+
* add fact execution metrics tracking and reporting ([dc3c541](https://github.com/zotoio/x-fidelity/commit/dc3c541370f93225280b713c8017306dd2f3c4d8))
|
|
20
|
+
* add getFormattedDate utility function for date formatting ([3586378](https://github.com/zotoio/x-fidelity/commit/3586378394f646102e80ca1d22d4f691fdb66a1a))
|
|
21
|
+
* add line number anchors to report table URLs ([a8723ce](https://github.com/zotoio/x-fidelity/commit/a8723cefc2250c096c8af5fd9cd1fc66649fce73))
|
|
22
|
+
* add line number anchors to sensitive data issue links ([f8488ea](https://github.com/zotoio/x-fidelity/commit/f8488ea01a12edb579b6cf370ea16cf6ab139cb5))
|
|
23
|
+
* add metrics tracking for dynamic fact executions ([757853f](https://github.com/zotoio/x-fidelity/commit/757853f5a3241e72d88ff57165b99e05334ab01d))
|
|
24
|
+
* add minimum version requirements to outdatedFramework rule ([3412333](https://github.com/zotoio/x-fidelity/commit/3412333dd2110e0cf0b50664407736528e531117))
|
|
25
|
+
* add repo name and date to report title ([f00855e](https://github.com/zotoio/x-fidelity/commit/f00855e4b5c2b400baaa4e8ee769cca8553d1ace))
|
|
26
|
+
* add report generation with JSON and Markdown output ([0b735e4](https://github.com/zotoio/x-fidelity/commit/0b735e4a86cd043c57f1e01160264641b151247d))
|
|
27
|
+
* add report generator for X-Fidelity analysis results ([e58d56d](https://github.com/zotoio/x-fidelity/commit/e58d56d510aadbd417c3950372680f704389788f))
|
|
28
|
+
|
|
1
29
|
## [3.19.1](https://github.com/zotoio/x-fidelity/compare/v3.19.0...v3.19.1) (2025-03-25)
|
|
2
30
|
|
|
3
31
|
|
|
@@ -8,13 +8,21 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
|
|
|
8
8
|
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
9
|
});
|
|
10
10
|
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
11
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
15
|
exports.analyzeCodebase = analyzeCodebase;
|
|
16
|
+
const promises_1 = __importDefault(require("fs/promises"));
|
|
17
|
+
const path_1 = __importDefault(require("path"));
|
|
13
18
|
const logger_1 = require("../../utils/logger");
|
|
19
|
+
const utils_1 = require("../../utils/utils");
|
|
14
20
|
const configManager_1 = require("../configManager");
|
|
21
|
+
const reportGenerator_1 = require("../../notifications/reportGenerator");
|
|
15
22
|
const package_json_1 = require("../../../package.json");
|
|
16
23
|
const openaiUtils_1 = require("../../utils/openaiUtils");
|
|
17
24
|
const telemetry_1 = require("../../utils/telemetry");
|
|
25
|
+
const factMetricsTracker_1 = require("../../utils/factMetricsTracker");
|
|
18
26
|
const repoFilesystemFacts_1 = require("../../facts/repoFilesystemFacts");
|
|
19
27
|
const repoXFIConfigLoader_1 = require("../../utils/repoXFIConfigLoader");
|
|
20
28
|
const repoDependencyFacts_1 = require("../../facts/repoDependencyFacts");
|
|
@@ -22,13 +30,15 @@ const openaiAnalysisFacts_1 = require("../../facts/openaiAnalysisFacts");
|
|
|
22
30
|
const telemetryCollector_1 = require("./telemetryCollector");
|
|
23
31
|
const engineSetup_1 = require("./engineSetup");
|
|
24
32
|
const engineRunner_1 = require("./engineRunner");
|
|
25
|
-
const
|
|
33
|
+
const utils_2 = require("../../utils/utils");
|
|
26
34
|
const jsonSchemas_1 = require("../../utils/jsonSchemas");
|
|
27
35
|
const pluginRegistry_1 = require("../pluginRegistry");
|
|
28
36
|
const cli_1 = require("../cli");
|
|
29
37
|
function analyzeCodebase(params) {
|
|
30
38
|
return __awaiter(this, void 0, void 0, function* () {
|
|
31
39
|
const { repoPath, archetype = 'node-fullstack', configServer = '', localConfigPath = '', executionLogPrefix = '' } = params;
|
|
40
|
+
// Reset metrics at start of analysis
|
|
41
|
+
factMetricsTracker_1.factMetricsTracker.reset();
|
|
32
42
|
logger_1.logger.info(`STARTING..`);
|
|
33
43
|
const telemetryData = yield (0, telemetryCollector_1.collectTelemetryData)({ repoPath, configServer });
|
|
34
44
|
const repoUrl = telemetryData.repoUrl;
|
|
@@ -125,12 +135,20 @@ function analyzeCodebase(params) {
|
|
|
125
135
|
}
|
|
126
136
|
if ((0, openaiUtils_1.isOpenAIEnabled)() && archetypeConfig.facts.includes('openaiAnalysisFacts')) {
|
|
127
137
|
logger_1.logger.info(`adding additional openai facts to engine..`);
|
|
128
|
-
engine.addFact('openaiAnalysis',
|
|
138
|
+
engine.addFact('openaiAnalysis', (params, almanac) => __awaiter(this, void 0, void 0, function* () {
|
|
139
|
+
return factMetricsTracker_1.factMetricsTracker.trackFactExecution('openaiAnalysis', () => (0, openaiAnalysisFacts_1.openaiAnalysis)(params, almanac));
|
|
140
|
+
}));
|
|
141
|
+
// Static data doesn't need execution tracking
|
|
129
142
|
engine.addFact('openaiSystemPrompt', openaiSystemPrompt);
|
|
130
143
|
}
|
|
131
144
|
// add functions for dependency and file analysis
|
|
132
|
-
engine.addFact('repoDependencyAnalysis',
|
|
133
|
-
|
|
145
|
+
engine.addFact('repoDependencyAnalysis', (params, almanac) => __awaiter(this, void 0, void 0, function* () {
|
|
146
|
+
return factMetricsTracker_1.factMetricsTracker.trackFactExecution('repoDependencyAnalysis', () => (0, repoDependencyFacts_1.repoDependencyAnalysis)(params, almanac));
|
|
147
|
+
}));
|
|
148
|
+
engine.addFact('repoFileAnalysis', (params, almanac) => __awaiter(this, void 0, void 0, function* () {
|
|
149
|
+
return factMetricsTracker_1.factMetricsTracker.trackFactExecution('repoFileAnalysis', () => (0, repoFilesystemFacts_1.repoFileAnalysis)(params, almanac));
|
|
150
|
+
}));
|
|
151
|
+
// Static data doesn't need execution tracking
|
|
134
152
|
engine.addFact('globalFileMetadata', fileData, { priority: 50 });
|
|
135
153
|
logger_1.logger.trace(fileData, 'Added globalFileData as fact');
|
|
136
154
|
// add xfiConfig as a fact
|
|
@@ -146,12 +164,12 @@ function analyzeCodebase(params) {
|
|
|
146
164
|
});
|
|
147
165
|
const finishMsg = `\n==========================\nCHECKS COMPLETED..\n==========================`;
|
|
148
166
|
logger_1.logger.info(finishMsg);
|
|
149
|
-
const totalFailureCount = (0,
|
|
167
|
+
const totalFailureCount = (0, utils_2.countRuleFailures)(failures);
|
|
150
168
|
logger_1.logger.info(`${fileData.length - 1} files analyzed. ${totalFailureCount} rule failures.`);
|
|
151
|
-
const fatalityCount = (0,
|
|
152
|
-
const warningCount = (0,
|
|
153
|
-
const exemptCount = (0,
|
|
154
|
-
const errorCount = (0,
|
|
169
|
+
const fatalityCount = (0, utils_2.countRuleFailures)(failures, 'fatality');
|
|
170
|
+
const warningCount = (0, utils_2.countRuleFailures)(failures, 'warning');
|
|
171
|
+
const exemptCount = (0, utils_2.countRuleFailures)(failures, 'exempt');
|
|
172
|
+
const errorCount = (0, utils_2.countRuleFailures)(failures, 'error');
|
|
155
173
|
const finishTime = new Date().getTime();
|
|
156
174
|
const memoryUsage = process.memoryUsage();
|
|
157
175
|
logger_1.logger.info('Assemblying result metadata..');
|
|
@@ -161,6 +179,7 @@ function analyzeCodebase(params) {
|
|
|
161
179
|
telemetryData,
|
|
162
180
|
memoryUsage,
|
|
163
181
|
repoXFIConfig: repoXFIConfig,
|
|
182
|
+
factMetrics: factMetricsTracker_1.factMetricsTracker.getMetrics(),
|
|
164
183
|
issueDetails: failures,
|
|
165
184
|
startTime: telemetryData.startTime,
|
|
166
185
|
finishTime: finishTime,
|
|
@@ -177,6 +196,25 @@ function analyzeCodebase(params) {
|
|
|
177
196
|
xfiVersion: package_json_1.version
|
|
178
197
|
}
|
|
179
198
|
};
|
|
199
|
+
// Generate reports
|
|
200
|
+
try {
|
|
201
|
+
// Save JSON report
|
|
202
|
+
const jsonReportPath = path_1.default.join(process.cwd(), `xfi-report-${(0, utils_1.getFormattedDate)()}.json`);
|
|
203
|
+
yield promises_1.default.writeFile(jsonReportPath, JSON.stringify(resultMetadata, null, 2));
|
|
204
|
+
logger_1.logger.info(`JSON report saved to: ${jsonReportPath}`);
|
|
205
|
+
// Generate and save markdown report
|
|
206
|
+
const generator = new reportGenerator_1.XFiReportGenerator(resultMetadata);
|
|
207
|
+
const markdownReportPath = path_1.default.join(process.cwd(), `xfi-report-${(0, utils_1.getFormattedDate)()}.md`);
|
|
208
|
+
try {
|
|
209
|
+
yield generator.saveReportToFile(markdownReportPath);
|
|
210
|
+
}
|
|
211
|
+
catch (error) {
|
|
212
|
+
logger_1.logger.error(`Failed to generate markdown report: ${error instanceof Error ? error.message : 'Unknown error'}`);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
catch (error) {
|
|
216
|
+
logger_1.logger.error('Failed to save analysis reports - continuing with execution');
|
|
217
|
+
}
|
|
180
218
|
// Send telemetry for analysis end
|
|
181
219
|
yield (0, telemetry_1.sendTelemetry)({
|
|
182
220
|
eventType: 'analysisResults',
|
|
@@ -9,9 +9,15 @@
|
|
|
9
9
|
"value": "REPO_GLOBAL_CHECK"
|
|
10
10
|
},
|
|
11
11
|
{
|
|
12
|
-
"fact": "repoDependencyAnalysis",
|
|
12
|
+
"fact": "repoDependencyAnalysis",
|
|
13
13
|
"params": {
|
|
14
|
-
"resultFact": "repoDependencyResults"
|
|
14
|
+
"resultFact": "repoDependencyResults",
|
|
15
|
+
"minimumDependencyVersions": {
|
|
16
|
+
"typescript": "5.0.0",
|
|
17
|
+
"node": "18.0.0",
|
|
18
|
+
"react": "18.2.0",
|
|
19
|
+
"next": "13.0.0"
|
|
20
|
+
}
|
|
15
21
|
},
|
|
16
22
|
"operator": "outdatedFramework",
|
|
17
23
|
"value": true
|
|
@@ -21,7 +27,7 @@
|
|
|
21
27
|
"event": {
|
|
22
28
|
"type": "fatality",
|
|
23
29
|
"params": {
|
|
24
|
-
"message": "
|
|
30
|
+
"message": "Core framework dependencies do not meet minimum version requirements! Please update your dependencies to the required versions.",
|
|
25
31
|
"details": {
|
|
26
32
|
"fact": "repoDependencyResults"
|
|
27
33
|
}
|
|
@@ -29,7 +35,7 @@
|
|
|
29
35
|
},
|
|
30
36
|
"errorBehavior": "fatal",
|
|
31
37
|
"onError": {
|
|
32
|
-
"action": "sendNotification",
|
|
38
|
+
"action": "sendNotification",
|
|
33
39
|
"params": {
|
|
34
40
|
"channel": "security-alerts",
|
|
35
41
|
"priority": "high"
|
package/dist/facts/index.js
CHANGED
|
@@ -17,24 +17,39 @@ const globalFileAnalysisFacts_1 = require("./globalFileAnalysisFacts");
|
|
|
17
17
|
const pluginRegistry_1 = require("../core/pluginRegistry");
|
|
18
18
|
const openaiUtils_1 = require("../utils/openaiUtils");
|
|
19
19
|
const logger_1 = require("../utils/logger");
|
|
20
|
+
const factMetricsTracker_1 = require("../utils/factMetricsTracker");
|
|
20
21
|
function loadFacts(factNames) {
|
|
21
22
|
return __awaiter(this, void 0, void 0, function* () {
|
|
22
23
|
// Get the latest facts including plugins
|
|
23
24
|
const allAvailableFacts = Object.assign({ repoFilesystemFacts: {
|
|
24
25
|
name: 'fileData',
|
|
25
|
-
fn:
|
|
26
|
+
fn: (params, almanac) => __awaiter(this, void 0, void 0, function* () {
|
|
27
|
+
return factMetricsTracker_1.factMetricsTracker.trackFactExecution('fileData', () => (0, repoFilesystemFacts_1.collectRepoFileData)(params, almanac));
|
|
28
|
+
}),
|
|
26
29
|
priority: 100
|
|
27
30
|
}, repoDependencyFacts: {
|
|
28
31
|
name: 'dependencyData',
|
|
29
|
-
fn:
|
|
32
|
+
fn: (params, almanac) => __awaiter(this, void 0, void 0, function* () {
|
|
33
|
+
const archetypeConfig = yield almanac.factValue('archetypeConfig');
|
|
34
|
+
return factMetricsTracker_1.factMetricsTracker.trackFactExecution('dependencyData', () => (0, repoDependencyFacts_1.getDependencyVersionFacts)(archetypeConfig));
|
|
35
|
+
})
|
|
30
36
|
}, openaiAnalysisFacts: {
|
|
31
37
|
name: 'openaiAnalysis',
|
|
32
|
-
fn:
|
|
38
|
+
fn: (params, almanac) => __awaiter(this, void 0, void 0, function* () {
|
|
39
|
+
return factMetricsTracker_1.factMetricsTracker.trackFactExecution('openaiAnalysis', () => (0, openaiAnalysisFacts_1.openaiAnalysis)(params, almanac));
|
|
40
|
+
})
|
|
33
41
|
}, globalFileAnalysisFacts: {
|
|
34
42
|
name: 'globalFileAnalysis',
|
|
35
|
-
fn:
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
fn: (params, almanac) => __awaiter(this, void 0, void 0, function* () {
|
|
44
|
+
return factMetricsTracker_1.factMetricsTracker.trackFactExecution('globalFileAnalysis', () => globalFileAnalysisFacts_1.globalFileAnalysis.fn(params, almanac));
|
|
45
|
+
}),
|
|
46
|
+
priority: 50
|
|
47
|
+
} }, Object.fromEntries(pluginRegistry_1.pluginRegistry.getPluginFacts().map(fact => [
|
|
48
|
+
fact.name,
|
|
49
|
+
Object.assign(Object.assign({}, fact), { fn: (params, almanac) => __awaiter(this, void 0, void 0, function* () {
|
|
50
|
+
return factMetricsTracker_1.factMetricsTracker.trackFactExecution(fact.name, () => fact.fn(params, almanac));
|
|
51
|
+
}) })
|
|
52
|
+
])));
|
|
38
53
|
logger_1.logger.info(`Loading facts: ${factNames.join(',')}`);
|
|
39
54
|
const pluginFacts = pluginRegistry_1.pluginRegistry.getPluginFacts();
|
|
40
55
|
logger_1.logger.info(`Found ${pluginFacts.length} plugin facts available`);
|
|
@@ -272,16 +272,24 @@ function repoDependencyAnalysis(params, almanac) {
|
|
|
272
272
|
const analysis = [];
|
|
273
273
|
const dependencyData = yield almanac.factValue('dependencyData');
|
|
274
274
|
const safeDependencyData = (0, utils_1.safeClone)(dependencyData);
|
|
275
|
-
|
|
275
|
+
// Use rule-provided versions if they exist, otherwise use the ones from dependencyData
|
|
276
|
+
const versionsToCheck = (params === null || params === void 0 ? void 0 : params.minimumDependencyVersions) ?
|
|
277
|
+
safeDependencyData.installedDependencyVersions.filter((versionData) => params.minimumDependencyVersions[versionData.dep]) :
|
|
278
|
+
safeDependencyData.installedDependencyVersions;
|
|
279
|
+
versionsToCheck.forEach((versionData) => {
|
|
280
|
+
var _a;
|
|
276
281
|
logger_1.logger.debug(`outdatedFramework: checking ${versionData.dep}`);
|
|
277
282
|
try {
|
|
278
283
|
// Check if the installed version satisfies the required version, supporting both ranges and specific versions
|
|
279
|
-
|
|
284
|
+
// Get required version from rule params if it exists, otherwise from archetype config
|
|
285
|
+
const requiredVersion = ((_a = params === null || params === void 0 ? void 0 : params.minimumDependencyVersions) === null || _a === void 0 ? void 0 : _a[versionData.dep]) || versionData.min;
|
|
286
|
+
// Check if the installed version satisfies the required version
|
|
287
|
+
const isValid = semverValid(versionData.ver, requiredVersion);
|
|
280
288
|
if (!isValid && semver.valid(versionData.ver)) {
|
|
281
289
|
const dependencyFailure = {
|
|
282
290
|
'dependency': versionData.dep,
|
|
283
291
|
'currentVersion': versionData.ver,
|
|
284
|
-
'requiredVersion':
|
|
292
|
+
'requiredVersion': requiredVersion
|
|
285
293
|
};
|
|
286
294
|
logger_1.logger.error(`dependencyFailure: ${(0, utils_1.safeStringify)(dependencyFailure)}`);
|
|
287
295
|
analysis.push(dependencyFailure);
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { ResultMetadata } from '../types/typeDefs';
|
|
2
|
+
export declare class XFiReportGenerator {
|
|
3
|
+
private data;
|
|
4
|
+
repoName: string;
|
|
5
|
+
private githubBaseUrl;
|
|
6
|
+
private githubHostname;
|
|
7
|
+
constructor(jsonData: ResultMetadata);
|
|
8
|
+
private getFileName;
|
|
9
|
+
private getGithubUrl;
|
|
10
|
+
private countIssuesByFile;
|
|
11
|
+
private countIssuesByRuleType;
|
|
12
|
+
private calculateSuccessRate;
|
|
13
|
+
private generateExecutiveSummary;
|
|
14
|
+
private generateFileStatusChart;
|
|
15
|
+
private generateTopRuleFailuresChart;
|
|
16
|
+
private generateFileIssuesChart;
|
|
17
|
+
private generateFactMetricsChart;
|
|
18
|
+
private generateTopIssuesSection;
|
|
19
|
+
private generateFunctionComplexitySection;
|
|
20
|
+
private generateDependencyIssuesSection;
|
|
21
|
+
private generateSensitiveDataSection;
|
|
22
|
+
private generateGlobalIssuesSection;
|
|
23
|
+
generateReport(): string;
|
|
24
|
+
saveReportToFile(outputPath: string): Promise<void>;
|
|
25
|
+
}
|