x-fidelity 3.8.0 → 3.9.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/.xfi-config.json +34 -1
- package/CHANGELOG.md +26 -0
- package/README.md +51 -6
- package/SECURITY.md +18 -0
- package/dist/core/engine/analyzer.js +59 -0
- package/dist/plugins/xfiPluginSimpleExample/facts/customFact.js +7 -2
- package/dist/plugins/xfiPluginSimpleExample/facts/customFact.test.js +1 -1
- package/dist/types/typeDefs.d.ts +4 -0
- package/dist/utils/jsonSchemas.js +25 -0
- package/dist/utils/repoXFIConfigLoader.js +10 -0
- package/dist/utils/ruleUtils.d.ts +2 -1
- package/dist/utils/ruleUtils.js +14 -0
- package/package.json +1 -4
- package/src/core/engine/analyzer.ts +66 -0
- package/src/plugins/xfiPluginSimpleExample/facts/customFact.test.ts +1 -1
- package/src/plugins/xfiPluginSimpleExample/facts/customFact.ts +9 -2
- package/src/types/typeDefs.ts +4 -0
- package/src/utils/jsonSchemas.ts +27 -2
- package/src/utils/repoXFIConfigLoader.ts +12 -1
- package/src/utils/ruleUtils.ts +16 -1
- package/website/docs/xfi-config.md +264 -40
package/.xfi-config.json
CHANGED
|
@@ -1,5 +1,38 @@
|
|
|
1
1
|
{
|
|
2
2
|
"sensitiveFileFalsePositives": [
|
|
3
3
|
"/src/facts/repoFilesystemFacts.ts"
|
|
4
|
-
]
|
|
4
|
+
],
|
|
5
|
+
"additionalRules": [
|
|
6
|
+
{
|
|
7
|
+
"name": "custom-rule",
|
|
8
|
+
"conditions": {
|
|
9
|
+
"all": [
|
|
10
|
+
{
|
|
11
|
+
"fact": "fileData",
|
|
12
|
+
"path": "$.fileName",
|
|
13
|
+
"operator": "equal",
|
|
14
|
+
"value": "REPO_GLOBAL_CHECK"
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
"fact": "customFact",
|
|
18
|
+
"operator": "customOperator",
|
|
19
|
+
"value": "custom fact data"
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
},
|
|
23
|
+
"event": {
|
|
24
|
+
"type": "warning",
|
|
25
|
+
"params": {
|
|
26
|
+
"message": "Custom rule detected matching data",
|
|
27
|
+
"details": {
|
|
28
|
+
"fact": "customFact"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
],
|
|
35
|
+
"additionalFacts": ["customFact"],
|
|
36
|
+
"additionalOperators": ["customOperator"],
|
|
37
|
+
"additionalPlugins": ["xfiPluginSimpleExample"]
|
|
5
38
|
}
|
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,29 @@
|
|
|
1
|
+
# [3.9.0](https://github.com/zotoio/x-fidelity/compare/v3.8.1...v3.9.0) (2025-03-02)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* add optional chaining for rule name access in analyzer ([d0c4b02](https://github.com/zotoio/x-fidelity/commit/d0c4b02c83bf77cade8e7310fe14ad0b10dd00c1))
|
|
7
|
+
* add type assertion to resolve schema type compatibility issue ([76f7618](https://github.com/zotoio/x-fidelity/commit/76f761869a85d09eb18a047010e6409475c766fc))
|
|
8
|
+
* **demo:** minor logic and test fix ([3b03804](https://github.com/zotoio/x-fidelity/commit/3b0380465dcc75355941f5e1818187f9b448ef6c))
|
|
9
|
+
* register plugin facts and operators before loading custom rules ([5ab7667](https://github.com/zotoio/x-fidelity/commit/5ab76675c7387a78bb43cb8bd959362a89e16ae9))
|
|
10
|
+
* resolve TypeScript error by casting rule to any type ([eba8fd1](https://github.com/zotoio/x-fidelity/commit/eba8fd1b968d64ec867ebeca76a92a2764321a08))
|
|
11
|
+
* resolve TypeScript errors in schema validation and rule handling ([8f3dd6f](https://github.com/zotoio/x-fidelity/commit/8f3dd6ffca0956a30a4b17794e1b2e0cdee178c0))
|
|
12
|
+
* update custom rule filename and enhance fact almanac handling ([8d11d55](https://github.com/zotoio/x-fidelity/commit/8d11d55c930e4389185905449dc6561958386317))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
### Features
|
|
16
|
+
|
|
17
|
+
* Add custom rule configuration with example plugin and operators ([7e54510](https://github.com/zotoio/x-fidelity/commit/7e54510d9ef25249d70f3e4691f9aae203bf2489))
|
|
18
|
+
* add support for custom rules and plugins in .xfi-config.json ([6206802](https://github.com/zotoio/x-fidelity/commit/62068028636b2da1a7f25df503be6bbb7c8dfdb3))
|
|
19
|
+
|
|
20
|
+
## [3.8.1](https://github.com/zotoio/x-fidelity/compare/v3.8.0...v3.8.1) (2025-03-02)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Bug Fixes
|
|
24
|
+
|
|
25
|
+
* **commitzen:** fix glob compatibilty issue ([73a7058](https://github.com/zotoio/x-fidelity/commit/73a7058e82d5853ceff3d3e5e3e48a03180f077d))
|
|
26
|
+
|
|
1
27
|
# [3.8.0](https://github.com/zotoio/x-fidelity/compare/v3.7.1...v3.8.0) (2025-03-02)
|
|
2
28
|
|
|
3
29
|
|
package/README.md
CHANGED
|
@@ -802,9 +802,13 @@ The `.xfi-config.json` file allows you to configure x-fidelity behavior specific
|
|
|
802
802
|
|
|
803
803
|
### Configuration Options
|
|
804
804
|
|
|
805
|
-
|
|
805
|
+
The `.xfi-config.json` file supports the following options:
|
|
806
806
|
|
|
807
807
|
1. `sensitiveFileFalsePositives`: An array of file paths that should be excluded from sensitive data checks.
|
|
808
|
+
2. `additionalPlugins`: An array of plugin module names to load for this repository.
|
|
809
|
+
3. `additionalFacts`: An array of fact names to add to the archetype's facts.
|
|
810
|
+
4. `additionalOperators`: An array of operator names to add to the archetype's operators.
|
|
811
|
+
5. `additionalRules`: An array of custom rule definitions to add to the archetype's rules.
|
|
808
812
|
|
|
809
813
|
Example `.xfi-config.json`:
|
|
810
814
|
|
|
@@ -813,6 +817,44 @@ Example `.xfi-config.json`:
|
|
|
813
817
|
"sensitiveFileFalsePositives": [
|
|
814
818
|
"path/to/exclude/file1.js",
|
|
815
819
|
"path/to/exclude/file2.ts"
|
|
820
|
+
],
|
|
821
|
+
"additionalPlugins": [
|
|
822
|
+
"xfiPluginSimpleExample"
|
|
823
|
+
],
|
|
824
|
+
"additionalFacts": [
|
|
825
|
+
"customFact"
|
|
826
|
+
],
|
|
827
|
+
"additionalOperators": [
|
|
828
|
+
"customOperator"
|
|
829
|
+
],
|
|
830
|
+
"additionalRules": [
|
|
831
|
+
{
|
|
832
|
+
"name": "custom-rule",
|
|
833
|
+
"conditions": {
|
|
834
|
+
"all": [
|
|
835
|
+
{
|
|
836
|
+
"fact": "fileData",
|
|
837
|
+
"path": "$.fileName",
|
|
838
|
+
"operator": "equal",
|
|
839
|
+
"value": "REPO_GLOBAL_CHECK"
|
|
840
|
+
},
|
|
841
|
+
{
|
|
842
|
+
"fact": "customFact",
|
|
843
|
+
"operator": "customOperator",
|
|
844
|
+
"value": "custom fact data"
|
|
845
|
+
}
|
|
846
|
+
]
|
|
847
|
+
},
|
|
848
|
+
"event": {
|
|
849
|
+
"type": "warning",
|
|
850
|
+
"params": {
|
|
851
|
+
"message": "Custom rule detected matching data",
|
|
852
|
+
"details": {
|
|
853
|
+
"fact": "customFact"
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
}
|
|
816
858
|
]
|
|
817
859
|
}
|
|
818
860
|
```
|
|
@@ -822,16 +864,19 @@ Example `.xfi-config.json`:
|
|
|
822
864
|
- When x-fidelity runs, it looks for the `.xfi-config.json` file in your project's root directory.
|
|
823
865
|
- If found, it applies the configurations specified in this file.
|
|
824
866
|
- For `sensitiveFileFalsePositives`, the specified files will be excluded from checks that look for sensitive data, such as API keys or passwords.
|
|
867
|
+
- For `additionalPlugins`, the specified plugins will be loaded, making their facts and operators available.
|
|
868
|
+
- For `additionalFacts` and `additionalOperators`, the specified facts and operators will be added to the archetype's facts and operators.
|
|
869
|
+
- For `additionalRules`, the specified rules will be added to the archetype's rules.
|
|
825
870
|
|
|
826
871
|
### How to use it
|
|
827
872
|
|
|
828
873
|
1. **Version Control**: Include `.xfi-config.json` in your version control system to ensure consistency across your team.
|
|
829
|
-
2. **Documentation**: Add comments in the listed file explaining why it is a false positive.
|
|
830
|
-
3. **Regular Review**: Periodically review your `.xfi-config.json` to ensure the
|
|
831
|
-
4. **Minimal Use**: Use exclusions sparingly. It's better to fix issues than to exclude them from checks.
|
|
832
|
-
5. **Feedback**: If the rules being applied are resulting in too many false-
|
|
874
|
+
2. **Documentation**: Add comments in the listed file explaining why it is a false positive or why custom rules are needed.
|
|
875
|
+
3. **Regular Review**: Periodically review your `.xfi-config.json` to ensure the configurations are still necessary and valid.
|
|
876
|
+
4. **Minimal Use**: Use exclusions and custom rules sparingly. It's better to fix issues than to exclude them from checks.
|
|
877
|
+
5. **Feedback**: If the rules being applied are resulting in too many false-positives, speak with the team that manages your central rule config.
|
|
833
878
|
|
|
834
|
-
Remember, while `.xfi-config.json` allows you to adjust x-fidelity's behavior
|
|
879
|
+
Remember, while `.xfi-config.json` allows you to adjust x-fidelity's behavior, it should be used judiciously to maintain the integrity of your code quality checks.
|
|
835
880
|
|
|
836
881
|
### Using Extensions
|
|
837
882
|
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Supported Versions
|
|
4
|
+
|
|
5
|
+
Use this section to tell people about which versions of your project are
|
|
6
|
+
currently being supported with security updates.
|
|
7
|
+
|
|
8
|
+
| Version | Supported |
|
|
9
|
+
| ------- | ------------------ |
|
|
10
|
+
| 3.8.x | :white_check_mark: |
|
|
11
|
+
| 2.17.x | :white_check_mark: |
|
|
12
|
+
| < 2.17 | :x: |
|
|
13
|
+
|
|
14
|
+
## Reporting a Vulnerability
|
|
15
|
+
|
|
16
|
+
If you discover a security vulnerability within x-fi, please submit a report via the GitHub's Private Vulnerability Reporting feature.
|
|
17
|
+
|
|
18
|
+
All security vulnerabilities will be promptly addressed.
|
|
@@ -22,6 +22,8 @@ const telemetryCollector_1 = require("./telemetryCollector");
|
|
|
22
22
|
const engineSetup_1 = require("./engineSetup");
|
|
23
23
|
const engineRunner_1 = require("./engineRunner");
|
|
24
24
|
const utils_1 = require("../../utils/utils");
|
|
25
|
+
const jsonSchemas_1 = require("../../utils/jsonSchemas");
|
|
26
|
+
const pluginRegistry_1 = require("../pluginRegistry");
|
|
25
27
|
const cli_1 = require("../cli");
|
|
26
28
|
function analyzeCodebase(params) {
|
|
27
29
|
return __awaiter(this, void 0, void 0, function* () {
|
|
@@ -45,6 +47,25 @@ function analyzeCodebase(params) {
|
|
|
45
47
|
const installedDependencyVersions = yield (0, repoDependencyFacts_1.getDependencyVersionFacts)(archetypeConfig);
|
|
46
48
|
const fileData = yield (0, repoFilesystemFacts_1.collectRepoFileData)(repoPath, archetypeConfig);
|
|
47
49
|
const repoXFIConfig = yield (0, repoXFIConfigLoader_1.loadRepoXFIConfig)(repoPath);
|
|
50
|
+
// Load additional plugins from repo config
|
|
51
|
+
if (repoXFIConfig.additionalPlugins && repoXFIConfig.additionalPlugins.length > 0) {
|
|
52
|
+
logger_1.logger.info(`Loading additional plugins from repo config: ${repoXFIConfig.additionalPlugins.join(', ')}`);
|
|
53
|
+
try {
|
|
54
|
+
yield configManager_1.ConfigManager.loadPlugins(repoXFIConfig.additionalPlugins);
|
|
55
|
+
}
|
|
56
|
+
catch (error) {
|
|
57
|
+
logger_1.logger.warn(`Error loading additional plugins from repo config: ${error}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
// Merge additional components into archetype config
|
|
61
|
+
if (repoXFIConfig.additionalFacts) {
|
|
62
|
+
archetypeConfig.facts = [...new Set([...archetypeConfig.facts, ...repoXFIConfig.additionalFacts])];
|
|
63
|
+
logger_1.logger.info(`Added additional facts from repo config: ${repoXFIConfig.additionalFacts.join(', ')}`);
|
|
64
|
+
}
|
|
65
|
+
if (repoXFIConfig.additionalOperators) {
|
|
66
|
+
archetypeConfig.operators = [...new Set([...archetypeConfig.operators, ...repoXFIConfig.additionalOperators])];
|
|
67
|
+
logger_1.logger.info(`Added additional operators from repo config: ${repoXFIConfig.additionalOperators.join(', ')}`);
|
|
68
|
+
}
|
|
48
69
|
// add REPO_GLOBAL_CHECK to fileData, which is the trigger for global checks
|
|
49
70
|
fileData.push({
|
|
50
71
|
fileName: configManager_1.REPO_GLOBAL_CHECK,
|
|
@@ -63,6 +84,44 @@ function analyzeCodebase(params) {
|
|
|
63
84
|
localConfigPath,
|
|
64
85
|
repoUrl
|
|
65
86
|
});
|
|
87
|
+
// Add plugin facts and operators directly to the engine
|
|
88
|
+
if (repoXFIConfig.additionalFacts) {
|
|
89
|
+
const pluginFacts = pluginRegistry_1.pluginRegistry.getPluginFacts();
|
|
90
|
+
for (const factName of repoXFIConfig.additionalFacts) {
|
|
91
|
+
const fact = pluginFacts.find(f => f.name === factName);
|
|
92
|
+
if (fact) {
|
|
93
|
+
logger_1.logger.info(`Adding custom fact to engine: ${fact.name}`);
|
|
94
|
+
engine.addFact(fact.name, fact.fn, { priority: fact.priority || 1 });
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
if (repoXFIConfig.additionalOperators) {
|
|
99
|
+
const pluginOperators = pluginRegistry_1.pluginRegistry.getPluginOperators();
|
|
100
|
+
for (const operatorName of repoXFIConfig.additionalOperators) {
|
|
101
|
+
const operator = pluginOperators.find(o => o.name === operatorName);
|
|
102
|
+
if (operator) {
|
|
103
|
+
logger_1.logger.info(`Adding custom operator to engine: ${operator.name}`);
|
|
104
|
+
engine.addOperator(operator.name, operator.fn);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Load additional rules from repo config
|
|
109
|
+
if (repoXFIConfig.additionalRules && repoXFIConfig.additionalRules.length > 0) {
|
|
110
|
+
logger_1.logger.info(`Loading additional rules from repo config: ${repoXFIConfig.additionalRules.length} rules`);
|
|
111
|
+
for (const rule of repoXFIConfig.additionalRules) {
|
|
112
|
+
if ((0, jsonSchemas_1.validateRule)(rule)) {
|
|
113
|
+
logger_1.logger.info(`Adding custom rule from repo config: ${rule.name}`);
|
|
114
|
+
// Convert RuleConfig to RuleProperties for Engine
|
|
115
|
+
const ruleProperties = Object.assign(Object.assign({}, rule), { conditions: rule.conditions });
|
|
116
|
+
engine.addRule(ruleProperties);
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
// Cast rule to any to safely access name property
|
|
120
|
+
const ruleName = (rule === null || rule === void 0 ? void 0 : rule.name) || 'unnamed rule';
|
|
121
|
+
logger_1.logger.warn(`Invalid custom rule in repo config: ${ruleName}`);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
66
125
|
if ((0, openaiUtils_1.isOpenAIEnabled)() && archetypeConfig.facts.includes('openaiAnalysisFacts')) {
|
|
67
126
|
logger_1.logger.info(`adding additional openai facts to engine..`);
|
|
68
127
|
engine.addFact('openaiAnalysis', openaiAnalysisFacts_1.openaiAnalysis);
|
|
@@ -17,10 +17,15 @@ const logger_1 = require("../../../utils/logger");
|
|
|
17
17
|
*/
|
|
18
18
|
exports.customFact = {
|
|
19
19
|
name: 'customFact',
|
|
20
|
-
fn: (params) => __awaiter(void 0, void 0, void 0, function* () {
|
|
20
|
+
fn: (params, almanac) => __awaiter(void 0, void 0, void 0, function* () {
|
|
21
21
|
try {
|
|
22
22
|
logger_1.logger.debug('Executing customFact');
|
|
23
|
-
|
|
23
|
+
const result = 'custom fact data';
|
|
24
|
+
// Add the result to the almanac if resultFact is provided
|
|
25
|
+
if (params && params.resultFact) {
|
|
26
|
+
almanac.addRuntimeFact(params.resultFact, result);
|
|
27
|
+
}
|
|
28
|
+
return result;
|
|
24
29
|
}
|
|
25
30
|
catch (error) {
|
|
26
31
|
logger_1.logger.error(`Error in customFact: ${error}`);
|
package/dist/types/typeDefs.d.ts
CHANGED
|
@@ -242,6 +242,10 @@ export interface ValidationResult {
|
|
|
242
242
|
}
|
|
243
243
|
export interface RepoXFIConfig {
|
|
244
244
|
sensitiveFileFalsePositives?: string[];
|
|
245
|
+
additionalRules?: RuleConfig[];
|
|
246
|
+
additionalFacts?: string[];
|
|
247
|
+
additionalOperators?: string[];
|
|
248
|
+
additionalPlugins?: string[];
|
|
245
249
|
[key: string]: any;
|
|
246
250
|
}
|
|
247
251
|
export type RepoXFIConfigSchema = JSONSchemaType<RepoXFIConfig>;
|
|
@@ -12,6 +12,7 @@ ajv.addFormat("semverPattern", {
|
|
|
12
12
|
type: "string",
|
|
13
13
|
validate: (x) => semver_1.default.valid(x) !== null && semver_1.default.validRange(x) !== null,
|
|
14
14
|
});
|
|
15
|
+
// Using a simpler schema definition to avoid TypeScript errors with complex Ajv types
|
|
15
16
|
const repoXFIConfigSchema = {
|
|
16
17
|
type: "object",
|
|
17
18
|
properties: {
|
|
@@ -21,6 +22,30 @@ const repoXFIConfigSchema = {
|
|
|
21
22
|
minItems: 0,
|
|
22
23
|
nullable: true,
|
|
23
24
|
},
|
|
25
|
+
additionalRules: {
|
|
26
|
+
type: "array",
|
|
27
|
+
items: { type: "object" },
|
|
28
|
+
minItems: 0,
|
|
29
|
+
nullable: true,
|
|
30
|
+
},
|
|
31
|
+
additionalFacts: {
|
|
32
|
+
type: "array",
|
|
33
|
+
items: { type: "string" },
|
|
34
|
+
minItems: 0,
|
|
35
|
+
nullable: true,
|
|
36
|
+
},
|
|
37
|
+
additionalOperators: {
|
|
38
|
+
type: "array",
|
|
39
|
+
items: { type: "string" },
|
|
40
|
+
minItems: 0,
|
|
41
|
+
nullable: true,
|
|
42
|
+
},
|
|
43
|
+
additionalPlugins: {
|
|
44
|
+
type: "array",
|
|
45
|
+
items: { type: "string" },
|
|
46
|
+
minItems: 0,
|
|
47
|
+
nullable: true,
|
|
48
|
+
},
|
|
24
49
|
},
|
|
25
50
|
required: [],
|
|
26
51
|
additionalProperties: true,
|
|
@@ -40,6 +40,16 @@ function loadRepoXFIConfig(repoPath) {
|
|
|
40
40
|
return filePath;
|
|
41
41
|
});
|
|
42
42
|
}
|
|
43
|
+
// Validate additional rules if present
|
|
44
|
+
if (parsedConfig.additionalRules && Array.isArray(parsedConfig.additionalRules)) {
|
|
45
|
+
for (let i = 0; i < parsedConfig.additionalRules.length; i++) {
|
|
46
|
+
if (!(0, jsonSchemas_1.validateRule)(parsedConfig.additionalRules[i])) {
|
|
47
|
+
logger_1.logger.warn(`Invalid rule at index ${i} in .xfi-config.json, removing it`);
|
|
48
|
+
parsedConfig.additionalRules.splice(i, 1);
|
|
49
|
+
i--;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
43
53
|
return parsedConfig;
|
|
44
54
|
}
|
|
45
55
|
else {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import { LoadRulesParams, RuleConfig } from '../types/typeDefs';
|
|
2
2
|
declare function loadRules(params: LoadRulesParams): Promise<RuleConfig[]>;
|
|
3
|
-
|
|
3
|
+
declare function validateCustomRules(rules: any[]): RuleConfig[];
|
|
4
|
+
export { loadRules, validateCustomRules };
|
package/dist/utils/ruleUtils.js
CHANGED
|
@@ -13,6 +13,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
13
13
|
};
|
|
14
14
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
15
15
|
exports.loadRules = loadRules;
|
|
16
|
+
exports.validateCustomRules = validateCustomRules;
|
|
16
17
|
const logger_1 = require("./logger");
|
|
17
18
|
const fs_1 = __importDefault(require("fs"));
|
|
18
19
|
const path_1 = __importDefault(require("path"));
|
|
@@ -92,3 +93,16 @@ function loadLocalConfigRule(params) {
|
|
|
92
93
|
return result;
|
|
93
94
|
});
|
|
94
95
|
}
|
|
96
|
+
// Function to validate custom rules
|
|
97
|
+
function validateCustomRules(rules) {
|
|
98
|
+
const validRules = [];
|
|
99
|
+
for (const rule of rules) {
|
|
100
|
+
if ((0, jsonSchemas_1.validateRule)(rule)) {
|
|
101
|
+
validRules.push(rule);
|
|
102
|
+
}
|
|
103
|
+
else {
|
|
104
|
+
logger_1.logger.error(`Invalid custom rule: ${rule.name || 'unnamed'}`);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return validRules;
|
|
108
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "x-fidelity",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.9.0",
|
|
4
4
|
"description": "cli for opinionated framework adherence checks",
|
|
5
5
|
"main": "dist/index",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -103,9 +103,6 @@
|
|
|
103
103
|
"peerDependencies": {
|
|
104
104
|
"artillery": "^2.0.22"
|
|
105
105
|
},
|
|
106
|
-
"resolutions": {
|
|
107
|
-
"glob": "^10.0.0"
|
|
108
|
-
},
|
|
109
106
|
"config": {
|
|
110
107
|
"commitizen": {
|
|
111
108
|
"path": "./node_modules/cz-conventional-changelog"
|
|
@@ -11,6 +11,8 @@ import { collectTelemetryData } from './telemetryCollector';
|
|
|
11
11
|
import { setupEngine } from './engineSetup';
|
|
12
12
|
import { runEngineOnFiles } from './engineRunner';
|
|
13
13
|
import { countRuleFailures, safeStringify } from '../../utils/utils';
|
|
14
|
+
import { validateRule } from '../../utils/jsonSchemas';
|
|
15
|
+
import { pluginRegistry } from '../pluginRegistry';
|
|
14
16
|
|
|
15
17
|
import { AnalyzeCodebaseParams } from '../../types/typeDefs';
|
|
16
18
|
import { options } from '../cli';
|
|
@@ -41,6 +43,27 @@ export async function analyzeCodebase(params: AnalyzeCodebaseParams): Promise<Re
|
|
|
41
43
|
const installedDependencyVersions = await getDependencyVersionFacts(archetypeConfig);
|
|
42
44
|
const fileData = await collectRepoFileData(repoPath, archetypeConfig);
|
|
43
45
|
const repoXFIConfig = await loadRepoXFIConfig(repoPath);
|
|
46
|
+
|
|
47
|
+
// Load additional plugins from repo config
|
|
48
|
+
if (repoXFIConfig.additionalPlugins && repoXFIConfig.additionalPlugins.length > 0) {
|
|
49
|
+
logger.info(`Loading additional plugins from repo config: ${repoXFIConfig.additionalPlugins.join(', ')}`);
|
|
50
|
+
try {
|
|
51
|
+
await ConfigManager.loadPlugins(repoXFIConfig.additionalPlugins);
|
|
52
|
+
} catch (error) {
|
|
53
|
+
logger.warn(`Error loading additional plugins from repo config: ${error}`);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Merge additional components into archetype config
|
|
58
|
+
if (repoXFIConfig.additionalFacts) {
|
|
59
|
+
archetypeConfig.facts = [...new Set([...archetypeConfig.facts, ...repoXFIConfig.additionalFacts])];
|
|
60
|
+
logger.info(`Added additional facts from repo config: ${repoXFIConfig.additionalFacts.join(', ')}`);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
if (repoXFIConfig.additionalOperators) {
|
|
64
|
+
archetypeConfig.operators = [...new Set([...archetypeConfig.operators, ...repoXFIConfig.additionalOperators])];
|
|
65
|
+
logger.info(`Added additional operators from repo config: ${repoXFIConfig.additionalOperators.join(', ')}`);
|
|
66
|
+
}
|
|
44
67
|
|
|
45
68
|
// add REPO_GLOBAL_CHECK to fileData, which is the trigger for global checks
|
|
46
69
|
fileData.push({
|
|
@@ -64,6 +87,49 @@ export async function analyzeCodebase(params: AnalyzeCodebaseParams): Promise<Re
|
|
|
64
87
|
repoUrl
|
|
65
88
|
});
|
|
66
89
|
|
|
90
|
+
// Add plugin facts and operators directly to the engine
|
|
91
|
+
if (repoXFIConfig.additionalFacts) {
|
|
92
|
+
const pluginFacts = pluginRegistry.getPluginFacts();
|
|
93
|
+
for (const factName of repoXFIConfig.additionalFacts) {
|
|
94
|
+
const fact = pluginFacts.find(f => f.name === factName);
|
|
95
|
+
if (fact) {
|
|
96
|
+
logger.info(`Adding custom fact to engine: ${fact.name}`);
|
|
97
|
+
engine.addFact(fact.name, fact.fn, { priority: fact.priority || 1 });
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
if (repoXFIConfig.additionalOperators) {
|
|
103
|
+
const pluginOperators = pluginRegistry.getPluginOperators();
|
|
104
|
+
for (const operatorName of repoXFIConfig.additionalOperators) {
|
|
105
|
+
const operator = pluginOperators.find(o => o.name === operatorName);
|
|
106
|
+
if (operator) {
|
|
107
|
+
logger.info(`Adding custom operator to engine: ${operator.name}`);
|
|
108
|
+
engine.addOperator(operator.name, operator.fn);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Load additional rules from repo config
|
|
114
|
+
if (repoXFIConfig.additionalRules && repoXFIConfig.additionalRules.length > 0) {
|
|
115
|
+
logger.info(`Loading additional rules from repo config: ${repoXFIConfig.additionalRules.length} rules`);
|
|
116
|
+
for (const rule of repoXFIConfig.additionalRules) {
|
|
117
|
+
if (validateRule(rule)) {
|
|
118
|
+
logger.info(`Adding custom rule from repo config: ${rule.name}`);
|
|
119
|
+
// Convert RuleConfig to RuleProperties for Engine
|
|
120
|
+
const ruleProperties = {
|
|
121
|
+
...rule,
|
|
122
|
+
conditions: rule.conditions as any
|
|
123
|
+
};
|
|
124
|
+
engine.addRule(ruleProperties);
|
|
125
|
+
} else {
|
|
126
|
+
// Cast rule to any to safely access name property
|
|
127
|
+
const ruleName = (rule as any)?.name || 'unnamed rule';
|
|
128
|
+
logger.warn(`Invalid custom rule in repo config: ${ruleName}`);
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
67
133
|
if (isOpenAIEnabled() && archetypeConfig.facts.includes('openaiAnalysisFacts')) {
|
|
68
134
|
logger.info(`adding additional openai facts to engine..`);
|
|
69
135
|
engine.addFact('openaiAnalysis', openaiAnalysis);
|
|
@@ -7,10 +7,17 @@ import { logger } from '../../../utils/logger';
|
|
|
7
7
|
*/
|
|
8
8
|
export const customFact: FactDefn = {
|
|
9
9
|
name: 'customFact',
|
|
10
|
-
fn: async (params) => {
|
|
10
|
+
fn: async (params, almanac) => {
|
|
11
11
|
try {
|
|
12
12
|
logger.debug('Executing customFact');
|
|
13
|
-
|
|
13
|
+
const result = 'custom fact data';
|
|
14
|
+
|
|
15
|
+
// Add the result to the almanac if resultFact is provided
|
|
16
|
+
if (params && params.resultFact) {
|
|
17
|
+
almanac.addRuntimeFact(params.resultFact, result);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
return result;
|
|
14
21
|
} catch (error) {
|
|
15
22
|
logger.error(`Error in customFact: ${error}`);
|
|
16
23
|
throw error;
|
package/src/types/typeDefs.ts
CHANGED
|
@@ -275,6 +275,10 @@ export interface ValidationResult {
|
|
|
275
275
|
|
|
276
276
|
export interface RepoXFIConfig {
|
|
277
277
|
sensitiveFileFalsePositives?: string[];
|
|
278
|
+
additionalRules?: RuleConfig[];
|
|
279
|
+
additionalFacts?: string[];
|
|
280
|
+
additionalOperators?: string[];
|
|
281
|
+
additionalPlugins?: string[];
|
|
278
282
|
[key: string]: any; // Allow for additional properties
|
|
279
283
|
}
|
|
280
284
|
|
package/src/utils/jsonSchemas.ts
CHANGED
|
@@ -15,7 +15,8 @@ ajv.addFormat("semverPattern", {
|
|
|
15
15
|
validate: (x) => semver.valid(x) !== null && semver.validRange(x) !== null,
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
// Using a simpler schema definition to avoid TypeScript errors with complex Ajv types
|
|
19
|
+
const repoXFIConfigSchema = {
|
|
19
20
|
type: "object",
|
|
20
21
|
properties: {
|
|
21
22
|
sensitiveFileFalsePositives: {
|
|
@@ -24,10 +25,34 @@ const repoXFIConfigSchema: RepoXFIConfigSchema = {
|
|
|
24
25
|
minItems: 0,
|
|
25
26
|
nullable: true,
|
|
26
27
|
},
|
|
28
|
+
additionalRules: {
|
|
29
|
+
type: "array",
|
|
30
|
+
items: { type: "object" },
|
|
31
|
+
minItems: 0,
|
|
32
|
+
nullable: true,
|
|
33
|
+
},
|
|
34
|
+
additionalFacts: {
|
|
35
|
+
type: "array",
|
|
36
|
+
items: { type: "string" },
|
|
37
|
+
minItems: 0,
|
|
38
|
+
nullable: true,
|
|
39
|
+
},
|
|
40
|
+
additionalOperators: {
|
|
41
|
+
type: "array",
|
|
42
|
+
items: { type: "string" },
|
|
43
|
+
minItems: 0,
|
|
44
|
+
nullable: true,
|
|
45
|
+
},
|
|
46
|
+
additionalPlugins: {
|
|
47
|
+
type: "array",
|
|
48
|
+
items: { type: "string" },
|
|
49
|
+
minItems: 0,
|
|
50
|
+
nullable: true,
|
|
51
|
+
},
|
|
27
52
|
},
|
|
28
53
|
required: [],
|
|
29
54
|
additionalProperties: true,
|
|
30
|
-
};
|
|
55
|
+
} as unknown as RepoXFIConfigSchema;
|
|
31
56
|
|
|
32
57
|
const archetypeSchema: ArchetypeConfigSchema = {
|
|
33
58
|
type: "object",
|
|
@@ -3,7 +3,7 @@ import path from 'path';
|
|
|
3
3
|
import { isPathInside } from './pathUtils';
|
|
4
4
|
import { logger } from './logger';
|
|
5
5
|
import { RepoXFIConfig } from '../types/typeDefs';
|
|
6
|
-
import { validateXFIConfig } from './jsonSchemas';
|
|
6
|
+
import { validateXFIConfig, validateRule } from './jsonSchemas';
|
|
7
7
|
|
|
8
8
|
const defaultXFIConfig: RepoXFIConfig = {
|
|
9
9
|
sensitiveFileFalsePositives: []};
|
|
@@ -29,6 +29,17 @@ export async function loadRepoXFIConfig(repoPath: string): Promise<RepoXFIConfig
|
|
|
29
29
|
});
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
+
// Validate additional rules if present
|
|
33
|
+
if (parsedConfig.additionalRules && Array.isArray(parsedConfig.additionalRules)) {
|
|
34
|
+
for (let i = 0; i < parsedConfig.additionalRules.length; i++) {
|
|
35
|
+
if (!validateRule(parsedConfig.additionalRules[i])) {
|
|
36
|
+
logger.warn(`Invalid rule at index ${i} in .xfi-config.json, removing it`);
|
|
37
|
+
parsedConfig.additionalRules.splice(i, 1);
|
|
38
|
+
i--;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
32
43
|
return parsedConfig;
|
|
33
44
|
} else {
|
|
34
45
|
logger.warn(`Ignoring invalid .xfi-config.json file, returing default config: ${JSON.stringify(defaultXFIConfig)}`);
|
package/src/utils/ruleUtils.ts
CHANGED
|
@@ -78,4 +78,19 @@ async function loadLocalConfigRule(params: LoadLocalConfigRuleParams): Promise<R
|
|
|
78
78
|
return result;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
|
-
|
|
81
|
+
// Function to validate custom rules
|
|
82
|
+
function validateCustomRules(rules: any[]): RuleConfig[] {
|
|
83
|
+
const validRules: RuleConfig[] = [];
|
|
84
|
+
|
|
85
|
+
for (const rule of rules) {
|
|
86
|
+
if (validateRule(rule)) {
|
|
87
|
+
validRules.push(rule);
|
|
88
|
+
} else {
|
|
89
|
+
logger.error(`Invalid custom rule: ${rule.name || 'unnamed'}`);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return validRules;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export { loadRules, validateCustomRules };
|
|
@@ -11,6 +11,7 @@ The `.xfi-config.json` file allows you to configure x-fidelity behavior specific
|
|
|
11
11
|
The `.xfi-config.json` file provides repository-specific configurations that override or supplement global settings. This is particularly useful for:
|
|
12
12
|
- Excluding false positives
|
|
13
13
|
- Customizing behavior for specific repositories
|
|
14
|
+
- Adding custom rules, facts, operators, and plugins
|
|
14
15
|
- Managing repository-specific exceptions
|
|
15
16
|
|
|
16
17
|
## Configuration File
|
|
@@ -22,7 +23,11 @@ Place `.xfi-config.json` in your repository's root directory:
|
|
|
22
23
|
"sensitiveFileFalsePositives": [
|
|
23
24
|
"path/to/exclude/file1.js",
|
|
24
25
|
"path/to/exclude/file2.ts"
|
|
25
|
-
]
|
|
26
|
+
],
|
|
27
|
+
"additionalRules": [],
|
|
28
|
+
"additionalFacts": [],
|
|
29
|
+
"additionalOperators": [],
|
|
30
|
+
"additionalPlugins": []
|
|
26
31
|
}
|
|
27
32
|
```
|
|
28
33
|
|
|
@@ -45,26 +50,254 @@ An array of file paths that should be excluded from sensitive data checks:
|
|
|
45
50
|
- Supports glob patterns
|
|
46
51
|
- Case-sensitive matching
|
|
47
52
|
|
|
48
|
-
|
|
53
|
+
### additionalPlugins
|
|
49
54
|
|
|
50
|
-
|
|
55
|
+
An array of plugin module names to load for this repository:
|
|
51
56
|
|
|
52
57
|
```json
|
|
53
58
|
{
|
|
54
|
-
"
|
|
55
|
-
"
|
|
56
|
-
"
|
|
59
|
+
"additionalPlugins": [
|
|
60
|
+
"xfiPluginSimpleExample",
|
|
61
|
+
"xfiPluginRequiredFiles",
|
|
62
|
+
"xfiPluginRemoteStringValidator"
|
|
57
63
|
]
|
|
58
64
|
}
|
|
59
65
|
```
|
|
60
66
|
|
|
61
|
-
|
|
67
|
+
- Plugin modules must be installed and accessible to x-fidelity
|
|
68
|
+
- Plugins provide custom facts and operators that can be used in rules
|
|
69
|
+
- Repository-specific plugins are loaded after archetype-specified plugins
|
|
70
|
+
|
|
71
|
+
### additionalFacts
|
|
72
|
+
|
|
73
|
+
An array of fact names to add to the archetype's facts:
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{
|
|
77
|
+
"additionalFacts": [
|
|
78
|
+
"customFact",
|
|
79
|
+
"missingRequiredFiles",
|
|
80
|
+
"remoteSubstringValidation"
|
|
81
|
+
]
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
- Facts must be provided by loaded plugins
|
|
86
|
+
- Repository-specific facts are merged with archetype facts
|
|
87
|
+
- Duplicate fact names are only loaded once
|
|
88
|
+
|
|
89
|
+
### additionalOperators
|
|
90
|
+
|
|
91
|
+
An array of operator names to add to the archetype's operators:
|
|
92
|
+
|
|
93
|
+
```json
|
|
94
|
+
{
|
|
95
|
+
"additionalOperators": [
|
|
96
|
+
"customOperator",
|
|
97
|
+
"missingRequiredFiles",
|
|
98
|
+
"invalidRemoteValidation"
|
|
99
|
+
]
|
|
100
|
+
}
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
- Operators must be provided by loaded plugins
|
|
104
|
+
- Repository-specific operators are merged with archetype operators
|
|
105
|
+
- Duplicate operator names are only loaded once
|
|
106
|
+
|
|
107
|
+
### additionalRules
|
|
108
|
+
|
|
109
|
+
An array of custom rule definitions to add to the archetype's rules:
|
|
110
|
+
|
|
111
|
+
```json
|
|
112
|
+
{
|
|
113
|
+
"additionalRules": [
|
|
114
|
+
{
|
|
115
|
+
"name": "custom-rule",
|
|
116
|
+
"conditions": {
|
|
117
|
+
"all": [
|
|
118
|
+
{
|
|
119
|
+
"fact": "fileData",
|
|
120
|
+
"path": "$.fileName",
|
|
121
|
+
"operator": "equal",
|
|
122
|
+
"value": "REPO_GLOBAL_CHECK"
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"fact": "customFact",
|
|
126
|
+
"operator": "customOperator",
|
|
127
|
+
"value": "custom fact data"
|
|
128
|
+
}
|
|
129
|
+
]
|
|
130
|
+
},
|
|
131
|
+
"event": {
|
|
132
|
+
"type": "warning",
|
|
133
|
+
"params": {
|
|
134
|
+
"message": "Custom rule detected matching data",
|
|
135
|
+
"details": {
|
|
136
|
+
"fact": "customFact"
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
]
|
|
142
|
+
}
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
- Rules must follow the standard rule schema
|
|
146
|
+
- Rules can use any facts and operators available (including custom ones)
|
|
147
|
+
- Repository-specific rules are added to the archetype rules
|
|
148
|
+
- Rules are validated before being added
|
|
149
|
+
|
|
150
|
+
## Complete Example
|
|
151
|
+
|
|
152
|
+
Here's a complete example of a `.xfi-config.json` file that uses all available options:
|
|
62
153
|
|
|
63
154
|
```json
|
|
64
155
|
{
|
|
65
156
|
"sensitiveFileFalsePositives": [
|
|
66
|
-
"config
|
|
67
|
-
"
|
|
157
|
+
"src/config/defaults.ts",
|
|
158
|
+
"test/fixtures/mockData.js"
|
|
159
|
+
],
|
|
160
|
+
"additionalPlugins": [
|
|
161
|
+
"xfiPluginSimpleExample"
|
|
162
|
+
],
|
|
163
|
+
"additionalFacts": [
|
|
164
|
+
"customFact"
|
|
165
|
+
],
|
|
166
|
+
"additionalOperators": [
|
|
167
|
+
"customOperator"
|
|
168
|
+
],
|
|
169
|
+
"additionalRules": [
|
|
170
|
+
{
|
|
171
|
+
"name": "custom-rule",
|
|
172
|
+
"conditions": {
|
|
173
|
+
"all": [
|
|
174
|
+
{
|
|
175
|
+
"fact": "fileData",
|
|
176
|
+
"path": "$.fileName",
|
|
177
|
+
"operator": "equal",
|
|
178
|
+
"value": "REPO_GLOBAL_CHECK"
|
|
179
|
+
},
|
|
180
|
+
{
|
|
181
|
+
"fact": "customFact",
|
|
182
|
+
"operator": "customOperator",
|
|
183
|
+
"value": "custom fact data"
|
|
184
|
+
}
|
|
185
|
+
]
|
|
186
|
+
},
|
|
187
|
+
"event": {
|
|
188
|
+
"type": "warning",
|
|
189
|
+
"params": {
|
|
190
|
+
"message": "Custom rule detected matching data",
|
|
191
|
+
"details": {
|
|
192
|
+
"fact": "customFact"
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
]
|
|
198
|
+
}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
## Usage Examples
|
|
202
|
+
|
|
203
|
+
### Adding Custom Validation with Remote API
|
|
204
|
+
|
|
205
|
+
```json
|
|
206
|
+
{
|
|
207
|
+
"additionalPlugins": ["xfiPluginRemoteStringValidator"],
|
|
208
|
+
"additionalFacts": ["remoteSubstringValidation"],
|
|
209
|
+
"additionalOperators": ["invalidRemoteValidation"],
|
|
210
|
+
"additionalRules": [
|
|
211
|
+
{
|
|
212
|
+
"name": "invalid-system-id",
|
|
213
|
+
"conditions": {
|
|
214
|
+
"all": [
|
|
215
|
+
{
|
|
216
|
+
"fact": "fileData",
|
|
217
|
+
"path": "$.fileName",
|
|
218
|
+
"operator": "equal",
|
|
219
|
+
"value": "config.json"
|
|
220
|
+
},
|
|
221
|
+
{
|
|
222
|
+
"fact": "remoteSubstringValidation",
|
|
223
|
+
"params": {
|
|
224
|
+
"pattern": "\"systemId\":[\\s]*\"([a-z]*)\"",
|
|
225
|
+
"flags": "gi",
|
|
226
|
+
"validationParams": {
|
|
227
|
+
"url": "http://validation-api/validate",
|
|
228
|
+
"method": "POST",
|
|
229
|
+
"headers": {
|
|
230
|
+
"Content-Type": "application/json"
|
|
231
|
+
},
|
|
232
|
+
"body": {
|
|
233
|
+
"systemId": "#MATCH#"
|
|
234
|
+
},
|
|
235
|
+
"checkJsonPath": "$.validSystems[?(@.id == '#MATCH#')]"
|
|
236
|
+
},
|
|
237
|
+
"resultFact": "systemIdValidationResult"
|
|
238
|
+
},
|
|
239
|
+
"operator": "invalidRemoteValidation",
|
|
240
|
+
"value": true
|
|
241
|
+
}
|
|
242
|
+
]
|
|
243
|
+
},
|
|
244
|
+
"event": {
|
|
245
|
+
"type": "fatality",
|
|
246
|
+
"params": {
|
|
247
|
+
"message": "Invalid system ID detected in configuration",
|
|
248
|
+
"details": {
|
|
249
|
+
"fact": "systemIdValidationResult"
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
]
|
|
255
|
+
}
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### Enforcing Required Files
|
|
259
|
+
|
|
260
|
+
```json
|
|
261
|
+
{
|
|
262
|
+
"additionalPlugins": ["xfiPluginRequiredFiles"],
|
|
263
|
+
"additionalFacts": ["missingRequiredFiles"],
|
|
264
|
+
"additionalOperators": ["missingRequiredFiles"],
|
|
265
|
+
"additionalRules": [
|
|
266
|
+
{
|
|
267
|
+
"name": "required-files-check",
|
|
268
|
+
"conditions": {
|
|
269
|
+
"all": [
|
|
270
|
+
{
|
|
271
|
+
"fact": "fileData",
|
|
272
|
+
"path": "$.fileName",
|
|
273
|
+
"operator": "equal",
|
|
274
|
+
"value": "REPO_GLOBAL_CHECK"
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
"fact": "missingRequiredFiles",
|
|
278
|
+
"params": {
|
|
279
|
+
"requiredFiles": [
|
|
280
|
+
"/README.md",
|
|
281
|
+
"/CONTRIBUTING.md",
|
|
282
|
+
"/LICENSE"
|
|
283
|
+
],
|
|
284
|
+
"resultFact": "missingRequiredFilesResult"
|
|
285
|
+
},
|
|
286
|
+
"operator": "missingRequiredFiles",
|
|
287
|
+
"value": true
|
|
288
|
+
}
|
|
289
|
+
]
|
|
290
|
+
},
|
|
291
|
+
"event": {
|
|
292
|
+
"type": "warning",
|
|
293
|
+
"params": {
|
|
294
|
+
"message": "Required files are missing from the repository",
|
|
295
|
+
"details": {
|
|
296
|
+
"fact": "missingRequiredFilesResult"
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
}
|
|
68
301
|
]
|
|
69
302
|
}
|
|
70
303
|
```
|
|
@@ -72,48 +305,33 @@ An array of file paths that should be excluded from sensitive data checks:
|
|
|
72
305
|
## Best Practices
|
|
73
306
|
|
|
74
307
|
1. **Version Control**:
|
|
75
|
-
- Include `.xfi-config.json` in version control
|
|
76
|
-
- Document changes in commit messages
|
|
77
|
-
- Review changes during code review
|
|
308
|
+
- Include `.xfi-config.json` in your version control system to ensure consistency across your team.
|
|
309
|
+
- Document changes in commit messages.
|
|
310
|
+
- Review changes during code review.
|
|
78
311
|
|
|
79
312
|
2. **Documentation**:
|
|
80
|
-
- Comment
|
|
81
|
-
- Explain
|
|
82
|
-
- Keep documentation up-to-date
|
|
313
|
+
- Comment custom rules and their purpose.
|
|
314
|
+
- Explain why specific plugins are needed.
|
|
315
|
+
- Keep documentation up-to-date.
|
|
83
316
|
|
|
84
317
|
3. **Regular Review**:
|
|
85
|
-
- Periodically review
|
|
86
|
-
- Remove unnecessary
|
|
87
|
-
- Update as codebase changes
|
|
318
|
+
- Periodically review your `.xfi-config.json` to ensure the configurations are still necessary and valid.
|
|
319
|
+
- Remove unnecessary rules or plugins.
|
|
320
|
+
- Update as codebase changes.
|
|
88
321
|
|
|
89
322
|
4. **Minimal Use**:
|
|
90
|
-
- Use sparingly
|
|
91
|
-
-
|
|
92
|
-
- Don't use to bypass security checks
|
|
323
|
+
- Use custom rules sparingly.
|
|
324
|
+
- Consider adding important rules to the archetype configuration instead.
|
|
325
|
+
- Don't use to bypass security checks.
|
|
93
326
|
|
|
94
327
|
5. **Team Communication**:
|
|
95
|
-
- Discuss
|
|
96
|
-
- Document decisions
|
|
97
|
-
- Consider alternatives
|
|
328
|
+
- Discuss custom rules with team.
|
|
329
|
+
- Document decisions.
|
|
330
|
+
- Consider alternatives.
|
|
98
331
|
|
|
99
332
|
## Validation
|
|
100
333
|
|
|
101
|
-
x-fidelity validates `.xfi-config.json` using JSON Schema
|
|
102
|
-
|
|
103
|
-
```json
|
|
104
|
-
{
|
|
105
|
-
"type": "object",
|
|
106
|
-
"properties": {
|
|
107
|
-
"sensitiveFileFalsePositives": {
|
|
108
|
-
"type": "array",
|
|
109
|
-
"items": {
|
|
110
|
-
"type": "string"
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
},
|
|
114
|
-
"additionalProperties": false
|
|
115
|
-
}
|
|
116
|
-
```
|
|
334
|
+
x-fidelity validates `.xfi-config.json` using JSON Schema. Custom rules are also validated against the rule schema before being added to the engine.
|
|
117
335
|
|
|
118
336
|
## Error Handling
|
|
119
337
|
|
|
@@ -122,8 +340,14 @@ If `.xfi-config.json` is invalid:
|
|
|
122
340
|
2. Default configuration used
|
|
123
341
|
3. Analysis continues
|
|
124
342
|
|
|
343
|
+
If individual custom rules are invalid:
|
|
344
|
+
1. Warning message displayed
|
|
345
|
+
2. Invalid rules are skipped
|
|
346
|
+
3. Valid rules are still applied
|
|
347
|
+
|
|
125
348
|
## Next Steps
|
|
126
349
|
|
|
127
350
|
- Configure [Local Rules](local-config)
|
|
128
351
|
- Set up [Remote Configuration](remote-config)
|
|
129
352
|
- Learn about [Exemptions](exemptions)
|
|
353
|
+
- Explore [Creating Plugins](plugins/creating-plugins)
|