framework-mcp 1.1.1 → 1.1.3
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/CAPABILITY_TRANSFORMATION_SUMMARY.md +158 -0
- package/DAYS_5_6_COMPLETION_SUMMARY.md +178 -0
- package/DEPLOYMENT_SUMMARY_v1.1.3.md +211 -0
- package/README.md +102 -40
- package/RELEASE_NOTES_v1.1.3.md +321 -0
- package/dist/index.d.ts +27 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +675 -335
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/src/index.ts +820 -394
- 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/dist/index.js
CHANGED
|
@@ -2,6 +2,34 @@
|
|
|
2
2
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
3
3
|
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
4
4
|
import { CallToolRequestSchema, ListToolsRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
|
|
5
|
+
// Domain-specific validation mapping
|
|
6
|
+
const SAFEGUARD_DOMAIN_REQUIREMENTS = {
|
|
7
|
+
"1.1": {
|
|
8
|
+
domain: "Asset Inventory",
|
|
9
|
+
required_tool_types: ["inventory", "asset_management", "cmdb", "discovery"],
|
|
10
|
+
description: "Only asset inventory and discovery tools can provide FULL/PARTIAL implementation capability"
|
|
11
|
+
},
|
|
12
|
+
"1.2": {
|
|
13
|
+
domain: "Asset Management",
|
|
14
|
+
required_tool_types: ["inventory", "asset_management", "network_security", "nac"],
|
|
15
|
+
description: "Asset management or network access control tools required for FULL/PARTIAL implementation capability"
|
|
16
|
+
},
|
|
17
|
+
"5.1": {
|
|
18
|
+
domain: "Account Management",
|
|
19
|
+
required_tool_types: ["identity_management", "iam", "directory", "account_management"],
|
|
20
|
+
description: "Identity and account management tools required for FULL/PARTIAL implementation capability"
|
|
21
|
+
},
|
|
22
|
+
"6.3": {
|
|
23
|
+
domain: "Authentication",
|
|
24
|
+
required_tool_types: ["mfa", "authentication", "identity_management", "iam"],
|
|
25
|
+
description: "Multi-factor authentication and identity tools required for FULL/PARTIAL implementation capability"
|
|
26
|
+
},
|
|
27
|
+
"7.1": {
|
|
28
|
+
domain: "Vulnerability Management",
|
|
29
|
+
required_tool_types: ["vulnerability_management", "vulnerability_scanner", "patch_management"],
|
|
30
|
+
description: "Vulnerability management and scanning tools required for FULL/PARTIAL implementation capability"
|
|
31
|
+
}
|
|
32
|
+
};
|
|
5
33
|
// Enhanced CIS Controls Framework Data with color-coded categorization
|
|
6
34
|
const CIS_SAFEGUARDS = {
|
|
7
35
|
"1.1": {
|
|
@@ -5434,6 +5462,19 @@ const CIS_SAFEGUARDS = {
|
|
|
5434
5462
|
};
|
|
5435
5463
|
export class GRCAnalysisServer {
|
|
5436
5464
|
constructor() {
|
|
5465
|
+
// Performance monitoring and caching
|
|
5466
|
+
this.performanceMetrics = {
|
|
5467
|
+
toolExecutionTimes: new Map(),
|
|
5468
|
+
startTime: Date.now(),
|
|
5469
|
+
totalRequests: 0,
|
|
5470
|
+
errorCount: 0
|
|
5471
|
+
};
|
|
5472
|
+
// Simple cache for safeguard details (most commonly requested data)
|
|
5473
|
+
this.cache = {
|
|
5474
|
+
safeguardDetails: new Map(),
|
|
5475
|
+
safeguardList: null,
|
|
5476
|
+
lastCacheCleanup: Date.now()
|
|
5477
|
+
};
|
|
5437
5478
|
this.server = new Server({
|
|
5438
5479
|
name: 'framework-mcp',
|
|
5439
5480
|
version: '1.0.0',
|
|
@@ -5445,7 +5486,7 @@ export class GRCAnalysisServer {
|
|
|
5445
5486
|
tools: [
|
|
5446
5487
|
{
|
|
5447
5488
|
name: 'analyze_vendor_response',
|
|
5448
|
-
description: 'Analyze a vendor response
|
|
5489
|
+
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',
|
|
5449
5490
|
inputSchema: {
|
|
5450
5491
|
type: 'object',
|
|
5451
5492
|
properties: {
|
|
@@ -5460,7 +5501,7 @@ export class GRCAnalysisServer {
|
|
|
5460
5501
|
},
|
|
5461
5502
|
response_text: {
|
|
5462
5503
|
type: 'string',
|
|
5463
|
-
description: 'Vendor response text
|
|
5504
|
+
description: 'Vendor response text describing their tool capabilities for the safeguard'
|
|
5464
5505
|
}
|
|
5465
5506
|
},
|
|
5466
5507
|
required: ['vendor_name', 'safeguard_id', 'response_text']
|
|
@@ -5488,7 +5529,7 @@ export class GRCAnalysisServer {
|
|
|
5488
5529
|
},
|
|
5489
5530
|
{
|
|
5490
5531
|
name: 'validate_coverage_claim',
|
|
5491
|
-
description: 'Validate a vendor\'s
|
|
5532
|
+
description: 'Validate a vendor\'s implementation capability claim (FULL/PARTIAL) against specific safeguard requirements and evidence quality',
|
|
5492
5533
|
inputSchema: {
|
|
5493
5534
|
type: 'object',
|
|
5494
5535
|
properties: {
|
|
@@ -5504,16 +5545,16 @@ export class GRCAnalysisServer {
|
|
|
5504
5545
|
coverage_claim: {
|
|
5505
5546
|
type: 'string',
|
|
5506
5547
|
enum: ['FULL', 'PARTIAL'],
|
|
5507
|
-
description: 'Vendor\'s
|
|
5548
|
+
description: 'Vendor\'s implementation capability claim (FULL = complete implementation, PARTIAL = limited scope implementation)'
|
|
5508
5549
|
},
|
|
5509
5550
|
response_text: {
|
|
5510
5551
|
type: 'string',
|
|
5511
|
-
description: 'Vendor response explaining their
|
|
5552
|
+
description: 'Vendor response explaining their implementation capabilities'
|
|
5512
5553
|
},
|
|
5513
5554
|
capabilities: {
|
|
5514
5555
|
type: 'array',
|
|
5515
5556
|
items: { type: 'string' },
|
|
5516
|
-
description: 'List of vendor
|
|
5557
|
+
description: 'List of additional vendor capability types (Governance, Facilitates, Validates)'
|
|
5517
5558
|
}
|
|
5518
5559
|
},
|
|
5519
5560
|
required: ['vendor_name', 'safeguard_id', 'coverage_claim', 'response_text', 'capabilities']
|
|
@@ -5540,7 +5581,7 @@ export class GRCAnalysisServer {
|
|
|
5540
5581
|
},
|
|
5541
5582
|
{
|
|
5542
5583
|
name: 'validate_vendor_mapping',
|
|
5543
|
-
description: 'Validate whether a vendor\'s
|
|
5584
|
+
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',
|
|
5544
5585
|
inputSchema: {
|
|
5545
5586
|
type: 'object',
|
|
5546
5587
|
properties: {
|
|
@@ -5557,11 +5598,11 @@ export class GRCAnalysisServer {
|
|
|
5557
5598
|
claimed_capability: {
|
|
5558
5599
|
type: 'string',
|
|
5559
5600
|
enum: ['full', 'partial', 'facilitates', 'governance', 'validates'],
|
|
5560
|
-
description: 'Vendor\'s claimed capability
|
|
5601
|
+
description: 'Vendor\'s claimed capability role: full (complete implementation), partial (limited implementation), facilitates (enables/enhances), governance (policies/processes), validates (evidence/reporting)'
|
|
5561
5602
|
},
|
|
5562
5603
|
supporting_text: {
|
|
5563
5604
|
type: 'string',
|
|
5564
|
-
description: 'Vendor\'s supporting
|
|
5605
|
+
description: 'Vendor\'s supporting evidence explaining how their tool fulfills the claimed capability role'
|
|
5565
5606
|
}
|
|
5566
5607
|
},
|
|
5567
5608
|
required: ['safeguard_id', 'claimed_capability', 'supporting_text']
|
|
@@ -5571,28 +5612,45 @@ export class GRCAnalysisServer {
|
|
|
5571
5612
|
}));
|
|
5572
5613
|
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
|
|
5573
5614
|
const { name, arguments: args } = request.params;
|
|
5615
|
+
const startTime = Date.now();
|
|
5574
5616
|
try {
|
|
5617
|
+
let result;
|
|
5575
5618
|
switch (name) {
|
|
5576
5619
|
case 'analyze_vendor_response':
|
|
5577
|
-
|
|
5620
|
+
result = await this.analyzeVendorResponse(args);
|
|
5621
|
+
break;
|
|
5578
5622
|
case 'get_safeguard_details':
|
|
5579
|
-
|
|
5623
|
+
result = await this.getSafeguardDetails(args);
|
|
5624
|
+
break;
|
|
5580
5625
|
case 'validate_coverage_claim':
|
|
5581
|
-
|
|
5626
|
+
result = await this.validateCoverageClaim(args);
|
|
5627
|
+
break;
|
|
5582
5628
|
case 'list_available_safeguards':
|
|
5583
|
-
|
|
5629
|
+
result = await this.listAvailableSafeguards(args);
|
|
5630
|
+
break;
|
|
5584
5631
|
case 'validate_vendor_mapping':
|
|
5585
|
-
|
|
5632
|
+
result = await this.validateVendorMapping(args);
|
|
5633
|
+
break;
|
|
5586
5634
|
default:
|
|
5587
5635
|
throw new Error(`Unknown tool: ${name}`);
|
|
5588
5636
|
}
|
|
5637
|
+
// Record successful execution time
|
|
5638
|
+
const executionTime = Date.now() - startTime;
|
|
5639
|
+
this.recordToolExecution(name, executionTime);
|
|
5640
|
+
return result;
|
|
5589
5641
|
}
|
|
5590
5642
|
catch (error) {
|
|
5643
|
+
// Record error and performance metrics
|
|
5644
|
+
this.performanceMetrics.errorCount++;
|
|
5645
|
+
const executionTime = Date.now() - startTime;
|
|
5646
|
+
this.recordToolExecution(`${name}_error`, executionTime);
|
|
5647
|
+
const errorMessage = this.formatErrorMessage(error, name);
|
|
5648
|
+
console.error(`[FrameworkMCP] Tool execution error: ${name}`, error);
|
|
5591
5649
|
return {
|
|
5592
5650
|
content: [
|
|
5593
5651
|
{
|
|
5594
5652
|
type: 'text',
|
|
5595
|
-
text:
|
|
5653
|
+
text: errorMessage,
|
|
5596
5654
|
},
|
|
5597
5655
|
],
|
|
5598
5656
|
};
|
|
@@ -5601,10 +5659,14 @@ export class GRCAnalysisServer {
|
|
|
5601
5659
|
}
|
|
5602
5660
|
async getSafeguardDetails(args) {
|
|
5603
5661
|
const { safeguard_id, include_examples = true } = args;
|
|
5604
|
-
|
|
5605
|
-
|
|
5606
|
-
|
|
5662
|
+
// Input validation
|
|
5663
|
+
this.validateSafeguardId(safeguard_id);
|
|
5664
|
+
// Check cache first
|
|
5665
|
+
const cached = this.getCachedSafeguardDetails(safeguard_id, include_examples);
|
|
5666
|
+
if (cached) {
|
|
5667
|
+
return cached;
|
|
5607
5668
|
}
|
|
5669
|
+
const safeguard = CIS_SAFEGUARDS[safeguard_id];
|
|
5608
5670
|
const result = {
|
|
5609
5671
|
...safeguard,
|
|
5610
5672
|
elementBreakdown: {
|
|
@@ -5632,7 +5694,7 @@ export class GRCAnalysisServer {
|
|
|
5632
5694
|
})
|
|
5633
5695
|
}
|
|
5634
5696
|
};
|
|
5635
|
-
|
|
5697
|
+
const response = {
|
|
5636
5698
|
content: [
|
|
5637
5699
|
{
|
|
5638
5700
|
type: 'text',
|
|
@@ -5640,9 +5702,19 @@ export class GRCAnalysisServer {
|
|
|
5640
5702
|
},
|
|
5641
5703
|
],
|
|
5642
5704
|
};
|
|
5705
|
+
// Cache the result for future requests
|
|
5706
|
+
this.setCachedSafeguardDetails(safeguard_id, include_examples, response);
|
|
5707
|
+
return response;
|
|
5643
5708
|
}
|
|
5644
5709
|
async listAvailableSafeguards(args) {
|
|
5645
5710
|
const { implementation_group, security_function } = args;
|
|
5711
|
+
// Check cache for complete safeguard list (only if no filters applied)
|
|
5712
|
+
if (!implementation_group && !security_function && this.cache.safeguardList) {
|
|
5713
|
+
const cacheAge = Date.now() - this.cache.safeguardList.timestamp;
|
|
5714
|
+
if (cacheAge < 10 * 60 * 1000) { // 10 minute cache for safeguard list
|
|
5715
|
+
return this.cache.safeguardList.data;
|
|
5716
|
+
}
|
|
5717
|
+
}
|
|
5646
5718
|
let safeguards = Object.values(CIS_SAFEGUARDS);
|
|
5647
5719
|
if (implementation_group) {
|
|
5648
5720
|
safeguards = safeguards.filter(s => s.implementationGroup === implementation_group);
|
|
@@ -5665,7 +5737,7 @@ export class GRCAnalysisServer {
|
|
|
5665
5737
|
securityFunction: s.securityFunction
|
|
5666
5738
|
}))
|
|
5667
5739
|
};
|
|
5668
|
-
|
|
5740
|
+
const response = {
|
|
5669
5741
|
content: [
|
|
5670
5742
|
{
|
|
5671
5743
|
type: 'text',
|
|
@@ -5673,14 +5745,25 @@ export class GRCAnalysisServer {
|
|
|
5673
5745
|
},
|
|
5674
5746
|
],
|
|
5675
5747
|
};
|
|
5748
|
+
// Cache the complete list if no filters were applied
|
|
5749
|
+
if (!implementation_group && !security_function) {
|
|
5750
|
+
this.cache.safeguardList = {
|
|
5751
|
+
data: response,
|
|
5752
|
+
timestamp: Date.now()
|
|
5753
|
+
};
|
|
5754
|
+
}
|
|
5755
|
+
return response;
|
|
5676
5756
|
}
|
|
5677
5757
|
async analyzeVendorResponse(args) {
|
|
5678
5758
|
const { vendor_name, safeguard_id, response_text } = args;
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5759
|
+
// Input validation
|
|
5760
|
+
this.validateSafeguardId(safeguard_id);
|
|
5761
|
+
this.validateTextInput(response_text, 'Response text');
|
|
5762
|
+
if (!vendor_name || typeof vendor_name !== 'string' || vendor_name.trim().length === 0) {
|
|
5763
|
+
throw new Error('Vendor name is required');
|
|
5682
5764
|
}
|
|
5683
|
-
const
|
|
5765
|
+
const safeguard = CIS_SAFEGUARDS[safeguard_id];
|
|
5766
|
+
const analysis = this.performCapabilityAnalysis(vendor_name, safeguard, response_text);
|
|
5684
5767
|
return {
|
|
5685
5768
|
content: [
|
|
5686
5769
|
{
|
|
@@ -5696,7 +5779,7 @@ export class GRCAnalysisServer {
|
|
|
5696
5779
|
if (!safeguard) {
|
|
5697
5780
|
throw new Error(`Safeguard ${safeguard_id} not found`);
|
|
5698
5781
|
}
|
|
5699
|
-
const analysis = this.
|
|
5782
|
+
const analysis = this.performCapabilityAnalysis(vendor_name, safeguard, response_text);
|
|
5700
5783
|
// Validate the coverage claim
|
|
5701
5784
|
const validation = this.validateClaim(coverage_claim, analysis, capabilities, safeguard);
|
|
5702
5785
|
return {
|
|
@@ -5715,163 +5798,242 @@ export class GRCAnalysisServer {
|
|
|
5715
5798
|
],
|
|
5716
5799
|
};
|
|
5717
5800
|
}
|
|
5718
|
-
|
|
5801
|
+
performCapabilityAnalysis(vendorName, safeguard, responseText) {
|
|
5719
5802
|
const text = responseText.toLowerCase();
|
|
5720
|
-
//
|
|
5721
|
-
const
|
|
5803
|
+
// Step 1: Determine what type of capability this tool is claiming
|
|
5804
|
+
const claimedCapability = this.determineClaimedCapability(text, safeguard);
|
|
5805
|
+
// Step 2: Assess how well the tool executes that specific capability type
|
|
5806
|
+
const qualityAssessment = this.assessCapabilityQuality(text, safeguard, claimedCapability);
|
|
5807
|
+
// Step 3: Generate capability-focused analysis
|
|
5808
|
+
return this.generateCapabilityAnalysis(vendorName, safeguard, responseText, claimedCapability, qualityAssessment);
|
|
5809
|
+
}
|
|
5810
|
+
determineClaimedCapability(text, safeguard) {
|
|
5811
|
+
// Capability detection keywords - focused on what the tool DOES, not what elements it covers
|
|
5812
|
+
const governanceIndicators = [
|
|
5722
5813
|
'policy', 'policies', 'manage', 'process', 'workflow', 'governance', 'grc',
|
|
5723
5814
|
'compliance management', 'documented', 'establish', 'maintain', 'procedure',
|
|
5724
5815
|
'control', 'controls', 'framework', 'standard', 'enterprise risk management',
|
|
5725
5816
|
'centralized management', 'oversight'
|
|
5726
5817
|
];
|
|
5727
|
-
const
|
|
5728
|
-
// Technical facilitation (original keywords)
|
|
5818
|
+
const facilitatesIndicators = [
|
|
5729
5819
|
'improve', 'enhance', 'optimize', 'faster', 'better', 'stronger', 'automate',
|
|
5730
5820
|
'streamline', 'efficiency', 'facilitate', 'support', 'enable', 'accelerate',
|
|
5731
5821
|
'api', 'integration', 'data', 'export', 'import', 'sync', 'feed',
|
|
5732
|
-
// Data provision and enrichment
|
|
5733
5822
|
'provides data', 'data source', 'data feeds', 'enrichment', 'data enrichment',
|
|
5734
5823
|
'supplemental data', 'additional data', 'contextual data', 'threat data',
|
|
5735
5824
|
'intelligence feeds', 'data aggregation', 'data collection', 'data gathering',
|
|
5736
5825
|
'feeds data', 'populates', 'informs', 'enriches', 'supplements',
|
|
5737
|
-
// Governance/process facilitation (new keywords for tools like Upolicy)
|
|
5738
5826
|
'enables compliance', 'facilitates implementation', 'supports compliance',
|
|
5739
5827
|
'creates framework', 'enables organizations', 'infrastructure', 'foundation',
|
|
5740
|
-
'compliance infrastructure', 'audit infrastructure', 'policy framework',
|
|
5741
|
-
'enables effective', 'working together', 'comprehensive coverage',
|
|
5742
5828
|
'template', 'templates', 'workflow automation', 'orchestration'
|
|
5743
5829
|
];
|
|
5744
|
-
const
|
|
5830
|
+
const validatesIndicators = [
|
|
5745
5831
|
'audit', 'report', 'evidence', 'verify', 'validate', 'check', 'monitor',
|
|
5746
5832
|
'compliance', 'compliance report', 'assessment', 'logging', 'tracking', 'review', 'attest',
|
|
5747
5833
|
'dashboard', 'metrics', 'analytics', 'visibility', 'alert', 'attestation',
|
|
5748
5834
|
'compliance tracking', 'audit trail', 'reporting capabilities', 'audit capabilities'
|
|
5749
5835
|
];
|
|
5750
|
-
//
|
|
5751
|
-
const
|
|
5752
|
-
|
|
5753
|
-
const
|
|
5754
|
-
const
|
|
5755
|
-
|
|
5756
|
-
const
|
|
5757
|
-
|
|
5758
|
-
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
const validatesCapability = validatesScore > 0.3;
|
|
5762
|
-
// Check for specific facilitation patterns (tools that enable/support compliance)
|
|
5763
|
-
const facilitationPatterns = [
|
|
5764
|
-
'enables compliance', 'facilitates implementation', 'creates framework',
|
|
5765
|
-
'policy framework', 'compliance infrastructure', 'audit infrastructure',
|
|
5766
|
-
'enables organizations', 'enables effective', 'working together',
|
|
5767
|
-
'creates the policy framework', 'enables organizations to implement',
|
|
5768
|
-
'facilitates implementation of', 'compliance infrastructure facilitates'
|
|
5769
|
-
];
|
|
5770
|
-
const hasFacilitationPattern = facilitationPatterns.some(pattern => text.includes(pattern));
|
|
5771
|
-
// Check for explicit non-implementation language
|
|
5772
|
-
const nonImplementationPatterns = [
|
|
5773
|
-
'don\'t scan', 'don\'t catalog', 'doesn\'t scan', 'doesn\'t catalog',
|
|
5774
|
-
'not scan', 'not catalog', 'even though we don\'t', 'we don\'t directly',
|
|
5775
|
-
'rather than direct', 'instead of direct'
|
|
5776
|
-
];
|
|
5777
|
-
const hasNonImplementationLanguage = nonImplementationPatterns.some(pattern => text.includes(pattern));
|
|
5778
|
-
// Determine if full or partial coverage (based on core + sub-taxonomical elements WITHIN SCOPE)
|
|
5779
|
-
// Full = addresses majority of core requirements + substantial sub-elements within their stated scope
|
|
5780
|
-
// Partial = addresses some core requirements with clear scope boundaries
|
|
5781
|
-
const corePercentage = safeguard.coreRequirements.length > 0 ?
|
|
5782
|
-
(coreCoverage.coveredElements.length / safeguard.coreRequirements.length) * 100 : 0;
|
|
5783
|
-
const subElementPercentage = safeguard.subTaxonomicalElements.length > 0 ?
|
|
5784
|
-
(subElementCoverage.coveredElements.length / safeguard.subTaxonomicalElements.length) * 100 : 0;
|
|
5785
|
-
let fullCapability = false;
|
|
5786
|
-
let partialCapability = false;
|
|
5787
|
-
// Full capability: High coverage of core requirements + reasonable sub-element coverage
|
|
5788
|
-
if (corePercentage >= 70 && subElementPercentage >= 50) {
|
|
5789
|
-
fullCapability = true;
|
|
5836
|
+
// Direct implementation indicators (tools that actually perform the safeguard)
|
|
5837
|
+
const implementationIndicators = this.getImplementationIndicators(safeguard.id);
|
|
5838
|
+
// Calculate keyword presence scores
|
|
5839
|
+
const governanceScore = this.calculateKeywordScore(text, governanceIndicators);
|
|
5840
|
+
const facilitatesScore = this.calculateKeywordScore(text, facilitatesIndicators);
|
|
5841
|
+
const validatesScore = this.calculateKeywordScore(text, validatesIndicators);
|
|
5842
|
+
const implementationScore = this.calculateKeywordScore(text, implementationIndicators);
|
|
5843
|
+
// Determine claimed capability based on strongest indicators and patterns
|
|
5844
|
+
if (implementationScore > 0.2 && implementationScore >= Math.max(facilitatesScore, governanceScore, validatesScore)) {
|
|
5845
|
+
// Tool claims to directly implement the safeguard
|
|
5846
|
+
return implementationScore > 0.5 ? 'full' : 'partial';
|
|
5790
5847
|
}
|
|
5791
|
-
|
|
5792
|
-
|
|
5793
|
-
partialCapability = true;
|
|
5848
|
+
else if (governanceScore > 0.2 && governanceScore >= Math.max(facilitatesScore, validatesScore)) {
|
|
5849
|
+
return 'governance';
|
|
5794
5850
|
}
|
|
5795
|
-
|
|
5796
|
-
|
|
5797
|
-
if (fullCapability) {
|
|
5798
|
-
primaryCapability = 'full';
|
|
5851
|
+
else if (validatesScore > 0.2 && validatesScore >= facilitatesScore) {
|
|
5852
|
+
return 'validates';
|
|
5799
5853
|
}
|
|
5800
|
-
else
|
|
5801
|
-
|
|
5802
|
-
// Prioritize facilitation when:
|
|
5803
|
-
// 1. Clear facilitation language patterns detected, OR
|
|
5804
|
-
// 2. Explicit non-implementation language (tool doesn't directly implement), OR
|
|
5805
|
-
// 3. Facilitates score is substantial AND significantly higher than governance
|
|
5806
|
-
primaryCapability = 'facilitates';
|
|
5854
|
+
else {
|
|
5855
|
+
return 'facilitates';
|
|
5807
5856
|
}
|
|
5808
|
-
|
|
5809
|
-
|
|
5857
|
+
}
|
|
5858
|
+
getImplementationIndicators(safeguardId) {
|
|
5859
|
+
// Return specific indicators for what constitutes direct implementation for each safeguard
|
|
5860
|
+
const implementationMap = {
|
|
5861
|
+
"1.1": ['inventory', 'discovery', 'asset management', 'catalog', 'enumerate', 'scan devices', 'device database'],
|
|
5862
|
+
"1.2": ['unauthorized', 'rogue', 'detect', 'identify unauthorized', 'quarantine', 'block unauthorized'],
|
|
5863
|
+
"5.1": ['account inventory', 'user management', 'identity management', 'account lifecycle', 'user provisioning'],
|
|
5864
|
+
"6.3": ['multi-factor', 'mfa', '2fa', 'authentication', 'two-factor', 'multi-factor authentication'],
|
|
5865
|
+
"7.1": ['vulnerability', 'vuln', 'scanning', 'vulnerability management', 'security testing', 'penetration testing']
|
|
5866
|
+
};
|
|
5867
|
+
return implementationMap[safeguardId] || [];
|
|
5868
|
+
}
|
|
5869
|
+
assessCapabilityQuality(text, safeguard, claimedCapability) {
|
|
5870
|
+
// Assess how well the tool executes the claimed capability type
|
|
5871
|
+
const evidence = [];
|
|
5872
|
+
const gaps = [];
|
|
5873
|
+
// Quality assessment based on capability type
|
|
5874
|
+
let qualityScore = 0;
|
|
5875
|
+
switch (claimedCapability) {
|
|
5876
|
+
case 'full':
|
|
5877
|
+
case 'partial':
|
|
5878
|
+
qualityScore = this.assessImplementationQuality(text, safeguard, evidence, gaps);
|
|
5879
|
+
break;
|
|
5880
|
+
case 'governance':
|
|
5881
|
+
qualityScore = this.assessGovernanceQuality(text, safeguard, evidence, gaps);
|
|
5882
|
+
break;
|
|
5883
|
+
case 'facilitates':
|
|
5884
|
+
qualityScore = this.assessFacilitationQuality(text, safeguard, evidence, gaps);
|
|
5885
|
+
break;
|
|
5886
|
+
case 'validates':
|
|
5887
|
+
qualityScore = this.assessValidationQuality(text, safeguard, evidence, gaps);
|
|
5888
|
+
break;
|
|
5810
5889
|
}
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
|
|
5890
|
+
// Convert score to quality rating
|
|
5891
|
+
let quality;
|
|
5892
|
+
if (qualityScore >= 0.8)
|
|
5893
|
+
quality = 'excellent';
|
|
5894
|
+
else if (qualityScore >= 0.6)
|
|
5895
|
+
quality = 'good';
|
|
5896
|
+
else if (qualityScore >= 0.4)
|
|
5897
|
+
quality = 'fair';
|
|
5898
|
+
else
|
|
5899
|
+
quality = 'poor';
|
|
5900
|
+
return {
|
|
5901
|
+
quality,
|
|
5902
|
+
confidence: Math.round(qualityScore * 100),
|
|
5903
|
+
evidence: evidence.slice(0, 5), // Top 5 pieces of evidence
|
|
5904
|
+
gaps: gaps.slice(0, 3) // Top 3 gaps identified
|
|
5905
|
+
};
|
|
5906
|
+
}
|
|
5907
|
+
assessImplementationQuality(text, safeguard, evidence, gaps) {
|
|
5908
|
+
// Assess quality of direct implementation capability
|
|
5909
|
+
const implementationIndicators = this.getImplementationIndicators(safeguard.id);
|
|
5910
|
+
let score = 0;
|
|
5911
|
+
// Check for strong implementation language
|
|
5912
|
+
const strongIndicators = implementationIndicators.filter(indicator => text.includes(indicator.toLowerCase()));
|
|
5913
|
+
if (strongIndicators.length > 0) {
|
|
5914
|
+
score += 0.4;
|
|
5915
|
+
evidence.push(`Strong implementation indicators: ${strongIndicators.join(', ')}`);
|
|
5814
5916
|
}
|
|
5815
|
-
|
|
5816
|
-
|
|
5817
|
-
|
|
5917
|
+
// Check for comprehensive functionality description
|
|
5918
|
+
if (text.includes('comprehensive') || text.includes('complete') || text.includes('full')) {
|
|
5919
|
+
score += 0.2;
|
|
5920
|
+
evidence.push('Claims comprehensive functionality');
|
|
5818
5921
|
}
|
|
5819
|
-
|
|
5820
|
-
|
|
5821
|
-
|
|
5922
|
+
// Check for automated vs manual implementation
|
|
5923
|
+
if (text.includes('automat') || text.includes('real-time') || text.includes('continuous')) {
|
|
5924
|
+
score += 0.2;
|
|
5925
|
+
evidence.push('Automated implementation capability');
|
|
5822
5926
|
}
|
|
5823
|
-
|
|
5824
|
-
|
|
5825
|
-
|
|
5927
|
+
// Identify potential gaps
|
|
5928
|
+
if (strongIndicators.length === 0) {
|
|
5929
|
+
gaps.push('No clear implementation indicators found');
|
|
5826
5930
|
}
|
|
5827
|
-
|
|
5828
|
-
|
|
5829
|
-
|
|
5830
|
-
const
|
|
5831
|
-
|
|
5832
|
-
const
|
|
5833
|
-
|
|
5834
|
-
|
|
5835
|
-
|
|
5931
|
+
return Math.min(score, 1.0);
|
|
5932
|
+
}
|
|
5933
|
+
assessGovernanceQuality(text, safeguard, evidence, gaps) {
|
|
5934
|
+
const governanceIndicators = ['policy', 'process', 'governance', 'compliance', 'documentation', 'oversight'];
|
|
5935
|
+
let score = 0;
|
|
5936
|
+
const foundIndicators = governanceIndicators.filter(indicator => text.includes(indicator));
|
|
5937
|
+
if (foundIndicators.length >= 3) {
|
|
5938
|
+
score += 0.5;
|
|
5939
|
+
evidence.push(`Strong governance capability: ${foundIndicators.join(', ')}`);
|
|
5940
|
+
}
|
|
5941
|
+
if (text.includes('documented') && text.includes('process')) {
|
|
5942
|
+
score += 0.3;
|
|
5943
|
+
evidence.push('Documented process management');
|
|
5944
|
+
}
|
|
5945
|
+
return Math.min(score, 1.0);
|
|
5946
|
+
}
|
|
5947
|
+
assessFacilitationQuality(text, safeguard, evidence, gaps) {
|
|
5948
|
+
const facilitationIndicators = ['enhance', 'enable', 'support', 'facilitate', 'improve', 'optimize'];
|
|
5949
|
+
let score = 0;
|
|
5950
|
+
const foundIndicators = facilitationIndicators.filter(indicator => text.includes(indicator));
|
|
5951
|
+
if (foundIndicators.length >= 2) {
|
|
5952
|
+
score += 0.4;
|
|
5953
|
+
evidence.push(`Clear facilitation capability: ${foundIndicators.join(', ')}`);
|
|
5954
|
+
}
|
|
5955
|
+
return Math.min(score, 1.0);
|
|
5956
|
+
}
|
|
5957
|
+
assessValidationQuality(text, safeguard, evidence, gaps) {
|
|
5958
|
+
const validationIndicators = ['audit', 'report', 'monitor', 'track', 'verify', 'validate'];
|
|
5959
|
+
let score = 0;
|
|
5960
|
+
const foundIndicators = validationIndicators.filter(indicator => text.includes(indicator));
|
|
5961
|
+
if (foundIndicators.length >= 2) {
|
|
5962
|
+
score += 0.4;
|
|
5963
|
+
evidence.push(`Strong validation capability: ${foundIndicators.join(', ')}`);
|
|
5964
|
+
}
|
|
5965
|
+
return Math.min(score, 1.0);
|
|
5966
|
+
}
|
|
5967
|
+
generateCapabilityAnalysis(vendorName, safeguard, responseText, claimedCapability, qualityAssessment) {
|
|
5968
|
+
// Generate the new capability-focused analysis result
|
|
5836
5969
|
return {
|
|
5837
5970
|
vendor: vendorName,
|
|
5838
5971
|
safeguardId: safeguard.id,
|
|
5839
5972
|
safeguardTitle: safeguard.title,
|
|
5840
|
-
capability:
|
|
5973
|
+
capability: claimedCapability,
|
|
5841
5974
|
capabilities: {
|
|
5842
|
-
full:
|
|
5843
|
-
partial:
|
|
5844
|
-
facilitates:
|
|
5845
|
-
governance:
|
|
5846
|
-
validates:
|
|
5847
|
-
},
|
|
5848
|
-
confidence: Math.round(confidence),
|
|
5849
|
-
reasoning: this.generateCapabilityReasoning(primaryCapability, fullCapability, partialCapability, governanceCapability, facilitatesCapability, validatesCapability, coreCoverage, subElementCoverage, safeguard, hasFacilitationPattern, hasNonImplementationLanguage),
|
|
5850
|
-
evidence,
|
|
5851
|
-
elementsCovered: {
|
|
5852
|
-
coreRequirements: coreCoverage.coveredElements,
|
|
5853
|
-
subTaxonomicalElements: subElementCoverage.coveredElements,
|
|
5854
|
-
governanceElements: governanceCoverage.coveredElements,
|
|
5855
|
-
implementationMethods: implementationCoverage.coveredElements
|
|
5975
|
+
full: claimedCapability === 'full',
|
|
5976
|
+
partial: claimedCapability === 'partial',
|
|
5977
|
+
facilitates: claimedCapability === 'facilitates',
|
|
5978
|
+
governance: claimedCapability === 'governance',
|
|
5979
|
+
validates: claimedCapability === 'validates'
|
|
5856
5980
|
},
|
|
5857
|
-
|
|
5858
|
-
|
|
5859
|
-
|
|
5860
|
-
|
|
5981
|
+
confidence: qualityAssessment.confidence,
|
|
5982
|
+
reasoning: this.generateCapabilityReasoning(claimedCapability, qualityAssessment, safeguard),
|
|
5983
|
+
evidence: qualityAssessment.evidence,
|
|
5984
|
+
// Note: elementsCovered is now less relevant in capability-focused analysis
|
|
5985
|
+
// We focus on tool capability rather than element coverage
|
|
5986
|
+
toolCapabilityDescription: this.generateToolCapabilityDescription(claimedCapability, qualityAssessment),
|
|
5987
|
+
recommendedUse: this.generateRecommendedUse(claimedCapability, safeguard)
|
|
5861
5988
|
};
|
|
5862
5989
|
}
|
|
5990
|
+
generateCapabilityReasoning(claimedCapability, qualityAssessment, safeguard) {
|
|
5991
|
+
const capabilityDescriptions = {
|
|
5992
|
+
full: "directly implements the core functionality of this safeguard",
|
|
5993
|
+
partial: "implements limited aspects of this safeguard with clear scope boundaries",
|
|
5994
|
+
facilitates: "enhances or enables the implementation of this safeguard by others",
|
|
5995
|
+
governance: "provides governance, policy, and oversight capabilities for this safeguard",
|
|
5996
|
+
validates: "provides evidence, audit, and compliance validation for this safeguard"
|
|
5997
|
+
};
|
|
5998
|
+
const qualityDescriptor = qualityAssessment.quality;
|
|
5999
|
+
const description = capabilityDescriptions[claimedCapability];
|
|
6000
|
+
return `This tool ${description} with ${qualityDescriptor} capability quality. ${qualityAssessment.evidence.length > 0 ? 'Evidence: ' + qualityAssessment.evidence.join('; ') : ''}`;
|
|
6001
|
+
}
|
|
6002
|
+
generateToolCapabilityDescription(claimedCapability, qualityAssessment) {
|
|
6003
|
+
const roleDescriptions = {
|
|
6004
|
+
full: "Core Implementation Tool - Directly performs the safeguard functionality",
|
|
6005
|
+
partial: "Focused Implementation Tool - Performs specific aspects of the safeguard",
|
|
6006
|
+
facilitates: "Enablement Tool - Helps organizations implement the safeguard more effectively",
|
|
6007
|
+
governance: "Governance Tool - Manages policies, processes, and oversight for the safeguard",
|
|
6008
|
+
validates: "Compliance Tool - Provides audit, evidence, and validation capabilities"
|
|
6009
|
+
};
|
|
6010
|
+
return roleDescriptions[claimedCapability] || "Support Tool";
|
|
6011
|
+
}
|
|
6012
|
+
generateRecommendedUse(claimedCapability, safeguard) {
|
|
6013
|
+
const recommendations = {
|
|
6014
|
+
full: `Use as primary implementation tool for ${safeguard.title}. Ensure proper configuration and integration.`,
|
|
6015
|
+
partial: `Use as part of a multi-tool strategy for ${safeguard.title}. Supplement with additional capabilities as needed.`,
|
|
6016
|
+
facilitates: `Use to enhance existing safeguard implementation. Combine with direct implementation tools.`,
|
|
6017
|
+
governance: `Use for policy management and governance oversight. Pair with implementation and validation tools.`,
|
|
6018
|
+
validates: `Use for compliance monitoring and evidence collection. Combine with implementation tools for complete coverage.`
|
|
6019
|
+
};
|
|
6020
|
+
return recommendations[claimedCapability] || "Evaluate specific use case alignment.";
|
|
6021
|
+
}
|
|
5863
6022
|
calculateKeywordScore(text, keywords) {
|
|
5864
|
-
let
|
|
5865
|
-
let
|
|
6023
|
+
let matchedKeywords = 0;
|
|
6024
|
+
let totalMatches = 0;
|
|
5866
6025
|
keywords.forEach(keyword => {
|
|
5867
6026
|
const regex = new RegExp(keyword.replace(/\s+/g, '\\s+'), 'gi');
|
|
5868
6027
|
const keywordMatches = (text.match(regex) || []).length;
|
|
5869
6028
|
if (keywordMatches > 0) {
|
|
5870
|
-
|
|
5871
|
-
|
|
6029
|
+
matchedKeywords++;
|
|
6030
|
+
totalMatches += keywordMatches;
|
|
5872
6031
|
}
|
|
5873
6032
|
});
|
|
5874
|
-
|
|
6033
|
+
// Return percentage of keywords that were found, with bonus for multiple matches
|
|
6034
|
+
const baseScore = matchedKeywords / keywords.length;
|
|
6035
|
+
const matchBonus = Math.min(totalMatches * 0.1, 0.5); // Up to 50% bonus for multiple matches
|
|
6036
|
+
return Math.min(baseScore + matchBonus, 1.0);
|
|
5875
6037
|
}
|
|
5876
6038
|
analyzeElementCoverage(text, elements) {
|
|
5877
6039
|
const coveredElements = [];
|
|
@@ -5981,63 +6143,6 @@ export class GRCAnalysisServer {
|
|
|
5981
6143
|
}
|
|
5982
6144
|
return reasons.join('. ');
|
|
5983
6145
|
}
|
|
5984
|
-
generateCapabilityReasoning(primaryCapability, full, partial, governance, facilitates, validates, coreCoverage, subElementCoverage, safeguard, hasFacilitationPattern = false, hasNonImplementationLanguage = false) {
|
|
5985
|
-
const reasons = [];
|
|
5986
|
-
// Primary capability explanation
|
|
5987
|
-
switch (primaryCapability) {
|
|
5988
|
-
case 'full':
|
|
5989
|
-
reasons.push(`Provides FULL coverage of ${safeguard.title} - directly implements all core and sub-taxonomical elements`);
|
|
5990
|
-
break;
|
|
5991
|
-
case 'partial':
|
|
5992
|
-
reasons.push(`Provides PARTIAL coverage of ${safeguard.title} - directly implements some but not all core and sub-taxonomical elements`);
|
|
5993
|
-
break;
|
|
5994
|
-
case 'facilitates':
|
|
5995
|
-
if (hasFacilitationPattern || hasNonImplementationLanguage || governance) {
|
|
5996
|
-
reasons.push(`FACILITATES ${safeguard.title} by creating governance frameworks, policy infrastructure, and compliance processes that enable organizations to implement the control effectively`);
|
|
5997
|
-
}
|
|
5998
|
-
else {
|
|
5999
|
-
reasons.push(`FACILITATES ${safeguard.title} through data integration, automation, or technical capabilities that support implementation`);
|
|
6000
|
-
}
|
|
6001
|
-
break;
|
|
6002
|
-
case 'governance':
|
|
6003
|
-
reasons.push(`Provides GOVERNANCE capabilities for ${safeguard.title} through centralized policy management, process controls, and compliance oversight`);
|
|
6004
|
-
break;
|
|
6005
|
-
case 'validates':
|
|
6006
|
-
reasons.push(`VALIDATES ${safeguard.title} implementation through evidence collection, compliance reporting, and audit capabilities`);
|
|
6007
|
-
break;
|
|
6008
|
-
default:
|
|
6009
|
-
reasons.push(`No clear capability identified for ${safeguard.title}`);
|
|
6010
|
-
}
|
|
6011
|
-
// Coverage details
|
|
6012
|
-
if (coreCoverage.coveredElements.length > 0) {
|
|
6013
|
-
reasons.push(`Core elements addressed: ${coreCoverage.coveredElements.length}/${safeguard.coreRequirements.length}`);
|
|
6014
|
-
}
|
|
6015
|
-
if (subElementCoverage.coveredElements.length > 0) {
|
|
6016
|
-
reasons.push(`Sub-taxonomical elements addressed: ${subElementCoverage.coveredElements.length}/${safeguard.subTaxonomicalElements.length}`);
|
|
6017
|
-
}
|
|
6018
|
-
// Additional context for facilitation tools
|
|
6019
|
-
if (primaryCapability === 'facilitates') {
|
|
6020
|
-
if (hasFacilitationPattern || hasNonImplementationLanguage || governance) {
|
|
6021
|
-
reasons.push(`Note: This type of facilitation tool works alongside technical implementation solutions (asset scanners, MDM tools, etc.) to provide comprehensive control coverage`);
|
|
6022
|
-
}
|
|
6023
|
-
if (hasNonImplementationLanguage) {
|
|
6024
|
-
reasons.push(`Tool explicitly enables compliance through governance/process rather than direct technical implementation`);
|
|
6025
|
-
}
|
|
6026
|
-
}
|
|
6027
|
-
// Multi-capability products
|
|
6028
|
-
const capabilityFlags = [governance, facilitates, validates].filter(Boolean);
|
|
6029
|
-
if (capabilityFlags.length > 1) {
|
|
6030
|
-
const capabilities = [];
|
|
6031
|
-
if (governance)
|
|
6032
|
-
capabilities.push('governance');
|
|
6033
|
-
if (facilitates)
|
|
6034
|
-
capabilities.push('facilitates');
|
|
6035
|
-
if (validates)
|
|
6036
|
-
capabilities.push('validates');
|
|
6037
|
-
reasons.push(`Multi-capability product with: ${capabilities.join(', ')}`);
|
|
6038
|
-
}
|
|
6039
|
-
return reasons.join('. ');
|
|
6040
|
-
}
|
|
6041
6146
|
validateClaim(claim, analysis, capabilities, safeguard) {
|
|
6042
6147
|
const validation = {
|
|
6043
6148
|
coverageClaimValid: false,
|
|
@@ -6050,16 +6155,14 @@ export class GRCAnalysisServer {
|
|
|
6050
6155
|
const meetsFullCriteria = analysis.capabilities.full;
|
|
6051
6156
|
validation.coverageClaimValid = meetsFullCriteria;
|
|
6052
6157
|
if (!meetsFullCriteria) {
|
|
6053
|
-
|
|
6054
|
-
const coveredElements = analysis.elementsCovered.coreRequirements.length + analysis.elementsCovered.subTaxonomicalElements.length;
|
|
6055
|
-
validation.gaps.push(`FULL coverage claim not supported: Only ${coveredElements}/${totalElements} core and sub-taxonomical elements covered`);
|
|
6158
|
+
validation.gaps.push(`FULL implementation capability claim not supported: Tool does not demonstrate direct implementation of core safeguard functionality`);
|
|
6056
6159
|
}
|
|
6057
6160
|
}
|
|
6058
6161
|
else if (claim === 'PARTIAL') {
|
|
6059
6162
|
const meetsPartialCriteria = analysis.capabilities.partial || analysis.capabilities.full;
|
|
6060
6163
|
validation.coverageClaimValid = meetsPartialCriteria;
|
|
6061
6164
|
if (!meetsPartialCriteria) {
|
|
6062
|
-
validation.gaps.push(`PARTIAL
|
|
6165
|
+
validation.gaps.push(`PARTIAL implementation capability claim questionable: No core or sub-taxonomical elements clearly addressed`);
|
|
6063
6166
|
}
|
|
6064
6167
|
}
|
|
6065
6168
|
// Validate capability claims
|
|
@@ -6103,12 +6206,18 @@ export class GRCAnalysisServer {
|
|
|
6103
6206
|
}
|
|
6104
6207
|
else {
|
|
6105
6208
|
validation.recommendations.push(`Consider requesting additional information about: ${validation.gaps.join(', ')}`);
|
|
6106
|
-
//
|
|
6107
|
-
if (analysis.
|
|
6108
|
-
validation.recommendations.push(
|
|
6209
|
+
// Capability-based recommendations
|
|
6210
|
+
if (analysis.capability === 'facilitates') {
|
|
6211
|
+
validation.recommendations.push('Consider pairing with direct implementation tools for complete safeguard coverage');
|
|
6212
|
+
}
|
|
6213
|
+
else if (analysis.capability === 'partial') {
|
|
6214
|
+
validation.recommendations.push('Evaluate scope limitations and identify complementary tools for full coverage');
|
|
6109
6215
|
}
|
|
6110
|
-
if (analysis.
|
|
6111
|
-
validation.recommendations.push(
|
|
6216
|
+
else if (analysis.capability === 'governance') {
|
|
6217
|
+
validation.recommendations.push('Combine with technical implementation tools for complete safeguard execution');
|
|
6218
|
+
}
|
|
6219
|
+
else if (analysis.capability === 'validates') {
|
|
6220
|
+
validation.recommendations.push('Pair with implementation tools to ensure both execution and validation coverage');
|
|
6112
6221
|
}
|
|
6113
6222
|
if (!analysis.capabilities.validates && capabilities.includes('Validates')) {
|
|
6114
6223
|
validation.recommendations.push(`Request examples of audit trails, reporting capabilities, and compliance evidence`);
|
|
@@ -6118,10 +6227,11 @@ export class GRCAnalysisServer {
|
|
|
6118
6227
|
}
|
|
6119
6228
|
async validateVendorMapping(args) {
|
|
6120
6229
|
const { vendor_name = 'Unknown Vendor', safeguard_id, claimed_capability, supporting_text } = args;
|
|
6230
|
+
// Input validation
|
|
6231
|
+
this.validateSafeguardId(safeguard_id);
|
|
6232
|
+
this.validateTextInput(supporting_text, 'Supporting text');
|
|
6233
|
+
this.validateCapability(claimed_capability);
|
|
6121
6234
|
const safeguard = CIS_SAFEGUARDS[safeguard_id];
|
|
6122
|
-
if (!safeguard) {
|
|
6123
|
-
throw new Error(`Safeguard ${safeguard_id} not found. Available safeguards: ${Object.keys(CIS_SAFEGUARDS).join(', ')}`);
|
|
6124
|
-
}
|
|
6125
6235
|
const validation = this.validateCapabilityClaim(vendor_name, safeguard, claimed_capability, supporting_text);
|
|
6126
6236
|
return {
|
|
6127
6237
|
content: [
|
|
@@ -6134,20 +6244,27 @@ export class GRCAnalysisServer {
|
|
|
6134
6244
|
}
|
|
6135
6245
|
validateCapabilityClaim(vendorName, safeguard, claimedCapability, supportingText) {
|
|
6136
6246
|
const text = supportingText.toLowerCase();
|
|
6137
|
-
//
|
|
6138
|
-
const
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
|
|
6143
|
-
|
|
6144
|
-
|
|
6145
|
-
|
|
6146
|
-
|
|
6147
|
-
|
|
6148
|
-
|
|
6149
|
-
// Validate
|
|
6150
|
-
const validation = this.
|
|
6247
|
+
// Detect tool type and validate domain match
|
|
6248
|
+
const detectedToolType = this.detectToolType(supportingText, safeguard.id);
|
|
6249
|
+
const domainValidation = this.validateDomainMatch(safeguard.id, claimedCapability, detectedToolType);
|
|
6250
|
+
// Adjust capability if domain mismatch detected
|
|
6251
|
+
let effectiveCapability = claimedCapability;
|
|
6252
|
+
let originalClaim;
|
|
6253
|
+
if (domainValidation.should_adjust_capability) {
|
|
6254
|
+
originalClaim = claimedCapability;
|
|
6255
|
+
effectiveCapability = domainValidation.adjusted_capability;
|
|
6256
|
+
}
|
|
6257
|
+
// Perform capability-focused analysis of the supporting text
|
|
6258
|
+
const actualAnalysis = this.performCapabilityAnalysis(vendorName, safeguard, supportingText);
|
|
6259
|
+
// Validate claimed capability against actual capability analysis and domain requirements
|
|
6260
|
+
const validation = this.assessCapabilityClaimAlignment(claimedCapability, effectiveCapability, actualAnalysis, domainValidation, text);
|
|
6261
|
+
// Add domain validation gaps if capability was adjusted
|
|
6262
|
+
if (domainValidation.should_adjust_capability) {
|
|
6263
|
+
validation.gaps.unshift(`Domain mismatch: ${domainValidation.reasoning}`);
|
|
6264
|
+
validation.recommendations.unshift(`Correct capability mapping should be '${effectiveCapability.toUpperCase()}' for ${detectedToolType} tools`);
|
|
6265
|
+
// Reduce confidence for domain mismatches
|
|
6266
|
+
validation.confidence = Math.max(validation.confidence - 20, 0);
|
|
6267
|
+
}
|
|
6151
6268
|
return {
|
|
6152
6269
|
vendor: vendorName,
|
|
6153
6270
|
safeguard_id: safeguard.id,
|
|
@@ -6155,11 +6272,16 @@ export class GRCAnalysisServer {
|
|
|
6155
6272
|
claimed_capability: claimedCapability,
|
|
6156
6273
|
validation_status: validation.status,
|
|
6157
6274
|
confidence_score: validation.confidence,
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
|
|
6161
|
-
|
|
6162
|
-
|
|
6275
|
+
actual_capability_detected: actualAnalysis.capability,
|
|
6276
|
+
capability_confidence: actualAnalysis.confidence,
|
|
6277
|
+
tool_capability_description: actualAnalysis.toolCapabilityDescription,
|
|
6278
|
+
recommended_use: actualAnalysis.recommendedUse,
|
|
6279
|
+
domain_validation: {
|
|
6280
|
+
required_tool_type: domainValidation.required_tool_types.join('/'),
|
|
6281
|
+
detected_tool_type: detectedToolType,
|
|
6282
|
+
domain_match: domainValidation.domain_match,
|
|
6283
|
+
capability_adjusted: domainValidation.should_adjust_capability,
|
|
6284
|
+
original_claim: originalClaim
|
|
6163
6285
|
},
|
|
6164
6286
|
gaps_identified: validation.gaps,
|
|
6165
6287
|
strengths_identified: validation.strengths,
|
|
@@ -6167,112 +6289,42 @@ export class GRCAnalysisServer {
|
|
|
6167
6289
|
detailed_feedback: validation.feedback
|
|
6168
6290
|
};
|
|
6169
6291
|
}
|
|
6170
|
-
|
|
6292
|
+
assessCapabilityClaimAlignment(claimedCapability, effectiveCapability, actualAnalysis, domainValidation, text) {
|
|
6171
6293
|
const gaps = [];
|
|
6172
6294
|
const strengths = [];
|
|
6173
6295
|
const recommendations = [];
|
|
6174
|
-
|
|
6296
|
+
// Compare claimed capability with what we actually detected
|
|
6297
|
+
const claimedLower = claimedCapability.toLowerCase();
|
|
6298
|
+
const effectiveLower = effectiveCapability.toLowerCase();
|
|
6299
|
+
const actualCapability = actualAnalysis.capability;
|
|
6175
6300
|
let alignmentScore = 0;
|
|
6176
|
-
|
|
6177
|
-
|
|
6178
|
-
|
|
6179
|
-
|
|
6180
|
-
|
|
6181
|
-
|
|
6182
|
-
|
|
6183
|
-
|
|
6184
|
-
|
|
6185
|
-
|
|
6186
|
-
|
|
6187
|
-
|
|
6188
|
-
|
|
6189
|
-
|
|
6190
|
-
|
|
6191
|
-
|
|
6192
|
-
|
|
6193
|
-
|
|
6194
|
-
|
|
6195
|
-
|
|
6196
|
-
|
|
6197
|
-
alignmentScore -= 30;
|
|
6198
|
-
gaps.push('Contains facilitation language inconsistent with FULL implementation claim');
|
|
6199
|
-
}
|
|
6200
|
-
languageConsistency = this.assessImplementationLanguage(text);
|
|
6201
|
-
break;
|
|
6202
|
-
case 'partial':
|
|
6203
|
-
// Validate PARTIAL claim
|
|
6204
|
-
if (corePercentage >= 30 || (corePercentage > 0 && subElementPercentage >= 20)) {
|
|
6205
|
-
alignmentScore = 75;
|
|
6206
|
-
strengths.push('Appropriate coverage level for PARTIAL implementation');
|
|
6207
|
-
}
|
|
6208
|
-
else {
|
|
6209
|
-
alignmentScore = Math.max(0, corePercentage + subElementPercentage - 10);
|
|
6210
|
-
gaps.push(`Coverage too low even for PARTIAL claim: ${Math.round(corePercentage)}% core, ${Math.round(subElementPercentage)}% sub-elements`);
|
|
6211
|
-
}
|
|
6212
|
-
// Check for scope boundary definition
|
|
6213
|
-
if (this.hasScopeBoundaries(text)) {
|
|
6214
|
-
strengths.push('Clearly defines scope boundaries and limitations');
|
|
6215
|
-
alignmentScore += 10;
|
|
6216
|
-
}
|
|
6217
|
-
else {
|
|
6218
|
-
gaps.push('Should clearly define scope boundaries for PARTIAL implementation');
|
|
6219
|
-
recommendations.push('Specify exactly which elements are covered and which are not');
|
|
6220
|
-
}
|
|
6221
|
-
languageConsistency = this.assessImplementationLanguage(text);
|
|
6222
|
-
break;
|
|
6223
|
-
case 'facilitates':
|
|
6224
|
-
// Validate FACILITATES claim
|
|
6225
|
-
if (this.hasFacilitationLanguage(text) || actualAnalysis.capabilities.facilitates) {
|
|
6226
|
-
alignmentScore = 80;
|
|
6227
|
-
strengths.push('Contains appropriate facilitation and enablement language');
|
|
6228
|
-
}
|
|
6229
|
-
else {
|
|
6230
|
-
alignmentScore = 40;
|
|
6231
|
-
gaps.push('Lacks clear facilitation language (enables, supports, provides framework)');
|
|
6232
|
-
}
|
|
6233
|
-
// Check that it doesn't claim direct implementation
|
|
6234
|
-
if (this.hasDirectImplementationLanguage(text)) {
|
|
6235
|
-
// Special handling: If it lacks facilitation language AND claims implementation, stay QUESTIONABLE
|
|
6236
|
-
if (alignmentScore <= 40) {
|
|
6237
|
-
alignmentScore = 45; // Keep it in QUESTIONABLE range
|
|
6238
|
-
}
|
|
6239
|
-
else {
|
|
6240
|
-
alignmentScore -= 15;
|
|
6241
|
-
}
|
|
6242
|
-
gaps.push('Claims direct implementation, inconsistent with FACILITATES capability');
|
|
6243
|
-
}
|
|
6244
|
-
languageConsistency = this.assessFacilitationLanguage(text);
|
|
6245
|
-
break;
|
|
6246
|
-
case 'governance':
|
|
6247
|
-
// Validate GOVERNANCE claim
|
|
6248
|
-
if (governancePercentage >= 60 || actualAnalysis.capabilities.governance) {
|
|
6249
|
-
alignmentScore = 85;
|
|
6250
|
-
strengths.push('Strong governance element coverage and policy management language');
|
|
6251
|
-
}
|
|
6252
|
-
else {
|
|
6253
|
-
alignmentScore = Math.max(30, governancePercentage);
|
|
6254
|
-
gaps.push(`Governance element coverage (${Math.round(governancePercentage)}%) below expected threshold (60%)`);
|
|
6255
|
-
}
|
|
6256
|
-
languageConsistency = this.assessGovernanceLanguage(text);
|
|
6257
|
-
break;
|
|
6258
|
-
case 'validates':
|
|
6259
|
-
// Validate VALIDATES claim
|
|
6260
|
-
if (actualAnalysis.capabilities.validates) {
|
|
6261
|
-
alignmentScore = 85;
|
|
6262
|
-
strengths.push('Contains evidence collection and reporting capabilities');
|
|
6263
|
-
}
|
|
6264
|
-
else {
|
|
6265
|
-
alignmentScore = 30;
|
|
6266
|
-
gaps.push('Lacks validation language (audit, report, evidence, verify, monitor)');
|
|
6267
|
-
}
|
|
6268
|
-
languageConsistency = this.assessValidationLanguage(text);
|
|
6269
|
-
break;
|
|
6270
|
-
default:
|
|
6271
|
-
alignmentScore = 0;
|
|
6272
|
-
gaps.push(`Unknown capability type: ${claimedCapability}`);
|
|
6273
|
-
languageConsistency = 0;
|
|
6301
|
+
// Check if claim aligns with actual analysis
|
|
6302
|
+
if (claimedLower === actualCapability) {
|
|
6303
|
+
alignmentScore = actualAnalysis.confidence;
|
|
6304
|
+
strengths.push(`Claimed capability '${claimedCapability}' aligns with detected capability`);
|
|
6305
|
+
strengths.push(`Tool demonstrates appropriate ${actualAnalysis.toolCapabilityDescription.toLowerCase()}`);
|
|
6306
|
+
}
|
|
6307
|
+
else if (effectiveLower === actualCapability) {
|
|
6308
|
+
// Domain validation adjusted the capability and it matches the analysis
|
|
6309
|
+
alignmentScore = Math.max(actualAnalysis.confidence - 20, 30);
|
|
6310
|
+
gaps.push(`Original claim '${claimedCapability}' doesn't match tool type, adjusted to '${effectiveCapability}'`);
|
|
6311
|
+
strengths.push(`Adjusted capability '${effectiveCapability}' aligns with tool analysis`);
|
|
6312
|
+
}
|
|
6313
|
+
else {
|
|
6314
|
+
// Neither claimed nor effective capability matches the analysis
|
|
6315
|
+
alignmentScore = Math.max(actualAnalysis.confidence - 40, 10);
|
|
6316
|
+
gaps.push(`Claimed capability '${claimedCapability}' doesn't align with detected capability '${actualCapability}'`);
|
|
6317
|
+
gaps.push(`Tool appears to be: ${actualAnalysis.toolCapabilityDescription}`);
|
|
6318
|
+
}
|
|
6319
|
+
// Add evidence from the capability analysis
|
|
6320
|
+
if (actualAnalysis.evidence && actualAnalysis.evidence.length > 0) {
|
|
6321
|
+
strengths.push(`Supporting evidence: ${actualAnalysis.evidence.slice(0, 2).join('; ')}`);
|
|
6274
6322
|
}
|
|
6275
|
-
//
|
|
6323
|
+
// Domain validation feedback
|
|
6324
|
+
if (!domainValidation.domain_match) {
|
|
6325
|
+
gaps.push(`Tool type '${domainValidation.detected_tool_type}' not appropriate for this safeguard domain`);
|
|
6326
|
+
}
|
|
6327
|
+
// Determine overall status based on alignment score
|
|
6276
6328
|
let status;
|
|
6277
6329
|
if (alignmentScore >= 70) {
|
|
6278
6330
|
status = 'SUPPORTED';
|
|
@@ -6283,18 +6335,18 @@ export class GRCAnalysisServer {
|
|
|
6283
6335
|
else {
|
|
6284
6336
|
status = 'UNSUPPORTED';
|
|
6285
6337
|
}
|
|
6286
|
-
// Generate recommendations
|
|
6287
|
-
|
|
6288
|
-
recommendations.push('Address identified gaps to strengthen capability claim');
|
|
6289
|
-
}
|
|
6338
|
+
// Generate capability-focused recommendations
|
|
6339
|
+
recommendations.push(actualAnalysis.recommendedUse);
|
|
6290
6340
|
if (status === 'QUESTIONABLE') {
|
|
6291
|
-
recommendations.push('
|
|
6341
|
+
recommendations.push('Consider clarifying tool capabilities or adjusting capability claim');
|
|
6342
|
+
}
|
|
6343
|
+
if (!domainValidation.domain_match) {
|
|
6344
|
+
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`);
|
|
6292
6345
|
}
|
|
6293
|
-
const feedback = this.
|
|
6346
|
+
const feedback = this.generateCapabilityValidationFeedback(claimedCapability, effectiveCapability, actualCapability, status, alignmentScore, domainValidation);
|
|
6294
6347
|
return {
|
|
6295
6348
|
status,
|
|
6296
6349
|
confidence: Math.round(alignmentScore),
|
|
6297
|
-
languageConsistency: Math.round(languageConsistency),
|
|
6298
6350
|
gaps,
|
|
6299
6351
|
strengths,
|
|
6300
6352
|
recommendations,
|
|
@@ -6352,8 +6404,195 @@ export class GRCAnalysisServer {
|
|
|
6352
6404
|
];
|
|
6353
6405
|
return this.calculateKeywordScore(text, validationKeywords) * 100;
|
|
6354
6406
|
}
|
|
6407
|
+
detectToolType(text, safeguardId) {
|
|
6408
|
+
const lowerText = text.toLowerCase();
|
|
6409
|
+
// Enhanced keyword definitions with scoring weights and context
|
|
6410
|
+
const toolTypePatterns = {
|
|
6411
|
+
'inventory': {
|
|
6412
|
+
primary: [
|
|
6413
|
+
'asset management', 'inventory management', 'cmdb', 'configuration management database',
|
|
6414
|
+
'asset discovery', 'hardware inventory', 'software inventory', 'device inventory',
|
|
6415
|
+
'asset tracking', 'it asset management', 'endpoint discovery', 'asset lifecycle'
|
|
6416
|
+
],
|
|
6417
|
+
secondary: [
|
|
6418
|
+
'inventory', 'discovery', 'device management', 'endpoint management',
|
|
6419
|
+
'configuration management', 'asset database', 'equipment tracking'
|
|
6420
|
+
],
|
|
6421
|
+
weight: { primary: 3, secondary: 1 }
|
|
6422
|
+
},
|
|
6423
|
+
'identity_management': {
|
|
6424
|
+
primary: [
|
|
6425
|
+
'identity management', 'iam', 'active directory', 'identity provider',
|
|
6426
|
+
'single sign-on', 'sso', 'multi-factor authentication', 'mfa',
|
|
6427
|
+
'user management', 'account management', 'directory service'
|
|
6428
|
+
],
|
|
6429
|
+
secondary: [
|
|
6430
|
+
'ldap', 'authentication', 'access management', 'identity access management',
|
|
6431
|
+
'user directory', 'account lifecycle', 'privileged access'
|
|
6432
|
+
],
|
|
6433
|
+
weight: { primary: 3, secondary: 1 }
|
|
6434
|
+
},
|
|
6435
|
+
'vulnerability_management': {
|
|
6436
|
+
primary: [
|
|
6437
|
+
'vulnerability management', 'vulnerability scanner', 'patch management',
|
|
6438
|
+
'security scanning', 'vulnerability assessment', 'penetration testing'
|
|
6439
|
+
],
|
|
6440
|
+
secondary: [
|
|
6441
|
+
'vuln scan', 'security scanner', 'network scanner', 'scanning capabilities',
|
|
6442
|
+
'security assessment', 'vulnerability scanning', 'patch deployment'
|
|
6443
|
+
],
|
|
6444
|
+
weight: { primary: 3, secondary: 1 }
|
|
6445
|
+
},
|
|
6446
|
+
'threat_intelligence': {
|
|
6447
|
+
primary: [
|
|
6448
|
+
'threat intelligence', 'cyber threat intelligence', 'threat intel',
|
|
6449
|
+
'threat feed', 'ioc feed', 'security intelligence', 'threat data'
|
|
6450
|
+
],
|
|
6451
|
+
secondary: [
|
|
6452
|
+
'enrichment', 'data feed', 'contextual data', 'risk intelligence',
|
|
6453
|
+
'threat indicators', 'intelligence platform', 'threat correlation'
|
|
6454
|
+
],
|
|
6455
|
+
weight: { primary: 3, secondary: 1 }
|
|
6456
|
+
},
|
|
6457
|
+
'network_security': {
|
|
6458
|
+
primary: [
|
|
6459
|
+
'firewall', 'network access control', 'nac', 'intrusion detection',
|
|
6460
|
+
'network security', 'network segmentation'
|
|
6461
|
+
],
|
|
6462
|
+
secondary: [
|
|
6463
|
+
'network monitoring', 'traffic analysis', 'perimeter security',
|
|
6464
|
+
'network protection', 'network filtering'
|
|
6465
|
+
],
|
|
6466
|
+
weight: { primary: 3, secondary: 1 }
|
|
6467
|
+
},
|
|
6468
|
+
'governance': {
|
|
6469
|
+
primary: [
|
|
6470
|
+
'grc', 'governance risk compliance', 'compliance management',
|
|
6471
|
+
'policy management', 'risk management', 'audit management'
|
|
6472
|
+
],
|
|
6473
|
+
secondary: [
|
|
6474
|
+
'governance', 'compliance platform', 'policy enforcement',
|
|
6475
|
+
'regulatory compliance', 'framework management'
|
|
6476
|
+
],
|
|
6477
|
+
weight: { primary: 3, secondary: 1 }
|
|
6478
|
+
},
|
|
6479
|
+
'security_analytics': {
|
|
6480
|
+
primary: [
|
|
6481
|
+
'siem', 'security information event management', 'security analytics',
|
|
6482
|
+
'soar', 'security orchestration', 'log management'
|
|
6483
|
+
],
|
|
6484
|
+
secondary: [
|
|
6485
|
+
'security monitoring', 'event correlation', 'log analysis',
|
|
6486
|
+
'security intelligence', 'incident response platform'
|
|
6487
|
+
],
|
|
6488
|
+
weight: { primary: 3, secondary: 1 }
|
|
6489
|
+
}
|
|
6490
|
+
};
|
|
6491
|
+
// Calculate scores for each tool type
|
|
6492
|
+
const toolScores = {};
|
|
6493
|
+
for (const [toolType, patterns] of Object.entries(toolTypePatterns)) {
|
|
6494
|
+
let score = 0;
|
|
6495
|
+
// Check primary keywords
|
|
6496
|
+
for (const keyword of patterns.primary) {
|
|
6497
|
+
if (lowerText.includes(keyword)) {
|
|
6498
|
+
score += patterns.weight.primary;
|
|
6499
|
+
}
|
|
6500
|
+
}
|
|
6501
|
+
// Check secondary keywords
|
|
6502
|
+
for (const keyword of patterns.secondary) {
|
|
6503
|
+
if (lowerText.includes(keyword)) {
|
|
6504
|
+
score += patterns.weight.secondary;
|
|
6505
|
+
}
|
|
6506
|
+
}
|
|
6507
|
+
toolScores[toolType] = score;
|
|
6508
|
+
}
|
|
6509
|
+
// Apply safeguard-specific context weighting if provided
|
|
6510
|
+
if (safeguardId && toolScores) {
|
|
6511
|
+
const contextBonus = 1; // Small bonus for domain alignment
|
|
6512
|
+
// Asset inventory safeguards (1.1, 1.2) favor inventory tools
|
|
6513
|
+
if (['1.1', '1.2'].includes(safeguardId) && toolScores['inventory'] > 0) {
|
|
6514
|
+
toolScores['inventory'] += contextBonus;
|
|
6515
|
+
}
|
|
6516
|
+
// Account inventory safeguards (5.1, 5.2, 5.3) favor identity tools
|
|
6517
|
+
if (['5.1', '5.2', '5.3'].includes(safeguardId) && toolScores['identity_management'] > 0) {
|
|
6518
|
+
toolScores['identity_management'] += contextBonus;
|
|
6519
|
+
}
|
|
6520
|
+
// Authentication safeguards (6.1, 6.2, 6.3) favor identity tools
|
|
6521
|
+
if (['6.1', '6.2', '6.3'].includes(safeguardId) && toolScores['identity_management'] > 0) {
|
|
6522
|
+
toolScores['identity_management'] += contextBonus;
|
|
6523
|
+
}
|
|
6524
|
+
// Vulnerability safeguards (7.1-7.7) favor vulnerability management tools
|
|
6525
|
+
if (['7.1', '7.2', '7.3', '7.4', '7.5', '7.6', '7.7'].includes(safeguardId) && toolScores['vulnerability_management'] > 0) {
|
|
6526
|
+
toolScores['vulnerability_management'] += contextBonus;
|
|
6527
|
+
}
|
|
6528
|
+
}
|
|
6529
|
+
// Find the tool type with highest score
|
|
6530
|
+
let maxScore = 0;
|
|
6531
|
+
let detectedType = 'unknown';
|
|
6532
|
+
for (const [toolType, score] of Object.entries(toolScores)) {
|
|
6533
|
+
if (score > maxScore) {
|
|
6534
|
+
maxScore = score;
|
|
6535
|
+
detectedType = toolType;
|
|
6536
|
+
}
|
|
6537
|
+
}
|
|
6538
|
+
// Require minimum score threshold to avoid false positives
|
|
6539
|
+
return maxScore >= 2 ? detectedType : 'unknown';
|
|
6540
|
+
}
|
|
6541
|
+
validateDomainMatch(safeguardId, claimedCapability, detectedToolType) {
|
|
6542
|
+
const domainReq = SAFEGUARD_DOMAIN_REQUIREMENTS[safeguardId];
|
|
6543
|
+
if (!domainReq) {
|
|
6544
|
+
return {
|
|
6545
|
+
domain_match: true,
|
|
6546
|
+
required_tool_types: [],
|
|
6547
|
+
should_adjust_capability: false,
|
|
6548
|
+
reasoning: 'No domain restrictions defined for this safeguard'
|
|
6549
|
+
};
|
|
6550
|
+
}
|
|
6551
|
+
const isFullOrPartial = ['full', 'partial'].includes(claimedCapability.toLowerCase());
|
|
6552
|
+
const toolTypeMatches = domainReq.required_tool_types.includes(detectedToolType);
|
|
6553
|
+
if (isFullOrPartial && !toolTypeMatches) {
|
|
6554
|
+
return {
|
|
6555
|
+
domain_match: false,
|
|
6556
|
+
required_tool_types: domainReq.required_tool_types,
|
|
6557
|
+
should_adjust_capability: true,
|
|
6558
|
+
adjusted_capability: 'facilitates',
|
|
6559
|
+
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.`
|
|
6560
|
+
};
|
|
6561
|
+
}
|
|
6562
|
+
return {
|
|
6563
|
+
domain_match: true,
|
|
6564
|
+
required_tool_types: domainReq.required_tool_types,
|
|
6565
|
+
should_adjust_capability: false,
|
|
6566
|
+
reasoning: toolTypeMatches ?
|
|
6567
|
+
`Tool type '${detectedToolType}' is appropriate for ${domainReq.domain} safeguard` :
|
|
6568
|
+
'No domain validation required for this capability type'
|
|
6569
|
+
};
|
|
6570
|
+
}
|
|
6571
|
+
generateCapabilityValidationFeedback(claimedCapability, effectiveCapability, actualCapability, status, score, domainValidation) {
|
|
6572
|
+
let feedback = `Capability Validation: ${claimedCapability.toUpperCase()} claim is ${status} (${Math.round(score)}% confidence)\n\n`;
|
|
6573
|
+
// Analysis summary
|
|
6574
|
+
feedback += `ANALYSIS:\n`;
|
|
6575
|
+
feedback += `• Claimed: ${claimedCapability.toUpperCase()}\n`;
|
|
6576
|
+
if (effectiveCapability !== claimedCapability) {
|
|
6577
|
+
feedback += `• Domain Adjusted: ${effectiveCapability.toUpperCase()} (${domainValidation.reasoning})\n`;
|
|
6578
|
+
}
|
|
6579
|
+
feedback += `• Detected: ${actualCapability.toUpperCase()}\n`;
|
|
6580
|
+
feedback += `• Tool Type: ${domainValidation.detected_tool_type}\n\n`;
|
|
6581
|
+
// Assessment
|
|
6582
|
+
feedback += `ASSESSMENT: `;
|
|
6583
|
+
if (claimedCapability.toLowerCase() === actualCapability) {
|
|
6584
|
+
feedback += 'Claimed capability aligns perfectly with tool analysis.';
|
|
6585
|
+
}
|
|
6586
|
+
else if (effectiveCapability.toLowerCase() === actualCapability) {
|
|
6587
|
+
feedback += 'After domain validation adjustment, capability aligns with tool analysis.';
|
|
6588
|
+
}
|
|
6589
|
+
else {
|
|
6590
|
+
feedback += `Capability mismatch detected. Tool functions as ${actualCapability.toUpperCase()} rather than claimed ${claimedCapability.toUpperCase()}.`;
|
|
6591
|
+
}
|
|
6592
|
+
return feedback;
|
|
6593
|
+
}
|
|
6355
6594
|
generateValidationFeedback(claimedCapability, status, gaps, strengths, score) {
|
|
6356
|
-
let feedback = `Validation of ${claimedCapability.toUpperCase()} capability claim: ${status} (${Math.round(score)}% alignment)\n\n`;
|
|
6595
|
+
let feedback = `Validation of ${claimedCapability.toUpperCase()} capability role claim: ${status} (${Math.round(score)}% alignment)\n\n`;
|
|
6357
6596
|
if (strengths.length > 0) {
|
|
6358
6597
|
feedback += `STRENGTHS:\n${strengths.map(s => `• ${s}`).join('\n')}\n\n`;
|
|
6359
6598
|
}
|
|
@@ -6363,21 +6602,122 @@ export class GRCAnalysisServer {
|
|
|
6363
6602
|
feedback += `ASSESSMENT: `;
|
|
6364
6603
|
switch (status) {
|
|
6365
6604
|
case 'SUPPORTED':
|
|
6366
|
-
feedback += 'The vendor\'s supporting evidence strongly aligns with their claimed capability.';
|
|
6605
|
+
feedback += 'The vendor\'s supporting evidence strongly aligns with their claimed capability role.';
|
|
6367
6606
|
break;
|
|
6368
6607
|
case 'QUESTIONABLE':
|
|
6369
6608
|
feedback += 'The vendor\'s evidence partially supports their claim but has notable gaps or inconsistencies.';
|
|
6370
6609
|
break;
|
|
6371
6610
|
case 'UNSUPPORTED':
|
|
6372
|
-
feedback += 'The vendor\'s evidence does not adequately support their claimed capability.';
|
|
6611
|
+
feedback += 'The vendor\'s evidence does not adequately support their claimed capability role.';
|
|
6373
6612
|
break;
|
|
6374
6613
|
}
|
|
6375
6614
|
return feedback;
|
|
6376
6615
|
}
|
|
6616
|
+
// Enhanced error handling and formatting
|
|
6617
|
+
formatErrorMessage(error, toolName) {
|
|
6618
|
+
if (error instanceof Error) {
|
|
6619
|
+
// Production-friendly error messages
|
|
6620
|
+
switch (error.message) {
|
|
6621
|
+
case /^Safeguard .+ not found/.test(error.message) ? error.message : '':
|
|
6622
|
+
return `❌ Invalid safeguard ID. Use 'list_available_safeguards' to see available CIS Control safeguards.`;
|
|
6623
|
+
case /^Unknown tool/.test(error.message) ? error.message : '':
|
|
6624
|
+
return `❌ Tool '${toolName}' is not available. Available tools: analyze_vendor_response, validate_vendor_mapping, validate_coverage_claim, get_safeguard_details, list_available_safeguards.`;
|
|
6625
|
+
default:
|
|
6626
|
+
return `❌ Error in ${toolName}: ${error.message}`;
|
|
6627
|
+
}
|
|
6628
|
+
}
|
|
6629
|
+
return `❌ Unexpected error in ${toolName}: ${String(error)}`;
|
|
6630
|
+
}
|
|
6631
|
+
getCachedSafeguardDetails(safeguardId, includeExamples) {
|
|
6632
|
+
const cacheKey = `${safeguardId}_${includeExamples}`;
|
|
6633
|
+
const cached = this.cache.safeguardDetails.get(cacheKey);
|
|
6634
|
+
if (cached && (Date.now() - cached.timestamp < 5 * 60 * 1000)) { // 5 minute cache
|
|
6635
|
+
return cached.data;
|
|
6636
|
+
}
|
|
6637
|
+
return null;
|
|
6638
|
+
}
|
|
6639
|
+
setCachedSafeguardDetails(safeguardId, includeExamples, data) {
|
|
6640
|
+
const cacheKey = `${safeguardId}_${includeExamples}`;
|
|
6641
|
+
this.cache.safeguardDetails.set(cacheKey, {
|
|
6642
|
+
data,
|
|
6643
|
+
timestamp: Date.now()
|
|
6644
|
+
});
|
|
6645
|
+
// Periodic cache cleanup to prevent memory leaks
|
|
6646
|
+
if (Date.now() - this.cache.lastCacheCleanup > 10 * 60 * 1000) { // 10 minutes
|
|
6647
|
+
this.cleanupCache();
|
|
6648
|
+
}
|
|
6649
|
+
}
|
|
6650
|
+
cleanupCache() {
|
|
6651
|
+
const now = Date.now();
|
|
6652
|
+
const maxAge = 10 * 60 * 1000; // 10 minutes
|
|
6653
|
+
// Clean up safeguard details cache
|
|
6654
|
+
for (const [key, value] of this.cache.safeguardDetails.entries()) {
|
|
6655
|
+
if (now - value.timestamp > maxAge) {
|
|
6656
|
+
this.cache.safeguardDetails.delete(key);
|
|
6657
|
+
}
|
|
6658
|
+
}
|
|
6659
|
+
this.cache.lastCacheCleanup = now;
|
|
6660
|
+
}
|
|
6661
|
+
recordToolExecution(toolName, executionTime) {
|
|
6662
|
+
this.performanceMetrics.totalRequests++;
|
|
6663
|
+
if (!this.performanceMetrics.toolExecutionTimes.has(toolName)) {
|
|
6664
|
+
this.performanceMetrics.toolExecutionTimes.set(toolName, []);
|
|
6665
|
+
}
|
|
6666
|
+
const times = this.performanceMetrics.toolExecutionTimes.get(toolName);
|
|
6667
|
+
times.push(executionTime);
|
|
6668
|
+
// Keep only last 100 measurements for memory efficiency
|
|
6669
|
+
if (times.length > 100) {
|
|
6670
|
+
times.shift();
|
|
6671
|
+
}
|
|
6672
|
+
}
|
|
6673
|
+
getPerformanceStats() {
|
|
6674
|
+
const uptime = Date.now() - this.performanceMetrics.startTime;
|
|
6675
|
+
const avgTimes = Array.from(this.performanceMetrics.toolExecutionTimes.entries())
|
|
6676
|
+
.map(([tool, times]) => {
|
|
6677
|
+
const avg = times.reduce((a, b) => a + b, 0) / times.length;
|
|
6678
|
+
return `${tool}: ${avg.toFixed(2)}ms`;
|
|
6679
|
+
});
|
|
6680
|
+
return `Performance Stats (Uptime: ${(uptime / 1000).toFixed(1)}s, Requests: ${this.performanceMetrics.totalRequests}, Errors: ${this.performanceMetrics.errorCount})\n${avgTimes.join(', ')}`;
|
|
6681
|
+
}
|
|
6682
|
+
// Input validation and sanitization
|
|
6683
|
+
validateSafeguardId(safeguardId) {
|
|
6684
|
+
if (!safeguardId || typeof safeguardId !== 'string') {
|
|
6685
|
+
throw new Error('Safeguard ID is required and must be a string');
|
|
6686
|
+
}
|
|
6687
|
+
if (!/^[0-9]+\.[0-9]+$/.test(safeguardId)) {
|
|
6688
|
+
throw new Error('Safeguard ID must be in format "X.Y" (e.g., "1.1", "5.1")');
|
|
6689
|
+
}
|
|
6690
|
+
if (!CIS_SAFEGUARDS[safeguardId]) {
|
|
6691
|
+
throw new Error(`Safeguard ${safeguardId} not found`);
|
|
6692
|
+
}
|
|
6693
|
+
}
|
|
6694
|
+
validateTextInput(text, fieldName) {
|
|
6695
|
+
if (!text || typeof text !== 'string') {
|
|
6696
|
+
throw new Error(`${fieldName} is required and must be a string`);
|
|
6697
|
+
}
|
|
6698
|
+
if (text.length > 10000) {
|
|
6699
|
+
throw new Error(`${fieldName} must be less than 10,000 characters`);
|
|
6700
|
+
}
|
|
6701
|
+
if (text.trim().length < 10) {
|
|
6702
|
+
throw new Error(`${fieldName} must contain at least 10 meaningful characters`);
|
|
6703
|
+
}
|
|
6704
|
+
}
|
|
6705
|
+
validateCapability(capability) {
|
|
6706
|
+
const validCapabilities = ['full', 'partial', 'facilitates', 'governance', 'validates'];
|
|
6707
|
+
if (!validCapabilities.includes(capability.toLowerCase())) {
|
|
6708
|
+
throw new Error(`Invalid capability. Must be one of: ${validCapabilities.join(', ')}`);
|
|
6709
|
+
}
|
|
6710
|
+
}
|
|
6377
6711
|
async run() {
|
|
6378
6712
|
const transport = new StdioServerTransport();
|
|
6379
6713
|
await this.server.connect(transport);
|
|
6380
6714
|
console.error('FrameworkMCP server running on stdio');
|
|
6715
|
+
// Log performance stats every 5 minutes in production
|
|
6716
|
+
if (process.env.NODE_ENV === 'production') {
|
|
6717
|
+
setInterval(() => {
|
|
6718
|
+
console.error(`[FrameworkMCP] ${this.getPerformanceStats()}`);
|
|
6719
|
+
}, 5 * 60 * 1000);
|
|
6720
|
+
}
|
|
6381
6721
|
}
|
|
6382
6722
|
}
|
|
6383
6723
|
const server = new GRCAnalysisServer();
|