x-fidelity 3.2.0 → 3.3.1
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 +21 -0
- package/dist/core/cli.js +30 -14
- package/dist/core/configManager.d.ts +1 -0
- package/dist/core/configManager.js +4 -0
- package/dist/core/engine/analyzer.js +8 -2
- package/dist/core/engine/analyzer.test.js +11 -3
- package/dist/core/engine/engineRunner.js +4 -2
- package/dist/demoConfig/node-fullstack.json +8 -4
- package/dist/demoConfig/rules/missingRequiredFiles-global-rule.json +35 -0
- package/dist/demoConfig/rules/sensitiveLogging-iterative-rule.json +2 -1
- package/dist/facts/repoDependencyFacts.js +0 -1
- package/dist/index.d.ts +1 -3
- package/dist/index.js +14 -11
- package/dist/operators/nonStandardDirectoryStructure.js +1 -1
- package/dist/plugins/xfiPluginRequiredFiles/facts/missingRequiredFiles.d.ts +2 -0
- package/dist/plugins/xfiPluginRequiredFiles/facts/missingRequiredFiles.js +75 -0
- package/dist/plugins/xfiPluginRequiredFiles/index.d.ts +1 -0
- package/dist/plugins/xfiPluginRequiredFiles/index.js +5 -0
- package/dist/plugins/xfiPluginRequiredFiles/operators/missingRequiredFiles.d.ts +2 -0
- package/dist/plugins/xfiPluginRequiredFiles/operators/missingRequiredFiles.js +23 -0
- package/dist/plugins/xfiPluginRequiredFiles/operators/missingRequiredFiles.test.d.ts +1 -0
- package/dist/plugins/xfiPluginRequiredFiles/operators/missingRequiredFiles.test.js +42 -0
- package/dist/plugins/xfiPluginRequiredFiles/xfiPluginRequiredFiles.d.ts +3 -0
- package/dist/plugins/xfiPluginRequiredFiles/xfiPluginRequiredFiles.js +17 -0
- package/dist/types/typeDefs.d.ts +3 -0
- package/dist/utils/logger.js +4 -9
- package/dist/xfidelity +14 -11
- package/package.json +3 -3
- package/src/core/cli.ts +31 -15
- package/src/core/configManager.ts +6 -0
- package/src/core/engine/analyzer.test.ts +11 -3
- package/src/core/engine/analyzer.ts +10 -2
- package/src/core/engine/engineRunner.ts +4 -2
- package/src/demoConfig/node-fullstack.json +8 -4
- package/src/demoConfig/rules/missingRequiredFiles-global-rule.json +35 -0
- package/src/demoConfig/rules/sensitiveLogging-iterative-rule.json +2 -1
- package/src/facts/repoDependencyFacts.ts +0 -1
- package/src/index.ts +16 -14
- package/src/operators/nonStandardDirectoryStructure.ts +1 -1
- package/src/plugins/xfiPluginRequiredFiles/facts/missingRequiredFiles.ts +69 -0
- package/src/plugins/xfiPluginRequiredFiles/index.ts +1 -0
- package/src/plugins/xfiPluginRequiredFiles/operators/missingRequiredFiles.test.ts +46 -0
- package/src/plugins/xfiPluginRequiredFiles/operators/missingRequiredFiles.ts +22 -0
- package/src/plugins/xfiPluginRequiredFiles/sampleRules/missingRequiredFiles-global-rule.json +35 -0
- package/src/plugins/xfiPluginRequiredFiles/xfiPluginRequiredFiles.ts +17 -0
- package/src/types/typeDefs.ts +4 -1
- package/src/utils/logger.ts +3 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
## [3.3.1](https://github.com/zotoio/x-fidelity/compare/v3.3.0...v3.3.1) (2025-02-26)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* **engine:** node 18 ([6c3e157](https://github.com/zotoio/x-fidelity/commit/6c3e157d0873dbd6148c568f213ee7ad997744bd))
|
|
7
|
+
|
|
8
|
+
# [3.3.0](https://github.com/zotoio/x-fidelity/compare/v3.2.0...v3.3.0) (2025-02-22)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
### Bug Fixes
|
|
12
|
+
|
|
13
|
+
* add required compareValue parameter to missingRequiredFiles operator ([65ea1b6](https://github.com/zotoio/x-fidelity/commit/65ea1b6ad93f50357eeb17929d52d1b3ee7c39cc))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Features
|
|
17
|
+
|
|
18
|
+
* add missingRequiredFiles operator to plugin and update rule ([c9a8f79](https://github.com/zotoio/x-fidelity/commit/c9a8f79bc9d2d5db61f953ca22563442c276b659))
|
|
19
|
+
* add required files plugin with configurable path checks ([3561c04](https://github.com/zotoio/x-fidelity/commit/3561c04a90add046c18b9a1e998dc94c24776ed0))
|
|
20
|
+
* Enhance missingRequiredFiles operator with path validation and logging ([962cf38](https://github.com/zotoio/x-fidelity/commit/962cf387bcd8dfbb16d62ec842d11153602b967c))
|
|
21
|
+
|
|
1
22
|
# [3.2.0](https://github.com/zotoio/x-fidelity/compare/v3.1.1...v3.2.0) (2025-02-20)
|
|
2
23
|
|
|
3
24
|
|
package/dist/core/cli.js
CHANGED
|
@@ -15,6 +15,18 @@ const prettyjson_1 = __importDefault(require("prettyjson"));
|
|
|
15
15
|
exports.DEMO_CONFIG_PATH = path_1.default.resolve(__dirname, '../demoConfig');
|
|
16
16
|
exports.options = commander_1.program.opts();
|
|
17
17
|
function initCLI() {
|
|
18
|
+
const bannerArt = `\n
|
|
19
|
+
=====================================
|
|
20
|
+
__ __ ________ ______
|
|
21
|
+
| ## | ## | ######## \\######
|
|
22
|
+
\\##\\/ ## ______ | ##__ | ##
|
|
23
|
+
>## ## | \\| ## \\ | ##
|
|
24
|
+
/ ####\\ \\######| ###### | ##
|
|
25
|
+
| ## \\##\\ | ## _| ##_
|
|
26
|
+
| ## | ## | ## | ## \\
|
|
27
|
+
\\## \\## \\## \\######
|
|
28
|
+
-------------------------------------
|
|
29
|
+
`;
|
|
18
30
|
// Ensure logger is initialized
|
|
19
31
|
if (!logger_1.logger || typeof logger_1.logger.info !== 'function') {
|
|
20
32
|
console.error({ msg: 'Logger is not properly initialized' });
|
|
@@ -40,7 +52,7 @@ function initCLI() {
|
|
|
40
52
|
}
|
|
41
53
|
});
|
|
42
54
|
commander_1.program
|
|
43
|
-
.option("-d, --dir <directory>", "
|
|
55
|
+
.option("-d, --dir <directory>", "local git repo directory path to analyze. equivalent of directory argument")
|
|
44
56
|
.option("-a, --archetype <archetype>", "The archetype to use for analysis", "node-fullstack")
|
|
45
57
|
.option("-c, --configServer <configServer>", "The config server URL for fetching remote archetype configurations and rules. This takes precedence over localConfigPath.")
|
|
46
58
|
.option("-o, --openaiEnabled <boolean>", "Enable OpenAI analysis", false)
|
|
@@ -53,7 +65,11 @@ function initCLI() {
|
|
|
53
65
|
.option("-x, --examine <archetype>", "Examine the archetype configuration and rules")
|
|
54
66
|
.version(package_json_1.version, "-v, --version", "Output the version number of xfidelity")
|
|
55
67
|
.helpOption("-h, --help", "Display help for command")
|
|
56
|
-
.
|
|
68
|
+
.summary("CLI for analyzing codebases for architectural fidelity")
|
|
69
|
+
.usage("[directory] [options]")
|
|
70
|
+
.argument('[directory]', 'local git repo directory path to analyze')
|
|
71
|
+
.addHelpText('before', bannerArt)
|
|
72
|
+
.addHelpText('after', '-------------------------------------');
|
|
57
73
|
commander_1.program.parse(process.argv);
|
|
58
74
|
// Resolve paths
|
|
59
75
|
const resolvePath = (inputPath) => {
|
|
@@ -90,18 +106,18 @@ function initCLI() {
|
|
|
90
106
|
if (process.env.NODE_ENV !== 'test')
|
|
91
107
|
commander_1.program.error(`LocalConfigPath does not exist or is invalid: ${error}`);
|
|
92
108
|
}
|
|
93
|
-
const bannerArt = `\n
|
|
94
|
-
=====================================
|
|
95
|
-
|
|
96
|
-
| ## | ## | ######## \\######
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
| ## \\##\\ | ## _| ##_
|
|
101
|
-
| ## | ## | ## | ## \\
|
|
102
|
-
|
|
103
|
-
-------------------------------------
|
|
104
|
-
`;
|
|
109
|
+
// const bannerArt = `\n
|
|
110
|
+
// =====================================
|
|
111
|
+
// __ __ ________ ______
|
|
112
|
+
// | ## | ## | ######## \\######
|
|
113
|
+
// \\##\\/ ## ______ | ##__ | ##
|
|
114
|
+
// >## ## | \\| ## \\ | ##
|
|
115
|
+
// / ####\\ \\######| ###### | ##
|
|
116
|
+
// | ## \\##\\ | ## _| ##_
|
|
117
|
+
// | ## | ## | ## | ## \\
|
|
118
|
+
// \\## \\## \\## \\######
|
|
119
|
+
// -------------------------------------
|
|
120
|
+
// `;
|
|
105
121
|
logger_1.logger.info(bannerArt);
|
|
106
122
|
logger_1.logger.info(`\n${prettyjson_1.default.render({
|
|
107
123
|
version: package_json_1.version,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { ExecutionConfig, GetConfigParams } from "../types/typeDefs";
|
|
2
2
|
export declare const REPO_GLOBAL_CHECK = "REPO_GLOBAL_CHECK";
|
|
3
|
+
export declare function repoDir(): any;
|
|
3
4
|
export declare class ConfigManager {
|
|
4
5
|
private static configs;
|
|
5
6
|
private static MAX_RETRIES;
|
|
@@ -46,6 +46,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
46
46
|
};
|
|
47
47
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
48
48
|
exports.ConfigManager = exports.REPO_GLOBAL_CHECK = void 0;
|
|
49
|
+
exports.repoDir = repoDir;
|
|
49
50
|
const child_process_1 = require("child_process");
|
|
50
51
|
const axiosClient_1 = require("../utils/axiosClient");
|
|
51
52
|
const logger_1 = require("../utils/logger");
|
|
@@ -57,6 +58,9 @@ const path = __importStar(require("path"));
|
|
|
57
58
|
const jsonSchemas_1 = require("../utils/jsonSchemas");
|
|
58
59
|
const ruleUtils_1 = require("../utils/ruleUtils");
|
|
59
60
|
exports.REPO_GLOBAL_CHECK = 'REPO_GLOBAL_CHECK';
|
|
61
|
+
function repoDir() {
|
|
62
|
+
return cli_1.options.dir;
|
|
63
|
+
}
|
|
60
64
|
class ConfigManager {
|
|
61
65
|
static getLoadedConfigs() {
|
|
62
66
|
return Object.keys(ConfigManager.configs);
|
|
@@ -71,6 +71,8 @@ function analyzeCodebase(params) {
|
|
|
71
71
|
// add functions for dependency and file analysis
|
|
72
72
|
engine.addFact('repoDependencyAnalysis', repoDependencyFacts_1.repoDependencyAnalysis);
|
|
73
73
|
engine.addFact('repoFileAnalysis', repoFilesystemFacts_1.repoFileAnalysis);
|
|
74
|
+
engine.addFact('globalFileMetadata', fileData, { priority: 50 });
|
|
75
|
+
logger_1.logger.trace(fileData, 'Added globalFileData as fact');
|
|
74
76
|
// add xfiConfig as a fact
|
|
75
77
|
engine.addFact('repoXFIConfig', repoXFIConfig);
|
|
76
78
|
logger_1.logger.info({ repoXFIConfig }, 'Added repoXFIConfig as fact');
|
|
@@ -85,22 +87,25 @@ function analyzeCodebase(params) {
|
|
|
85
87
|
const finishMsg = `\n==========================\nCHECKS COMPLETED..\n==========================`;
|
|
86
88
|
logger_1.logger.info(finishMsg);
|
|
87
89
|
const totalFailureCount = (0, utils_1.countRuleFailures)(failures);
|
|
88
|
-
logger_1.logger.info(`${fileData.length} files analyzed. ${totalFailureCount} rule failures.`);
|
|
90
|
+
logger_1.logger.info(`${fileData.length - 1} files analyzed. ${totalFailureCount} rule failures.`);
|
|
89
91
|
const fatalityCount = (0, utils_1.countRuleFailures)(failures, 'fatality');
|
|
90
92
|
const warningCount = (0, utils_1.countRuleFailures)(failures, 'warning');
|
|
91
93
|
const exemptCount = (0, utils_1.countRuleFailures)(failures, 'exempt');
|
|
92
94
|
const errorCount = (0, utils_1.countRuleFailures)(failures, 'error');
|
|
93
95
|
const finishTime = new Date().getTime();
|
|
96
|
+
const memoryUsage = process.memoryUsage();
|
|
97
|
+
logger_1.logger.info('Assemblying result metadata..');
|
|
94
98
|
const resultMetadata = {
|
|
95
99
|
XFI_RESULT: {
|
|
96
100
|
archetype,
|
|
97
101
|
telemetryData,
|
|
102
|
+
memoryUsage,
|
|
98
103
|
repoXFIConfig: repoXFIConfig,
|
|
99
104
|
issueDetails: failures,
|
|
100
105
|
startTime: telemetryData.startTime,
|
|
101
106
|
finishTime: finishTime,
|
|
102
107
|
durationSeconds: (finishTime - telemetryData.startTime) / 1000,
|
|
103
|
-
fileCount: fileData.length,
|
|
108
|
+
fileCount: fileData.length - 1,
|
|
104
109
|
totalIssues: totalFailureCount,
|
|
105
110
|
warningCount: warningCount,
|
|
106
111
|
fatalityCount: fatalityCount,
|
|
@@ -108,6 +113,7 @@ function analyzeCodebase(params) {
|
|
|
108
113
|
exemptCount: exemptCount,
|
|
109
114
|
options: cli_1.options,
|
|
110
115
|
repoPath,
|
|
116
|
+
repoUrl
|
|
111
117
|
}
|
|
112
118
|
};
|
|
113
119
|
// Send telemetry for analysis end
|
|
@@ -106,15 +106,17 @@ describe('analyzeCodebase', () => {
|
|
|
106
106
|
XFI_RESULT: expect.objectContaining({
|
|
107
107
|
archetype: 'node-fullstack',
|
|
108
108
|
repoPath: 'mockRepoPath',
|
|
109
|
-
fileCount:
|
|
109
|
+
fileCount: expect.any(Number),
|
|
110
110
|
totalIssues: expect.any(Number),
|
|
111
111
|
warningCount: expect.any(Number),
|
|
112
112
|
fatalityCount: expect.any(Number),
|
|
113
|
+
errorCount: expect.any(Number),
|
|
113
114
|
exemptCount: expect.any(Number),
|
|
114
115
|
issueDetails: expect.any(Array),
|
|
115
116
|
durationSeconds: expect.any(Number),
|
|
116
117
|
finishTime: expect.any(Number),
|
|
117
118
|
startTime: expect.any(Number),
|
|
119
|
+
memoryUsage: expect.any(Object),
|
|
118
120
|
options: expect.objectContaining({
|
|
119
121
|
archetype: 'node-fullstack',
|
|
120
122
|
configServer: '',
|
|
@@ -132,6 +134,7 @@ describe('analyzeCodebase', () => {
|
|
|
132
134
|
startTime: expect.any(Number),
|
|
133
135
|
userInfo: expect.any(Object),
|
|
134
136
|
}),
|
|
137
|
+
repoUrl: expect.any(String),
|
|
135
138
|
repoXFIConfig: expect.objectContaining({
|
|
136
139
|
sensitiveFileFalsePositives: expect.any(Array),
|
|
137
140
|
})
|
|
@@ -177,7 +180,7 @@ describe('analyzeCodebase', () => {
|
|
|
177
180
|
XFI_RESULT: expect.objectContaining({
|
|
178
181
|
archetype: 'node-fullstack',
|
|
179
182
|
repoPath: 'mockRepoPath',
|
|
180
|
-
fileCount:
|
|
183
|
+
fileCount: expect.any(Number),
|
|
181
184
|
totalIssues: 3,
|
|
182
185
|
warningCount: 0,
|
|
183
186
|
fatalityCount: 0,
|
|
@@ -202,8 +205,10 @@ describe('analyzeCodebase', () => {
|
|
|
202
205
|
durationSeconds: expect.any(Number),
|
|
203
206
|
finishTime: expect.any(Number),
|
|
204
207
|
startTime: expect.any(Number),
|
|
208
|
+
memoryUsage: expect.any(Object),
|
|
205
209
|
options: expect.any(Object),
|
|
206
210
|
telemetryData: expect.any(Object),
|
|
211
|
+
repoUrl: expect.any(String),
|
|
207
212
|
repoXFIConfig: expect.objectContaining({
|
|
208
213
|
sensitiveFileFalsePositives: expect.any(Array)
|
|
209
214
|
})
|
|
@@ -305,7 +310,7 @@ describe('analyzeCodebase', () => {
|
|
|
305
310
|
XFI_RESULT: expect.objectContaining({
|
|
306
311
|
archetype: 'node-fullstack',
|
|
307
312
|
repoPath: 'mockRepoPath',
|
|
308
|
-
fileCount:
|
|
313
|
+
fileCount: expect.any(Number),
|
|
309
314
|
totalIssues: 3,
|
|
310
315
|
warningCount: 0,
|
|
311
316
|
fatalityCount: 3,
|
|
@@ -321,8 +326,11 @@ describe('analyzeCodebase', () => {
|
|
|
321
326
|
durationSeconds: expect.any(Number),
|
|
322
327
|
finishTime: expect.any(Number),
|
|
323
328
|
startTime: expect.any(Number),
|
|
329
|
+
memoryUsage: expect.any(Object),
|
|
324
330
|
options: expect.any(Object),
|
|
325
331
|
telemetryData: expect.any(Object),
|
|
332
|
+
repoUrl: expect.any(String),
|
|
333
|
+
repoXFIConfig: expect.any(Object)
|
|
326
334
|
})
|
|
327
335
|
});
|
|
328
336
|
expect(telemetry_1.sendTelemetry).toHaveBeenCalledTimes(2); // Start and end
|
|
@@ -20,13 +20,15 @@ function runEngineOnFiles(params) {
|
|
|
20
20
|
const msg = `\n==========================\nRUNNING FILE CHECKS..\n==========================`;
|
|
21
21
|
logger_1.logger.info(msg);
|
|
22
22
|
const failures = [];
|
|
23
|
-
|
|
23
|
+
const fileCount = fileData.length;
|
|
24
|
+
for (let i = 0; i < fileCount; i++) {
|
|
25
|
+
const file = fileData[i];
|
|
24
26
|
if (file.fileName === configManager_1.REPO_GLOBAL_CHECK) {
|
|
25
27
|
const msg = `\n==========================\nRUNNING GLOBAL REPO CHECKS..\n==========================`;
|
|
26
28
|
logger_1.logger.info(msg);
|
|
27
29
|
}
|
|
28
30
|
else {
|
|
29
|
-
const msg = `analysing ${file.filePath} ...`;
|
|
31
|
+
const msg = `analysing (${i + 1} of ${fileCount - 1}) ${file.filePath} ...`;
|
|
30
32
|
logger_1.logger.info(msg);
|
|
31
33
|
}
|
|
32
34
|
const facts = {
|
|
@@ -7,20 +7,23 @@
|
|
|
7
7
|
"nonStandardDirectoryStructure-global",
|
|
8
8
|
"openaiAnalysisTop5-global",
|
|
9
9
|
"openaiAnalysisA11y-global",
|
|
10
|
-
"invalidSystemIdConfigured-iterative"
|
|
10
|
+
"invalidSystemIdConfigured-iterative",
|
|
11
|
+
"missingRequiredFiles-global"
|
|
11
12
|
],
|
|
12
13
|
"operators": [
|
|
13
14
|
"fileContains",
|
|
14
15
|
"outdatedFramework",
|
|
15
16
|
"nonStandardDirectoryStructure",
|
|
16
17
|
"openaiAnalysisHighSeverity",
|
|
17
|
-
"invalidRemoteValidation"
|
|
18
|
+
"invalidRemoteValidation",
|
|
19
|
+
"missingRequiredFiles"
|
|
18
20
|
],
|
|
19
21
|
"facts": [
|
|
20
22
|
"repoFilesystemFacts",
|
|
21
23
|
"repoDependencyFacts",
|
|
22
24
|
"openaiAnalysisFacts",
|
|
23
|
-
"remoteSubstringValidation"
|
|
25
|
+
"remoteSubstringValidation",
|
|
26
|
+
"missingRequiredFiles"
|
|
24
27
|
],
|
|
25
28
|
"config": {
|
|
26
29
|
"minimumDependencyVersions": {
|
|
@@ -44,7 +47,8 @@
|
|
|
44
47
|
],
|
|
45
48
|
"whitelistPatterns": [
|
|
46
49
|
".*\\.(ts|tsx|js|jsx)$",
|
|
47
|
-
".*\\/xfiTestMatch\\.json$"
|
|
50
|
+
".*\\/xfiTestMatch\\.json$",
|
|
51
|
+
".*\\/README\\.md$"
|
|
48
52
|
]
|
|
49
53
|
}
|
|
50
54
|
}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "missingRequiredFiles-global",
|
|
3
|
+
"conditions": {
|
|
4
|
+
"all": [
|
|
5
|
+
{
|
|
6
|
+
"fact": "fileData",
|
|
7
|
+
"path": "$.fileName",
|
|
8
|
+
"operator": "equal",
|
|
9
|
+
"value": "REPO_GLOBAL_CHECK"
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
"fact": "missingRequiredFiles",
|
|
13
|
+
"params": {
|
|
14
|
+
"requiredFiles": [
|
|
15
|
+
"/README.md",
|
|
16
|
+
"../../src/\\core//cli&.ts",
|
|
17
|
+
"missingRequiredFiles-testing.js"
|
|
18
|
+
],
|
|
19
|
+
"resultFact": "missingRequiredFilesResult"
|
|
20
|
+
},
|
|
21
|
+
"operator": "missingRequiredFiles",
|
|
22
|
+
"value": true
|
|
23
|
+
}
|
|
24
|
+
]
|
|
25
|
+
},
|
|
26
|
+
"event": {
|
|
27
|
+
"type": "fatality",
|
|
28
|
+
"params": {
|
|
29
|
+
"message": "Required files are missing from the repository",
|
|
30
|
+
"details": {
|
|
31
|
+
"fact": "missingRequiredFilesResult"
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -76,7 +76,6 @@ function collectLocalDependencies() {
|
|
|
76
76
|
else {
|
|
77
77
|
logger_1.logger.error('No yarn.lock or package-lock.json found');
|
|
78
78
|
process.exit(1);
|
|
79
|
-
throw new Error('Unsupported package manager');
|
|
80
79
|
}
|
|
81
80
|
logger_1.logger.trace(`collectLocalDependencies: ${(0, utils_1.safeStringify)(result)}`);
|
|
82
81
|
return result;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
export declare function main(): Promise<void>;
|
|
3
|
-
export
|
|
4
|
-
export * from './core/configManager';
|
|
3
|
+
export { repoDir } from './core/configManager';
|
|
5
4
|
export * from './utils/logger';
|
|
6
|
-
export * from './core/engine/analyzer';
|
|
7
5
|
export * from './types';
|
package/dist/index.js
CHANGED
|
@@ -49,11 +49,11 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
49
49
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
50
50
|
};
|
|
51
51
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
52
|
+
exports.repoDir = void 0;
|
|
52
53
|
exports.main = main;
|
|
53
54
|
const logger_1 = require("./utils/logger");
|
|
54
55
|
const cli_1 = require("./core/cli");
|
|
55
56
|
if (require.main === module) {
|
|
56
|
-
(0, logger_1.initializeLogger)();
|
|
57
57
|
(0, logger_1.setLogLevel)(process.env.XFI_LOG_LEVEL || 'info');
|
|
58
58
|
(0, cli_1.initCLI)();
|
|
59
59
|
}
|
|
@@ -70,7 +70,8 @@ const handleError = (error) => __awaiter(void 0, void 0, void 0, function* () {
|
|
|
70
70
|
archetype: cli_1.options.archetype,
|
|
71
71
|
repoPath: cli_1.options.dir,
|
|
72
72
|
options: cli_1.options,
|
|
73
|
-
errorMessage: error.message
|
|
73
|
+
errorMessage: error.message,
|
|
74
|
+
errorStack: error.stack
|
|
74
75
|
},
|
|
75
76
|
timestamp: new Date().toISOString()
|
|
76
77
|
}, executionLogPrefix);
|
|
@@ -100,38 +101,41 @@ function main() {
|
|
|
100
101
|
localConfigPath: cli_1.options.localConfigPath,
|
|
101
102
|
executionLogPrefix
|
|
102
103
|
});
|
|
104
|
+
const resultString = JSON.stringify(resultMetadata);
|
|
105
|
+
const prettyResult = prettyjson_1.default.render(resultMetadata.XFI_RESULT);
|
|
103
106
|
// if results are found, there were issues found in the codebase
|
|
104
107
|
if (resultMetadata.XFI_RESULT.totalIssues > 0) {
|
|
105
108
|
logger_1.logger.warn(`WARNING: lo-fi attributes detected in codebase. ${resultMetadata.XFI_RESULT.warningCount} are warnings, ${resultMetadata.XFI_RESULT.fatalityCount} are fatal.`);
|
|
106
|
-
logger_1.logger.warn(
|
|
109
|
+
logger_1.logger.warn(resultString);
|
|
107
110
|
if (resultMetadata.XFI_RESULT.errorCount > 0) {
|
|
108
111
|
logger_1.logger.error(outcomeMessage(`THERE WERE ${resultMetadata.XFI_RESULT.errorCount} UNEXPECTED ERRORS!`));
|
|
109
|
-
logger_1.logger.error(`\n${
|
|
112
|
+
logger_1.logger.error(`\n${prettyResult}\n\n`);
|
|
110
113
|
logger_1.logger.error(outcomeMessage(`THERE WERE ${resultMetadata.XFI_RESULT.errorCount} UNEXPECTED ERRORS!`));
|
|
111
114
|
process.exit(1);
|
|
112
115
|
}
|
|
113
116
|
if (resultMetadata.XFI_RESULT.fatalityCount > 0) {
|
|
114
117
|
logger_1.logger.error(outcomeMessage(`THERE WERE ${resultMetadata.XFI_RESULT.fatalityCount} FATAL ERRORS DETECTED TO BE IMMEDIATELY ADDRESSED!`));
|
|
115
|
-
logger_1.logger.error(`\n${
|
|
118
|
+
logger_1.logger.error(`\n${prettyResult}\n\n`);
|
|
116
119
|
logger_1.logger.error(outcomeMessage(`THERE WERE ${resultMetadata.XFI_RESULT.fatalityCount} FATAL ERRORS DETECTED TO BE IMMEDIATELY ADDRESSED!`));
|
|
117
120
|
process.exit(1);
|
|
118
121
|
}
|
|
119
122
|
else {
|
|
120
123
|
logger_1.logger.warn(outcomeMessage('No fatal errors were found, however please review the following warnings.'));
|
|
121
|
-
logger_1.logger.warn(`\n${
|
|
124
|
+
logger_1.logger.warn(`\n${prettyResult}\n\n`);
|
|
122
125
|
logger_1.logger.warn(outcomeMessage('No fatal errors were found, however please review the above warnings.'));
|
|
123
126
|
}
|
|
124
127
|
}
|
|
125
128
|
else {
|
|
126
129
|
logger_1.logger.info(outcomeMessage('SUCCESS! hi-fi codebase detected.'));
|
|
127
|
-
logger_1.logger.info(
|
|
128
|
-
logger_1.logger.info(`\n${
|
|
130
|
+
logger_1.logger.info(resultString);
|
|
131
|
+
logger_1.logger.info(`\n${prettyResult}\n\n`);
|
|
129
132
|
logger_1.logger.info(outcomeMessage('SUCCESS! hi-fi codebase detected.'));
|
|
130
133
|
}
|
|
131
134
|
}
|
|
132
135
|
}
|
|
133
136
|
}
|
|
134
137
|
catch (e) {
|
|
138
|
+
logger_1.logger.error(e, `Error during execution ${JSON.stringify(e.message)} \n ${e.stack}`);
|
|
135
139
|
yield handleError(e).then(() => {
|
|
136
140
|
// give some time async ops to finish if not handled directly
|
|
137
141
|
if (process.env.NODE_ENV !== 'test') {
|
|
@@ -143,10 +147,9 @@ function main() {
|
|
|
143
147
|
}
|
|
144
148
|
});
|
|
145
149
|
}
|
|
146
|
-
|
|
147
|
-
|
|
150
|
+
var configManager_1 = require("./core/configManager");
|
|
151
|
+
Object.defineProperty(exports, "repoDir", { enumerable: true, get: function () { return configManager_1.repoDir; } });
|
|
148
152
|
__exportStar(require("./utils/logger"), exports);
|
|
149
|
-
__exportStar(require("./core/engine/analyzer"), exports);
|
|
150
153
|
__exportStar(require("./types"), exports);
|
|
151
154
|
if (require.main === module) {
|
|
152
155
|
main();
|
|
@@ -16,7 +16,7 @@ const nonStandardDirectoryStructure = {
|
|
|
16
16
|
if (filePath !== configManager_1.REPO_GLOBAL_CHECK) {
|
|
17
17
|
return false;
|
|
18
18
|
}
|
|
19
|
-
logger_1.logger.
|
|
19
|
+
logger_1.logger.info(`running global directory structure analysis..`);
|
|
20
20
|
const repoPath = cli_1.options.dir || process.cwd();
|
|
21
21
|
let result = false;
|
|
22
22
|
// check the directory structure of the repo against the standard structure
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
3
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
4
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
5
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
6
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
7
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
8
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
9
|
+
});
|
|
10
|
+
};
|
|
11
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
12
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
13
|
+
};
|
|
14
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
|
+
exports.missingRequiredFiles = void 0;
|
|
16
|
+
const logger_1 = require("../../../utils/logger");
|
|
17
|
+
const configManager_1 = require("../../../core/configManager");
|
|
18
|
+
const path_1 = __importDefault(require("path"));
|
|
19
|
+
exports.missingRequiredFiles = {
|
|
20
|
+
name: 'missingRequiredFiles',
|
|
21
|
+
fn: (params, almanac) => __awaiter(void 0, void 0, void 0, function* () {
|
|
22
|
+
const result = { 'result': [] };
|
|
23
|
+
try {
|
|
24
|
+
// Get the required files from params
|
|
25
|
+
const requiredFiles = params.requiredFiles;
|
|
26
|
+
if (!Array.isArray(requiredFiles)) {
|
|
27
|
+
return { result: ['Required files parameter must be an array'] };
|
|
28
|
+
}
|
|
29
|
+
// Get globalFileData from almanac
|
|
30
|
+
const globalFileMetadata = yield almanac.factValue('globalFileMetadata');
|
|
31
|
+
if (!Array.isArray(globalFileMetadata)) {
|
|
32
|
+
return { result: ['Invalid globalFileData'] };
|
|
33
|
+
}
|
|
34
|
+
logger_1.logger.info('Executing missingRequiredFiles check', { requiredFiles });
|
|
35
|
+
// Get all file paths from the fileData fact
|
|
36
|
+
const repoFiles = new Set(globalFileMetadata.map((file) => {
|
|
37
|
+
logger_1.logger.trace(`${file.filePath} added to missingRequiredFiles check set`);
|
|
38
|
+
return file.filePath;
|
|
39
|
+
}));
|
|
40
|
+
// get the repo dir for the current repo as prefix
|
|
41
|
+
const repoDirPrefix = (0, configManager_1.repoDir)();
|
|
42
|
+
logger_1.logger.info(`Repo dir prefix: ${repoDirPrefix}`);
|
|
43
|
+
// Find which required files are missing
|
|
44
|
+
const missingFiles = requiredFiles.filter(file => {
|
|
45
|
+
let pathCheck = path_1.default.join(repoDirPrefix, file);
|
|
46
|
+
if (!pathCheck.startsWith(repoDirPrefix)) {
|
|
47
|
+
logger_1.logger.error(`Potential malicious input detected: ${file}`);
|
|
48
|
+
return true;
|
|
49
|
+
}
|
|
50
|
+
let result = !repoFiles.has(pathCheck);
|
|
51
|
+
if (result) {
|
|
52
|
+
logger_1.logger.error(`Required file: ${pathCheck} is missing`);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
logger_1.logger.info(`Required file: ${pathCheck} is present`);
|
|
56
|
+
}
|
|
57
|
+
return result;
|
|
58
|
+
});
|
|
59
|
+
if (missingFiles.length > 0) {
|
|
60
|
+
logger_1.logger.error(`Missing required files: ${JSON.stringify(missingFiles)}`);
|
|
61
|
+
result.result = missingFiles;
|
|
62
|
+
}
|
|
63
|
+
else {
|
|
64
|
+
logger_1.logger.debug('All required files present');
|
|
65
|
+
}
|
|
66
|
+
// Add the result to the almanac
|
|
67
|
+
almanac.addRuntimeFact(params.resultFact, result);
|
|
68
|
+
return result;
|
|
69
|
+
}
|
|
70
|
+
catch (error) {
|
|
71
|
+
logger_1.logger.error(`Error in missingRequiredFiles: ${error}`);
|
|
72
|
+
return result;
|
|
73
|
+
}
|
|
74
|
+
})
|
|
75
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { plugin } from './xfiPluginRequiredFiles';
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.plugin = void 0;
|
|
4
|
+
var xfiPluginRequiredFiles_1 = require("./xfiPluginRequiredFiles");
|
|
5
|
+
Object.defineProperty(exports, "plugin", { enumerable: true, get: function () { return xfiPluginRequiredFiles_1.plugin; } });
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.missingRequiredFiles = void 0;
|
|
4
|
+
const logger_1 = require("../../../utils/logger");
|
|
5
|
+
exports.missingRequiredFiles = {
|
|
6
|
+
name: 'missingRequiredFiles',
|
|
7
|
+
fn: (factValue, compareValue) => {
|
|
8
|
+
var _a;
|
|
9
|
+
try {
|
|
10
|
+
logger_1.logger.debug('missingRequiredFiles: processing..');
|
|
11
|
+
if (((_a = factValue === null || factValue === void 0 ? void 0 : factValue.result) === null || _a === void 0 ? void 0 : _a.length) > 0) {
|
|
12
|
+
logger_1.logger.debug('missingRequiredFiles: true');
|
|
13
|
+
return compareValue;
|
|
14
|
+
}
|
|
15
|
+
logger_1.logger.debug('missingRequiredFiles: false');
|
|
16
|
+
return !compareValue;
|
|
17
|
+
}
|
|
18
|
+
catch (e) {
|
|
19
|
+
logger_1.logger.error(`missingRequiredFiles: ${e}`);
|
|
20
|
+
return !compareValue;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const missingRequiredFiles_1 = require("./missingRequiredFiles");
|
|
4
|
+
const logger_1 = require("../../../utils/logger");
|
|
5
|
+
jest.mock('../../../utils/logger', () => ({
|
|
6
|
+
logger: {
|
|
7
|
+
debug: jest.fn(),
|
|
8
|
+
error: jest.fn()
|
|
9
|
+
},
|
|
10
|
+
}));
|
|
11
|
+
describe('missingRequiredFiles', () => {
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
jest.clearAllMocks();
|
|
14
|
+
});
|
|
15
|
+
it('should return true when missing files are found', () => {
|
|
16
|
+
const factValue = {
|
|
17
|
+
result: [{ file: 'missing.txt' }]
|
|
18
|
+
};
|
|
19
|
+
const result = missingRequiredFiles_1.missingRequiredFiles.fn(factValue, true);
|
|
20
|
+
expect(result).toBe(true);
|
|
21
|
+
expect(logger_1.logger.debug).toHaveBeenCalledWith('missingRequiredFiles: true');
|
|
22
|
+
});
|
|
23
|
+
it('should return false when no missing files are found', () => {
|
|
24
|
+
const factValue = {
|
|
25
|
+
result: []
|
|
26
|
+
};
|
|
27
|
+
const result = missingRequiredFiles_1.missingRequiredFiles.fn(factValue, true);
|
|
28
|
+
expect(result).toBe(false);
|
|
29
|
+
expect(logger_1.logger.debug).toHaveBeenCalledWith('missingRequiredFiles: false');
|
|
30
|
+
});
|
|
31
|
+
it('should handle undefined input gracefully', () => {
|
|
32
|
+
const result = missingRequiredFiles_1.missingRequiredFiles.fn(undefined, true);
|
|
33
|
+
expect(result).toBe(false);
|
|
34
|
+
expect(logger_1.logger.debug).toHaveBeenCalledWith('missingRequiredFiles: false');
|
|
35
|
+
});
|
|
36
|
+
it('should handle errors gracefully', () => {
|
|
37
|
+
const factValue = null;
|
|
38
|
+
const result = missingRequiredFiles_1.missingRequiredFiles.fn(factValue, true);
|
|
39
|
+
expect(result).toBe(false);
|
|
40
|
+
expect(logger_1.logger.debug).toHaveBeenCalledWith('missingRequiredFiles: false');
|
|
41
|
+
});
|
|
42
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.plugin = void 0;
|
|
4
|
+
const missingRequiredFiles_1 = require("./facts/missingRequiredFiles");
|
|
5
|
+
const missingRequiredFiles_2 = require("./operators/missingRequiredFiles");
|
|
6
|
+
const plugin = {
|
|
7
|
+
name: 'xfiPluginRequiredFiles',
|
|
8
|
+
version: '1.0.0',
|
|
9
|
+
facts: [missingRequiredFiles_1.missingRequiredFiles],
|
|
10
|
+
operators: [missingRequiredFiles_2.missingRequiredFiles],
|
|
11
|
+
onError: (error) => ({
|
|
12
|
+
message: `Required files check error: ${error.message}`,
|
|
13
|
+
level: 'warning',
|
|
14
|
+
details: error.stack
|
|
15
|
+
})
|
|
16
|
+
};
|
|
17
|
+
exports.plugin = plugin;
|