framework-mcp 1.5.2 → 2.2.2
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/.claude/commands/speckit.analyze.md +184 -0
- package/.claude/commands/speckit.checklist.md +294 -0
- package/.claude/commands/speckit.clarify.md +181 -0
- package/.claude/commands/speckit.constitution.md +82 -0
- package/.claude/commands/speckit.implement.md +135 -0
- package/.claude/commands/speckit.plan.md +89 -0
- package/.claude/commands/speckit.specify.md +258 -0
- package/.claude/commands/speckit.tasks.md +137 -0
- package/.claude/commands/speckit.taskstoissues.md +30 -0
- package/.do/app.yaml +1 -1
- package/.github/dependabot.yml +15 -0
- package/.github/workflows/ci.yml +19 -1
- package/.specify/memory/constitution.md +50 -0
- package/.specify/scripts/bash/check-prerequisites.sh +166 -0
- package/.specify/scripts/bash/common.sh +156 -0
- package/.specify/scripts/bash/create-new-feature.sh +297 -0
- package/.specify/scripts/bash/setup-plan.sh +61 -0
- package/.specify/scripts/bash/update-agent-context.sh +799 -0
- package/.specify/templates/agent-file-template.md +28 -0
- package/.specify/templates/checklist-template.md +40 -0
- package/.specify/templates/plan-template.md +104 -0
- package/.specify/templates/spec-template.md +115 -0
- package/.specify/templates/tasks-template.md +251 -0
- package/README.md +84 -435
- package/dist/core/safeguard-manager.d.ts.map +1 -1
- package/dist/core/safeguard-manager.js +7295 -2700
- package/dist/core/safeguard-manager.js.map +1 -1
- package/dist/interfaces/http/http-server.d.ts +2 -0
- package/dist/interfaces/http/http-server.d.ts.map +1 -1
- package/dist/interfaces/http/http-server.js +95 -3
- package/dist/interfaces/http/http-server.js.map +1 -1
- package/dist/interfaces/mcp/mcp-server.js +3 -3
- package/dist/shared/types.d.ts +85 -2
- package/dist/shared/types.d.ts.map +1 -1
- package/dist/shared/types.js +132 -1
- package/dist/shared/types.js.map +1 -1
- package/package.json +7 -4
- package/scripts/standardize-prompts.js +325 -0
- package/scripts/validate-capability-prompts.js +110 -0
- package/src/core/safeguard-manager.ts +12376 -2586
- package/src/interfaces/http/http-server.ts +109 -4
- package/src/interfaces/mcp/mcp-server.ts +3 -3
- package/src/shared/types.ts +268 -2
- package/swagger.json +58 -38
- package/CAPABILITY_TRANSFORMATION_SUMMARY.md +0 -158
- package/CIS_CONTROLS_IMPLEMENTATION_PLAN.md +0 -220
- package/COPILOT_INTEGRATION.md +0 -322
- package/DAYS_5_6_COMPLETION_SUMMARY.md +0 -178
- package/DEPLOYMENT_GUIDE.md +0 -334
- package/DEPLOYMENT_SUMMARY_v1.1.3.md +0 -211
- package/MCP_INTEGRATION_GUIDE.md +0 -285
- package/MIGRATION_GUIDE_v1.4.0.md +0 -190
- package/RELEASE_NOTES_v1.1.3.md +0 -321
- package/RELEASE_NOTES_v1.2.0.md +0 -396
- package/RELEASE_NOTES_v1.3.7.md +0 -275
- package/RELEASE_NOTES_v1.4.0.md +0 -178
- package/SAFEGUARDS_VERIFICATION_LOG.md +0 -157
- package/coordinator-bot-compact.txt +0 -33
- package/coordinator-bot-system-prompt.md +0 -192
- package/docs/installation.md +0 -71
- package/scripts/analyze-data-structure.cjs +0 -74
- package/scripts/clean-safeguards-data.cjs +0 -60
- package/scripts/comprehensive-validation.cjs +0 -176
- package/scripts/count-safeguards.cjs +0 -89
- package/scripts/format-safeguards-proper.cjs +0 -44
- package/scripts/validate-formatted-data.cjs +0 -88
- package/test_capability_integration.js +0 -73
- package/test_comprehensive_scenarios.js +0 -192
- package/test_enhanced_detection.js +0 -74
- package/test_integrated_validation.js +0 -112
- package/test_language_update.js +0 -101
- package/test_live_validation.json +0 -12
- package/test_performance_monitoring.js +0 -124
- package/test_runner_automated.js +0 -156
- package/test_suite_comprehensive.js +0 -218
|
@@ -4,7 +4,9 @@ import express from 'express';
|
|
|
4
4
|
import cors from 'cors';
|
|
5
5
|
import helmet from 'helmet';
|
|
6
6
|
import compression from 'compression';
|
|
7
|
+
import rateLimit from 'express-rate-limit';
|
|
7
8
|
import { SafeguardManager } from '../../core/safeguard-manager.js';
|
|
9
|
+
import { RateLimitConfig, RateLimitErrorResponse } from '../../shared/types.js';
|
|
8
10
|
|
|
9
11
|
interface ErrorResponse {
|
|
10
12
|
error: string;
|
|
@@ -16,18 +18,54 @@ export class FrameworkHttpServer {
|
|
|
16
18
|
private app: express.Application;
|
|
17
19
|
private safeguardManager: SafeguardManager;
|
|
18
20
|
private port: number;
|
|
21
|
+
private rateLimitConfig: RateLimitConfig;
|
|
19
22
|
|
|
20
23
|
constructor(port: number = 8080) {
|
|
21
24
|
this.app = express();
|
|
22
25
|
this.safeguardManager = new SafeguardManager();
|
|
23
26
|
this.port = port;
|
|
24
|
-
|
|
27
|
+
this.rateLimitConfig = this.parseRateLimitConfig();
|
|
28
|
+
|
|
25
29
|
this.setupMiddleware();
|
|
26
30
|
this.setupRoutes();
|
|
27
31
|
this.setupErrorHandling();
|
|
28
32
|
}
|
|
29
33
|
|
|
34
|
+
private parseRateLimitConfig(): RateLimitConfig {
|
|
35
|
+
const skipIpsEnv = process.env.RATE_LIMIT_SKIP_IPS;
|
|
36
|
+
return {
|
|
37
|
+
windowMs: parseInt(process.env.RATE_LIMIT_WINDOW_MS || '60000', 10),
|
|
38
|
+
max: parseInt(process.env.RATE_LIMIT_MAX || '100', 10),
|
|
39
|
+
skipIps: skipIpsEnv ? skipIpsEnv.split(',').map(ip => ip.trim()) : undefined
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
|
|
30
43
|
private setupMiddleware(): void {
|
|
44
|
+
// Rate limiting middleware - must be before other middleware
|
|
45
|
+
const limiter = rateLimit({
|
|
46
|
+
windowMs: this.rateLimitConfig.windowMs,
|
|
47
|
+
max: this.rateLimitConfig.max,
|
|
48
|
+
standardHeaders: true,
|
|
49
|
+
legacyHeaders: false,
|
|
50
|
+
skip: (req) => {
|
|
51
|
+
if (this.rateLimitConfig.skipIps && req.ip) {
|
|
52
|
+
return this.rateLimitConfig.skipIps.includes(req.ip);
|
|
53
|
+
}
|
|
54
|
+
return false;
|
|
55
|
+
},
|
|
56
|
+
message: {
|
|
57
|
+
error: 'Too many requests',
|
|
58
|
+
retryAfter: 'See Retry-After header',
|
|
59
|
+
timestamp: new Date().toISOString()
|
|
60
|
+
},
|
|
61
|
+
handler: (req, res, _next, options) => {
|
|
62
|
+
console.log(`[Rate Limit] IP ${req.ip} exceeded limit`);
|
|
63
|
+
res.status(429).json(options.message);
|
|
64
|
+
}
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
this.app.use(limiter);
|
|
68
|
+
|
|
31
69
|
// Security middleware
|
|
32
70
|
this.app.use(helmet({
|
|
33
71
|
contentSecurityPolicy: {
|
|
@@ -68,11 +106,78 @@ export class FrameworkHttpServer {
|
|
|
68
106
|
res.json({
|
|
69
107
|
status: 'healthy',
|
|
70
108
|
uptime: Math.round(process.uptime()),
|
|
71
|
-
version: '
|
|
109
|
+
version: '2.2.2',
|
|
72
110
|
timestamp: new Date().toISOString()
|
|
73
111
|
});
|
|
74
112
|
});
|
|
75
113
|
|
|
114
|
+
// Safeguards health check endpoint - validates data completeness
|
|
115
|
+
this.app.get('/api/health/safeguards', (req, res) => {
|
|
116
|
+
try {
|
|
117
|
+
const allSafeguards = this.safeguardManager.getAllSafeguards();
|
|
118
|
+
const safeguardIds = Object.keys(allSafeguards);
|
|
119
|
+
|
|
120
|
+
let totalValidated = 0;
|
|
121
|
+
let errors: string[] = [];
|
|
122
|
+
const expectedFields = [
|
|
123
|
+
'systemPromptFull',
|
|
124
|
+
'systemPromptPartial',
|
|
125
|
+
'systemPromptFacilitates',
|
|
126
|
+
'systemPromptGovernance',
|
|
127
|
+
'systemPromptValidates'
|
|
128
|
+
];
|
|
129
|
+
|
|
130
|
+
for (const safeguardId of safeguardIds) {
|
|
131
|
+
const safeguard = allSafeguards[safeguardId];
|
|
132
|
+
|
|
133
|
+
// Check all five capability prompts exist and are complete
|
|
134
|
+
for (const field of expectedFields) {
|
|
135
|
+
const prompt = (safeguard as any)[field];
|
|
136
|
+
if (!prompt) {
|
|
137
|
+
errors.push(`${safeguardId}: Missing ${field}`);
|
|
138
|
+
continue;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
if (!prompt.role || !prompt.context || !prompt.objective ||
|
|
142
|
+
!prompt.guidelines || !prompt.outputFormat) {
|
|
143
|
+
errors.push(`${safeguardId}.${field}: Incomplete structure`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Check deprecated field is gone
|
|
148
|
+
if ('systemPrompt' in safeguard) {
|
|
149
|
+
errors.push(`${safeguardId}: Deprecated systemPrompt field exists`);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
totalValidated++;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
res.json({
|
|
156
|
+
status: errors.length === 0 ? 'healthy' : 'unhealthy',
|
|
157
|
+
safeguards: {
|
|
158
|
+
total: totalValidated,
|
|
159
|
+
expected: 153,
|
|
160
|
+
complete: totalValidated === 153 && errors.length === 0
|
|
161
|
+
},
|
|
162
|
+
capabilityPrompts: {
|
|
163
|
+
expectedFields: expectedFields.length,
|
|
164
|
+
validatedFields: expectedFields.length
|
|
165
|
+
},
|
|
166
|
+
errors: errors.length,
|
|
167
|
+
errorDetails: errors.slice(0, 10), // Show first 10 errors only
|
|
168
|
+
timestamp: new Date().toISOString()
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
} catch (error) {
|
|
172
|
+
res.status(500).json({
|
|
173
|
+
status: 'error',
|
|
174
|
+
message: 'Failed to validate safeguards data',
|
|
175
|
+
error: error instanceof Error ? error.message : 'Unknown error',
|
|
176
|
+
timestamp: new Date().toISOString()
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
|
|
76
181
|
|
|
77
182
|
|
|
78
183
|
// Get safeguard details endpoint
|
|
@@ -117,7 +222,7 @@ export class FrameworkHttpServer {
|
|
|
117
222
|
this.app.get('/api', (req, res) => {
|
|
118
223
|
res.json({
|
|
119
224
|
name: 'Framework MCP HTTP API',
|
|
120
|
-
version: '
|
|
225
|
+
version: '2.2.2',
|
|
121
226
|
description: 'Pure Data Provider serving authentic CIS Controls Framework data',
|
|
122
227
|
endpoints: {
|
|
123
228
|
'GET /api/safeguards': 'List all available CIS safeguards',
|
|
@@ -168,7 +273,7 @@ export class FrameworkHttpServer {
|
|
|
168
273
|
|
|
169
274
|
public start(): void {
|
|
170
275
|
this.app.listen(this.port, '0.0.0.0', () => {
|
|
171
|
-
console.log(`🚀 Framework MCP HTTP Server
|
|
276
|
+
console.log(`🚀 Framework MCP HTTP Server v2.2.0 running on port ${this.port}`);
|
|
172
277
|
console.log(`📊 Health check: http://localhost:${this.port}/health`);
|
|
173
278
|
console.log(`📖 API docs: http://localhost:${this.port}/api`);
|
|
174
279
|
console.log(`🔧 Environment: ${process.env.NODE_ENV || 'development'}`);
|
|
@@ -18,7 +18,7 @@ export class FrameworkMcpServer {
|
|
|
18
18
|
this.server = new Server(
|
|
19
19
|
{
|
|
20
20
|
name: 'framework-analyzer',
|
|
21
|
-
version: '
|
|
21
|
+
version: '2.2.2',
|
|
22
22
|
}
|
|
23
23
|
);
|
|
24
24
|
|
|
@@ -129,7 +129,7 @@ export class FrameworkMcpServer {
|
|
|
129
129
|
safeguards,
|
|
130
130
|
total: safeguards.length,
|
|
131
131
|
framework: 'CIS Controls v8.1',
|
|
132
|
-
version: '
|
|
132
|
+
version: '2.2.2'
|
|
133
133
|
}, null, 2),
|
|
134
134
|
},
|
|
135
135
|
],
|
|
@@ -153,7 +153,7 @@ export class FrameworkMcpServer {
|
|
|
153
153
|
const transport = new StdioServerTransport();
|
|
154
154
|
await this.server.connect(transport);
|
|
155
155
|
|
|
156
|
-
console.error('🤖 Framework MCP Server
|
|
156
|
+
console.error('🤖 Framework MCP Server v2.2.0 running via stdio');
|
|
157
157
|
console.error('📊 Pure Data Provider for CIS Controls v8.1');
|
|
158
158
|
}
|
|
159
159
|
}
|
package/src/shared/types.ts
CHANGED
|
@@ -1,5 +1,30 @@
|
|
|
1
1
|
// Shared TypeScript types for dual architecture
|
|
2
2
|
|
|
3
|
+
// Enhanced relationship type system for v1.5.4+
|
|
4
|
+
export type RelationshipType =
|
|
5
|
+
| 'dependency' // Must be implemented for this to work
|
|
6
|
+
| 'prerequisite' // Should be implemented first
|
|
7
|
+
| 'complement' // Work together synergistically
|
|
8
|
+
| 'supports' // Enhanced by this safeguard
|
|
9
|
+
| 'validates' // Provides evidence/validation
|
|
10
|
+
| 'governance' // Provides oversight/policy
|
|
11
|
+
| 'sequence'; // Part of logical implementation sequence
|
|
12
|
+
|
|
13
|
+
export type RelationshipStrength =
|
|
14
|
+
| 'critical' // Essential relationship
|
|
15
|
+
| 'strong' // Important relationship
|
|
16
|
+
| 'moderate' // Useful relationship
|
|
17
|
+
| 'weak'; // Minor relationship
|
|
18
|
+
|
|
19
|
+
export interface SafeguardRelationship {
|
|
20
|
+
id: string; // Target safeguard ID
|
|
21
|
+
type: RelationshipType; // Why they're related
|
|
22
|
+
strength: RelationshipStrength; // How important the relationship is
|
|
23
|
+
context: string; // Brief human-readable explanation
|
|
24
|
+
bidirectional: boolean; // Whether reverse relationship exists
|
|
25
|
+
controlGroup?: string; // Optional CIS Control grouping
|
|
26
|
+
}
|
|
27
|
+
|
|
3
28
|
export interface SafeguardElement {
|
|
4
29
|
id: string;
|
|
5
30
|
title: string;
|
|
@@ -12,15 +37,49 @@ export interface SafeguardElement {
|
|
|
12
37
|
coreRequirements: string[]; // Green - The "what" of the safeguard
|
|
13
38
|
subTaxonomicalElements: string[]; // Yellow - Sub-taxonomical elements
|
|
14
39
|
implementationSuggestions: string[]; // Gray - Suggestions for implementation
|
|
40
|
+
|
|
41
|
+
// Backward compatibility - existing consumers still get string[]
|
|
15
42
|
relatedSafeguards: string[];
|
|
16
|
-
|
|
17
|
-
|
|
43
|
+
|
|
44
|
+
// Enhanced relationships - new optional field for rich relationship data
|
|
45
|
+
enhancedRelationships?: SafeguardRelationship[];
|
|
46
|
+
|
|
47
|
+
// Capability-specific system prompts for different evaluation levels
|
|
48
|
+
systemPromptFull?: {
|
|
18
49
|
role: string; // e.g., "asset_inventory_expert", "access_control_specialist"
|
|
19
50
|
context: string; // Brief context about the safeguard for AI understanding
|
|
20
51
|
objective: string; // What the AI should accomplish
|
|
21
52
|
guidelines: string[]; // Specific evaluation criteria and methods
|
|
22
53
|
outputFormat: string; // Expected response structure for n8n processing
|
|
23
54
|
};
|
|
55
|
+
systemPromptPartial?: {
|
|
56
|
+
role: string;
|
|
57
|
+
context: string;
|
|
58
|
+
objective: string;
|
|
59
|
+
guidelines: string[];
|
|
60
|
+
outputFormat: string;
|
|
61
|
+
};
|
|
62
|
+
systemPromptFacilitates?: {
|
|
63
|
+
role: string;
|
|
64
|
+
context: string;
|
|
65
|
+
objective: string;
|
|
66
|
+
guidelines: string[];
|
|
67
|
+
outputFormat: string;
|
|
68
|
+
};
|
|
69
|
+
systemPromptGovernance?: {
|
|
70
|
+
role: string;
|
|
71
|
+
context: string;
|
|
72
|
+
objective: string;
|
|
73
|
+
guidelines: string[];
|
|
74
|
+
outputFormat: string;
|
|
75
|
+
};
|
|
76
|
+
systemPromptValidates?: {
|
|
77
|
+
role: string;
|
|
78
|
+
context: string;
|
|
79
|
+
objective: string;
|
|
80
|
+
guidelines: string[];
|
|
81
|
+
outputFormat: string;
|
|
82
|
+
};
|
|
24
83
|
}
|
|
25
84
|
|
|
26
85
|
export interface VendorAnalysis {
|
|
@@ -69,3 +128,210 @@ export interface QualityAssessment {
|
|
|
69
128
|
|
|
70
129
|
export type CapabilityType = 'full' | 'partial' | 'facilitates' | 'governance' | 'validates';
|
|
71
130
|
|
|
131
|
+
// Utility functions for enhanced relationship system
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Converts SafeguardRelationship[] to string[] for backward compatibility
|
|
135
|
+
*/
|
|
136
|
+
export function relationshipsToStringArray(relationships: SafeguardRelationship[]): string[] {
|
|
137
|
+
return relationships.map(rel => rel.id);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* Converts string[] to basic SafeguardRelationship[] (when migrating legacy data)
|
|
142
|
+
*/
|
|
143
|
+
export function stringArrayToRelationships(
|
|
144
|
+
ids: string[],
|
|
145
|
+
defaultType: RelationshipType = 'supports',
|
|
146
|
+
defaultStrength: RelationshipStrength = 'moderate'
|
|
147
|
+
): SafeguardRelationship[] {
|
|
148
|
+
return ids.map(id => ({
|
|
149
|
+
id,
|
|
150
|
+
type: defaultType,
|
|
151
|
+
strength: defaultStrength,
|
|
152
|
+
context: `Legacy relationship to ${id}`,
|
|
153
|
+
bidirectional: false
|
|
154
|
+
}));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
* Validates that all referenced safeguard IDs exist in the provided set
|
|
159
|
+
*/
|
|
160
|
+
export function validateSafeguardReferences(
|
|
161
|
+
relationships: SafeguardRelationship[],
|
|
162
|
+
validSafeguardIds: Set<string>
|
|
163
|
+
): ValidationResult {
|
|
164
|
+
const invalidIds: string[] = [];
|
|
165
|
+
|
|
166
|
+
for (const rel of relationships) {
|
|
167
|
+
if (!validSafeguardIds.has(rel.id)) {
|
|
168
|
+
invalidIds.push(rel.id);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
return {
|
|
173
|
+
isValid: invalidIds.length === 0,
|
|
174
|
+
errors: invalidIds.map(id => `Invalid safeguard ID reference: ${id}`)
|
|
175
|
+
};
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* Validates bidirectional relationship consistency
|
|
180
|
+
* Returns relationships that claim to be bidirectional but lack reverse relationships
|
|
181
|
+
*/
|
|
182
|
+
export function validateBidirectionalConsistency(
|
|
183
|
+
safeguardId: string,
|
|
184
|
+
relationships: SafeguardRelationship[],
|
|
185
|
+
allSafeguards: Map<string, SafeguardElement>
|
|
186
|
+
): ValidationResult {
|
|
187
|
+
const errors: string[] = [];
|
|
188
|
+
|
|
189
|
+
for (const rel of relationships) {
|
|
190
|
+
if (rel.bidirectional) {
|
|
191
|
+
const targetSafeguard = allSafeguards.get(rel.id);
|
|
192
|
+
if (!targetSafeguard?.enhancedRelationships) {
|
|
193
|
+
errors.push(`Bidirectional relationship with ${rel.id} but target has no enhanced relationships`);
|
|
194
|
+
continue;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
const reverseRelExists = targetSafeguard.enhancedRelationships.some(
|
|
198
|
+
reverseRel => reverseRel.id === safeguardId && reverseRel.bidirectional
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
if (!reverseRelExists) {
|
|
202
|
+
errors.push(`Bidirectional relationship with ${rel.id} but no reverse relationship found`);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return {
|
|
208
|
+
isValid: errors.length === 0,
|
|
209
|
+
errors
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Validates relationship data integrity for a single safeguard
|
|
215
|
+
*/
|
|
216
|
+
export function validateSafeguardRelationships(
|
|
217
|
+
safeguard: SafeguardElement,
|
|
218
|
+
allSafeguards: Map<string, SafeguardElement>
|
|
219
|
+
): ValidationResult {
|
|
220
|
+
const errors: string[] = [];
|
|
221
|
+
|
|
222
|
+
if (!safeguard.enhancedRelationships) {
|
|
223
|
+
// Only validate basic string array consistency
|
|
224
|
+
if (safeguard.relatedSafeguards.length === 0) {
|
|
225
|
+
return { isValid: true, errors: [] };
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
const validIds = new Set(allSafeguards.keys());
|
|
229
|
+
const invalidBasicRefs = safeguard.relatedSafeguards.filter(id => !validIds.has(id));
|
|
230
|
+
if (invalidBasicRefs.length > 0) {
|
|
231
|
+
errors.push(...invalidBasicRefs.map(id => `Invalid basic reference: ${id}`));
|
|
232
|
+
}
|
|
233
|
+
} else {
|
|
234
|
+
// Validate enhanced relationships
|
|
235
|
+
const validIds = new Set(allSafeguards.keys());
|
|
236
|
+
const refValidation = validateSafeguardReferences(safeguard.enhancedRelationships, validIds);
|
|
237
|
+
errors.push(...refValidation.errors);
|
|
238
|
+
|
|
239
|
+
const bidirValidation = validateBidirectionalConsistency(
|
|
240
|
+
safeguard.id,
|
|
241
|
+
safeguard.enhancedRelationships,
|
|
242
|
+
allSafeguards
|
|
243
|
+
);
|
|
244
|
+
errors.push(...bidirValidation.errors);
|
|
245
|
+
|
|
246
|
+
// Validate consistency between legacy and enhanced relationships
|
|
247
|
+
const enhancedIds = new Set(relationshipsToStringArray(safeguard.enhancedRelationships));
|
|
248
|
+
const legacyIds = new Set(safeguard.relatedSafeguards);
|
|
249
|
+
|
|
250
|
+
// Check if legacy array matches enhanced relationships
|
|
251
|
+
if (enhancedIds.size !== legacyIds.size ||
|
|
252
|
+
!Array.from(enhancedIds).every(id => legacyIds.has(id))) {
|
|
253
|
+
errors.push('Mismatch between relatedSafeguards and enhancedRelationships arrays');
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
return {
|
|
258
|
+
isValid: errors.length === 0,
|
|
259
|
+
errors
|
|
260
|
+
};
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
/**
|
|
264
|
+
* Finds potential circular dependencies in relationships
|
|
265
|
+
*/
|
|
266
|
+
export function detectCircularDependencies(
|
|
267
|
+
allSafeguards: Map<string, SafeguardElement>
|
|
268
|
+
): ValidationResult {
|
|
269
|
+
const errors: string[] = [];
|
|
270
|
+
const visited = new Set<string>();
|
|
271
|
+
const recursionStack = new Set<string>();
|
|
272
|
+
|
|
273
|
+
function dfs(safeguardId: string, path: string[]): void {
|
|
274
|
+
if (recursionStack.has(safeguardId)) {
|
|
275
|
+
errors.push(`Circular dependency detected: ${[...path, safeguardId].join(' -> ')}`);
|
|
276
|
+
return;
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (visited.has(safeguardId)) {
|
|
280
|
+
return;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
visited.add(safeguardId);
|
|
284
|
+
recursionStack.add(safeguardId);
|
|
285
|
+
|
|
286
|
+
const safeguard = allSafeguards.get(safeguardId);
|
|
287
|
+
if (safeguard?.enhancedRelationships) {
|
|
288
|
+
const dependencies = safeguard.enhancedRelationships.filter(
|
|
289
|
+
rel => rel.type === 'dependency' || rel.type === 'prerequisite'
|
|
290
|
+
);
|
|
291
|
+
|
|
292
|
+
for (const dep of dependencies) {
|
|
293
|
+
dfs(dep.id, [...path, safeguardId]);
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
recursionStack.delete(safeguardId);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
// Check all safeguards for circular dependencies
|
|
301
|
+
for (const safeguardId of allSafeguards.keys()) {
|
|
302
|
+
if (!visited.has(safeguardId)) {
|
|
303
|
+
dfs(safeguardId, []);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return {
|
|
308
|
+
isValid: errors.length === 0,
|
|
309
|
+
errors
|
|
310
|
+
};
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
export interface ValidationResult {
|
|
314
|
+
isValid: boolean;
|
|
315
|
+
errors: string[];
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Rate Limiting Types (v2.2.0+)
|
|
319
|
+
|
|
320
|
+
/**
|
|
321
|
+
* Configuration for rate limiting middleware
|
|
322
|
+
*/
|
|
323
|
+
export interface RateLimitConfig {
|
|
324
|
+
windowMs: number; // Time window in milliseconds
|
|
325
|
+
max: number; // Maximum requests per window
|
|
326
|
+
skipIps?: string[]; // IP addresses to exempt from rate limiting
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Error response returned when rate limit is exceeded
|
|
331
|
+
*/
|
|
332
|
+
export interface RateLimitErrorResponse {
|
|
333
|
+
error: string; // Error message
|
|
334
|
+
retryAfter?: number; // Seconds until rate limit resets
|
|
335
|
+
timestamp: string; // ISO 8601 timestamp
|
|
336
|
+
}
|
|
337
|
+
|
package/swagger.json
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
"info": {
|
|
4
4
|
"title": "Framework MCP API - Pure Data Provider",
|
|
5
5
|
"description": "Microsoft Copilot-compatible API providing authoritative CIS Controls Framework v8.1 data (153 safeguards). Pure Data Provider architecture empowers LLMs with structured safeguards data and AI-driven systemPrompts for sophisticated, context-aware vendor capability analysis and n8n workflow automation.",
|
|
6
|
-
"version": "
|
|
6
|
+
"version": "2.0.0",
|
|
7
7
|
"contact": {
|
|
8
8
|
"name": "Framework MCP Support",
|
|
9
9
|
"url": "https://github.com/therealcybermattlee/FrameworkMCP"
|
|
@@ -67,7 +67,7 @@
|
|
|
67
67
|
"/api/safeguards/{safeguardId}": {
|
|
68
68
|
"get": {
|
|
69
69
|
"summary": "Get Safeguard Details",
|
|
70
|
-
"description": "Get detailed information about a specific CIS safeguard including governance elements, core requirements, implementation suggestions, and AI-driven
|
|
70
|
+
"description": "Get detailed information about a specific CIS safeguard including governance elements, core requirements, implementation suggestions, and five capability-specific AI-driven system prompts for n8n workflow integration",
|
|
71
71
|
"operationId": "getSafeguardDetails",
|
|
72
72
|
"tags": ["Safeguards"],
|
|
73
73
|
"parameters": [
|
|
@@ -256,40 +256,25 @@
|
|
|
256
256
|
},
|
|
257
257
|
"description": "Implementation methods and suggestions (Gray elements)"
|
|
258
258
|
},
|
|
259
|
-
"
|
|
260
|
-
"
|
|
261
|
-
"description": "AI-driven system prompt for
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
"guidelines": {
|
|
279
|
-
"type": "array",
|
|
280
|
-
"items": {
|
|
281
|
-
"type": "string"
|
|
282
|
-
},
|
|
283
|
-
"description": "Specific evaluation criteria and methods",
|
|
284
|
-
"example": ["Verify coverage of all asset types", "Confirm data collection accuracy"]
|
|
285
|
-
},
|
|
286
|
-
"outputFormat": {
|
|
287
|
-
"type": "string",
|
|
288
|
-
"description": "Expected response structure for n8n processing",
|
|
289
|
-
"example": "Provide structured assessment with capability level (FULL/PARTIAL/FACILITATES/GOVERNANCE/VALIDATES), confidence score, and evidence summary"
|
|
290
|
-
}
|
|
291
|
-
},
|
|
292
|
-
"required": ["role", "context", "objective", "guidelines", "outputFormat"]
|
|
259
|
+
"systemPromptFull": {
|
|
260
|
+
"$ref": "#/components/schemas/SystemPromptStructure",
|
|
261
|
+
"description": "AI-driven system prompt for FULL capability evaluation"
|
|
262
|
+
},
|
|
263
|
+
"systemPromptPartial": {
|
|
264
|
+
"$ref": "#/components/schemas/SystemPromptStructure",
|
|
265
|
+
"description": "AI-driven system prompt for PARTIAL capability evaluation"
|
|
266
|
+
},
|
|
267
|
+
"systemPromptFacilitates": {
|
|
268
|
+
"$ref": "#/components/schemas/SystemPromptStructure",
|
|
269
|
+
"description": "AI-driven system prompt for FACILITATES capability evaluation"
|
|
270
|
+
},
|
|
271
|
+
"systemPromptGovernance": {
|
|
272
|
+
"$ref": "#/components/schemas/SystemPromptStructure",
|
|
273
|
+
"description": "AI-driven system prompt for GOVERNANCE capability evaluation"
|
|
274
|
+
},
|
|
275
|
+
"systemPromptValidates": {
|
|
276
|
+
"$ref": "#/components/schemas/SystemPromptStructure",
|
|
277
|
+
"description": "AI-driven system prompt for VALIDATES capability evaluation"
|
|
293
278
|
}
|
|
294
279
|
}
|
|
295
280
|
},
|
|
@@ -314,7 +299,7 @@
|
|
|
314
299
|
},
|
|
315
300
|
"version": {
|
|
316
301
|
"type": "string",
|
|
317
|
-
"example": "1.5.
|
|
302
|
+
"example": "1.5.3"
|
|
318
303
|
},
|
|
319
304
|
"timestamp": {
|
|
320
305
|
"type": "string",
|
|
@@ -359,7 +344,7 @@
|
|
|
359
344
|
},
|
|
360
345
|
"version": {
|
|
361
346
|
"type": "string",
|
|
362
|
-
"example": "1.5.
|
|
347
|
+
"example": "1.5.3"
|
|
363
348
|
},
|
|
364
349
|
"description": {
|
|
365
350
|
"type": "string",
|
|
@@ -405,6 +390,41 @@
|
|
|
405
390
|
"format": "date-time"
|
|
406
391
|
}
|
|
407
392
|
}
|
|
393
|
+
},
|
|
394
|
+
"SystemPromptStructure": {
|
|
395
|
+
"type": "object",
|
|
396
|
+
"description": "AI-driven system prompt structure for vendor capability analysis",
|
|
397
|
+
"properties": {
|
|
398
|
+
"role": {
|
|
399
|
+
"type": "string",
|
|
400
|
+
"description": "Expert role for the specific control type",
|
|
401
|
+
"example": "asset_inventory_expert"
|
|
402
|
+
},
|
|
403
|
+
"context": {
|
|
404
|
+
"type": "string",
|
|
405
|
+
"description": "Brief context about the safeguard for AI understanding",
|
|
406
|
+
"example": "You are evaluating enterprise asset inventory solutions against CIS Control 1.1 requirements"
|
|
407
|
+
},
|
|
408
|
+
"objective": {
|
|
409
|
+
"type": "string",
|
|
410
|
+
"description": "What the AI should accomplish",
|
|
411
|
+
"example": "Determine if vendor solution provides complete asset inventory capabilities"
|
|
412
|
+
},
|
|
413
|
+
"guidelines": {
|
|
414
|
+
"type": "array",
|
|
415
|
+
"items": {
|
|
416
|
+
"type": "string"
|
|
417
|
+
},
|
|
418
|
+
"description": "Specific evaluation criteria and methods",
|
|
419
|
+
"example": ["Verify coverage of all asset types", "Confirm data collection accuracy"]
|
|
420
|
+
},
|
|
421
|
+
"outputFormat": {
|
|
422
|
+
"type": "string",
|
|
423
|
+
"description": "Expected response structure for n8n processing",
|
|
424
|
+
"example": "Provide structured assessment with capability level (FULL/PARTIAL/FACILITATES/GOVERNANCE/VALIDATES), confidence score, and evidence summary"
|
|
425
|
+
}
|
|
426
|
+
},
|
|
427
|
+
"required": ["role", "context", "objective", "guidelines", "outputFormat"]
|
|
408
428
|
}
|
|
409
429
|
}
|
|
410
430
|
},
|