x-fidelity 2.0.0 → 2.2.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 +65 -0
- package/dist/core/cli.js +14 -6
- package/dist/facts/repoDependencyFacts.js +97 -33
- package/dist/facts/repoDependencyFacts.test.js +203 -192
- package/dist/rules/index.test.js +1 -0
- package/dist/server/configServer.js +13 -1
- package/dist/server/expressLogger.js +11 -2
- package/dist/utils/inputValidation.js +29 -0
- package/dist/utils/maskSensitiveData.js +25 -0
- package/dist/utils/telemetry.js +9 -9
- package/package.json +1 -1
- package/src/core/cli.ts +14 -6
- package/src/facts/repoDependencyFacts.test.ts +225 -235
- package/src/facts/repoDependencyFacts.ts +93 -28
- package/src/rules/index.test.ts +1 -0
- package/src/server/configServer.ts +15 -1
- package/src/server/expressLogger.ts +13 -3
- package/src/types/typeDefs.ts +3 -1
- package/src/utils/inputValidation.ts +32 -0
- package/src/utils/maskSensitiveData.ts +25 -0
- package/src/utils/telemetry.ts +10 -9
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,68 @@
|
|
|
1
|
+
# [2.2.0](https://github.com/zotoio/x-fidelity/compare/v2.1.0...v2.2.0) (2024-08-20)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* Centralize SHARED_SECRET check in sendTelemetry function ([2a99183](https://github.com/zotoio/x-fidelity/commit/2a99183059e815dc56ba731da9f432bad5049e16))
|
|
7
|
+
* Ensure object to be masked is not mutated in expressLogger ([af111a8](https://github.com/zotoio/x-fidelity/commit/af111a8eb6a9467f84d35db65ed21466097dfc38))
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* add shared secret header security to restrict access to the telemetry server using an environment variable, and update the client in the same way ([7935f69](https://github.com/zotoio/x-fidelity/commit/7935f6958bec827b8d4c8d144d4dc8c647948934))
|
|
13
|
+
* Apply shared secret check only to the /telemetry route ([72e7466](https://github.com/zotoio/x-fidelity/commit/72e746623d5058f4b7b36f9f00494d5aad4f9add))
|
|
14
|
+
* centralise masking in one reusable function ([d2f29d5](https://github.com/zotoio/x-fidelity/commit/d2f29d53f65ee76112774a2590559b1538af855e))
|
|
15
|
+
* Mask X-Shared-Secret header in request and response logs ([c6056ce](https://github.com/zotoio/x-fidelity/commit/c6056cecc527119123e8fb2d2f06ea44a9cbe803))
|
|
16
|
+
* partially mask shared secret and avoid logging it in full ([953be35](https://github.com/zotoio/x-fidelity/commit/953be35ab716692439e95121b13e96cbe0347716))
|
|
17
|
+
* **telemetry:** option for sharedSecret for telemetry client and server ([f85b312](https://github.com/zotoio/x-fidelity/commit/f85b312f7773668cd44e1e1799694ac421825a35))
|
|
18
|
+
|
|
19
|
+
# [2.1.0](https://github.com/zotoio/x-fidelity/compare/v2.0.0...v2.1.0) (2024-08-19)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
### Bug Fixes
|
|
23
|
+
|
|
24
|
+
* Add missing mock implementation for fs.existsSync in repoDependencyFacts.test.ts ([f69c22b](https://github.com/zotoio/x-fidelity/commit/f69c22b6421c1e98714c5391a6f6c97e0f11f917))
|
|
25
|
+
* Add mocks for semver in repoDependencyFacts.test.ts ([a852ff5](https://github.com/zotoio/x-fidelity/commit/a852ff5092a0f7f65292b98013e435685a16f2c2))
|
|
26
|
+
* Add null check for input in validateInput function ([c5d8bf3](https://github.com/zotoio/x-fidelity/commit/c5d8bf3c735ac6aa9598ba5254de14a9f75ddcf1))
|
|
27
|
+
* Add type annotation for mockLocalDependencies in repoDependencyFacts.test.ts ([79cfff0](https://github.com/zotoio/x-fidelity/commit/79cfff07a78328a881ae24309564e4b6954f7770))
|
|
28
|
+
* Correct the structure of LocalDependencies in repoDependencyFacts.test.ts ([346924f](https://github.com/zotoio/x-fidelity/commit/346924f93b968baf123f4fc5e2e7de45dbba81e9))
|
|
29
|
+
* Ensure dependencies are properly added to the result array in processNpmDependencies ([21025db](https://github.com/zotoio/x-fidelity/commit/21025db2ef520c104bb32d3dd0396d93503e3061))
|
|
30
|
+
* **facts:** ensure dependencies are compatible with npm and yarn, and extensible ([fe0e40f](https://github.com/zotoio/x-fidelity/commit/fe0e40f7e0fb2c263fa63ad2eeda1ff5574fc669))
|
|
31
|
+
* Fix mocked import path for cli options ([8806297](https://github.com/zotoio/x-fidelity/commit/8806297dafe2d6a587efb6957c93028964393879))
|
|
32
|
+
* fix type annotation for collectLocalDependencies mock ([d2a7739](https://github.com/zotoio/x-fidelity/commit/d2a7739fcd78f775dbff648727729204474507ac))
|
|
33
|
+
* Fix type error in unit test ([58f14aa](https://github.com/zotoio/x-fidelity/commit/58f14aaaf92070805194f5012df798fe78f3bdcb))
|
|
34
|
+
* Fix TypeScript errors in repoDependencyFacts.test.ts ([50a2029](https://github.com/zotoio/x-fidelity/commit/50a2029bb49304177a2fec1f092642bf19689a4e))
|
|
35
|
+
* Fix TypeScript errors in repoDependencyFacts.test.ts ([a3da3da](https://github.com/zotoio/x-fidelity/commit/a3da3dacf4cf08810969e8b988c978ef7781c66b))
|
|
36
|
+
* Fix TypeScript errors in repoDependencyFacts.test.ts ([1869968](https://github.com/zotoio/x-fidelity/commit/1869968282cbc609235ee061d953081bd6113675))
|
|
37
|
+
* Handle missing package manager files gracefully ([95da9ab](https://github.com/zotoio/x-fidelity/commit/95da9ab4fe5dcfadfae6209ffffcf74ed6274f06))
|
|
38
|
+
* Implement dependency analysis tests ([9b0426b](https://github.com/zotoio/x-fidelity/commit/9b0426b2a5be278f9dae8f8d4eee8293b7cffad9))
|
|
39
|
+
* Improve error handling and return value in collectLocalDependencies function ([7c6c06c](https://github.com/zotoio/x-fidelity/commit/7c6c06c223bc5f239f937b707948b67320ba0d2d))
|
|
40
|
+
* Improve input validation and add logging for potential attacks ([e5e2cd4](https://github.com/zotoio/x-fidelity/commit/e5e2cd4bd907d54837d512e5907b49ce6f4d8f6b))
|
|
41
|
+
* Mock `collectLocalDependencies` function in `repoDependencyFacts.test.ts` ([33a1634](https://github.com/zotoio/x-fidelity/commit/33a16349c7bb4396d7217138deda2ddf13a07d52))
|
|
42
|
+
* mock collectLocalDependencies function correctly ([fde463a](https://github.com/zotoio/x-fidelity/commit/fde463aa536ce466b605d038acefe57ef85c91bc))
|
|
43
|
+
* Mock fs and child_process modules in repoDependencyFacts.test.ts ([f43c3a5](https://github.com/zotoio/x-fidelity/commit/f43c3a53d8961962cfda6107a37815a3e13bbc01))
|
|
44
|
+
* Refactor repoDependencyFacts tests ([cb2fd9a](https://github.com/zotoio/x-fidelity/commit/cb2fd9a3d941061fc9aff928b17c6640498abdf9))
|
|
45
|
+
* Resolve TypeScript error in repoDependencyFacts.test.ts ([6bb0f22](https://github.com/zotoio/x-fidelity/commit/6bb0f220538e4b672309f20c57688a9b2de1039a))
|
|
46
|
+
* rewrite src/facts/repoDependencyFacts.test.ts to ensure it adheres to the logic in the implementation and that it mocks required objects correctly and covers all positive and negative use-cases ([2d4548c](https://github.com/zotoio/x-fidelity/commit/2d4548c5b922bea31c7b1aa5accafbf1ae1593dd))
|
|
47
|
+
* Throw error when no lock file is found and return empty array when no local dependencies are found ([a30a660](https://github.com/zotoio/x-fidelity/commit/a30a6600c3b930cbb8237c1e82f91e3b5d76bc91))
|
|
48
|
+
* Update `src/facts/repoDependencyFacts.test.ts` to fix TypeScript error ([254f770](https://github.com/zotoio/x-fidelity/commit/254f7706f807558f5a227c2091953a499e70c23c))
|
|
49
|
+
* Update collectLocalDependencies test to return an empty array ([04bdda7](https://github.com/zotoio/x-fidelity/commit/04bdda734f335c06c56965fa7043c9d40c5e78a7))
|
|
50
|
+
* Update error message expectation in test ([6f287bd](https://github.com/zotoio/x-fidelity/commit/6f287bd9bfca340d9e2e3f6fd3d268196251effe))
|
|
51
|
+
* Update yarn dependency processing logic ([5f2a39d](https://github.com/zotoio/x-fidelity/commit/5f2a39dbd19e3a72bee7bb9964568ff2dfc499b5))
|
|
52
|
+
* Use yarn instead of npm to collect local dependencies ([482b479](https://github.com/zotoio/x-fidelity/commit/482b479a372897f95c50bed63a2ca9faac92b96d))
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
### Features
|
|
56
|
+
|
|
57
|
+
* create comprehensive unit test file for repoDependencyFacts ([1253f74](https://github.com/zotoio/x-fidelity/commit/1253f744dcfa6c267c33ae02dfbf418710d1c85b))
|
|
58
|
+
* Decompose collectLocalDependencies ([b865d09](https://github.com/zotoio/x-fidelity/commit/b865d0977482f33f9708f623655bcf3e26812b25))
|
|
59
|
+
* Implement recursive processing of dependencies in repoDependencyFacts.ts ([557916a](https://github.com/zotoio/x-fidelity/commit/557916abe77acb9eaefd682e8b2374d4fd000abc))
|
|
60
|
+
* Refactor dependency collection and processing ([fc7e037](https://github.com/zotoio/x-fidelity/commit/fc7e0376d59992f573af7fe1b3a031f3cb279a81))
|
|
61
|
+
* Rewrite the entire `src/facts/repoDependencyFacts.test.ts` based on the new implementations ([83466b4](https://github.com/zotoio/x-fidelity/commit/83466b41ba8ebcb87593277adeab9c695f7200c7))
|
|
62
|
+
* update `findPropertiesInTree` to operate on the new output structure of the `LocalDependencies` ([608f301](https://github.com/zotoio/x-fidelity/commit/608f301ef4997dad923952700672115c5725149a))
|
|
63
|
+
* update code to conform to updated `LocalDependencies` interface ([864bc68](https://github.com/zotoio/x-fidelity/commit/864bc683b95eccfa92f5b4135e7e0821994928e9))
|
|
64
|
+
* update repoDependencyFacts unit tests to match implementations ([7f56ead](https://github.com/zotoio/x-fidelity/commit/7f56ead5659d45ddbc359d5976a47cc16154452e))
|
|
65
|
+
|
|
1
66
|
# [2.0.0](https://github.com/zotoio/x-fidelity/compare/v1.17.0...v2.0.0) (2024-08-17)
|
|
2
67
|
|
|
3
68
|
|
package/dist/core/cli.js
CHANGED
|
@@ -9,6 +9,7 @@ const commander_1 = require("commander");
|
|
|
9
9
|
const path_1 = __importDefault(require("path"));
|
|
10
10
|
const fs_1 = __importDefault(require("fs"));
|
|
11
11
|
const package_json_1 = require("../../package.json");
|
|
12
|
+
const inputValidation_1 = require("../utils/inputValidation");
|
|
12
13
|
// Ensure logger is initialized
|
|
13
14
|
if (!logger_1.logger || typeof logger_1.logger.info !== 'function') {
|
|
14
15
|
console.error('Logger is not properly initialized');
|
|
@@ -46,20 +47,27 @@ if (process.argv.length === 2 && commander_1.program.args.length === 0) {
|
|
|
46
47
|
// Resolve paths
|
|
47
48
|
if (process.env.NODE_ENV === 'test' || options.mode === 'server')
|
|
48
49
|
options.dir = '.';
|
|
49
|
-
const resolvePath = (inputPath) =>
|
|
50
|
+
const resolvePath = (inputPath) => {
|
|
51
|
+
const resolvedPath = path_1.default === null || path_1.default === void 0 ? void 0 : path_1.default.resolve(process.cwd(), inputPath);
|
|
52
|
+
if (!(0, inputValidation_1.validateInput)(resolvedPath)) {
|
|
53
|
+
logger_1.logger.warn(`Potential malicious input detected: ${inputPath}`);
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
return resolvedPath;
|
|
57
|
+
};
|
|
50
58
|
options.dir = commander_1.program.args.length == 1 ? resolvePath(commander_1.program.args[0]) : resolvePath(options.dir);
|
|
51
59
|
if (options.localConfigPath) {
|
|
52
60
|
options.localConfigPath = resolvePath(options.localConfigPath);
|
|
53
61
|
}
|
|
54
|
-
// if dir does not exist, exit
|
|
62
|
+
// if dir does not exist or is invalid, exit
|
|
55
63
|
if (!options.dir || !fs_1.default.existsSync(options.dir)) {
|
|
56
|
-
logger_1.logger.error(`
|
|
64
|
+
logger_1.logger.error(`Target directory ${options.dir} does not exist or is invalid`);
|
|
57
65
|
if (process.env.NODE_ENV !== 'test')
|
|
58
66
|
process.exit(1);
|
|
59
67
|
}
|
|
60
|
-
// if localConfig path does not exist, exit
|
|
61
|
-
if (options.localConfigPath && !fs_1.default.existsSync(options.localConfigPath)) {
|
|
62
|
-
logger_1.logger.error(`
|
|
68
|
+
// if localConfig path does not exist or is invalid, exit
|
|
69
|
+
if (options.localConfigPath && (!fs_1.default.existsSync(options.localConfigPath) || !(0, inputValidation_1.validateInput)(options.localConfigPath))) {
|
|
70
|
+
logger_1.logger.error(`LocalConfigPath ${options.localConfigPath} does not exist or is invalid`);
|
|
63
71
|
if (process.env.NODE_ENV !== 'test')
|
|
64
72
|
process.exit(1);
|
|
65
73
|
}
|
|
@@ -40,26 +40,98 @@ exports.getDependencyVersionFacts = getDependencyVersionFacts;
|
|
|
40
40
|
exports.findPropertiesInTree = findPropertiesInTree;
|
|
41
41
|
exports.repoDependencyAnalysis = repoDependencyAnalysis;
|
|
42
42
|
const logger_1 = require("../utils/logger");
|
|
43
|
-
const lodash_1 = __importDefault(require("lodash"));
|
|
44
43
|
const child_process_1 = require("child_process");
|
|
45
44
|
const semver = __importStar(require("semver"));
|
|
46
45
|
const cli_1 = require("../core/cli");
|
|
46
|
+
const fs_1 = __importDefault(require("fs"));
|
|
47
|
+
const path_1 = __importDefault(require("path"));
|
|
47
48
|
/**
|
|
48
49
|
* Collects the local dependencies.
|
|
49
50
|
* @returns The local dependencies.
|
|
50
51
|
*/
|
|
51
52
|
function collectLocalDependencies() {
|
|
52
|
-
let result =
|
|
53
|
+
let result = [];
|
|
54
|
+
if (fs_1.default.existsSync(path_1.default.join(cli_1.options.dir, 'yarn.lock'))) {
|
|
55
|
+
result = collectYarnDependencies();
|
|
56
|
+
}
|
|
57
|
+
else if (fs_1.default.existsSync(path_1.default.join(cli_1.options.dir, 'package-lock.json'))) {
|
|
58
|
+
result = collectNpmDependencies();
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
logger_1.logger.error('No yarn.lock or package-lock.json found');
|
|
62
|
+
throw new Error('Unsupported package manager');
|
|
63
|
+
}
|
|
64
|
+
logger_1.logger.debug(`collectLocalDependencies: ${JSON.stringify(result)}`);
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
function collectYarnDependencies() {
|
|
68
|
+
try {
|
|
69
|
+
const stdout = (0, child_process_1.execSync)(`yarn list --json --cwd ${cli_1.options.dir}`);
|
|
70
|
+
const result = JSON.parse(stdout.toString());
|
|
71
|
+
logger_1.logger.debug(`collectYarnDependencies: ${JSON.stringify(result)}`);
|
|
72
|
+
return processYarnDependencies(result);
|
|
73
|
+
}
|
|
74
|
+
catch (e) {
|
|
75
|
+
logger_1.logger.error(`Error collecting Yarn dependencies: ${e}`);
|
|
76
|
+
throw e;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
function collectNpmDependencies() {
|
|
53
80
|
try {
|
|
54
81
|
const stdout = (0, child_process_1.execSync)(`npm ls -a --json --prefix ${cli_1.options.dir}`);
|
|
55
|
-
result = JSON.parse(stdout.toString());
|
|
56
|
-
logger_1.logger.debug(`
|
|
82
|
+
const result = JSON.parse(stdout.toString());
|
|
83
|
+
logger_1.logger.debug(`collectNpmDependencies: ${JSON.stringify(result)}`);
|
|
84
|
+
return processNpmDependencies(result);
|
|
57
85
|
}
|
|
58
86
|
catch (e) {
|
|
59
|
-
logger_1.logger.error(`
|
|
60
|
-
|
|
87
|
+
logger_1.logger.error(`Error collecting NPM dependencies: ${e}`);
|
|
88
|
+
throw e;
|
|
61
89
|
}
|
|
62
|
-
|
|
90
|
+
}
|
|
91
|
+
function processYarnDependencies(yarnOutput) {
|
|
92
|
+
var _a;
|
|
93
|
+
const dependencies = [];
|
|
94
|
+
if ((_a = yarnOutput === null || yarnOutput === void 0 ? void 0 : yarnOutput.data) === null || _a === void 0 ? void 0 : _a.trees) {
|
|
95
|
+
const processDependency = (node) => {
|
|
96
|
+
const newDep = extractNameAndVersion(node.name);
|
|
97
|
+
if (node.children) {
|
|
98
|
+
newDep.dependencies = [];
|
|
99
|
+
node.children.forEach((child) => {
|
|
100
|
+
var _a;
|
|
101
|
+
(_a = newDep.dependencies) === null || _a === void 0 ? void 0 : _a.push(processDependency(child));
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
return newDep;
|
|
105
|
+
};
|
|
106
|
+
const extractNameAndVersion = (nameAndVersion) => {
|
|
107
|
+
const parts = nameAndVersion.split('@');
|
|
108
|
+
return { name: parts[0], version: parts[1] };
|
|
109
|
+
};
|
|
110
|
+
yarnOutput.data.trees.forEach((tree) => {
|
|
111
|
+
dependencies.push(processDependency(tree));
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
return dependencies;
|
|
115
|
+
}
|
|
116
|
+
function processNpmDependencies(npmOutput) {
|
|
117
|
+
const dependencies = [];
|
|
118
|
+
const processDependency = (name, info) => {
|
|
119
|
+
const newDep = { name, version: info.version };
|
|
120
|
+
if (info.dependencies) {
|
|
121
|
+
newDep.dependencies = [];
|
|
122
|
+
Object.entries(info.dependencies).forEach(([childName, childInfo]) => {
|
|
123
|
+
var _a;
|
|
124
|
+
(_a = newDep.dependencies) === null || _a === void 0 ? void 0 : _a.push(processDependency(childName, childInfo));
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
return newDep;
|
|
128
|
+
};
|
|
129
|
+
if (npmOutput.dependencies) {
|
|
130
|
+
Object.entries(npmOutput.dependencies).forEach(([name, info]) => {
|
|
131
|
+
dependencies.push(processDependency(name, info));
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
return dependencies;
|
|
63
135
|
}
|
|
64
136
|
/**
|
|
65
137
|
* Gets the installed dependency versions.
|
|
@@ -67,16 +139,14 @@ function collectLocalDependencies() {
|
|
|
67
139
|
* @returns The installed dependency versions.
|
|
68
140
|
*/
|
|
69
141
|
function getDependencyVersionFacts(archetypeConfig) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
return installedDependencyVersions;
|
|
79
|
-
});
|
|
142
|
+
const localDependencies = collectLocalDependencies();
|
|
143
|
+
const minimumDependencyVersions = archetypeConfig.config.minimumDependencyVersions;
|
|
144
|
+
if (!localDependencies || localDependencies.length === 0) {
|
|
145
|
+
logger_1.logger.error('getDependencyVersionFacts: no local dependencies found');
|
|
146
|
+
return [];
|
|
147
|
+
}
|
|
148
|
+
const installedDependencyVersions = findPropertiesInTree(localDependencies, minimumDependencyVersions);
|
|
149
|
+
return installedDependencyVersions;
|
|
80
150
|
}
|
|
81
151
|
/**
|
|
82
152
|
* Recursively search for properties in a tree of objects.
|
|
@@ -86,25 +156,19 @@ function getDependencyVersionFacts(archetypeConfig) {
|
|
|
86
156
|
*/
|
|
87
157
|
function findPropertiesInTree(depGraph, minVersions) {
|
|
88
158
|
const results = [];
|
|
89
|
-
logger_1.logger.debug(`depGraph: ${depGraph}`);
|
|
90
|
-
function walk(
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
results.push({ dep: depName, ver: depGraph[depName].version, min: minVersions[depName] });
|
|
95
|
-
}
|
|
96
|
-
if (lodash_1.default.isObject(depGraph[depName])) {
|
|
97
|
-
walk(depGraph[depName]);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
159
|
+
logger_1.logger.debug(`depGraph: ${JSON.stringify(depGraph)}`);
|
|
160
|
+
function walk(dep, parentName = '') {
|
|
161
|
+
const fullName = parentName ? `${parentName}/${dep.name}` : dep.name;
|
|
162
|
+
if (Object.keys(minVersions).includes(dep.name)) {
|
|
163
|
+
results.push({ dep: fullName, ver: dep.version, min: minVersions[dep.name] });
|
|
100
164
|
}
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
walk(
|
|
104
|
-
}
|
|
165
|
+
if (dep.dependencies) {
|
|
166
|
+
dep.dependencies.forEach(childDep => {
|
|
167
|
+
walk(childDep, fullName);
|
|
168
|
+
});
|
|
105
169
|
}
|
|
106
170
|
}
|
|
107
|
-
walk(
|
|
171
|
+
depGraph.forEach(dep => walk(dep));
|
|
108
172
|
return results;
|
|
109
173
|
}
|
|
110
174
|
function repoDependencyAnalysis(params, almanac) {
|