x-fidelity 3.7.0 → 3.8.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/.github/dependabot.yml +24 -0
- package/.github/workflows/codeql.yml +98 -0
- package/.yarnrc +2 -0
- package/CHANGELOG.md +19 -0
- package/dist/core/engine/engineRunner.js +4 -2
- package/dist/demoConfig/node-fullstack.json +1 -1
- package/dist/demoConfig/rules/{apiUsageConsistency-global-rule.json → newSdkFeatureNotAdoped-global-rule.json} +4 -4
- package/dist/facts/globalFileAnalysisFacts.test.js +3 -3
- package/dist/facts/repoFilesystemFacts.js +14 -8
- package/dist/index.js +4 -9
- package/dist/utils/exemptionUtils.js +7 -5
- package/dist/xfidelity +4 -9
- package/package.json +30 -29
- package/src/IDEAS.md +84 -0
- package/src/core/engine/engineRunner.ts +4 -2
- package/src/demoConfig/node-fullstack.json +1 -1
- package/src/demoConfig/rules/{apiUsageConsistency-global-rule.json → newSdkFeatureNotAdoped-global-rule.json} +4 -4
- package/src/facts/globalFileAnalysisFacts.test.ts +3 -3
- package/src/facts/repoFilesystemFacts.ts +15 -10
- package/src/index.ts +5 -9
- package/src/utils/exemptionUtils.ts +7 -5
- package/website/package.json +1 -1
- package/website/yarn.lock +4 -4
package/.github/dependabot.yml
CHANGED
|
@@ -9,3 +9,27 @@ updates:
|
|
|
9
9
|
directory: "/" # Location of package manifests
|
|
10
10
|
schedule:
|
|
11
11
|
interval: "weekly"
|
|
12
|
+
groups:
|
|
13
|
+
# Specify a name for the group, which will be used in pull request titles
|
|
14
|
+
# and branch names
|
|
15
|
+
xfi-app:
|
|
16
|
+
applies-to: version-updates
|
|
17
|
+
patterns:
|
|
18
|
+
- "*"
|
|
19
|
+
update-types:
|
|
20
|
+
- "minor"
|
|
21
|
+
- "patch"
|
|
22
|
+
- package-ecosystem: "npm" # See documentation for possible values
|
|
23
|
+
directory: "/website" # Location of package manifests
|
|
24
|
+
schedule:
|
|
25
|
+
interval: "weekly"
|
|
26
|
+
groups:
|
|
27
|
+
# Specify a name for the group, which will be used in pull request titles
|
|
28
|
+
# and branch names
|
|
29
|
+
xfi-web:
|
|
30
|
+
applies-to: version-updates
|
|
31
|
+
patterns:
|
|
32
|
+
- "*"
|
|
33
|
+
update-types:
|
|
34
|
+
- "minor"
|
|
35
|
+
- "patch"
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# For most projects, this workflow file will not need changing; you simply need
|
|
2
|
+
# to commit it to your repository.
|
|
3
|
+
#
|
|
4
|
+
# You may wish to alter this file to override the set of languages analyzed,
|
|
5
|
+
# or to provide custom queries or build logic.
|
|
6
|
+
#
|
|
7
|
+
# ******** NOTE ********
|
|
8
|
+
# We have attempted to detect the languages in your repository. Please check
|
|
9
|
+
# the `language` matrix defined below to confirm you have the correct set of
|
|
10
|
+
# supported CodeQL languages.
|
|
11
|
+
#
|
|
12
|
+
name: "CodeQL Advanced"
|
|
13
|
+
|
|
14
|
+
on:
|
|
15
|
+
push:
|
|
16
|
+
branches: [ "master" ]
|
|
17
|
+
pull_request:
|
|
18
|
+
branches: [ "master" ]
|
|
19
|
+
schedule:
|
|
20
|
+
- cron: '36 11 * * 4'
|
|
21
|
+
|
|
22
|
+
jobs:
|
|
23
|
+
analyze:
|
|
24
|
+
name: Analyze (${{ matrix.language }})
|
|
25
|
+
# Runner size impacts CodeQL analysis time. To learn more, please see:
|
|
26
|
+
# - https://gh.io/recommended-hardware-resources-for-running-codeql
|
|
27
|
+
# - https://gh.io/supported-runners-and-hardware-resources
|
|
28
|
+
# - https://gh.io/using-larger-runners (GitHub.com only)
|
|
29
|
+
# Consider using larger runners or machines with greater resources for possible analysis time improvements.
|
|
30
|
+
runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}
|
|
31
|
+
permissions:
|
|
32
|
+
# required for all workflows
|
|
33
|
+
security-events: write
|
|
34
|
+
|
|
35
|
+
# required to fetch internal or private CodeQL packs
|
|
36
|
+
packages: read
|
|
37
|
+
|
|
38
|
+
# only required for workflows in private repositories
|
|
39
|
+
actions: read
|
|
40
|
+
contents: read
|
|
41
|
+
|
|
42
|
+
strategy:
|
|
43
|
+
fail-fast: false
|
|
44
|
+
matrix:
|
|
45
|
+
include:
|
|
46
|
+
- language: javascript-typescript
|
|
47
|
+
build-mode: none
|
|
48
|
+
# CodeQL supports the following values keywords for 'language': 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift'
|
|
49
|
+
# Use `c-cpp` to analyze code written in C, C++ or both
|
|
50
|
+
# Use 'java-kotlin' to analyze code written in Java, Kotlin or both
|
|
51
|
+
# Use 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both
|
|
52
|
+
# To learn more about changing the languages that are analyzed or customizing the build mode for your analysis,
|
|
53
|
+
# see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/customizing-your-advanced-setup-for-code-scanning.
|
|
54
|
+
# If you are analyzing a compiled language, you can modify the 'build-mode' for that language to customize how
|
|
55
|
+
# your codebase is analyzed, see https://docs.github.com/en/code-security/code-scanning/creating-an-advanced-setup-for-code-scanning/codeql-code-scanning-for-compiled-languages
|
|
56
|
+
steps:
|
|
57
|
+
- name: Checkout repository
|
|
58
|
+
uses: actions/checkout@v4
|
|
59
|
+
|
|
60
|
+
# Add any setup steps before running the `github/codeql-action/init` action.
|
|
61
|
+
# This includes steps like installing compilers or runtimes (`actions/setup-node`
|
|
62
|
+
# or others). This is typically only required for manual builds.
|
|
63
|
+
# - name: Setup runtime (example)
|
|
64
|
+
# uses: actions/setup-example@v1
|
|
65
|
+
|
|
66
|
+
# Initializes the CodeQL tools for scanning.
|
|
67
|
+
- name: Initialize CodeQL
|
|
68
|
+
uses: github/codeql-action/init@v3
|
|
69
|
+
with:
|
|
70
|
+
languages: ${{ matrix.language }}
|
|
71
|
+
build-mode: ${{ matrix.build-mode }}
|
|
72
|
+
# If you wish to specify custom queries, you can do so here or in a config file.
|
|
73
|
+
# By default, queries listed here will override any specified in a config file.
|
|
74
|
+
# Prefix the list here with "+" to use these queries and those in the config file.
|
|
75
|
+
|
|
76
|
+
# For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs
|
|
77
|
+
# queries: security-extended,security-and-quality
|
|
78
|
+
|
|
79
|
+
# If the analyze step fails for one of the languages you are analyzing with
|
|
80
|
+
# "We were unable to automatically build your code", modify the matrix above
|
|
81
|
+
# to set the build mode to "manual" for that language. Then modify this step
|
|
82
|
+
# to build your code.
|
|
83
|
+
# ℹ️ Command-line programs to run using the OS shell.
|
|
84
|
+
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
|
|
85
|
+
- if: matrix.build-mode == 'manual'
|
|
86
|
+
shell: bash
|
|
87
|
+
run: |
|
|
88
|
+
echo 'If you are using a "manual" build mode for one or more of the' \
|
|
89
|
+
'languages you are analyzing, replace this with the commands to build' \
|
|
90
|
+
'your code, for example:'
|
|
91
|
+
echo ' make bootstrap'
|
|
92
|
+
echo ' make release'
|
|
93
|
+
exit 1
|
|
94
|
+
|
|
95
|
+
- name: Perform CodeQL Analysis
|
|
96
|
+
uses: github/codeql-action/analyze@v3
|
|
97
|
+
with:
|
|
98
|
+
category: "/language:${{matrix.language}}"
|
package/.yarnrc
ADDED
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
# [3.8.0](https://github.com/zotoio/x-fidelity/compare/v3.7.1...v3.8.0) (2025-03-02)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* enhance error logging with file context and flush logs before exit ([ebdffb4](https://github.com/zotoio/x-fidelity/commit/ebdffb475b6529355660949092bb9e045ad359a3))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Performance Improvements
|
|
10
|
+
|
|
11
|
+
* **analysis:** fix performance issue for very large codebases ([067ab7e](https://github.com/zotoio/x-fidelity/commit/067ab7e5d10fc1c45d44bb936f808e477ed85303))
|
|
12
|
+
|
|
13
|
+
## [3.7.1](https://github.com/zotoio/x-fidelity/compare/v3.7.0...v3.7.1) (2025-03-01)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
* package.json & yarn.lock to reduce vulnerabilities ([b21eab3](https://github.com/zotoio/x-fidelity/commit/b21eab312ec803f4a9f9fb078ece0a21a5b6b610))
|
|
19
|
+
|
|
1
20
|
# [3.7.0](https://github.com/zotoio/x-fidelity/compare/v3.6.0...v3.7.0) (2025-02-27)
|
|
2
21
|
|
|
3
22
|
|
|
@@ -83,13 +83,15 @@ function runEngineOnFiles(params) {
|
|
|
83
83
|
errorLevel = (rule === null || rule === void 0 ? void 0 : rule.errorBehavior) === 'fatal' || ((_f = rule === null || rule === void 0 ? void 0 : rule.event) === null || _f === void 0 ? void 0 : _f.type) === 'fatality' ? 'fatality' : 'error';
|
|
84
84
|
}
|
|
85
85
|
logger_1.logger.error({
|
|
86
|
+
index: i,
|
|
87
|
+
file: file.filePath,
|
|
86
88
|
err: handledError || error,
|
|
87
89
|
rule: failedRuleName,
|
|
88
90
|
source: errorSource,
|
|
89
91
|
type: errorLevel,
|
|
90
|
-
|
|
92
|
+
stack: (handledError || error).stack,
|
|
91
93
|
details: ((_g = error === null || error === void 0 ? void 0 : error.pluginError) === null || _g === void 0 ? void 0 : _g.details) || error.message
|
|
92
|
-
},
|
|
94
|
+
}, `Execution error occurred at file ${file.filePath} (${i + 1} of ${fileCount})`);
|
|
93
95
|
// Execute error action if specified
|
|
94
96
|
if ((_h = rule === null || rule === void 0 ? void 0 : rule.onError) === null || _h === void 0 ? void 0 : _h.action) {
|
|
95
97
|
try {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "
|
|
2
|
+
"name": "newSdkFeatureNotAdoped-global",
|
|
3
3
|
"conditions": {
|
|
4
4
|
"all": [
|
|
5
5
|
{
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"logger\\.debug\\("
|
|
19
19
|
],
|
|
20
20
|
"fileFilter": ".*\\.(ts|js)$",
|
|
21
|
-
"resultFact": "
|
|
21
|
+
"resultFact": "sdkUsageAnalysis"
|
|
22
22
|
},
|
|
23
23
|
"operator": "globalPatternRatio",
|
|
24
24
|
"value": 0.6
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
"event": {
|
|
29
29
|
"type": "warning",
|
|
30
30
|
"params": {
|
|
31
|
-
"message": "The codebase
|
|
31
|
+
"message": "The codebase does not appear to be using some important new SDK features.",
|
|
32
32
|
"details": {
|
|
33
|
-
"fact": "
|
|
33
|
+
"fact": "sdkUsageAnalysis"
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
}
|
|
@@ -44,13 +44,13 @@ describe('globalFileAnalysis', () => {
|
|
|
44
44
|
const params = {
|
|
45
45
|
patterns: ['newApiMethod\\(', 'legacyApiMethod\\('],
|
|
46
46
|
fileFilter: '\\.ts$',
|
|
47
|
-
resultFact: '
|
|
47
|
+
resultFact: 'sdkUsageAnalysis'
|
|
48
48
|
};
|
|
49
49
|
const result = yield globalFileAnalysisFacts_1.globalFileAnalysis.fn(params, mockAlmanac);
|
|
50
50
|
expect(result.summary.totalFiles).toBe(2);
|
|
51
51
|
expect(result.matchCounts['newApiMethod\\(']).toBe(3);
|
|
52
52
|
expect(result.matchCounts['legacyApiMethod\\(']).toBe(1);
|
|
53
|
-
expect(mockAlmanac.addRuntimeFact).toHaveBeenCalledWith('
|
|
53
|
+
expect(mockAlmanac.addRuntimeFact).toHaveBeenCalledWith('sdkUsageAnalysis', expect.any(Object));
|
|
54
54
|
}));
|
|
55
55
|
it('should handle errors gracefully', () => __awaiter(void 0, void 0, void 0, function* () {
|
|
56
56
|
const mockAlmanac = {
|
|
@@ -60,7 +60,7 @@ describe('globalFileAnalysis', () => {
|
|
|
60
60
|
const params = {
|
|
61
61
|
patterns: ['newApiMethod\\('],
|
|
62
62
|
fileFilter: '\\.ts$',
|
|
63
|
-
resultFact: '
|
|
63
|
+
resultFact: 'sdkUsageAnalysis'
|
|
64
64
|
};
|
|
65
65
|
const result = yield globalFileAnalysisFacts_1.globalFileAnalysis.fn(params, mockAlmanac);
|
|
66
66
|
expect(result.result).toEqual([]);
|
|
@@ -124,11 +124,11 @@ function repoFileAnalysis(params, almanac) {
|
|
|
124
124
|
return result;
|
|
125
125
|
}
|
|
126
126
|
//if there is already a resultFact for this file, we need to append
|
|
127
|
-
const existingResult = almanac.factValue(params.resultFact);
|
|
128
|
-
if (Object.keys(existingResult).includes('result')) {
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
}
|
|
127
|
+
// const existingResult = almanac.factValue(params.resultFact);
|
|
128
|
+
// if (Object.keys(existingResult).includes('result')) {
|
|
129
|
+
// logger.error(JSON.stringify(existingResult));
|
|
130
|
+
// result.result = existingResult.result;
|
|
131
|
+
// }
|
|
132
132
|
const analysis = [];
|
|
133
133
|
const lines = fileContent.split('\n');
|
|
134
134
|
logger_1.logger.debug({ lineCount: lines.length }, 'Processing file lines');
|
|
@@ -179,11 +179,17 @@ function repoFileAnalysis(params, almanac) {
|
|
|
179
179
|
}
|
|
180
180
|
}
|
|
181
181
|
}
|
|
182
|
-
|
|
182
|
+
const resultLength = result.result.length;
|
|
183
|
+
const analysisLength = analysis.length;
|
|
184
|
+
if (analysisLength > 0) {
|
|
183
185
|
logger_1.logger.warn({ filePath, analysis }, 'Found issues in file analysis');
|
|
186
|
+
//preallocate the array to the correct length
|
|
187
|
+
result.result.length = resultLength + analysisLength;
|
|
188
|
+
for (let i = 0; i < analysisLength; i++) {
|
|
189
|
+
const fileAnalysis = analysis[i];
|
|
190
|
+
result.result[resultLength + i] = fileAnalysis[i];
|
|
191
|
+
}
|
|
184
192
|
}
|
|
185
|
-
//merge the results
|
|
186
|
-
result.result = result.result.concat(analysis);
|
|
187
193
|
//result.result. = analysis;
|
|
188
194
|
almanac.addRuntimeFact(params.resultFact, result);
|
|
189
195
|
return result;
|
package/dist/index.js
CHANGED
|
@@ -135,15 +135,10 @@ function main() {
|
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
137
|
catch (e) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
setTimeout(() => {
|
|
143
|
-
process.exit(1);
|
|
144
|
-
}, 3000);
|
|
145
|
-
}
|
|
146
|
-
});
|
|
138
|
+
yield handleError(e);
|
|
139
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
140
|
+
setTimeout(() => process.exit(1), 3000);
|
|
141
|
+
}
|
|
147
142
|
}
|
|
148
143
|
});
|
|
149
144
|
}
|
|
@@ -23,6 +23,7 @@ const telemetry_1 = require("./telemetry");
|
|
|
23
23
|
const path_1 = __importDefault(require("path"));
|
|
24
24
|
const fs_1 = __importDefault(require("fs"));
|
|
25
25
|
const pathUtils_1 = require("./pathUtils");
|
|
26
|
+
const sanitize_filename_1 = __importDefault(require("sanitize-filename"));
|
|
26
27
|
const XFI_SHARED_SECRET = process.env.XFI_SHARED_SECRET;
|
|
27
28
|
function loadExemptions(params) {
|
|
28
29
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -71,12 +72,13 @@ function loadRemoteExemptions(params) {
|
|
|
71
72
|
function loadLocalExemptions(params) {
|
|
72
73
|
return __awaiter(this, void 0, void 0, function* () {
|
|
73
74
|
const { localConfigPath, archetype } = params;
|
|
75
|
+
const sanitizedArchetype = (0, sanitize_filename_1.default)(archetype);
|
|
74
76
|
const exemptions = [];
|
|
75
|
-
const expectedSuffix = `-${
|
|
77
|
+
const expectedSuffix = `-${sanitizedArchetype}-exemptions.json`;
|
|
76
78
|
try {
|
|
77
79
|
// Load from legacy file
|
|
78
80
|
const baseConfigPath = path_1.default.resolve(localConfigPath);
|
|
79
|
-
const legacyExemptionsPath = path_1.default.resolve(baseConfigPath, `${
|
|
81
|
+
const legacyExemptionsPath = path_1.default.resolve(baseConfigPath, `${sanitizedArchetype}-exemptions.json`);
|
|
80
82
|
if (fs_1.default.existsSync(legacyExemptionsPath)) {
|
|
81
83
|
const legacyExemptionsData = yield fs_1.default.promises.readFile(legacyExemptionsPath, 'utf-8');
|
|
82
84
|
const legacyExemptions = JSON.parse(legacyExemptionsData);
|
|
@@ -86,7 +88,7 @@ function loadLocalExemptions(params) {
|
|
|
86
88
|
}
|
|
87
89
|
}
|
|
88
90
|
// Load from exemptions directory
|
|
89
|
-
const exemptionsDirPath = path_1.default.resolve(baseConfigPath, `${
|
|
91
|
+
const exemptionsDirPath = path_1.default.resolve(baseConfigPath, `${sanitizedArchetype}-exemptions`);
|
|
90
92
|
if (fs_1.default.existsSync(exemptionsDirPath)) {
|
|
91
93
|
const files = yield fs_1.default.promises.readdir(exemptionsDirPath);
|
|
92
94
|
for (const file of files) {
|
|
@@ -117,9 +119,9 @@ function loadLocalExemptions(params) {
|
|
|
117
119
|
}
|
|
118
120
|
}
|
|
119
121
|
if (!fs_1.default.existsSync(legacyExemptionsPath) && !fs_1.default.existsSync(exemptionsDirPath)) {
|
|
120
|
-
logger_1.logger.warn(`No exemption files found for archetype ${
|
|
122
|
+
logger_1.logger.warn(`No exemption files found for archetype ${sanitizedArchetype}`);
|
|
121
123
|
}
|
|
122
|
-
logger_1.logger.info(`Loaded ${exemptions.length} total exemptions for archetype ${
|
|
124
|
+
logger_1.logger.info(`Loaded ${exemptions.length} total exemptions for archetype ${sanitizedArchetype}`);
|
|
123
125
|
return exemptions;
|
|
124
126
|
}
|
|
125
127
|
catch (error) {
|
package/dist/xfidelity
CHANGED
|
@@ -135,15 +135,10 @@ function main() {
|
|
|
135
135
|
}
|
|
136
136
|
}
|
|
137
137
|
catch (e) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
setTimeout(() => {
|
|
143
|
-
process.exit(1);
|
|
144
|
-
}, 3000);
|
|
145
|
-
}
|
|
146
|
-
});
|
|
138
|
+
yield handleError(e);
|
|
139
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
140
|
+
setTimeout(() => process.exit(1), 3000);
|
|
141
|
+
}
|
|
147
142
|
}
|
|
148
143
|
});
|
|
149
144
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "x-fidelity",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.8.0",
|
|
4
4
|
"description": "cli for opinionated framework adherence checks",
|
|
5
5
|
"main": "dist/index",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -46,64 +46,65 @@
|
|
|
46
46
|
"devDependencies": {
|
|
47
47
|
"@jest/globals": "^29.7.0",
|
|
48
48
|
"@semantic-release/changelog": "^6.0.3",
|
|
49
|
-
"@semantic-release/commit-analyzer": "^13.0.
|
|
49
|
+
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
50
50
|
"@semantic-release/git": "^10.0.1",
|
|
51
|
-
"@semantic-release/github": "^11.0.
|
|
51
|
+
"@semantic-release/github": "^11.0.1",
|
|
52
52
|
"@semantic-release/npm": "^12.0.1",
|
|
53
|
-
"@semantic-release/release-notes-generator": "^14.0.
|
|
53
|
+
"@semantic-release/release-notes-generator": "^14.0.3",
|
|
54
54
|
"@types/esprima": "^4.0.6",
|
|
55
55
|
"@types/express": "^4.17.21",
|
|
56
|
-
"@types/jest": "^29.5.
|
|
57
|
-
"@types/lodash": "^4.17.
|
|
58
|
-
"@types/node": "^22.
|
|
59
|
-
"@types/ora": "^3.2.0",
|
|
60
|
-
"@types/parse-json": "^4.0.2",
|
|
56
|
+
"@types/jest": "^29.5.14",
|
|
57
|
+
"@types/lodash": "^4.17.16",
|
|
58
|
+
"@types/node": "^22.13.8",
|
|
61
59
|
"@types/prettyjson": "^0.0.33",
|
|
62
60
|
"@types/semver": "^7.5.8",
|
|
63
61
|
"@types/supertest": "^6.0.2",
|
|
64
|
-
"@
|
|
65
|
-
"@typescript-eslint/
|
|
66
|
-
"
|
|
67
|
-
"commitizen": "^4.3.0",
|
|
62
|
+
"@typescript-eslint/eslint-plugin": "^8.25.0",
|
|
63
|
+
"@typescript-eslint/parser": "^8.25.0",
|
|
64
|
+
"commitizen": "^4.3.1",
|
|
68
65
|
"conventional-changelog-cli": "^5.0.0",
|
|
69
|
-
"conventional-recommended-bump": "^
|
|
66
|
+
"conventional-recommended-bump": "^11.0.0",
|
|
70
67
|
"cz-conventional-changelog": "^3.3.0",
|
|
71
|
-
"eslint": "^9.
|
|
68
|
+
"eslint": "^9.21.0",
|
|
72
69
|
"jest": "^29.7.0",
|
|
73
70
|
"rimraf": "^6.0.1",
|
|
74
|
-
"semantic-release": "^24.
|
|
71
|
+
"semantic-release": "^24.2.3",
|
|
75
72
|
"supertest": "^7.0.0",
|
|
76
|
-
"ts-jest": "^29.
|
|
77
|
-
"ts-node": "^10.
|
|
78
|
-
"typescript": "^5.
|
|
73
|
+
"ts-jest": "^29.2.6",
|
|
74
|
+
"ts-node": "^10.9.2",
|
|
75
|
+
"typescript": "^5.8.2"
|
|
79
76
|
},
|
|
80
77
|
"dependencies": {
|
|
81
78
|
"@types/body-parser": "^1.19.5",
|
|
82
79
|
"@yarnpkg/lockfile": "^1.1.0",
|
|
83
80
|
"ajv": "^8.17.1",
|
|
84
|
-
"axios": "^1.
|
|
81
|
+
"axios": "^1.8.1",
|
|
85
82
|
"body-parser": "^1.20.3",
|
|
86
83
|
"commander": "^13.1.0",
|
|
87
|
-
"dotenv": "^16.4.
|
|
84
|
+
"dotenv": "^16.4.7",
|
|
88
85
|
"esprima": "^4.0.1",
|
|
89
86
|
"express": "^4.21.2",
|
|
90
|
-
"express-rate-limit": "^7.
|
|
87
|
+
"express-rate-limit": "^7.5.0",
|
|
91
88
|
"helmet": "^8.0.0",
|
|
92
|
-
"json-rules-engine": "^7.
|
|
89
|
+
"json-rules-engine": "^7.3.1",
|
|
93
90
|
"jsonpath-plus": "^10.3.0",
|
|
94
91
|
"kill-port": "^2.0.1",
|
|
95
92
|
"lodash": "^4.17.21",
|
|
96
|
-
"nodemon": "^3.
|
|
97
|
-
"openai": "^4.
|
|
98
|
-
"ora": "^8.0
|
|
93
|
+
"nodemon": "^3.1.9",
|
|
94
|
+
"openai": "^4.86.1",
|
|
95
|
+
"ora": "^8.2.0",
|
|
99
96
|
"pino": "^9.6.0",
|
|
100
97
|
"pino-pretty": "^13.0.0",
|
|
101
98
|
"prettyjson": "^1.2.5",
|
|
102
|
-
"semver": "^7.
|
|
103
|
-
"yarn": "^1.22.
|
|
99
|
+
"semver": "^7.7.1",
|
|
100
|
+
"yarn": "^1.22.22",
|
|
101
|
+
"sanitize-filename": "^1.6.3"
|
|
104
102
|
},
|
|
105
103
|
"peerDependencies": {
|
|
106
|
-
"artillery": "^2.0.
|
|
104
|
+
"artillery": "^2.0.22"
|
|
105
|
+
},
|
|
106
|
+
"resolutions": {
|
|
107
|
+
"glob": "^10.0.0"
|
|
107
108
|
},
|
|
108
109
|
"config": {
|
|
109
110
|
"commitizen": {
|
package/src/IDEAS.md
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Innovative Check Types for Codebase Standardization
|
|
2
|
+
|
|
3
|
+
## aider.chat Claude 3.7 Sonnet Prompt
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
/architect what are some other unusual check types we could add that are not
|
|
7
|
+
covered by linting, security, sonarqube or similar tools. Remember the goal
|
|
8
|
+
is to encourage teams to follow patterns that simplify codebases from internal
|
|
9
|
+
company SDKs frameworks, with important rules enforced. Have a think about
|
|
10
|
+
50 examples that are both simple to understand, and help improve productivity.
|
|
11
|
+
Use an innovative mindset and consider react microfrontends using GraphQL
|
|
12
|
+
as well as microservices using GraphQL and others using standard REST.
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Response: 50 Innovative Check Types
|
|
16
|
+
|
|
17
|
+
These innovative check types could be added to the X-Fidelity tool to encourage teams to follow patterns that simplify codebases and improve productivity. These go beyond what typical linting, security, or SonarQube tools cover.
|
|
18
|
+
|
|
19
|
+
### Frontend Architecture Patterns
|
|
20
|
+
|
|
21
|
+
1. **Component Reuse Ratio** - Measure the reuse of React components across the codebase to encourage shared component libraries.
|
|
22
|
+
2. **Microfrontend Boundary Violations** - Detect when one microfrontend directly imports from another instead of using defined contracts.
|
|
23
|
+
3. **GraphQL Fragment Consistency** - Ensure GraphQL fragments follow naming conventions and are reused appropriately.
|
|
24
|
+
4. **Component Prop Explosion** - Flag React components with too many props that should be refactored into smaller components.
|
|
25
|
+
5. **State Management Consistency** - Ensure consistent state management patterns (Redux, Context API, etc.) within a microfrontend.
|
|
26
|
+
6. **CSS-in-JS Pattern Adherence** - Verify that styling follows the team's chosen CSS-in-JS approach consistently.
|
|
27
|
+
7. **Component Documentation Coverage** - Check that all shared components have proper documentation and examples.
|
|
28
|
+
8. **Microfrontend Shell Integration** - Verify that microfrontends properly register with the application shell.
|
|
29
|
+
9. **Feature Flag Implementation** - Ensure feature flags follow the company's standard implementation pattern.
|
|
30
|
+
10. **A11y Pattern Compliance** - Check that custom UI components implement the team's accessibility patterns correctly.
|
|
31
|
+
|
|
32
|
+
### Backend Architecture Patterns
|
|
33
|
+
|
|
34
|
+
11. **Microservice Boundary Enforcement** - Detect when services directly access another service's database instead of using APIs.
|
|
35
|
+
12. **API Version Consistency** - Ensure all endpoints follow the company's versioning strategy.
|
|
36
|
+
13. **GraphQL Resolver Structure** - Verify GraphQL resolvers follow the team's architectural patterns.
|
|
37
|
+
14. **Circuit Breaker Implementation** - Check that external service calls implement circuit breakers according to standards.
|
|
38
|
+
15. **Idempotency Pattern Usage** - Ensure critical endpoints implement proper idempotency patterns.
|
|
39
|
+
16. **Pagination Standard Adherence** - Verify that list endpoints follow the company's pagination standards.
|
|
40
|
+
17. **Error Response Format Consistency** - Check that error responses follow the company's standardized format.
|
|
41
|
+
18. **Service Discovery Registration** - Ensure services properly register with the service discovery mechanism.
|
|
42
|
+
19. **Database Transaction Pattern** - Verify that database transactions follow the team's patterns for consistency.
|
|
43
|
+
20. **Async Processing Pattern** - Check that async operations follow the company's queue/event processing patterns.
|
|
44
|
+
|
|
45
|
+
### Cross-Cutting Concerns
|
|
46
|
+
|
|
47
|
+
21. **Logging Context Propagation** - Ensure request context is properly propagated in logs across service boundaries.
|
|
48
|
+
22. **Distributed Tracing Integration** - Verify that services properly integrate with the distributed tracing system.
|
|
49
|
+
23. **Metric Naming Convention** - Check that metrics follow the company's naming conventions for easier dashboarding.
|
|
50
|
+
24. **Health Check Implementation** - Ensure services implement standardized health check endpoints.
|
|
51
|
+
25. **Configuration Management** - Verify services use the company's standard configuration management approach.
|
|
52
|
+
26. **Graceful Shutdown Implementation** - Check that services implement proper graceful shutdown procedures.
|
|
53
|
+
27. **Retry Policy Consistency** - Ensure retry policies follow company standards for external service calls.
|
|
54
|
+
28. **Cache Usage Patterns** - Verify that caching follows the team's established patterns.
|
|
55
|
+
29. **Dependency Injection Pattern** - Check that services follow the company's dependency injection approach.
|
|
56
|
+
30. **Feature Toggle Framework Usage** - Ensure the standard feature toggle framework is used consistently.
|
|
57
|
+
|
|
58
|
+
### Development Workflow
|
|
59
|
+
|
|
60
|
+
31. **Branch Naming Convention** - Verify branch names follow the team's convention for easier automation.
|
|
61
|
+
32. **Commit Message Format** - Check that commit messages follow the company's format for better release notes.
|
|
62
|
+
33. **PR Size Limits** - Flag PRs that exceed the team's guidelines for reviewable code size.
|
|
63
|
+
34. **Test Coverage Distribution** - Ensure test coverage is distributed appropriately (not just in easy-to-test areas).
|
|
64
|
+
35. **Test Fixture Standardization** - Verify test fixtures follow the team's patterns for consistency.
|
|
65
|
+
36. **API Contract Test Coverage** - Check that all API contracts have corresponding contract tests.
|
|
66
|
+
37. **Documentation Update Verification** - Ensure code changes that affect public APIs also update documentation.
|
|
67
|
+
38. **Breaking Change Detection** - Flag changes that would break existing clients according to team standards.
|
|
68
|
+
39. **Dependency Update Frequency** - Check that dependencies are updated according to the team's schedule.
|
|
69
|
+
40. **Code Ownership Adherence** - Verify that changes respect the team's code ownership boundaries.
|
|
70
|
+
|
|
71
|
+
### Company-Specific SDK Usage
|
|
72
|
+
|
|
73
|
+
41. **Internal SDK Version Compliance** - Ensure teams use the approved versions of internal SDKs.
|
|
74
|
+
42. **SDK Feature Adoption** - Check that teams are using new SDK features rather than maintaining legacy implementations.
|
|
75
|
+
43. **SDK Configuration Standardization** - Verify that SDK configuration follows company standards.
|
|
76
|
+
44. **SDK Extension Pattern** - Ensure extensions to SDKs follow the approved patterns.
|
|
77
|
+
45. **SDK Authentication Pattern** - Check that authentication with internal services uses the company's SDK patterns.
|
|
78
|
+
46. **SDK Initialization Order** - Verify that SDKs are initialized in the correct order according to dependencies.
|
|
79
|
+
47. **SDK Event Handling Pattern** - Ensure event handling with SDKs follows the company's patterns.
|
|
80
|
+
48. **SDK Logging Integration** - Check that SDK logging is properly integrated with the application's logging.
|
|
81
|
+
49. **SDK Error Handling Pattern** - Verify that SDK errors are handled according to company standards.
|
|
82
|
+
50. **SDK Resource Cleanup** - Ensure resources from SDKs are properly cleaned up when no longer needed.
|
|
83
|
+
|
|
84
|
+
> Each of these checks could be implemented as a rule in the X-Fidelity tool to encourage teams to follow patterns that simplify codebases and improve productivity. The focus is on architectural patterns and company-specific standards rather than general code quality issues that would be caught by traditional tools.
|
|
@@ -76,13 +76,15 @@ export async function runEngineOnFiles(params: RunEngineOnFilesParams): Promise<
|
|
|
76
76
|
}
|
|
77
77
|
|
|
78
78
|
logger.error({
|
|
79
|
+
index: i,
|
|
80
|
+
file: file.filePath,
|
|
79
81
|
err: handledError || error,
|
|
80
82
|
rule: failedRuleName,
|
|
81
83
|
source: errorSource,
|
|
82
84
|
type: errorLevel,
|
|
83
|
-
|
|
85
|
+
stack: (handledError || error).stack,
|
|
84
86
|
details: (error as any)?.pluginError?.details || error.message
|
|
85
|
-
},
|
|
87
|
+
}, `Execution error occurred at file ${file.filePath} (${i + 1} of ${fileCount})`);
|
|
86
88
|
|
|
87
89
|
// Execute error action if specified
|
|
88
90
|
if (rule?.onError?.action) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"name": "
|
|
2
|
+
"name": "newSdkFeatureNotAdoped-global",
|
|
3
3
|
"conditions": {
|
|
4
4
|
"all": [
|
|
5
5
|
{
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"logger\\.debug\\("
|
|
19
19
|
],
|
|
20
20
|
"fileFilter": ".*\\.(ts|js)$",
|
|
21
|
-
"resultFact": "
|
|
21
|
+
"resultFact": "sdkUsageAnalysis"
|
|
22
22
|
},
|
|
23
23
|
"operator": "globalPatternRatio",
|
|
24
24
|
"value": 0.6
|
|
@@ -28,9 +28,9 @@
|
|
|
28
28
|
"event": {
|
|
29
29
|
"type": "warning",
|
|
30
30
|
"params": {
|
|
31
|
-
"message": "The codebase
|
|
31
|
+
"message": "The codebase does not appear to be using some important new SDK features.",
|
|
32
32
|
"details": {
|
|
33
|
-
"fact": "
|
|
33
|
+
"fact": "sdkUsageAnalysis"
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
36
|
}
|
|
@@ -36,7 +36,7 @@ describe('globalFileAnalysis', () => {
|
|
|
36
36
|
const params = {
|
|
37
37
|
patterns: ['newApiMethod\\(', 'legacyApiMethod\\('],
|
|
38
38
|
fileFilter: '\\.ts$',
|
|
39
|
-
resultFact: '
|
|
39
|
+
resultFact: 'sdkUsageAnalysis'
|
|
40
40
|
};
|
|
41
41
|
|
|
42
42
|
const result = await globalFileAnalysis.fn(params, mockAlmanac);
|
|
@@ -44,7 +44,7 @@ describe('globalFileAnalysis', () => {
|
|
|
44
44
|
expect(result.summary.totalFiles).toBe(2);
|
|
45
45
|
expect(result.matchCounts['newApiMethod\\(']).toBe(3);
|
|
46
46
|
expect(result.matchCounts['legacyApiMethod\\(']).toBe(1);
|
|
47
|
-
expect(mockAlmanac.addRuntimeFact).toHaveBeenCalledWith('
|
|
47
|
+
expect(mockAlmanac.addRuntimeFact).toHaveBeenCalledWith('sdkUsageAnalysis', expect.any(Object));
|
|
48
48
|
});
|
|
49
49
|
|
|
50
50
|
it('should handle errors gracefully', async () => {
|
|
@@ -56,7 +56,7 @@ describe('globalFileAnalysis', () => {
|
|
|
56
56
|
const params = {
|
|
57
57
|
patterns: ['newApiMethod\\('],
|
|
58
58
|
fileFilter: '\\.ts$',
|
|
59
|
-
resultFact: '
|
|
59
|
+
resultFact: 'sdkUsageAnalysis'
|
|
60
60
|
};
|
|
61
61
|
|
|
62
62
|
const result = await globalFileAnalysis.fn(params, mockAlmanac);
|
|
@@ -114,11 +114,11 @@ async function repoFileAnalysis(params: any, almanac: any) {
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
//if there is already a resultFact for this file, we need to append
|
|
117
|
-
const existingResult = almanac.factValue(params.resultFact);
|
|
118
|
-
if (Object.keys(existingResult).includes('result')) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
}
|
|
117
|
+
// const existingResult = almanac.factValue(params.resultFact);
|
|
118
|
+
// if (Object.keys(existingResult).includes('result')) {
|
|
119
|
+
// logger.error(JSON.stringify(existingResult));
|
|
120
|
+
// result.result = existingResult.result;
|
|
121
|
+
// }
|
|
122
122
|
|
|
123
123
|
const analysis: any = [];
|
|
124
124
|
const lines = fileContent.split('\n');
|
|
@@ -172,13 +172,18 @@ async function repoFileAnalysis(params: any, almanac: any) {
|
|
|
172
172
|
}
|
|
173
173
|
}
|
|
174
174
|
|
|
175
|
-
|
|
175
|
+
const resultLength = result.result.length;
|
|
176
|
+
const analysisLength = analysis.length;
|
|
177
|
+
if (analysisLength > 0) {
|
|
176
178
|
logger.warn({ filePath, analysis }, 'Found issues in file analysis');
|
|
177
|
-
|
|
178
|
-
}
|
|
179
179
|
|
|
180
|
-
|
|
181
|
-
|
|
180
|
+
//preallocate the array to the correct length
|
|
181
|
+
result.result.length = resultLength + analysisLength;
|
|
182
|
+
for (let i = 0; i < analysisLength; i++) {
|
|
183
|
+
const fileAnalysis = analysis[i];
|
|
184
|
+
result.result[resultLength + i] = fileAnalysis[i];
|
|
185
|
+
}
|
|
186
|
+
}
|
|
182
187
|
|
|
183
188
|
//result.result. = analysis;
|
|
184
189
|
|
package/src/index.ts
CHANGED
|
@@ -88,15 +88,11 @@ export async function main() {
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
} catch (e: any) {
|
|
91
|
-
|
|
92
|
-
await handleError(e)
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
process.exit(1);
|
|
97
|
-
}, 3000);
|
|
98
|
-
}
|
|
99
|
-
});
|
|
91
|
+
|
|
92
|
+
await handleError(e);
|
|
93
|
+
if (process.env.NODE_ENV !== 'test') {
|
|
94
|
+
setTimeout(() => process.exit(1), 3000);
|
|
95
|
+
}
|
|
100
96
|
}
|
|
101
97
|
}
|
|
102
98
|
|
|
@@ -5,6 +5,7 @@ import { sendTelemetry } from "./telemetry";
|
|
|
5
5
|
import path from "path";
|
|
6
6
|
import fs from "fs";
|
|
7
7
|
import { isPathInside } from "./pathUtils";
|
|
8
|
+
import sanitize from "sanitize-filename";
|
|
8
9
|
|
|
9
10
|
const XFI_SHARED_SECRET = process.env.XFI_SHARED_SECRET;
|
|
10
11
|
|
|
@@ -51,13 +52,14 @@ export async function loadRemoteExemptions(params: LoadExemptionsParams): Promis
|
|
|
51
52
|
|
|
52
53
|
export async function loadLocalExemptions(params: LoadExemptionsParams): Promise<Exemption[]> {
|
|
53
54
|
const { localConfigPath, archetype } = params;
|
|
55
|
+
const sanitizedArchetype = sanitize(archetype);
|
|
54
56
|
const exemptions: Exemption[] = [];
|
|
55
|
-
const expectedSuffix = `-${
|
|
57
|
+
const expectedSuffix = `-${sanitizedArchetype}-exemptions.json`;
|
|
56
58
|
|
|
57
59
|
try {
|
|
58
60
|
// Load from legacy file
|
|
59
61
|
const baseConfigPath = path.resolve(localConfigPath);
|
|
60
|
-
const legacyExemptionsPath = path.resolve(baseConfigPath, `${
|
|
62
|
+
const legacyExemptionsPath = path.resolve(baseConfigPath, `${sanitizedArchetype}-exemptions.json`);
|
|
61
63
|
if (fs.existsSync(legacyExemptionsPath)) {
|
|
62
64
|
const legacyExemptionsData = await fs.promises.readFile(legacyExemptionsPath, 'utf-8');
|
|
63
65
|
const legacyExemptions = JSON.parse(legacyExemptionsData);
|
|
@@ -68,7 +70,7 @@ export async function loadLocalExemptions(params: LoadExemptionsParams): Promise
|
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
// Load from exemptions directory
|
|
71
|
-
const exemptionsDirPath = path.resolve(baseConfigPath, `${
|
|
73
|
+
const exemptionsDirPath = path.resolve(baseConfigPath, `${sanitizedArchetype}-exemptions`);
|
|
72
74
|
if (fs.existsSync(exemptionsDirPath)) {
|
|
73
75
|
const files = await fs.promises.readdir(exemptionsDirPath);
|
|
74
76
|
for (const file of files) {
|
|
@@ -101,10 +103,10 @@ export async function loadLocalExemptions(params: LoadExemptionsParams): Promise
|
|
|
101
103
|
}
|
|
102
104
|
|
|
103
105
|
if (!fs.existsSync(legacyExemptionsPath) && !fs.existsSync(exemptionsDirPath)) {
|
|
104
|
-
logger.warn(`No exemption files found for archetype ${
|
|
106
|
+
logger.warn(`No exemption files found for archetype ${sanitizedArchetype}`);
|
|
105
107
|
}
|
|
106
108
|
|
|
107
|
-
logger.info(`Loaded ${exemptions.length} total exemptions for archetype ${
|
|
109
|
+
logger.info(`Loaded ${exemptions.length} total exemptions for archetype ${sanitizedArchetype}`);
|
|
108
110
|
return exemptions;
|
|
109
111
|
} catch (error) {
|
|
110
112
|
logger.warn(`Failed to load exemptions: ${error}`);
|
package/website/package.json
CHANGED
package/website/yarn.lock
CHANGED
|
@@ -9396,10 +9396,10 @@ typedarray-to-buffer@^3.1.5:
|
|
|
9396
9396
|
dependencies:
|
|
9397
9397
|
is-typedarray "^1.0.0"
|
|
9398
9398
|
|
|
9399
|
-
typescript@~5.
|
|
9400
|
-
version "5.
|
|
9401
|
-
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.
|
|
9402
|
-
integrity sha512-
|
|
9399
|
+
typescript@~5.8.2:
|
|
9400
|
+
version "5.8.2"
|
|
9401
|
+
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.8.2.tgz#8170b3702f74b79db2e5a96207c15e65807999e4"
|
|
9402
|
+
integrity sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==
|
|
9403
9403
|
|
|
9404
9404
|
ufo@^1.5.4:
|
|
9405
9405
|
version "1.5.4"
|