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.
Files changed (47) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/dist/core/cli.js +30 -14
  3. package/dist/core/configManager.d.ts +1 -0
  4. package/dist/core/configManager.js +4 -0
  5. package/dist/core/engine/analyzer.js +8 -2
  6. package/dist/core/engine/analyzer.test.js +11 -3
  7. package/dist/core/engine/engineRunner.js +4 -2
  8. package/dist/demoConfig/node-fullstack.json +8 -4
  9. package/dist/demoConfig/rules/missingRequiredFiles-global-rule.json +35 -0
  10. package/dist/demoConfig/rules/sensitiveLogging-iterative-rule.json +2 -1
  11. package/dist/facts/repoDependencyFacts.js +0 -1
  12. package/dist/index.d.ts +1 -3
  13. package/dist/index.js +14 -11
  14. package/dist/operators/nonStandardDirectoryStructure.js +1 -1
  15. package/dist/plugins/xfiPluginRequiredFiles/facts/missingRequiredFiles.d.ts +2 -0
  16. package/dist/plugins/xfiPluginRequiredFiles/facts/missingRequiredFiles.js +75 -0
  17. package/dist/plugins/xfiPluginRequiredFiles/index.d.ts +1 -0
  18. package/dist/plugins/xfiPluginRequiredFiles/index.js +5 -0
  19. package/dist/plugins/xfiPluginRequiredFiles/operators/missingRequiredFiles.d.ts +2 -0
  20. package/dist/plugins/xfiPluginRequiredFiles/operators/missingRequiredFiles.js +23 -0
  21. package/dist/plugins/xfiPluginRequiredFiles/operators/missingRequiredFiles.test.d.ts +1 -0
  22. package/dist/plugins/xfiPluginRequiredFiles/operators/missingRequiredFiles.test.js +42 -0
  23. package/dist/plugins/xfiPluginRequiredFiles/xfiPluginRequiredFiles.d.ts +3 -0
  24. package/dist/plugins/xfiPluginRequiredFiles/xfiPluginRequiredFiles.js +17 -0
  25. package/dist/types/typeDefs.d.ts +3 -0
  26. package/dist/utils/logger.js +4 -9
  27. package/dist/xfidelity +14 -11
  28. package/package.json +3 -3
  29. package/src/core/cli.ts +31 -15
  30. package/src/core/configManager.ts +6 -0
  31. package/src/core/engine/analyzer.test.ts +11 -3
  32. package/src/core/engine/analyzer.ts +10 -2
  33. package/src/core/engine/engineRunner.ts +4 -2
  34. package/src/demoConfig/node-fullstack.json +8 -4
  35. package/src/demoConfig/rules/missingRequiredFiles-global-rule.json +35 -0
  36. package/src/demoConfig/rules/sensitiveLogging-iterative-rule.json +2 -1
  37. package/src/facts/repoDependencyFacts.ts +0 -1
  38. package/src/index.ts +16 -14
  39. package/src/operators/nonStandardDirectoryStructure.ts +1 -1
  40. package/src/plugins/xfiPluginRequiredFiles/facts/missingRequiredFiles.ts +69 -0
  41. package/src/plugins/xfiPluginRequiredFiles/index.ts +1 -0
  42. package/src/plugins/xfiPluginRequiredFiles/operators/missingRequiredFiles.test.ts +46 -0
  43. package/src/plugins/xfiPluginRequiredFiles/operators/missingRequiredFiles.ts +22 -0
  44. package/src/plugins/xfiPluginRequiredFiles/sampleRules/missingRequiredFiles-global-rule.json +35 -0
  45. package/src/plugins/xfiPluginRequiredFiles/xfiPluginRequiredFiles.ts +17 -0
  46. package/src/types/typeDefs.ts +4 -1
  47. 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>", "code directory to analyze. equivalent of directory argument")
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
- .argument('[directory]', 'code directory to analyze');
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: 3,
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: 3,
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: 3,
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
- for (const file of fileData) {
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
+ }
@@ -26,7 +26,8 @@
26
26
  "(password|passphrase)",
27
27
  "(private[_-]?key|ssh[_-]?key)",
28
28
  "(oauth[_-]?token|jwt[_-]?token)",
29
- "db[_-]?password"
29
+ "db[_-]?password",
30
+ "(declare)"
30
31
  ],
31
32
  "resultFact": "fileResults"
32
33
  },
@@ -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 * from './utils/axiosClient';
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(JSON.stringify(resultMetadata));
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${prettyjson_1.default.render(resultMetadata.XFI_RESULT)}\n\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${prettyjson_1.default.render(resultMetadata.XFI_RESULT)}\n\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${prettyjson_1.default.render(resultMetadata.XFI_RESULT)}\n\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(JSON.stringify(resultMetadata));
128
- logger_1.logger.info(`\n${prettyjson_1.default.render(resultMetadata)}\n\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
- __exportStar(require("./utils/axiosClient"), exports);
147
- __exportStar(require("./core/configManager"), exports);
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.debug(`running global directory structure analysis..`);
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,2 @@
1
+ import { FactDefn } from '../../../types/typeDefs';
2
+ export declare const missingRequiredFiles: FactDefn;
@@ -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,2 @@
1
+ import { OperatorDefn } from '../../../types/typeDefs';
2
+ export declare const missingRequiredFiles: OperatorDefn;
@@ -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,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,3 @@
1
+ import { XFiPlugin } from '../../types/typeDefs';
2
+ declare const plugin: XFiPlugin;
3
+ export { plugin };
@@ -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;