framework-mcp 1.1.2 → 1.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/.do/app.yaml +78 -0
- package/CAPABILITY_TRANSFORMATION_SUMMARY.md +158 -0
- package/DAYS_5_6_COMPLETION_SUMMARY.md +178 -0
- package/DEPLOYMENT_GUIDE.md +335 -0
- package/DEPLOYMENT_SUMMARY_v1.1.3.md +211 -0
- package/README.md +34 -35
- package/RELEASE_NOTES_v1.1.3.md +321 -0
- package/RELEASE_NOTES_v1.2.0.md +396 -0
- package/dist/core/capability-analyzer.d.ts +29 -0
- package/dist/core/capability-analyzer.d.ts.map +1 -0
- package/dist/core/capability-analyzer.js +568 -0
- package/dist/core/capability-analyzer.js.map +1 -0
- package/dist/core/safeguard-manager.d.ts +15 -0
- package/dist/core/safeguard-manager.d.ts.map +1 -0
- package/dist/core/safeguard-manager.js +315 -0
- package/dist/core/safeguard-manager.js.map +1 -0
- package/dist/index.d.ts +29 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +609 -403
- package/dist/index.js.map +1 -1
- package/dist/interfaces/http/http-server.d.ts +17 -0
- package/dist/interfaces/http/http-server.d.ts.map +1 -0
- package/dist/interfaces/http/http-server.js +285 -0
- package/dist/interfaces/http/http-server.js.map +1 -0
- package/dist/interfaces/mcp/mcp-server.d.ts +18 -0
- package/dist/interfaces/mcp/mcp-server.d.ts.map +1 -0
- package/dist/interfaces/mcp/mcp-server.js +299 -0
- package/dist/interfaces/mcp/mcp-server.js.map +1 -0
- package/dist/shared/types.d.ts +89 -0
- package/dist/shared/types.d.ts.map +1 -0
- package/dist/shared/types.js +3 -0
- package/dist/shared/types.js.map +1 -0
- package/package.json +17 -6
- package/src/core/capability-analyzer.ts +708 -0
- package/src/core/safeguard-manager.ts +339 -0
- package/src/index.ts +722 -461
- package/src/interfaces/http/http-server.ts +360 -0
- package/src/interfaces/mcp/mcp-server.ts +367 -0
- package/src/shared/types.ts +104 -0
- package/test_capability_integration.js +73 -0
- package/test_comprehensive_scenarios.js +192 -0
- package/test_enhanced_detection.js +74 -0
- package/test_integrated_validation.js +112 -0
- package/test_language_update.js +101 -0
- package/test_live_validation.json +12 -0
- package/test_performance_monitoring.js +124 -0
- package/test_runner_automated.js +156 -0
- package/test_suite_comprehensive.js +218 -0
package/src/index.ts
CHANGED
|
@@ -1,5 +1,22 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
+
// Re-export the MCP server for backward compatibility
|
|
4
|
+
import { FrameworkMcpServer } from './interfaces/mcp/mcp-server.js';
|
|
5
|
+
|
|
6
|
+
// Start MCP server if this file is run directly
|
|
7
|
+
if (import.meta.url === `file://${process.argv[1]}`) {
|
|
8
|
+
const server = new FrameworkMcpServer();
|
|
9
|
+
server.run().catch(console.error);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export { FrameworkMcpServer } from './interfaces/mcp/mcp-server.js';
|
|
13
|
+
export { FrameworkHttpServer } from './interfaces/http/http-server.js';
|
|
14
|
+
export { CapabilityAnalyzer } from './core/capability-analyzer.js';
|
|
15
|
+
export { SafeguardManager } from './core/safeguard-manager.js';
|
|
16
|
+
|
|
17
|
+
// Legacy compatibility - keep the original massive implementation for reference
|
|
18
|
+
// This will be removed in a future version once migration is complete
|
|
19
|
+
|
|
3
20
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
4
21
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
5
22
|
import {
|
|
@@ -30,30 +47,22 @@ interface VendorAnalysis {
|
|
|
30
47
|
vendor: string;
|
|
31
48
|
safeguardId: string;
|
|
32
49
|
safeguardTitle: string;
|
|
33
|
-
// Primary capability categorization
|
|
34
|
-
capability: 'full' | 'partial' | 'facilitates' | 'governance' | 'validates'
|
|
35
|
-
// Detailed breakdown
|
|
50
|
+
// Primary capability categorization - what role does this tool play?
|
|
51
|
+
capability: 'full' | 'partial' | 'facilitates' | 'governance' | 'validates';
|
|
52
|
+
// Detailed capability breakdown
|
|
36
53
|
capabilities: {
|
|
37
|
-
full: boolean; //
|
|
38
|
-
partial: boolean; //
|
|
39
|
-
facilitates: boolean; //
|
|
40
|
-
governance: boolean; //
|
|
41
|
-
validates: boolean; // Provides evidence
|
|
54
|
+
full: boolean; // Directly implements the core safeguard functionality
|
|
55
|
+
partial: boolean; // Implements limited aspects of the safeguard
|
|
56
|
+
facilitates: boolean; // Enhances or enables safeguard implementation by others
|
|
57
|
+
governance: boolean; // Provides policy, process, and oversight capabilities
|
|
58
|
+
validates: boolean; // Provides evidence, audit, and validation reporting
|
|
42
59
|
};
|
|
43
60
|
confidence: number;
|
|
44
61
|
reasoning: string;
|
|
45
62
|
evidence: string[];
|
|
46
|
-
//
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
subTaxonomicalElements: string[]; // Yellow elements addressed
|
|
50
|
-
governanceElements: string[]; // Orange elements addressed
|
|
51
|
-
implementationMethods: string[]; // Gray elements used
|
|
52
|
-
};
|
|
53
|
-
elementsNotCovered: {
|
|
54
|
-
coreRequirements: string[];
|
|
55
|
-
subTaxonomicalElements: string[];
|
|
56
|
-
};
|
|
63
|
+
// Capability-focused descriptions (replaces element coverage scoring)
|
|
64
|
+
toolCapabilityDescription: string; // What type of tool this is and its role
|
|
65
|
+
recommendedUse: string; // How practitioners should use this tool
|
|
57
66
|
}
|
|
58
67
|
|
|
59
68
|
interface AnalysisResult {
|
|
@@ -91,12 +100,10 @@ interface ValidationResult {
|
|
|
91
100
|
claimed_capability: string;
|
|
92
101
|
validation_status: 'SUPPORTED' | 'QUESTIONABLE' | 'UNSUPPORTED';
|
|
93
102
|
confidence_score: number; // 0-100
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
language_consistency: number;
|
|
99
|
-
};
|
|
103
|
+
actual_capability_detected: string; // What capability the tool actually provides
|
|
104
|
+
capability_confidence: number; // Confidence in the detected capability
|
|
105
|
+
tool_capability_description: string; // Description of what type of tool this is
|
|
106
|
+
recommended_use: string; // How practitioners should use this tool
|
|
100
107
|
domain_validation: {
|
|
101
108
|
required_tool_type: string;
|
|
102
109
|
detected_tool_type: string;
|
|
@@ -119,27 +126,27 @@ const SAFEGUARD_DOMAIN_REQUIREMENTS: Record<string, {
|
|
|
119
126
|
"1.1": {
|
|
120
127
|
domain: "Asset Inventory",
|
|
121
128
|
required_tool_types: ["inventory", "asset_management", "cmdb", "discovery"],
|
|
122
|
-
description: "Only asset inventory and discovery tools can provide FULL/PARTIAL
|
|
129
|
+
description: "Only asset inventory and discovery tools can provide FULL/PARTIAL implementation capability"
|
|
123
130
|
},
|
|
124
131
|
"1.2": {
|
|
125
132
|
domain: "Asset Management",
|
|
126
133
|
required_tool_types: ["inventory", "asset_management", "network_security", "nac"],
|
|
127
|
-
description: "Asset management or network access control tools required for FULL/PARTIAL"
|
|
134
|
+
description: "Asset management or network access control tools required for FULL/PARTIAL implementation capability"
|
|
128
135
|
},
|
|
129
136
|
"5.1": {
|
|
130
137
|
domain: "Account Management",
|
|
131
138
|
required_tool_types: ["identity_management", "iam", "directory", "account_management"],
|
|
132
|
-
description: "Identity and account management tools required for FULL/PARTIAL"
|
|
139
|
+
description: "Identity and account management tools required for FULL/PARTIAL implementation capability"
|
|
133
140
|
},
|
|
134
141
|
"6.3": {
|
|
135
142
|
domain: "Authentication",
|
|
136
143
|
required_tool_types: ["mfa", "authentication", "identity_management", "iam"],
|
|
137
|
-
description: "Multi-factor authentication and identity tools required for FULL/PARTIAL"
|
|
144
|
+
description: "Multi-factor authentication and identity tools required for FULL/PARTIAL implementation capability"
|
|
138
145
|
},
|
|
139
146
|
"7.1": {
|
|
140
147
|
domain: "Vulnerability Management",
|
|
141
148
|
required_tool_types: ["vulnerability_management", "vulnerability_scanner", "patch_management"],
|
|
142
|
-
description: "Vulnerability management and scanning tools required for FULL/PARTIAL"
|
|
149
|
+
description: "Vulnerability management and scanning tools required for FULL/PARTIAL implementation capability"
|
|
143
150
|
}
|
|
144
151
|
};
|
|
145
152
|
|
|
@@ -5600,7 +5607,7 @@ export class GRCAnalysisServer {
|
|
|
5600
5607
|
tools: [
|
|
5601
5608
|
{
|
|
5602
5609
|
name: 'analyze_vendor_response',
|
|
5603
|
-
description: 'Analyze a vendor response
|
|
5610
|
+
description: 'Analyze a vendor response to determine their tool capability role (Full Implementation, Partial Implementation, Facilitates, Governance, or Validates) for a specific CIS Control safeguard',
|
|
5604
5611
|
inputSchema: {
|
|
5605
5612
|
type: 'object',
|
|
5606
5613
|
properties: {
|
|
@@ -5615,7 +5622,7 @@ export class GRCAnalysisServer {
|
|
|
5615
5622
|
},
|
|
5616
5623
|
response_text: {
|
|
5617
5624
|
type: 'string',
|
|
5618
|
-
description: 'Vendor response text
|
|
5625
|
+
description: 'Vendor response text describing their tool capabilities for the safeguard'
|
|
5619
5626
|
}
|
|
5620
5627
|
},
|
|
5621
5628
|
required: ['vendor_name', 'safeguard_id', 'response_text']
|
|
@@ -5643,7 +5650,7 @@ export class GRCAnalysisServer {
|
|
|
5643
5650
|
} as Tool,
|
|
5644
5651
|
{
|
|
5645
5652
|
name: 'validate_coverage_claim',
|
|
5646
|
-
description: 'Validate a vendor\'s
|
|
5653
|
+
description: 'Validate a vendor\'s implementation capability claim (FULL/PARTIAL) against specific safeguard requirements and evidence quality',
|
|
5647
5654
|
inputSchema: {
|
|
5648
5655
|
type: 'object',
|
|
5649
5656
|
properties: {
|
|
@@ -5659,16 +5666,16 @@ export class GRCAnalysisServer {
|
|
|
5659
5666
|
coverage_claim: {
|
|
5660
5667
|
type: 'string',
|
|
5661
5668
|
enum: ['FULL', 'PARTIAL'],
|
|
5662
|
-
description: 'Vendor\'s
|
|
5669
|
+
description: 'Vendor\'s implementation capability claim (FULL = complete implementation, PARTIAL = limited scope implementation)'
|
|
5663
5670
|
},
|
|
5664
5671
|
response_text: {
|
|
5665
5672
|
type: 'string',
|
|
5666
|
-
description: 'Vendor response explaining their
|
|
5673
|
+
description: 'Vendor response explaining their implementation capabilities'
|
|
5667
5674
|
},
|
|
5668
5675
|
capabilities: {
|
|
5669
5676
|
type: 'array',
|
|
5670
5677
|
items: { type: 'string' },
|
|
5671
|
-
description: 'List of vendor
|
|
5678
|
+
description: 'List of additional vendor capability types (Governance, Facilitates, Validates)'
|
|
5672
5679
|
}
|
|
5673
5680
|
},
|
|
5674
5681
|
required: ['vendor_name', 'safeguard_id', 'coverage_claim', 'response_text', 'capabilities']
|
|
@@ -5695,7 +5702,7 @@ export class GRCAnalysisServer {
|
|
|
5695
5702
|
} as Tool,
|
|
5696
5703
|
{
|
|
5697
5704
|
name: 'validate_vendor_mapping',
|
|
5698
|
-
description: 'Validate whether a vendor\'s
|
|
5705
|
+
description: 'Validate whether a vendor\'s claimed capability role (Full Implementation/Partial Implementation/Facilitates/Governance/Validates) is actually supported by their supporting evidence for a specific CIS safeguard',
|
|
5699
5706
|
inputSchema: {
|
|
5700
5707
|
type: 'object',
|
|
5701
5708
|
properties: {
|
|
@@ -5712,11 +5719,11 @@ export class GRCAnalysisServer {
|
|
|
5712
5719
|
claimed_capability: {
|
|
5713
5720
|
type: 'string',
|
|
5714
5721
|
enum: ['full', 'partial', 'facilitates', 'governance', 'validates'],
|
|
5715
|
-
description: 'Vendor\'s claimed capability
|
|
5722
|
+
description: 'Vendor\'s claimed capability role: full (complete implementation), partial (limited implementation), facilitates (enables/enhances), governance (policies/processes), validates (evidence/reporting)'
|
|
5716
5723
|
},
|
|
5717
5724
|
supporting_text: {
|
|
5718
5725
|
type: 'string',
|
|
5719
|
-
description: 'Vendor\'s supporting
|
|
5726
|
+
description: 'Vendor\'s supporting evidence explaining how their tool fulfills the claimed capability role'
|
|
5720
5727
|
}
|
|
5721
5728
|
},
|
|
5722
5729
|
required: ['safeguard_id', 'claimed_capability', 'supporting_text']
|
|
@@ -5727,28 +5734,49 @@ export class GRCAnalysisServer {
|
|
|
5727
5734
|
|
|
5728
5735
|
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
5729
5736
|
const { name, arguments: args } = request.params;
|
|
5737
|
+
const startTime = Date.now();
|
|
5730
5738
|
|
|
5731
5739
|
try {
|
|
5740
|
+
let result;
|
|
5732
5741
|
switch (name) {
|
|
5733
5742
|
case 'analyze_vendor_response':
|
|
5734
|
-
|
|
5743
|
+
result = await this.analyzeVendorResponse(args);
|
|
5744
|
+
break;
|
|
5735
5745
|
case 'get_safeguard_details':
|
|
5736
|
-
|
|
5746
|
+
result = await this.getSafeguardDetails(args);
|
|
5747
|
+
break;
|
|
5737
5748
|
case 'validate_coverage_claim':
|
|
5738
|
-
|
|
5749
|
+
result = await this.validateCoverageClaim(args);
|
|
5750
|
+
break;
|
|
5739
5751
|
case 'list_available_safeguards':
|
|
5740
|
-
|
|
5752
|
+
result = await this.listAvailableSafeguards(args);
|
|
5753
|
+
break;
|
|
5741
5754
|
case 'validate_vendor_mapping':
|
|
5742
|
-
|
|
5755
|
+
result = await this.validateVendorMapping(args);
|
|
5756
|
+
break;
|
|
5743
5757
|
default:
|
|
5744
5758
|
throw new Error(`Unknown tool: ${name}`);
|
|
5745
5759
|
}
|
|
5760
|
+
|
|
5761
|
+
// Record successful execution time
|
|
5762
|
+
const executionTime = Date.now() - startTime;
|
|
5763
|
+
this.recordToolExecution(name, executionTime);
|
|
5764
|
+
|
|
5765
|
+
return result;
|
|
5746
5766
|
} catch (error) {
|
|
5767
|
+
// Record error and performance metrics
|
|
5768
|
+
this.performanceMetrics.errorCount++;
|
|
5769
|
+
const executionTime = Date.now() - startTime;
|
|
5770
|
+
this.recordToolExecution(`${name}_error`, executionTime);
|
|
5771
|
+
|
|
5772
|
+
const errorMessage = this.formatErrorMessage(error, name);
|
|
5773
|
+
console.error(`[FrameworkMCP] Tool execution error: ${name}`, error);
|
|
5774
|
+
|
|
5747
5775
|
return {
|
|
5748
5776
|
content: [
|
|
5749
5777
|
{
|
|
5750
5778
|
type: 'text',
|
|
5751
|
-
text:
|
|
5779
|
+
text: errorMessage,
|
|
5752
5780
|
},
|
|
5753
5781
|
],
|
|
5754
5782
|
};
|
|
@@ -5759,10 +5787,16 @@ export class GRCAnalysisServer {
|
|
|
5759
5787
|
private async getSafeguardDetails(args: any) {
|
|
5760
5788
|
const { safeguard_id, include_examples = true } = args;
|
|
5761
5789
|
|
|
5762
|
-
|
|
5763
|
-
|
|
5764
|
-
|
|
5790
|
+
// Input validation
|
|
5791
|
+
this.validateSafeguardId(safeguard_id);
|
|
5792
|
+
|
|
5793
|
+
// Check cache first
|
|
5794
|
+
const cached = this.getCachedSafeguardDetails(safeguard_id, include_examples);
|
|
5795
|
+
if (cached) {
|
|
5796
|
+
return cached;
|
|
5765
5797
|
}
|
|
5798
|
+
|
|
5799
|
+
const safeguard = CIS_SAFEGUARDS[safeguard_id];
|
|
5766
5800
|
|
|
5767
5801
|
const result = {
|
|
5768
5802
|
...safeguard,
|
|
@@ -5792,7 +5826,7 @@ export class GRCAnalysisServer {
|
|
|
5792
5826
|
}
|
|
5793
5827
|
};
|
|
5794
5828
|
|
|
5795
|
-
|
|
5829
|
+
const response = {
|
|
5796
5830
|
content: [
|
|
5797
5831
|
{
|
|
5798
5832
|
type: 'text',
|
|
@@ -5800,11 +5834,24 @@ export class GRCAnalysisServer {
|
|
|
5800
5834
|
},
|
|
5801
5835
|
],
|
|
5802
5836
|
};
|
|
5837
|
+
|
|
5838
|
+
// Cache the result for future requests
|
|
5839
|
+
this.setCachedSafeguardDetails(safeguard_id, include_examples, response);
|
|
5840
|
+
|
|
5841
|
+
return response;
|
|
5803
5842
|
}
|
|
5804
5843
|
|
|
5805
5844
|
private async listAvailableSafeguards(args: any) {
|
|
5806
5845
|
const { implementation_group, security_function } = args;
|
|
5807
5846
|
|
|
5847
|
+
// Check cache for complete safeguard list (only if no filters applied)
|
|
5848
|
+
if (!implementation_group && !security_function && this.cache.safeguardList) {
|
|
5849
|
+
const cacheAge = Date.now() - this.cache.safeguardList.timestamp;
|
|
5850
|
+
if (cacheAge < 10 * 60 * 1000) { // 10 minute cache for safeguard list
|
|
5851
|
+
return this.cache.safeguardList.data;
|
|
5852
|
+
}
|
|
5853
|
+
}
|
|
5854
|
+
|
|
5808
5855
|
let safeguards = Object.values(CIS_SAFEGUARDS);
|
|
5809
5856
|
|
|
5810
5857
|
if (implementation_group) {
|
|
@@ -5831,7 +5878,7 @@ export class GRCAnalysisServer {
|
|
|
5831
5878
|
}))
|
|
5832
5879
|
};
|
|
5833
5880
|
|
|
5834
|
-
|
|
5881
|
+
const response = {
|
|
5835
5882
|
content: [
|
|
5836
5883
|
{
|
|
5837
5884
|
type: 'text',
|
|
@@ -5839,17 +5886,32 @@ export class GRCAnalysisServer {
|
|
|
5839
5886
|
},
|
|
5840
5887
|
],
|
|
5841
5888
|
};
|
|
5889
|
+
|
|
5890
|
+
// Cache the complete list if no filters were applied
|
|
5891
|
+
if (!implementation_group && !security_function) {
|
|
5892
|
+
this.cache.safeguardList = {
|
|
5893
|
+
data: response,
|
|
5894
|
+
timestamp: Date.now()
|
|
5895
|
+
};
|
|
5896
|
+
}
|
|
5897
|
+
|
|
5898
|
+
return response;
|
|
5842
5899
|
}
|
|
5843
5900
|
|
|
5844
5901
|
private async analyzeVendorResponse(args: any) {
|
|
5845
5902
|
const { vendor_name, safeguard_id, response_text } = args;
|
|
5846
5903
|
|
|
5847
|
-
|
|
5848
|
-
|
|
5849
|
-
|
|
5904
|
+
// Input validation
|
|
5905
|
+
this.validateSafeguardId(safeguard_id);
|
|
5906
|
+
this.validateTextInput(response_text, 'Response text');
|
|
5907
|
+
|
|
5908
|
+
if (!vendor_name || typeof vendor_name !== 'string' || vendor_name.trim().length === 0) {
|
|
5909
|
+
throw new Error('Vendor name is required');
|
|
5850
5910
|
}
|
|
5851
5911
|
|
|
5852
|
-
const
|
|
5912
|
+
const safeguard = CIS_SAFEGUARDS[safeguard_id];
|
|
5913
|
+
|
|
5914
|
+
const analysis = this.performCapabilityAnalysis(vendor_name, safeguard, response_text);
|
|
5853
5915
|
|
|
5854
5916
|
return {
|
|
5855
5917
|
content: [
|
|
@@ -5869,7 +5931,7 @@ export class GRCAnalysisServer {
|
|
|
5869
5931
|
throw new Error(`Safeguard ${safeguard_id} not found`);
|
|
5870
5932
|
}
|
|
5871
5933
|
|
|
5872
|
-
const analysis = this.
|
|
5934
|
+
const analysis = this.performCapabilityAnalysis(vendor_name, safeguard, response_text);
|
|
5873
5935
|
|
|
5874
5936
|
// Validate the coverage claim
|
|
5875
5937
|
const validation = this.validateClaim(coverage_claim, analysis, capabilities, safeguard);
|
|
@@ -5891,182 +5953,284 @@ export class GRCAnalysisServer {
|
|
|
5891
5953
|
};
|
|
5892
5954
|
}
|
|
5893
5955
|
|
|
5894
|
-
private
|
|
5956
|
+
private performCapabilityAnalysis(vendorName: string, safeguard: SafeguardElement, responseText: string): VendorAnalysis {
|
|
5895
5957
|
const text = responseText.toLowerCase();
|
|
5896
5958
|
|
|
5897
|
-
//
|
|
5898
|
-
const
|
|
5959
|
+
// Step 1: Determine what type of capability this tool is claiming
|
|
5960
|
+
const claimedCapability = this.determineClaimedCapability(text, safeguard);
|
|
5961
|
+
|
|
5962
|
+
// Step 2: Assess how well the tool executes that specific capability type
|
|
5963
|
+
const qualityAssessment = this.assessCapabilityQuality(text, safeguard, claimedCapability);
|
|
5964
|
+
|
|
5965
|
+
// Step 3: Generate capability-focused analysis
|
|
5966
|
+
return this.generateCapabilityAnalysis(vendorName, safeguard, responseText, claimedCapability, qualityAssessment);
|
|
5967
|
+
}
|
|
5968
|
+
|
|
5969
|
+
private determineClaimedCapability(text: string, safeguard: SafeguardElement): 'full' | 'partial' | 'facilitates' | 'governance' | 'validates' {
|
|
5970
|
+
// Capability detection keywords - focused on what the tool DOES, not what elements it covers
|
|
5971
|
+
const governanceIndicators = [
|
|
5899
5972
|
'policy', 'policies', 'manage', 'process', 'workflow', 'governance', 'grc',
|
|
5900
5973
|
'compliance management', 'documented', 'establish', 'maintain', 'procedure',
|
|
5901
5974
|
'control', 'controls', 'framework', 'standard', 'enterprise risk management',
|
|
5902
5975
|
'centralized management', 'oversight'
|
|
5903
5976
|
];
|
|
5904
5977
|
|
|
5905
|
-
const
|
|
5906
|
-
// Technical facilitation (original keywords)
|
|
5978
|
+
const facilitatesIndicators = [
|
|
5907
5979
|
'improve', 'enhance', 'optimize', 'faster', 'better', 'stronger', 'automate',
|
|
5908
5980
|
'streamline', 'efficiency', 'facilitate', 'support', 'enable', 'accelerate',
|
|
5909
5981
|
'api', 'integration', 'data', 'export', 'import', 'sync', 'feed',
|
|
5910
|
-
// Data provision and enrichment
|
|
5911
5982
|
'provides data', 'data source', 'data feeds', 'enrichment', 'data enrichment',
|
|
5912
5983
|
'supplemental data', 'additional data', 'contextual data', 'threat data',
|
|
5913
5984
|
'intelligence feeds', 'data aggregation', 'data collection', 'data gathering',
|
|
5914
5985
|
'feeds data', 'populates', 'informs', 'enriches', 'supplements',
|
|
5915
|
-
// Governance/process facilitation (new keywords for tools like Upolicy)
|
|
5916
5986
|
'enables compliance', 'facilitates implementation', 'supports compliance',
|
|
5917
5987
|
'creates framework', 'enables organizations', 'infrastructure', 'foundation',
|
|
5918
|
-
'compliance infrastructure', 'audit infrastructure', 'policy framework',
|
|
5919
|
-
'enables effective', 'working together', 'comprehensive coverage',
|
|
5920
5988
|
'template', 'templates', 'workflow automation', 'orchestration'
|
|
5921
5989
|
];
|
|
5922
5990
|
|
|
5923
|
-
const
|
|
5991
|
+
const validatesIndicators = [
|
|
5924
5992
|
'audit', 'report', 'evidence', 'verify', 'validate', 'check', 'monitor',
|
|
5925
5993
|
'compliance', 'compliance report', 'assessment', 'logging', 'tracking', 'review', 'attest',
|
|
5926
5994
|
'dashboard', 'metrics', 'analytics', 'visibility', 'alert', 'attestation',
|
|
5927
5995
|
'compliance tracking', 'audit trail', 'reporting capabilities', 'audit capabilities'
|
|
5928
5996
|
];
|
|
5929
5997
|
|
|
5930
|
-
//
|
|
5931
|
-
const
|
|
5932
|
-
|
|
5933
|
-
|
|
5934
|
-
const
|
|
5998
|
+
// Direct implementation indicators (tools that actually perform the safeguard)
|
|
5999
|
+
const implementationIndicators = this.getImplementationIndicators(safeguard.id);
|
|
6000
|
+
|
|
6001
|
+
// Calculate keyword presence scores
|
|
6002
|
+
const governanceScore = this.calculateKeywordScore(text, governanceIndicators);
|
|
6003
|
+
const facilitatesScore = this.calculateKeywordScore(text, facilitatesIndicators);
|
|
6004
|
+
const validatesScore = this.calculateKeywordScore(text, validatesIndicators);
|
|
6005
|
+
const implementationScore = this.calculateKeywordScore(text, implementationIndicators);
|
|
6006
|
+
|
|
6007
|
+
// Determine claimed capability based on strongest indicators and patterns
|
|
6008
|
+
if (implementationScore > 0.2 && implementationScore >= Math.max(facilitatesScore, governanceScore, validatesScore)) {
|
|
6009
|
+
// Tool claims to directly implement the safeguard
|
|
6010
|
+
return implementationScore > 0.5 ? 'full' : 'partial';
|
|
6011
|
+
} else if (governanceScore > 0.2 && governanceScore >= Math.max(facilitatesScore, validatesScore)) {
|
|
6012
|
+
return 'governance';
|
|
6013
|
+
} else if (validatesScore > 0.2 && validatesScore >= facilitatesScore) {
|
|
6014
|
+
return 'validates';
|
|
6015
|
+
} else {
|
|
6016
|
+
return 'facilitates';
|
|
6017
|
+
}
|
|
6018
|
+
}
|
|
5935
6019
|
|
|
5936
|
-
|
|
5937
|
-
|
|
5938
|
-
const
|
|
5939
|
-
|
|
6020
|
+
private getImplementationIndicators(safeguardId: string): string[] {
|
|
6021
|
+
// Return specific indicators for what constitutes direct implementation for each safeguard
|
|
6022
|
+
const implementationMap: Record<string, string[]> = {
|
|
6023
|
+
"1.1": ['inventory', 'discovery', 'asset management', 'catalog', 'enumerate', 'scan devices', 'device database'],
|
|
6024
|
+
"1.2": ['unauthorized', 'rogue', 'detect', 'identify unauthorized', 'quarantine', 'block unauthorized'],
|
|
6025
|
+
"5.1": ['account inventory', 'user management', 'identity management', 'account lifecycle', 'user provisioning'],
|
|
6026
|
+
"6.3": ['multi-factor', 'mfa', '2fa', 'authentication', 'two-factor', 'multi-factor authentication'],
|
|
6027
|
+
"7.1": ['vulnerability', 'vuln', 'scanning', 'vulnerability management', 'security testing', 'penetration testing']
|
|
6028
|
+
};
|
|
5940
6029
|
|
|
5941
|
-
|
|
5942
|
-
|
|
5943
|
-
|
|
6030
|
+
return implementationMap[safeguardId] || [];
|
|
6031
|
+
}
|
|
6032
|
+
|
|
6033
|
+
private assessCapabilityQuality(text: string, safeguard: SafeguardElement, claimedCapability: string): {
|
|
6034
|
+
quality: 'excellent' | 'good' | 'fair' | 'poor',
|
|
6035
|
+
confidence: number,
|
|
6036
|
+
evidence: string[],
|
|
6037
|
+
gaps: string[]
|
|
6038
|
+
} {
|
|
6039
|
+
// Assess how well the tool executes the claimed capability type
|
|
6040
|
+
const evidence: string[] = [];
|
|
6041
|
+
const gaps: string[] = [];
|
|
5944
6042
|
|
|
5945
|
-
//
|
|
5946
|
-
|
|
5947
|
-
'enables compliance', 'facilitates implementation', 'creates framework',
|
|
5948
|
-
'policy framework', 'compliance infrastructure', 'audit infrastructure',
|
|
5949
|
-
'enables organizations', 'enables effective', 'working together',
|
|
5950
|
-
'creates the policy framework', 'enables organizations to implement',
|
|
5951
|
-
'facilitates implementation of', 'compliance infrastructure facilitates'
|
|
5952
|
-
];
|
|
5953
|
-
const hasFacilitationPattern = facilitationPatterns.some(pattern => text.includes(pattern));
|
|
6043
|
+
// Quality assessment based on capability type
|
|
6044
|
+
let qualityScore = 0;
|
|
5954
6045
|
|
|
5955
|
-
|
|
5956
|
-
|
|
5957
|
-
|
|
5958
|
-
|
|
5959
|
-
|
|
5960
|
-
|
|
5961
|
-
|
|
6046
|
+
switch (claimedCapability) {
|
|
6047
|
+
case 'full':
|
|
6048
|
+
case 'partial':
|
|
6049
|
+
qualityScore = this.assessImplementationQuality(text, safeguard, evidence, gaps);
|
|
6050
|
+
break;
|
|
6051
|
+
case 'governance':
|
|
6052
|
+
qualityScore = this.assessGovernanceQuality(text, safeguard, evidence, gaps);
|
|
6053
|
+
break;
|
|
6054
|
+
case 'facilitates':
|
|
6055
|
+
qualityScore = this.assessFacilitationQuality(text, safeguard, evidence, gaps);
|
|
6056
|
+
break;
|
|
6057
|
+
case 'validates':
|
|
6058
|
+
qualityScore = this.assessValidationQuality(text, safeguard, evidence, gaps);
|
|
6059
|
+
break;
|
|
6060
|
+
}
|
|
6061
|
+
|
|
6062
|
+
// Convert score to quality rating
|
|
6063
|
+
let quality: 'excellent' | 'good' | 'fair' | 'poor';
|
|
6064
|
+
if (qualityScore >= 0.8) quality = 'excellent';
|
|
6065
|
+
else if (qualityScore >= 0.6) quality = 'good';
|
|
6066
|
+
else if (qualityScore >= 0.4) quality = 'fair';
|
|
6067
|
+
else quality = 'poor';
|
|
5962
6068
|
|
|
5963
|
-
|
|
5964
|
-
|
|
5965
|
-
|
|
6069
|
+
return {
|
|
6070
|
+
quality,
|
|
6071
|
+
confidence: Math.round(qualityScore * 100),
|
|
6072
|
+
evidence: evidence.slice(0, 5), // Top 5 pieces of evidence
|
|
6073
|
+
gaps: gaps.slice(0, 3) // Top 3 gaps identified
|
|
6074
|
+
};
|
|
6075
|
+
}
|
|
6076
|
+
|
|
6077
|
+
private assessImplementationQuality(text: string, safeguard: SafeguardElement, evidence: string[], gaps: string[]): number {
|
|
6078
|
+
// Assess quality of direct implementation capability
|
|
6079
|
+
const implementationIndicators = this.getImplementationIndicators(safeguard.id);
|
|
6080
|
+
let score = 0;
|
|
5966
6081
|
|
|
5967
|
-
|
|
5968
|
-
|
|
5969
|
-
|
|
5970
|
-
|
|
6082
|
+
// Check for strong implementation language
|
|
6083
|
+
const strongIndicators = implementationIndicators.filter(indicator => text.includes(indicator.toLowerCase()));
|
|
6084
|
+
if (strongIndicators.length > 0) {
|
|
6085
|
+
score += 0.4;
|
|
6086
|
+
evidence.push(`Strong implementation indicators: ${strongIndicators.join(', ')}`);
|
|
6087
|
+
}
|
|
5971
6088
|
|
|
5972
|
-
|
|
5973
|
-
|
|
6089
|
+
// Check for comprehensive functionality description
|
|
6090
|
+
if (text.includes('comprehensive') || text.includes('complete') || text.includes('full')) {
|
|
6091
|
+
score += 0.2;
|
|
6092
|
+
evidence.push('Claims comprehensive functionality');
|
|
6093
|
+
}
|
|
5974
6094
|
|
|
5975
|
-
//
|
|
5976
|
-
if (
|
|
5977
|
-
|
|
6095
|
+
// Check for automated vs manual implementation
|
|
6096
|
+
if (text.includes('automat') || text.includes('real-time') || text.includes('continuous')) {
|
|
6097
|
+
score += 0.2;
|
|
6098
|
+
evidence.push('Automated implementation capability');
|
|
5978
6099
|
}
|
|
5979
|
-
|
|
5980
|
-
|
|
5981
|
-
|
|
6100
|
+
|
|
6101
|
+
// Identify potential gaps
|
|
6102
|
+
if (strongIndicators.length === 0) {
|
|
6103
|
+
gaps.push('No clear implementation indicators found');
|
|
5982
6104
|
}
|
|
6105
|
+
|
|
6106
|
+
return Math.min(score, 1.0);
|
|
6107
|
+
}
|
|
5983
6108
|
|
|
5984
|
-
|
|
5985
|
-
|
|
6109
|
+
private assessGovernanceQuality(text: string, safeguard: SafeguardElement, evidence: string[], gaps: string[]): number {
|
|
6110
|
+
const governanceIndicators = ['policy', 'process', 'governance', 'compliance', 'documentation', 'oversight'];
|
|
6111
|
+
let score = 0;
|
|
5986
6112
|
|
|
5987
|
-
|
|
5988
|
-
|
|
5989
|
-
|
|
5990
|
-
|
|
5991
|
-
// Prioritize facilitation when:
|
|
5992
|
-
// 1. Clear facilitation language patterns detected, OR
|
|
5993
|
-
// 2. Explicit non-implementation language (tool doesn't directly implement), OR
|
|
5994
|
-
// 3. Facilitates score is substantial AND significantly higher than governance
|
|
5995
|
-
primaryCapability = 'facilitates';
|
|
5996
|
-
} else if (partialCapability) {
|
|
5997
|
-
primaryCapability = 'partial';
|
|
5998
|
-
} else if (governanceCapability && (facilitatesCapability || validatesCapability)) {
|
|
5999
|
-
// Tools that primarily manage governance but also facilitate/validate
|
|
6000
|
-
primaryCapability = 'governance';
|
|
6001
|
-
} else if (governanceScore > facilitatesScore && governanceCapability) {
|
|
6002
|
-
// Pure governance tools
|
|
6003
|
-
primaryCapability = 'governance';
|
|
6004
|
-
} else if (validatesScore > facilitatesScore && validatesCapability) {
|
|
6005
|
-
// Validation-focused tools
|
|
6006
|
-
primaryCapability = 'validates';
|
|
6007
|
-
} else if (facilitatesCapability) {
|
|
6008
|
-
// Default facilitation
|
|
6009
|
-
primaryCapability = 'facilitates';
|
|
6113
|
+
const foundIndicators = governanceIndicators.filter(indicator => text.includes(indicator));
|
|
6114
|
+
if (foundIndicators.length >= 3) {
|
|
6115
|
+
score += 0.5;
|
|
6116
|
+
evidence.push(`Strong governance capability: ${foundIndicators.join(', ')}`);
|
|
6010
6117
|
}
|
|
6118
|
+
|
|
6119
|
+
if (text.includes('documented') && text.includes('process')) {
|
|
6120
|
+
score += 0.3;
|
|
6121
|
+
evidence.push('Documented process management');
|
|
6122
|
+
}
|
|
6123
|
+
|
|
6124
|
+
return Math.min(score, 1.0);
|
|
6125
|
+
}
|
|
6011
6126
|
|
|
6012
|
-
|
|
6013
|
-
const
|
|
6127
|
+
private assessFacilitationQuality(text: string, safeguard: SafeguardElement, evidence: string[], gaps: string[]): number {
|
|
6128
|
+
const facilitationIndicators = ['enhance', 'enable', 'support', 'facilitate', 'improve', 'optimize'];
|
|
6129
|
+
let score = 0;
|
|
6130
|
+
|
|
6131
|
+
const foundIndicators = facilitationIndicators.filter(indicator => text.includes(indicator));
|
|
6132
|
+
if (foundIndicators.length >= 2) {
|
|
6133
|
+
score += 0.4;
|
|
6134
|
+
evidence.push(`Clear facilitation capability: ${foundIndicators.join(', ')}`);
|
|
6135
|
+
}
|
|
6136
|
+
|
|
6137
|
+
return Math.min(score, 1.0);
|
|
6138
|
+
}
|
|
6014
6139
|
|
|
6015
|
-
|
|
6016
|
-
const
|
|
6140
|
+
private assessValidationQuality(text: string, safeguard: SafeguardElement, evidence: string[], gaps: string[]): number {
|
|
6141
|
+
const validationIndicators = ['audit', 'report', 'monitor', 'track', 'verify', 'validate'];
|
|
6142
|
+
let score = 0;
|
|
6017
6143
|
|
|
6018
|
-
const
|
|
6019
|
-
|
|
6020
|
-
|
|
6021
|
-
|
|
6144
|
+
const foundIndicators = validationIndicators.filter(indicator => text.includes(indicator));
|
|
6145
|
+
if (foundIndicators.length >= 2) {
|
|
6146
|
+
score += 0.4;
|
|
6147
|
+
evidence.push(`Strong validation capability: ${foundIndicators.join(', ')}`);
|
|
6148
|
+
}
|
|
6022
6149
|
|
|
6023
|
-
|
|
6024
|
-
|
|
6025
|
-
100
|
|
6026
|
-
);
|
|
6150
|
+
return Math.min(score, 1.0);
|
|
6151
|
+
}
|
|
6027
6152
|
|
|
6153
|
+
private generateCapabilityAnalysis(vendorName: string, safeguard: SafeguardElement, responseText: string,
|
|
6154
|
+
claimedCapability: string, qualityAssessment: any): VendorAnalysis {
|
|
6155
|
+
// Generate the new capability-focused analysis result
|
|
6028
6156
|
return {
|
|
6029
6157
|
vendor: vendorName,
|
|
6030
6158
|
safeguardId: safeguard.id,
|
|
6031
6159
|
safeguardTitle: safeguard.title,
|
|
6032
|
-
capability:
|
|
6160
|
+
capability: claimedCapability as 'full' | 'partial' | 'facilitates' | 'governance' | 'validates',
|
|
6033
6161
|
capabilities: {
|
|
6034
|
-
full:
|
|
6035
|
-
partial:
|
|
6036
|
-
facilitates:
|
|
6037
|
-
governance:
|
|
6038
|
-
validates:
|
|
6162
|
+
full: claimedCapability === 'full',
|
|
6163
|
+
partial: claimedCapability === 'partial',
|
|
6164
|
+
facilitates: claimedCapability === 'facilitates',
|
|
6165
|
+
governance: claimedCapability === 'governance',
|
|
6166
|
+
validates: claimedCapability === 'validates'
|
|
6039
6167
|
},
|
|
6040
|
-
confidence:
|
|
6041
|
-
reasoning: this.generateCapabilityReasoning(
|
|
6042
|
-
evidence,
|
|
6043
|
-
|
|
6044
|
-
|
|
6045
|
-
|
|
6046
|
-
|
|
6047
|
-
implementationMethods: implementationCoverage.coveredElements
|
|
6048
|
-
},
|
|
6049
|
-
elementsNotCovered: {
|
|
6050
|
-
coreRequirements: coreCoverage.uncoveredElements,
|
|
6051
|
-
subTaxonomicalElements: subElementCoverage.uncoveredElements
|
|
6052
|
-
}
|
|
6168
|
+
confidence: qualityAssessment.confidence,
|
|
6169
|
+
reasoning: this.generateCapabilityReasoning(claimedCapability, qualityAssessment, safeguard),
|
|
6170
|
+
evidence: qualityAssessment.evidence,
|
|
6171
|
+
// Note: elementsCovered is now less relevant in capability-focused analysis
|
|
6172
|
+
// We focus on tool capability rather than element coverage
|
|
6173
|
+
toolCapabilityDescription: this.generateToolCapabilityDescription(claimedCapability, qualityAssessment),
|
|
6174
|
+
recommendedUse: this.generateRecommendedUse(claimedCapability, safeguard)
|
|
6053
6175
|
};
|
|
6054
6176
|
}
|
|
6055
6177
|
|
|
6178
|
+
private generateCapabilityReasoning(claimedCapability: string, qualityAssessment: any, safeguard: SafeguardElement): string {
|
|
6179
|
+
const capabilityDescriptions = {
|
|
6180
|
+
full: "directly implements the core functionality of this safeguard",
|
|
6181
|
+
partial: "implements limited aspects of this safeguard with clear scope boundaries",
|
|
6182
|
+
facilitates: "enhances or enables the implementation of this safeguard by others",
|
|
6183
|
+
governance: "provides governance, policy, and oversight capabilities for this safeguard",
|
|
6184
|
+
validates: "provides evidence, audit, and compliance validation for this safeguard"
|
|
6185
|
+
};
|
|
6186
|
+
|
|
6187
|
+
const qualityDescriptor = qualityAssessment.quality;
|
|
6188
|
+
const description = capabilityDescriptions[claimedCapability as keyof typeof capabilityDescriptions];
|
|
6189
|
+
|
|
6190
|
+
return `This tool ${description} with ${qualityDescriptor} capability quality. ${qualityAssessment.evidence.length > 0 ? 'Evidence: ' + qualityAssessment.evidence.join('; ') : ''}`;
|
|
6191
|
+
}
|
|
6192
|
+
|
|
6193
|
+
private generateToolCapabilityDescription(claimedCapability: string, qualityAssessment: any): string {
|
|
6194
|
+
const roleDescriptions = {
|
|
6195
|
+
full: "Core Implementation Tool - Directly performs the safeguard functionality",
|
|
6196
|
+
partial: "Focused Implementation Tool - Performs specific aspects of the safeguard",
|
|
6197
|
+
facilitates: "Enablement Tool - Helps organizations implement the safeguard more effectively",
|
|
6198
|
+
governance: "Governance Tool - Manages policies, processes, and oversight for the safeguard",
|
|
6199
|
+
validates: "Compliance Tool - Provides audit, evidence, and validation capabilities"
|
|
6200
|
+
};
|
|
6201
|
+
|
|
6202
|
+
return roleDescriptions[claimedCapability as keyof typeof roleDescriptions] || "Support Tool";
|
|
6203
|
+
}
|
|
6204
|
+
|
|
6205
|
+
private generateRecommendedUse(claimedCapability: string, safeguard: SafeguardElement): string {
|
|
6206
|
+
const recommendations = {
|
|
6207
|
+
full: `Use as primary implementation tool for ${safeguard.title}. Ensure proper configuration and integration.`,
|
|
6208
|
+
partial: `Use as part of a multi-tool strategy for ${safeguard.title}. Supplement with additional capabilities as needed.`,
|
|
6209
|
+
facilitates: `Use to enhance existing safeguard implementation. Combine with direct implementation tools.`,
|
|
6210
|
+
governance: `Use for policy management and governance oversight. Pair with implementation and validation tools.`,
|
|
6211
|
+
validates: `Use for compliance monitoring and evidence collection. Combine with implementation tools for complete coverage.`
|
|
6212
|
+
};
|
|
6213
|
+
|
|
6214
|
+
return recommendations[claimedCapability as keyof typeof recommendations] || "Evaluate specific use case alignment.";
|
|
6215
|
+
}
|
|
6216
|
+
|
|
6056
6217
|
private calculateKeywordScore(text: string, keywords: string[]): number {
|
|
6057
|
-
let
|
|
6058
|
-
let
|
|
6218
|
+
let matchedKeywords = 0;
|
|
6219
|
+
let totalMatches = 0;
|
|
6059
6220
|
|
|
6060
6221
|
keywords.forEach(keyword => {
|
|
6061
6222
|
const regex = new RegExp(keyword.replace(/\s+/g, '\\s+'), 'gi');
|
|
6062
6223
|
const keywordMatches = (text.match(regex) || []).length;
|
|
6063
6224
|
if (keywordMatches > 0) {
|
|
6064
|
-
|
|
6065
|
-
|
|
6225
|
+
matchedKeywords++;
|
|
6226
|
+
totalMatches += keywordMatches;
|
|
6066
6227
|
}
|
|
6067
6228
|
});
|
|
6068
6229
|
|
|
6069
|
-
|
|
6230
|
+
// Return percentage of keywords that were found, with bonus for multiple matches
|
|
6231
|
+
const baseScore = matchedKeywords / keywords.length;
|
|
6232
|
+
const matchBonus = Math.min(totalMatches * 0.1, 0.5); // Up to 50% bonus for multiple matches
|
|
6233
|
+
return Math.min(baseScore + matchBonus, 1.0);
|
|
6070
6234
|
}
|
|
6071
6235
|
|
|
6072
6236
|
private analyzeElementCoverage(text: string, elements: string[]): {
|
|
@@ -6208,76 +6372,6 @@ export class GRCAnalysisServer {
|
|
|
6208
6372
|
return reasons.join('. ');
|
|
6209
6373
|
}
|
|
6210
6374
|
|
|
6211
|
-
private generateCapabilityReasoning(
|
|
6212
|
-
primaryCapability: string,
|
|
6213
|
-
full: boolean,
|
|
6214
|
-
partial: boolean,
|
|
6215
|
-
governance: boolean,
|
|
6216
|
-
facilitates: boolean,
|
|
6217
|
-
validates: boolean,
|
|
6218
|
-
coreCoverage: any,
|
|
6219
|
-
subElementCoverage: any,
|
|
6220
|
-
safeguard: SafeguardElement,
|
|
6221
|
-
hasFacilitationPattern: boolean = false,
|
|
6222
|
-
hasNonImplementationLanguage: boolean = false
|
|
6223
|
-
): string {
|
|
6224
|
-
const reasons = [];
|
|
6225
|
-
|
|
6226
|
-
// Primary capability explanation
|
|
6227
|
-
switch (primaryCapability) {
|
|
6228
|
-
case 'full':
|
|
6229
|
-
reasons.push(`Provides FULL coverage of ${safeguard.title} - directly implements all core and sub-taxonomical elements`);
|
|
6230
|
-
break;
|
|
6231
|
-
case 'partial':
|
|
6232
|
-
reasons.push(`Provides PARTIAL coverage of ${safeguard.title} - directly implements some but not all core and sub-taxonomical elements`);
|
|
6233
|
-
break;
|
|
6234
|
-
case 'facilitates':
|
|
6235
|
-
if (hasFacilitationPattern || hasNonImplementationLanguage || governance) {
|
|
6236
|
-
reasons.push(`FACILITATES ${safeguard.title} by creating governance frameworks, policy infrastructure, and compliance processes that enable organizations to implement the control effectively`);
|
|
6237
|
-
} else {
|
|
6238
|
-
reasons.push(`FACILITATES ${safeguard.title} through data integration, automation, or technical capabilities that support implementation`);
|
|
6239
|
-
}
|
|
6240
|
-
break;
|
|
6241
|
-
case 'governance':
|
|
6242
|
-
reasons.push(`Provides GOVERNANCE capabilities for ${safeguard.title} through centralized policy management, process controls, and compliance oversight`);
|
|
6243
|
-
break;
|
|
6244
|
-
case 'validates':
|
|
6245
|
-
reasons.push(`VALIDATES ${safeguard.title} implementation through evidence collection, compliance reporting, and audit capabilities`);
|
|
6246
|
-
break;
|
|
6247
|
-
default:
|
|
6248
|
-
reasons.push(`No clear capability identified for ${safeguard.title}`);
|
|
6249
|
-
}
|
|
6250
|
-
|
|
6251
|
-
// Coverage details
|
|
6252
|
-
if (coreCoverage.coveredElements.length > 0) {
|
|
6253
|
-
reasons.push(`Core elements addressed: ${coreCoverage.coveredElements.length}/${safeguard.coreRequirements.length}`);
|
|
6254
|
-
}
|
|
6255
|
-
if (subElementCoverage.coveredElements.length > 0) {
|
|
6256
|
-
reasons.push(`Sub-taxonomical elements addressed: ${subElementCoverage.coveredElements.length}/${safeguard.subTaxonomicalElements.length}`);
|
|
6257
|
-
}
|
|
6258
|
-
|
|
6259
|
-
// Additional context for facilitation tools
|
|
6260
|
-
if (primaryCapability === 'facilitates') {
|
|
6261
|
-
if (hasFacilitationPattern || hasNonImplementationLanguage || governance) {
|
|
6262
|
-
reasons.push(`Note: This type of facilitation tool works alongside technical implementation solutions (asset scanners, MDM tools, etc.) to provide comprehensive control coverage`);
|
|
6263
|
-
}
|
|
6264
|
-
if (hasNonImplementationLanguage) {
|
|
6265
|
-
reasons.push(`Tool explicitly enables compliance through governance/process rather than direct technical implementation`);
|
|
6266
|
-
}
|
|
6267
|
-
}
|
|
6268
|
-
|
|
6269
|
-
// Multi-capability products
|
|
6270
|
-
const capabilityFlags = [governance, facilitates, validates].filter(Boolean);
|
|
6271
|
-
if (capabilityFlags.length > 1) {
|
|
6272
|
-
const capabilities = [];
|
|
6273
|
-
if (governance) capabilities.push('governance');
|
|
6274
|
-
if (facilitates) capabilities.push('facilitates');
|
|
6275
|
-
if (validates) capabilities.push('validates');
|
|
6276
|
-
reasons.push(`Multi-capability product with: ${capabilities.join(', ')}`);
|
|
6277
|
-
}
|
|
6278
|
-
|
|
6279
|
-
return reasons.join('. ');
|
|
6280
|
-
}
|
|
6281
6375
|
|
|
6282
6376
|
private validateClaim(claim: string, analysis: VendorAnalysis, capabilities: string[], safeguard: SafeguardElement) {
|
|
6283
6377
|
const validation = {
|
|
@@ -6293,16 +6387,14 @@ export class GRCAnalysisServer {
|
|
|
6293
6387
|
validation.coverageClaimValid = meetsFullCriteria;
|
|
6294
6388
|
|
|
6295
6389
|
if (!meetsFullCriteria) {
|
|
6296
|
-
|
|
6297
|
-
const coveredElements = analysis.elementsCovered.coreRequirements.length + analysis.elementsCovered.subTaxonomicalElements.length;
|
|
6298
|
-
validation.gaps.push(`FULL coverage claim not supported: Only ${coveredElements}/${totalElements} core and sub-taxonomical elements covered`);
|
|
6390
|
+
validation.gaps.push(`FULL implementation capability claim not supported: Tool does not demonstrate direct implementation of core safeguard functionality`);
|
|
6299
6391
|
}
|
|
6300
6392
|
} else if (claim === 'PARTIAL') {
|
|
6301
6393
|
const meetsPartialCriteria = analysis.capabilities.partial || analysis.capabilities.full;
|
|
6302
6394
|
validation.coverageClaimValid = meetsPartialCriteria;
|
|
6303
6395
|
|
|
6304
6396
|
if (!meetsPartialCriteria) {
|
|
6305
|
-
validation.gaps.push(`PARTIAL
|
|
6397
|
+
validation.gaps.push(`PARTIAL implementation capability claim questionable: No core or sub-taxonomical elements clearly addressed`);
|
|
6306
6398
|
}
|
|
6307
6399
|
}
|
|
6308
6400
|
|
|
@@ -6348,13 +6440,15 @@ export class GRCAnalysisServer {
|
|
|
6348
6440
|
} else {
|
|
6349
6441
|
validation.recommendations.push(`Consider requesting additional information about: ${validation.gaps.join(', ')}`);
|
|
6350
6442
|
|
|
6351
|
-
//
|
|
6352
|
-
if (analysis.
|
|
6353
|
-
validation.recommendations.push(
|
|
6354
|
-
}
|
|
6355
|
-
|
|
6356
|
-
if (analysis.
|
|
6357
|
-
validation.recommendations.push(
|
|
6443
|
+
// Capability-based recommendations
|
|
6444
|
+
if (analysis.capability === 'facilitates') {
|
|
6445
|
+
validation.recommendations.push('Consider pairing with direct implementation tools for complete safeguard coverage');
|
|
6446
|
+
} else if (analysis.capability === 'partial') {
|
|
6447
|
+
validation.recommendations.push('Evaluate scope limitations and identify complementary tools for full coverage');
|
|
6448
|
+
} else if (analysis.capability === 'governance') {
|
|
6449
|
+
validation.recommendations.push('Combine with technical implementation tools for complete safeguard execution');
|
|
6450
|
+
} else if (analysis.capability === 'validates') {
|
|
6451
|
+
validation.recommendations.push('Pair with implementation tools to ensure both execution and validation coverage');
|
|
6358
6452
|
}
|
|
6359
6453
|
|
|
6360
6454
|
if (!analysis.capabilities.validates && capabilities.includes('Validates')) {
|
|
@@ -6368,10 +6462,12 @@ export class GRCAnalysisServer {
|
|
|
6368
6462
|
private async validateVendorMapping(args: any) {
|
|
6369
6463
|
const { vendor_name = 'Unknown Vendor', safeguard_id, claimed_capability, supporting_text } = args;
|
|
6370
6464
|
|
|
6465
|
+
// Input validation
|
|
6466
|
+
this.validateSafeguardId(safeguard_id);
|
|
6467
|
+
this.validateTextInput(supporting_text, 'Supporting text');
|
|
6468
|
+
this.validateCapability(claimed_capability);
|
|
6469
|
+
|
|
6371
6470
|
const safeguard = CIS_SAFEGUARDS[safeguard_id];
|
|
6372
|
-
if (!safeguard) {
|
|
6373
|
-
throw new Error(`Safeguard ${safeguard_id} not found. Available safeguards: ${Object.keys(CIS_SAFEGUARDS).join(', ')}`);
|
|
6374
|
-
}
|
|
6375
6471
|
|
|
6376
6472
|
const validation = this.validateCapabilityClaim(
|
|
6377
6473
|
vendor_name,
|
|
@@ -6399,7 +6495,7 @@ export class GRCAnalysisServer {
|
|
|
6399
6495
|
const text = supportingText.toLowerCase();
|
|
6400
6496
|
|
|
6401
6497
|
// Detect tool type and validate domain match
|
|
6402
|
-
const detectedToolType = this.detectToolType(supportingText);
|
|
6498
|
+
const detectedToolType = this.detectToolType(supportingText, safeguard.id);
|
|
6403
6499
|
const domainValidation = this.validateDomainMatch(safeguard.id, claimedCapability, detectedToolType);
|
|
6404
6500
|
|
|
6405
6501
|
// Adjust capability if domain mismatch detected
|
|
@@ -6411,28 +6507,15 @@ export class GRCAnalysisServer {
|
|
|
6411
6507
|
effectiveCapability = domainValidation.adjusted_capability!;
|
|
6412
6508
|
}
|
|
6413
6509
|
|
|
6414
|
-
// Perform
|
|
6415
|
-
const actualAnalysis = this.
|
|
6416
|
-
|
|
6417
|
-
// Calculate coverage percentages
|
|
6418
|
-
const coreCoverage = this.analyzeBinaryElementCoverage(text, safeguard.coreRequirements);
|
|
6419
|
-
const subElementCoverage = this.analyzeBinaryElementCoverage(text, safeguard.subTaxonomicalElements);
|
|
6420
|
-
const governanceCoverage = this.analyzeBinaryElementCoverage(text, safeguard.governanceElements);
|
|
6510
|
+
// Perform capability-focused analysis of the supporting text
|
|
6511
|
+
const actualAnalysis = this.performCapabilityAnalysis(vendorName, safeguard, supportingText);
|
|
6421
6512
|
|
|
6422
|
-
|
|
6423
|
-
|
|
6424
|
-
|
|
6425
|
-
(subElementCoverage.coveredElements.length / safeguard.subTaxonomicalElements.length) * 100 : 0;
|
|
6426
|
-
const governancePercentage = safeguard.governanceElements.length > 0 ?
|
|
6427
|
-
(governanceCoverage.coveredElements.length / safeguard.governanceElements.length) * 100 : 0;
|
|
6428
|
-
|
|
6429
|
-
// Validate claim against criteria (using effective capability after domain adjustment)
|
|
6430
|
-
const validation = this.assessClaimAlignment(
|
|
6513
|
+
// Validate claimed capability against actual capability analysis and domain requirements
|
|
6514
|
+
const validation = this.assessCapabilityClaimAlignment(
|
|
6515
|
+
claimedCapability,
|
|
6431
6516
|
effectiveCapability,
|
|
6432
|
-
actualAnalysis,
|
|
6433
|
-
|
|
6434
|
-
subElementPercentage,
|
|
6435
|
-
governancePercentage,
|
|
6517
|
+
actualAnalysis,
|
|
6518
|
+
domainValidation,
|
|
6436
6519
|
text
|
|
6437
6520
|
);
|
|
6438
6521
|
|
|
@@ -6451,12 +6534,10 @@ export class GRCAnalysisServer {
|
|
|
6451
6534
|
claimed_capability: claimedCapability,
|
|
6452
6535
|
validation_status: validation.status,
|
|
6453
6536
|
confidence_score: validation.confidence,
|
|
6454
|
-
|
|
6455
|
-
|
|
6456
|
-
|
|
6457
|
-
|
|
6458
|
-
language_consistency: validation.languageConsistency
|
|
6459
|
-
},
|
|
6537
|
+
actual_capability_detected: actualAnalysis.capability,
|
|
6538
|
+
capability_confidence: actualAnalysis.confidence,
|
|
6539
|
+
tool_capability_description: actualAnalysis.toolCapabilityDescription,
|
|
6540
|
+
recommended_use: actualAnalysis.recommendedUse,
|
|
6460
6541
|
domain_validation: {
|
|
6461
6542
|
required_tool_type: domainValidation.required_tool_types.join('/'),
|
|
6462
6543
|
detected_tool_type: detectedToolType,
|
|
@@ -6471,17 +6552,15 @@ export class GRCAnalysisServer {
|
|
|
6471
6552
|
};
|
|
6472
6553
|
}
|
|
6473
6554
|
|
|
6474
|
-
private
|
|
6555
|
+
private assessCapabilityClaimAlignment(
|
|
6475
6556
|
claimedCapability: string,
|
|
6557
|
+
effectiveCapability: string,
|
|
6476
6558
|
actualAnalysis: VendorAnalysis,
|
|
6477
|
-
|
|
6478
|
-
subElementPercentage: number,
|
|
6479
|
-
governancePercentage: number,
|
|
6559
|
+
domainValidation: any,
|
|
6480
6560
|
text: string
|
|
6481
6561
|
): {
|
|
6482
6562
|
status: 'SUPPORTED' | 'QUESTIONABLE' | 'UNSUPPORTED';
|
|
6483
6563
|
confidence: number;
|
|
6484
|
-
languageConsistency: number;
|
|
6485
6564
|
gaps: string[];
|
|
6486
6565
|
strengths: string[];
|
|
6487
6566
|
recommendations: string[];
|
|
@@ -6490,113 +6569,42 @@ export class GRCAnalysisServer {
|
|
|
6490
6569
|
const gaps: string[] = [];
|
|
6491
6570
|
const strengths: string[] = [];
|
|
6492
6571
|
const recommendations: string[] = [];
|
|
6493
|
-
|
|
6572
|
+
|
|
6573
|
+
// Compare claimed capability with what we actually detected
|
|
6574
|
+
const claimedLower = claimedCapability.toLowerCase();
|
|
6575
|
+
const effectiveLower = effectiveCapability.toLowerCase();
|
|
6576
|
+
const actualCapability = actualAnalysis.capability;
|
|
6577
|
+
|
|
6494
6578
|
let alignmentScore = 0;
|
|
6495
|
-
|
|
6496
|
-
|
|
6497
|
-
|
|
6498
|
-
|
|
6499
|
-
|
|
6500
|
-
|
|
6501
|
-
|
|
6502
|
-
|
|
6503
|
-
|
|
6504
|
-
|
|
6505
|
-
|
|
6506
|
-
|
|
6507
|
-
|
|
6508
|
-
|
|
6509
|
-
|
|
6510
|
-
|
|
6511
|
-
|
|
6512
|
-
// Check for conflicting facilitation language
|
|
6513
|
-
if (this.hasFacilitationLanguage(text)) {
|
|
6514
|
-
alignmentScore -= 30;
|
|
6515
|
-
gaps.push('Contains facilitation language inconsistent with FULL implementation claim');
|
|
6516
|
-
}
|
|
6517
|
-
|
|
6518
|
-
languageConsistency = this.assessImplementationLanguage(text);
|
|
6519
|
-
break;
|
|
6520
|
-
|
|
6521
|
-
case 'partial':
|
|
6522
|
-
// Validate PARTIAL claim
|
|
6523
|
-
if (corePercentage >= 30 || (corePercentage > 0 && subElementPercentage >= 20)) {
|
|
6524
|
-
alignmentScore = 75;
|
|
6525
|
-
strengths.push('Appropriate coverage level for PARTIAL implementation');
|
|
6526
|
-
} else {
|
|
6527
|
-
alignmentScore = Math.max(0, corePercentage + subElementPercentage - 10);
|
|
6528
|
-
gaps.push(`Coverage too low even for PARTIAL claim: ${Math.round(corePercentage)}% core, ${Math.round(subElementPercentage)}% sub-elements`);
|
|
6529
|
-
}
|
|
6530
|
-
|
|
6531
|
-
// Check for scope boundary definition
|
|
6532
|
-
if (this.hasScopeBoundaries(text)) {
|
|
6533
|
-
strengths.push('Clearly defines scope boundaries and limitations');
|
|
6534
|
-
alignmentScore += 10;
|
|
6535
|
-
} else {
|
|
6536
|
-
gaps.push('Should clearly define scope boundaries for PARTIAL implementation');
|
|
6537
|
-
recommendations.push('Specify exactly which elements are covered and which are not');
|
|
6538
|
-
}
|
|
6539
|
-
|
|
6540
|
-
languageConsistency = this.assessImplementationLanguage(text);
|
|
6541
|
-
break;
|
|
6542
|
-
|
|
6543
|
-
case 'facilitates':
|
|
6544
|
-
// Validate FACILITATES claim
|
|
6545
|
-
if (this.hasFacilitationLanguage(text) || actualAnalysis.capabilities.facilitates) {
|
|
6546
|
-
alignmentScore = 80;
|
|
6547
|
-
strengths.push('Contains appropriate facilitation and enablement language');
|
|
6548
|
-
} else {
|
|
6549
|
-
alignmentScore = 40;
|
|
6550
|
-
gaps.push('Lacks clear facilitation language (enables, supports, provides framework)');
|
|
6551
|
-
}
|
|
6552
|
-
|
|
6553
|
-
// Check that it doesn't claim direct implementation
|
|
6554
|
-
if (this.hasDirectImplementationLanguage(text)) {
|
|
6555
|
-
// Special handling: If it lacks facilitation language AND claims implementation, stay QUESTIONABLE
|
|
6556
|
-
if (alignmentScore <= 40) {
|
|
6557
|
-
alignmentScore = 45; // Keep it in QUESTIONABLE range
|
|
6558
|
-
} else {
|
|
6559
|
-
alignmentScore -= 15;
|
|
6560
|
-
}
|
|
6561
|
-
gaps.push('Claims direct implementation, inconsistent with FACILITATES capability');
|
|
6562
|
-
}
|
|
6563
|
-
|
|
6564
|
-
languageConsistency = this.assessFacilitationLanguage(text);
|
|
6565
|
-
break;
|
|
6566
|
-
|
|
6567
|
-
case 'governance':
|
|
6568
|
-
// Validate GOVERNANCE claim
|
|
6569
|
-
if (governancePercentage >= 60 || actualAnalysis.capabilities.governance) {
|
|
6570
|
-
alignmentScore = 85;
|
|
6571
|
-
strengths.push('Strong governance element coverage and policy management language');
|
|
6572
|
-
} else {
|
|
6573
|
-
alignmentScore = Math.max(30, governancePercentage);
|
|
6574
|
-
gaps.push(`Governance element coverage (${Math.round(governancePercentage)}%) below expected threshold (60%)`);
|
|
6575
|
-
}
|
|
6576
|
-
|
|
6577
|
-
languageConsistency = this.assessGovernanceLanguage(text);
|
|
6578
|
-
break;
|
|
6579
|
-
|
|
6580
|
-
case 'validates':
|
|
6581
|
-
// Validate VALIDATES claim
|
|
6582
|
-
if (actualAnalysis.capabilities.validates) {
|
|
6583
|
-
alignmentScore = 85;
|
|
6584
|
-
strengths.push('Contains evidence collection and reporting capabilities');
|
|
6585
|
-
} else {
|
|
6586
|
-
alignmentScore = 30;
|
|
6587
|
-
gaps.push('Lacks validation language (audit, report, evidence, verify, monitor)');
|
|
6588
|
-
}
|
|
6589
|
-
|
|
6590
|
-
languageConsistency = this.assessValidationLanguage(text);
|
|
6591
|
-
break;
|
|
6592
|
-
|
|
6593
|
-
default:
|
|
6594
|
-
alignmentScore = 0;
|
|
6595
|
-
gaps.push(`Unknown capability type: ${claimedCapability}`);
|
|
6596
|
-
languageConsistency = 0;
|
|
6579
|
+
|
|
6580
|
+
// Check if claim aligns with actual analysis
|
|
6581
|
+
if (claimedLower === actualCapability) {
|
|
6582
|
+
alignmentScore = actualAnalysis.confidence;
|
|
6583
|
+
strengths.push(`Claimed capability '${claimedCapability}' aligns with detected capability`);
|
|
6584
|
+
strengths.push(`Tool demonstrates appropriate ${actualAnalysis.toolCapabilityDescription.toLowerCase()}`);
|
|
6585
|
+
} else if (effectiveLower === actualCapability) {
|
|
6586
|
+
// Domain validation adjusted the capability and it matches the analysis
|
|
6587
|
+
alignmentScore = Math.max(actualAnalysis.confidence - 20, 30);
|
|
6588
|
+
gaps.push(`Original claim '${claimedCapability}' doesn't match tool type, adjusted to '${effectiveCapability}'`);
|
|
6589
|
+
strengths.push(`Adjusted capability '${effectiveCapability}' aligns with tool analysis`);
|
|
6590
|
+
} else {
|
|
6591
|
+
// Neither claimed nor effective capability matches the analysis
|
|
6592
|
+
alignmentScore = Math.max(actualAnalysis.confidence - 40, 10);
|
|
6593
|
+
gaps.push(`Claimed capability '${claimedCapability}' doesn't align with detected capability '${actualCapability}'`);
|
|
6594
|
+
gaps.push(`Tool appears to be: ${actualAnalysis.toolCapabilityDescription}`);
|
|
6597
6595
|
}
|
|
6598
|
-
|
|
6599
|
-
//
|
|
6596
|
+
|
|
6597
|
+
// Add evidence from the capability analysis
|
|
6598
|
+
if (actualAnalysis.evidence && actualAnalysis.evidence.length > 0) {
|
|
6599
|
+
strengths.push(`Supporting evidence: ${actualAnalysis.evidence.slice(0, 2).join('; ')}`);
|
|
6600
|
+
}
|
|
6601
|
+
|
|
6602
|
+
// Domain validation feedback
|
|
6603
|
+
if (!domainValidation.domain_match) {
|
|
6604
|
+
gaps.push(`Tool type '${domainValidation.detected_tool_type}' not appropriate for this safeguard domain`);
|
|
6605
|
+
}
|
|
6606
|
+
|
|
6607
|
+
// Determine overall status based on alignment score
|
|
6600
6608
|
let status: 'SUPPORTED' | 'QUESTIONABLE' | 'UNSUPPORTED';
|
|
6601
6609
|
if (alignmentScore >= 70) {
|
|
6602
6610
|
status = 'SUPPORTED';
|
|
@@ -6605,21 +6613,23 @@ export class GRCAnalysisServer {
|
|
|
6605
6613
|
} else {
|
|
6606
6614
|
status = 'UNSUPPORTED';
|
|
6607
6615
|
}
|
|
6608
|
-
|
|
6609
|
-
// Generate recommendations
|
|
6610
|
-
|
|
6611
|
-
|
|
6612
|
-
}
|
|
6616
|
+
|
|
6617
|
+
// Generate capability-focused recommendations
|
|
6618
|
+
recommendations.push(actualAnalysis.recommendedUse);
|
|
6619
|
+
|
|
6613
6620
|
if (status === 'QUESTIONABLE') {
|
|
6614
|
-
recommendations.push('
|
|
6621
|
+
recommendations.push('Consider clarifying tool capabilities or adjusting capability claim');
|
|
6615
6622
|
}
|
|
6616
|
-
|
|
6617
|
-
|
|
6623
|
+
|
|
6624
|
+
if (!domainValidation.domain_match) {
|
|
6625
|
+
recommendations.push(`For ${actualCapability.toUpperCase()} capability, focus on how the tool ${actualCapability === 'facilitates' ? 'enables and enhances' : actualCapability === 'governance' ? 'manages policies and processes for' : actualCapability === 'validates' ? 'provides evidence and reporting on' : 'directly implements'} this safeguard`);
|
|
6626
|
+
}
|
|
6627
|
+
|
|
6628
|
+
const feedback = this.generateCapabilityValidationFeedback(claimedCapability, effectiveCapability, actualCapability, status, alignmentScore, domainValidation);
|
|
6618
6629
|
|
|
6619
6630
|
return {
|
|
6620
6631
|
status,
|
|
6621
6632
|
confidence: Math.round(alignmentScore),
|
|
6622
|
-
languageConsistency: Math.round(languageConsistency),
|
|
6623
6633
|
gaps,
|
|
6624
6634
|
strengths,
|
|
6625
6635
|
recommendations,
|
|
@@ -6685,73 +6695,153 @@ export class GRCAnalysisServer {
|
|
|
6685
6695
|
return this.calculateKeywordScore(text, validationKeywords) * 100;
|
|
6686
6696
|
}
|
|
6687
6697
|
|
|
6688
|
-
private detectToolType(text: string): string {
|
|
6698
|
+
private detectToolType(text: string, safeguardId?: string): string {
|
|
6689
6699
|
const lowerText = text.toLowerCase();
|
|
6690
6700
|
|
|
6691
|
-
//
|
|
6692
|
-
const
|
|
6693
|
-
'
|
|
6694
|
-
|
|
6695
|
-
|
|
6696
|
-
|
|
6697
|
-
|
|
6698
|
-
|
|
6699
|
-
|
|
6700
|
-
|
|
6701
|
-
|
|
6702
|
-
|
|
6703
|
-
|
|
6704
|
-
|
|
6705
|
-
|
|
6706
|
-
|
|
6707
|
-
|
|
6708
|
-
|
|
6709
|
-
|
|
6710
|
-
|
|
6701
|
+
// Enhanced keyword definitions with scoring weights and context
|
|
6702
|
+
const toolTypePatterns = {
|
|
6703
|
+
'inventory': {
|
|
6704
|
+
primary: [
|
|
6705
|
+
'asset management', 'inventory management', 'cmdb', 'configuration management database',
|
|
6706
|
+
'asset discovery', 'hardware inventory', 'software inventory', 'device inventory',
|
|
6707
|
+
'asset tracking', 'it asset management', 'endpoint discovery', 'asset lifecycle'
|
|
6708
|
+
],
|
|
6709
|
+
secondary: [
|
|
6710
|
+
'inventory', 'discovery', 'device management', 'endpoint management',
|
|
6711
|
+
'configuration management', 'asset database', 'equipment tracking'
|
|
6712
|
+
],
|
|
6713
|
+
weight: { primary: 3, secondary: 1 }
|
|
6714
|
+
},
|
|
6715
|
+
'identity_management': {
|
|
6716
|
+
primary: [
|
|
6717
|
+
'identity management', 'iam', 'active directory', 'identity provider',
|
|
6718
|
+
'single sign-on', 'sso', 'multi-factor authentication', 'mfa',
|
|
6719
|
+
'user management', 'account management', 'directory service'
|
|
6720
|
+
],
|
|
6721
|
+
secondary: [
|
|
6722
|
+
'ldap', 'authentication', 'access management', 'identity access management',
|
|
6723
|
+
'user directory', 'account lifecycle', 'privileged access'
|
|
6724
|
+
],
|
|
6725
|
+
weight: { primary: 3, secondary: 1 }
|
|
6726
|
+
},
|
|
6727
|
+
'vulnerability_management': {
|
|
6728
|
+
primary: [
|
|
6729
|
+
'vulnerability management', 'vulnerability scanner', 'patch management',
|
|
6730
|
+
'security scanning', 'vulnerability assessment', 'penetration testing'
|
|
6731
|
+
],
|
|
6732
|
+
secondary: [
|
|
6733
|
+
'vuln scan', 'security scanner', 'network scanner', 'scanning capabilities',
|
|
6734
|
+
'security assessment', 'vulnerability scanning', 'patch deployment'
|
|
6735
|
+
],
|
|
6736
|
+
weight: { primary: 3, secondary: 1 }
|
|
6737
|
+
},
|
|
6738
|
+
'threat_intelligence': {
|
|
6739
|
+
primary: [
|
|
6740
|
+
'threat intelligence', 'cyber threat intelligence', 'threat intel',
|
|
6741
|
+
'threat feed', 'ioc feed', 'security intelligence', 'threat data'
|
|
6742
|
+
],
|
|
6743
|
+
secondary: [
|
|
6744
|
+
'enrichment', 'data feed', 'contextual data', 'risk intelligence',
|
|
6745
|
+
'threat indicators', 'intelligence platform', 'threat correlation'
|
|
6746
|
+
],
|
|
6747
|
+
weight: { primary: 3, secondary: 1 }
|
|
6748
|
+
},
|
|
6749
|
+
'network_security': {
|
|
6750
|
+
primary: [
|
|
6751
|
+
'firewall', 'network access control', 'nac', 'intrusion detection',
|
|
6752
|
+
'network security', 'network segmentation'
|
|
6753
|
+
],
|
|
6754
|
+
secondary: [
|
|
6755
|
+
'network monitoring', 'traffic analysis', 'perimeter security',
|
|
6756
|
+
'network protection', 'network filtering'
|
|
6757
|
+
],
|
|
6758
|
+
weight: { primary: 3, secondary: 1 }
|
|
6759
|
+
},
|
|
6760
|
+
'governance': {
|
|
6761
|
+
primary: [
|
|
6762
|
+
'grc', 'governance risk compliance', 'compliance management',
|
|
6763
|
+
'policy management', 'risk management', 'audit management'
|
|
6764
|
+
],
|
|
6765
|
+
secondary: [
|
|
6766
|
+
'governance', 'compliance platform', 'policy enforcement',
|
|
6767
|
+
'regulatory compliance', 'framework management'
|
|
6768
|
+
],
|
|
6769
|
+
weight: { primary: 3, secondary: 1 }
|
|
6770
|
+
},
|
|
6771
|
+
'security_analytics': {
|
|
6772
|
+
primary: [
|
|
6773
|
+
'siem', 'security information event management', 'security analytics',
|
|
6774
|
+
'soar', 'security orchestration', 'log management'
|
|
6775
|
+
],
|
|
6776
|
+
secondary: [
|
|
6777
|
+
'security monitoring', 'event correlation', 'log analysis',
|
|
6778
|
+
'security intelligence', 'incident response platform'
|
|
6779
|
+
],
|
|
6780
|
+
weight: { primary: 3, secondary: 1 }
|
|
6781
|
+
}
|
|
6782
|
+
};
|
|
6711
6783
|
|
|
6712
|
-
//
|
|
6713
|
-
const
|
|
6714
|
-
'firewall', 'network access control', 'nac', 'network security', 'intrusion detection',
|
|
6715
|
-
'network monitoring', 'traffic analysis', 'network segmentation'
|
|
6716
|
-
];
|
|
6784
|
+
// Calculate scores for each tool type
|
|
6785
|
+
const toolScores: Record<string, number> = {};
|
|
6717
6786
|
|
|
6718
|
-
|
|
6719
|
-
|
|
6720
|
-
|
|
6721
|
-
|
|
6722
|
-
|
|
6723
|
-
|
|
6787
|
+
for (const [toolType, patterns] of Object.entries(toolTypePatterns)) {
|
|
6788
|
+
let score = 0;
|
|
6789
|
+
|
|
6790
|
+
// Check primary keywords
|
|
6791
|
+
for (const keyword of patterns.primary) {
|
|
6792
|
+
if (lowerText.includes(keyword)) {
|
|
6793
|
+
score += patterns.weight.primary;
|
|
6794
|
+
}
|
|
6795
|
+
}
|
|
6796
|
+
|
|
6797
|
+
// Check secondary keywords
|
|
6798
|
+
for (const keyword of patterns.secondary) {
|
|
6799
|
+
if (lowerText.includes(keyword)) {
|
|
6800
|
+
score += patterns.weight.secondary;
|
|
6801
|
+
}
|
|
6802
|
+
}
|
|
6803
|
+
|
|
6804
|
+
toolScores[toolType] = score;
|
|
6805
|
+
}
|
|
6724
6806
|
|
|
6725
|
-
//
|
|
6726
|
-
|
|
6727
|
-
|
|
6728
|
-
|
|
6729
|
-
|
|
6807
|
+
// Apply safeguard-specific context weighting if provided
|
|
6808
|
+
if (safeguardId && toolScores) {
|
|
6809
|
+
const contextBonus = 1; // Small bonus for domain alignment
|
|
6810
|
+
|
|
6811
|
+
// Asset inventory safeguards (1.1, 1.2) favor inventory tools
|
|
6812
|
+
if (['1.1', '1.2'].includes(safeguardId) && toolScores['inventory'] > 0) {
|
|
6813
|
+
toolScores['inventory'] += contextBonus;
|
|
6814
|
+
}
|
|
6815
|
+
|
|
6816
|
+
// Account inventory safeguards (5.1, 5.2, 5.3) favor identity tools
|
|
6817
|
+
if (['5.1', '5.2', '5.3'].includes(safeguardId) && toolScores['identity_management'] > 0) {
|
|
6818
|
+
toolScores['identity_management'] += contextBonus;
|
|
6819
|
+
}
|
|
6820
|
+
|
|
6821
|
+
// Authentication safeguards (6.1, 6.2, 6.3) favor identity tools
|
|
6822
|
+
if (['6.1', '6.2', '6.3'].includes(safeguardId) && toolScores['identity_management'] > 0) {
|
|
6823
|
+
toolScores['identity_management'] += contextBonus;
|
|
6824
|
+
}
|
|
6825
|
+
|
|
6826
|
+
// Vulnerability safeguards (7.1-7.7) favor vulnerability management tools
|
|
6827
|
+
if (['7.1', '7.2', '7.3', '7.4', '7.5', '7.6', '7.7'].includes(safeguardId) && toolScores['vulnerability_management'] > 0) {
|
|
6828
|
+
toolScores['vulnerability_management'] += contextBonus;
|
|
6829
|
+
}
|
|
6830
|
+
}
|
|
6730
6831
|
|
|
6731
|
-
//
|
|
6732
|
-
|
|
6733
|
-
|
|
6734
|
-
'event correlation', 'security orchestration', 'soar'
|
|
6735
|
-
];
|
|
6832
|
+
// Find the tool type with highest score
|
|
6833
|
+
let maxScore = 0;
|
|
6834
|
+
let detectedType = 'unknown';
|
|
6736
6835
|
|
|
6737
|
-
|
|
6738
|
-
|
|
6739
|
-
|
|
6740
|
-
|
|
6741
|
-
|
|
6742
|
-
} else if (identityKeywords.some(keyword => lowerText.includes(keyword))) {
|
|
6743
|
-
return 'identity_management';
|
|
6744
|
-
} else if (networkSecurityKeywords.some(keyword => lowerText.includes(keyword))) {
|
|
6745
|
-
return 'network_security';
|
|
6746
|
-
} else if (governanceKeywords.some(keyword => lowerText.includes(keyword))) {
|
|
6747
|
-
return 'governance';
|
|
6748
|
-
} else if (analyticsKeywords.some(keyword => lowerText.includes(keyword))) {
|
|
6749
|
-
return 'security_analytics';
|
|
6750
|
-
} else if (inventoryKeywords.some(keyword => lowerText.includes(keyword))) {
|
|
6751
|
-
return 'inventory';
|
|
6836
|
+
for (const [toolType, score] of Object.entries(toolScores)) {
|
|
6837
|
+
if (score > maxScore) {
|
|
6838
|
+
maxScore = score;
|
|
6839
|
+
detectedType = toolType;
|
|
6840
|
+
}
|
|
6752
6841
|
}
|
|
6753
6842
|
|
|
6754
|
-
|
|
6843
|
+
// Require minimum score threshold to avoid false positives
|
|
6844
|
+
return maxScore >= 2 ? detectedType : 'unknown';
|
|
6755
6845
|
}
|
|
6756
6846
|
|
|
6757
6847
|
private validateDomainMatch(
|
|
@@ -6785,7 +6875,7 @@ export class GRCAnalysisServer {
|
|
|
6785
6875
|
required_tool_types: domainReq.required_tool_types,
|
|
6786
6876
|
should_adjust_capability: true,
|
|
6787
6877
|
adjusted_capability: 'facilitates',
|
|
6788
|
-
reasoning: `${domainReq.domain} safeguard requires ${domainReq.required_tool_types.join('/')} tool types for FULL/PARTIAL
|
|
6878
|
+
reasoning: `${domainReq.domain} safeguard requires ${domainReq.required_tool_types.join('/')} tool types for FULL/PARTIAL implementation capability. Detected tool type '${detectedToolType}' can only facilitate implementation.`
|
|
6789
6879
|
};
|
|
6790
6880
|
}
|
|
6791
6881
|
|
|
@@ -6799,6 +6889,38 @@ export class GRCAnalysisServer {
|
|
|
6799
6889
|
};
|
|
6800
6890
|
}
|
|
6801
6891
|
|
|
6892
|
+
private generateCapabilityValidationFeedback(
|
|
6893
|
+
claimedCapability: string,
|
|
6894
|
+
effectiveCapability: string,
|
|
6895
|
+
actualCapability: string,
|
|
6896
|
+
status: string,
|
|
6897
|
+
score: number,
|
|
6898
|
+
domainValidation: any
|
|
6899
|
+
): string {
|
|
6900
|
+
let feedback = `Capability Validation: ${claimedCapability.toUpperCase()} claim is ${status} (${Math.round(score)}% confidence)\n\n`;
|
|
6901
|
+
|
|
6902
|
+
// Analysis summary
|
|
6903
|
+
feedback += `ANALYSIS:\n`;
|
|
6904
|
+
feedback += `• Claimed: ${claimedCapability.toUpperCase()}\n`;
|
|
6905
|
+
if (effectiveCapability !== claimedCapability) {
|
|
6906
|
+
feedback += `• Domain Adjusted: ${effectiveCapability.toUpperCase()} (${domainValidation.reasoning})\n`;
|
|
6907
|
+
}
|
|
6908
|
+
feedback += `• Detected: ${actualCapability.toUpperCase()}\n`;
|
|
6909
|
+
feedback += `• Tool Type: ${domainValidation.detected_tool_type}\n\n`;
|
|
6910
|
+
|
|
6911
|
+
// Assessment
|
|
6912
|
+
feedback += `ASSESSMENT: `;
|
|
6913
|
+
if (claimedCapability.toLowerCase() === actualCapability) {
|
|
6914
|
+
feedback += 'Claimed capability aligns perfectly with tool analysis.';
|
|
6915
|
+
} else if (effectiveCapability.toLowerCase() === actualCapability) {
|
|
6916
|
+
feedback += 'After domain validation adjustment, capability aligns with tool analysis.';
|
|
6917
|
+
} else {
|
|
6918
|
+
feedback += `Capability mismatch detected. Tool functions as ${actualCapability.toUpperCase()} rather than claimed ${claimedCapability.toUpperCase()}.`;
|
|
6919
|
+
}
|
|
6920
|
+
|
|
6921
|
+
return feedback;
|
|
6922
|
+
}
|
|
6923
|
+
|
|
6802
6924
|
private generateValidationFeedback(
|
|
6803
6925
|
claimedCapability: string,
|
|
6804
6926
|
status: string,
|
|
@@ -6806,7 +6928,7 @@ export class GRCAnalysisServer {
|
|
|
6806
6928
|
strengths: string[],
|
|
6807
6929
|
score: number
|
|
6808
6930
|
): string {
|
|
6809
|
-
let feedback = `Validation of ${claimedCapability.toUpperCase()} capability claim: ${status} (${Math.round(score)}% alignment)\n\n`;
|
|
6931
|
+
let feedback = `Validation of ${claimedCapability.toUpperCase()} capability role claim: ${status} (${Math.round(score)}% alignment)\n\n`;
|
|
6810
6932
|
|
|
6811
6933
|
if (strengths.length > 0) {
|
|
6812
6934
|
feedback += `STRENGTHS:\n${strengths.map(s => `• ${s}`).join('\n')}\n\n`;
|
|
@@ -6819,23 +6941,162 @@ export class GRCAnalysisServer {
|
|
|
6819
6941
|
feedback += `ASSESSMENT: `;
|
|
6820
6942
|
switch (status) {
|
|
6821
6943
|
case 'SUPPORTED':
|
|
6822
|
-
feedback += 'The vendor\'s supporting evidence strongly aligns with their claimed capability.';
|
|
6944
|
+
feedback += 'The vendor\'s supporting evidence strongly aligns with their claimed capability role.';
|
|
6823
6945
|
break;
|
|
6824
6946
|
case 'QUESTIONABLE':
|
|
6825
6947
|
feedback += 'The vendor\'s evidence partially supports their claim but has notable gaps or inconsistencies.';
|
|
6826
6948
|
break;
|
|
6827
6949
|
case 'UNSUPPORTED':
|
|
6828
|
-
feedback += 'The vendor\'s evidence does not adequately support their claimed capability.';
|
|
6950
|
+
feedback += 'The vendor\'s evidence does not adequately support their claimed capability role.';
|
|
6829
6951
|
break;
|
|
6830
6952
|
}
|
|
6831
6953
|
|
|
6832
6954
|
return feedback;
|
|
6833
6955
|
}
|
|
6834
6956
|
|
|
6957
|
+
// Enhanced error handling and formatting
|
|
6958
|
+
private formatErrorMessage(error: unknown, toolName: string): string {
|
|
6959
|
+
if (error instanceof Error) {
|
|
6960
|
+
// Production-friendly error messages
|
|
6961
|
+
switch (error.message) {
|
|
6962
|
+
case /^Safeguard .+ not found/.test(error.message) ? error.message : '':
|
|
6963
|
+
return `❌ Invalid safeguard ID. Use 'list_available_safeguards' to see available CIS Control safeguards.`;
|
|
6964
|
+
case /^Unknown tool/.test(error.message) ? error.message : '':
|
|
6965
|
+
return `❌ Tool '${toolName}' is not available. Available tools: analyze_vendor_response, validate_vendor_mapping, validate_coverage_claim, get_safeguard_details, list_available_safeguards.`;
|
|
6966
|
+
default:
|
|
6967
|
+
return `❌ Error in ${toolName}: ${error.message}`;
|
|
6968
|
+
}
|
|
6969
|
+
}
|
|
6970
|
+
return `❌ Unexpected error in ${toolName}: ${String(error)}`;
|
|
6971
|
+
}
|
|
6972
|
+
|
|
6973
|
+
// Performance monitoring and caching
|
|
6974
|
+
private performanceMetrics = {
|
|
6975
|
+
toolExecutionTimes: new Map<string, number[]>(),
|
|
6976
|
+
startTime: Date.now(),
|
|
6977
|
+
totalRequests: 0,
|
|
6978
|
+
errorCount: 0
|
|
6979
|
+
};
|
|
6980
|
+
|
|
6981
|
+
// Simple cache for safeguard details (most commonly requested data)
|
|
6982
|
+
private cache = {
|
|
6983
|
+
safeguardDetails: new Map<string, any>(),
|
|
6984
|
+
safeguardList: null as any,
|
|
6985
|
+
lastCacheCleanup: Date.now()
|
|
6986
|
+
};
|
|
6987
|
+
|
|
6988
|
+
private getCachedSafeguardDetails(safeguardId: string, includeExamples: boolean): any | null {
|
|
6989
|
+
const cacheKey = `${safeguardId}_${includeExamples}`;
|
|
6990
|
+
const cached = this.cache.safeguardDetails.get(cacheKey);
|
|
6991
|
+
|
|
6992
|
+
if (cached && (Date.now() - cached.timestamp < 5 * 60 * 1000)) { // 5 minute cache
|
|
6993
|
+
return cached.data;
|
|
6994
|
+
}
|
|
6995
|
+
|
|
6996
|
+
return null;
|
|
6997
|
+
}
|
|
6998
|
+
|
|
6999
|
+
private setCachedSafeguardDetails(safeguardId: string, includeExamples: boolean, data: any): void {
|
|
7000
|
+
const cacheKey = `${safeguardId}_${includeExamples}`;
|
|
7001
|
+
this.cache.safeguardDetails.set(cacheKey, {
|
|
7002
|
+
data,
|
|
7003
|
+
timestamp: Date.now()
|
|
7004
|
+
});
|
|
7005
|
+
|
|
7006
|
+
// Periodic cache cleanup to prevent memory leaks
|
|
7007
|
+
if (Date.now() - this.cache.lastCacheCleanup > 10 * 60 * 1000) { // 10 minutes
|
|
7008
|
+
this.cleanupCache();
|
|
7009
|
+
}
|
|
7010
|
+
}
|
|
7011
|
+
|
|
7012
|
+
private cleanupCache(): void {
|
|
7013
|
+
const now = Date.now();
|
|
7014
|
+
const maxAge = 10 * 60 * 1000; // 10 minutes
|
|
7015
|
+
|
|
7016
|
+
// Clean up safeguard details cache
|
|
7017
|
+
for (const [key, value] of this.cache.safeguardDetails.entries()) {
|
|
7018
|
+
if (now - value.timestamp > maxAge) {
|
|
7019
|
+
this.cache.safeguardDetails.delete(key);
|
|
7020
|
+
}
|
|
7021
|
+
}
|
|
7022
|
+
|
|
7023
|
+
this.cache.lastCacheCleanup = now;
|
|
7024
|
+
}
|
|
7025
|
+
|
|
7026
|
+
private recordToolExecution(toolName: string, executionTime: number) {
|
|
7027
|
+
this.performanceMetrics.totalRequests++;
|
|
7028
|
+
|
|
7029
|
+
if (!this.performanceMetrics.toolExecutionTimes.has(toolName)) {
|
|
7030
|
+
this.performanceMetrics.toolExecutionTimes.set(toolName, []);
|
|
7031
|
+
}
|
|
7032
|
+
|
|
7033
|
+
const times = this.performanceMetrics.toolExecutionTimes.get(toolName)!;
|
|
7034
|
+
times.push(executionTime);
|
|
7035
|
+
|
|
7036
|
+
// Keep only last 100 measurements for memory efficiency
|
|
7037
|
+
if (times.length > 100) {
|
|
7038
|
+
times.shift();
|
|
7039
|
+
}
|
|
7040
|
+
}
|
|
7041
|
+
|
|
7042
|
+
private getPerformanceStats(): string {
|
|
7043
|
+
const uptime = Date.now() - this.performanceMetrics.startTime;
|
|
7044
|
+
const avgTimes = Array.from(this.performanceMetrics.toolExecutionTimes.entries())
|
|
7045
|
+
.map(([tool, times]) => {
|
|
7046
|
+
const avg = times.reduce((a, b) => a + b, 0) / times.length;
|
|
7047
|
+
return `${tool}: ${avg.toFixed(2)}ms`;
|
|
7048
|
+
});
|
|
7049
|
+
|
|
7050
|
+
return `Performance Stats (Uptime: ${(uptime / 1000).toFixed(1)}s, Requests: ${this.performanceMetrics.totalRequests}, Errors: ${this.performanceMetrics.errorCount})\n${avgTimes.join(', ')}`;
|
|
7051
|
+
}
|
|
7052
|
+
|
|
7053
|
+
// Input validation and sanitization
|
|
7054
|
+
private validateSafeguardId(safeguardId: string): void {
|
|
7055
|
+
if (!safeguardId || typeof safeguardId !== 'string') {
|
|
7056
|
+
throw new Error('Safeguard ID is required and must be a string');
|
|
7057
|
+
}
|
|
7058
|
+
|
|
7059
|
+
if (!/^[0-9]+\.[0-9]+$/.test(safeguardId)) {
|
|
7060
|
+
throw new Error('Safeguard ID must be in format "X.Y" (e.g., "1.1", "5.1")');
|
|
7061
|
+
}
|
|
7062
|
+
|
|
7063
|
+
if (!CIS_SAFEGUARDS[safeguardId]) {
|
|
7064
|
+
throw new Error(`Safeguard ${safeguardId} not found`);
|
|
7065
|
+
}
|
|
7066
|
+
}
|
|
7067
|
+
|
|
7068
|
+
private validateTextInput(text: string, fieldName: string): void {
|
|
7069
|
+
if (!text || typeof text !== 'string') {
|
|
7070
|
+
throw new Error(`${fieldName} is required and must be a string`);
|
|
7071
|
+
}
|
|
7072
|
+
|
|
7073
|
+
if (text.length > 10000) {
|
|
7074
|
+
throw new Error(`${fieldName} must be less than 10,000 characters`);
|
|
7075
|
+
}
|
|
7076
|
+
|
|
7077
|
+
if (text.trim().length < 10) {
|
|
7078
|
+
throw new Error(`${fieldName} must contain at least 10 meaningful characters`);
|
|
7079
|
+
}
|
|
7080
|
+
}
|
|
7081
|
+
|
|
7082
|
+
private validateCapability(capability: string): void {
|
|
7083
|
+
const validCapabilities = ['full', 'partial', 'facilitates', 'governance', 'validates'];
|
|
7084
|
+
if (!validCapabilities.includes(capability.toLowerCase())) {
|
|
7085
|
+
throw new Error(`Invalid capability. Must be one of: ${validCapabilities.join(', ')}`);
|
|
7086
|
+
}
|
|
7087
|
+
}
|
|
7088
|
+
|
|
6835
7089
|
async run() {
|
|
6836
7090
|
const transport = new StdioServerTransport();
|
|
6837
7091
|
await this.server.connect(transport);
|
|
6838
7092
|
console.error('FrameworkMCP server running on stdio');
|
|
7093
|
+
|
|
7094
|
+
// Log performance stats every 5 minutes in production
|
|
7095
|
+
if (process.env.NODE_ENV === 'production') {
|
|
7096
|
+
setInterval(() => {
|
|
7097
|
+
console.error(`[FrameworkMCP] ${this.getPerformanceStats()}`);
|
|
7098
|
+
}, 5 * 60 * 1000);
|
|
7099
|
+
}
|
|
6839
7100
|
}
|
|
6840
7101
|
}
|
|
6841
7102
|
|