@greenarmor/ges-mcp-server 1.4.3 → 1.5.1

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.
Files changed (2) hide show
  1. package/dist/server.js +148 -3
  2. package/package.json +12 -12
package/dist/server.js CHANGED
@@ -11,6 +11,7 @@ import { GESF_VERSION, GES_DIR, COMPLIANCE_DIR, SECURITY_DIR, CONTROLS_DIR, POLI
11
11
  import { appendFixHistory, createFixHistoryEntry } from "@greenarmor/ges-core";
12
12
  import { addFrameworkToConfig, removeFrameworkFromConfig, loadControlsFromDisk, getInstalledPackIds, recordActivity, recordAIRecommendation } from "@greenarmor/ges-core";
13
13
  import { loadGovernanceRecords, createGovernanceRecord, addGovernanceRecord, findGovernanceRecord, setGovernanceApproval, addGovernanceEvidence, createEvidenceRef, verifyGovernanceRecord, setGovernanceRiskAssessment, setGovernancePolicyBasis, setGovernanceReviewCycle, setGovernanceDataInventory, setGovernanceComplianceLinks, setGovernanceCommittee, } from "@greenarmor/ges-core";
14
+ import { loadFixAssignments, createFixAssignment, addFixAssignment, resolveFixAssignment, findFixAssignmentsForRecord, } from "@greenarmor/ges-core";
14
15
  import { ProjectConfigSchema } from "@greenarmor/ges-core";
15
16
  import { generateComplianceDocs, generateSecurityDocs, generateConfigJson, generateMetadataJson, generateFrameworkVersionJson, generateScoreJson } from "@greenarmor/ges-doc-generator";
16
17
  import { generateAllWorkflows } from "@greenarmor/ges-cicd-generator";
@@ -682,6 +683,60 @@ const TOOLS = [
682
683
  required: ["project_path", "record_id"],
683
684
  },
684
685
  },
686
+ {
687
+ name: "assign_fix_to_governance",
688
+ description: "Assign a pending audit finding (fix) to an existing governance provenance record. Creates a traceable link between a specific security finding and the governance chain (who approved the system, under what policy, what risk assessment supports it). Requires a finding_key (ruleId:file:line), governance record ID, and assignee name.",
689
+ inputSchema: {
690
+ type: "object",
691
+ properties: {
692
+ project_path: { type: "string", description: "Absolute path to the project root." },
693
+ finding_key: { type: "string", description: "Finding identifier in format ruleId:file:line (e.g., SECRETS-001:src/auth.ts:42)." },
694
+ finding_rule_id: { type: "string", description: "The rule ID of the finding (e.g., SECRETS-001)." },
695
+ finding_title: { type: "string", description: "Title of the finding." },
696
+ finding_file: { type: "string", description: "File path of the finding." },
697
+ finding_line: { type: "number", description: "Line number of the finding." },
698
+ finding_severity: { type: "string", description: "Severity: critical, high, medium, or low." },
699
+ finding_control_ids: { type: "string", description: "Control IDs linked to this finding (comma-separated)." },
700
+ governance_record_id: { type: "string", description: "Governance record ID or system name to link this fix to." },
701
+ assignee: { type: "string", description: "Name of the person assigned to fix this." },
702
+ assignee_role: { type: "string", description: "Role of the assignee." },
703
+ notes: { type: "string", description: "Optional notes for this assignment." },
704
+ actor_name: { type: "string", description: "Name of the person making this assignment." },
705
+ actor_role: { type: "string", description: "Role of the person making this assignment." },
706
+ },
707
+ required: ["project_path", "finding_key", "governance_record_id", "assignee"],
708
+ },
709
+ },
710
+ {
711
+ name: "list_fix_assignments",
712
+ description: "List all fix assignments linking pending audit findings to governance provenance records. Shows which fixes are assigned, to whom, linked to which governance record, and their status (assigned, in-progress, fixed, verified).",
713
+ inputSchema: {
714
+ type: "object",
715
+ properties: {
716
+ project_path: { type: "string", description: "Absolute path to the project root." },
717
+ governance_record_id: { type: "string", description: "Optional: filter assignments by governance record ID." },
718
+ },
719
+ required: ["project_path"],
720
+ },
721
+ },
722
+ {
723
+ name: "resolve_fix_assignment",
724
+ description: "Resolve (mark as fixed) a fix assignment that was linked to a governance record. Records who resolved it, the method used (auto-fix, manual, not-applicable), and resolution notes. Updates the provenance chain to show the fix has been addressed.",
725
+ inputSchema: {
726
+ type: "object",
727
+ properties: {
728
+ project_path: { type: "string", description: "Absolute path to the project root." },
729
+ finding_key: { type: "string", description: "Finding key (ruleId:file:line) of the assignment to resolve." },
730
+ resolved_by: { type: "string", description: "Name of the person who resolved the fix." },
731
+ resolved_by_role: { type: "string", description: "Role of the resolver." },
732
+ method: { type: "string", description: "Resolution method: auto-fix, manual, or not-applicable." },
733
+ resolution_notes: { type: "string", description: "Notes about how the fix was resolved." },
734
+ actor_name: { type: "string", description: "Name of the person performing this action." },
735
+ actor_role: { type: "string", description: "Role of the person performing this action." },
736
+ },
737
+ required: ["project_path", "finding_key", "resolved_by"],
738
+ },
739
+ },
685
740
  ];
686
741
  function send(message) {
687
742
  process.stdout.write(JSON.stringify(message) + "\n");
@@ -3086,13 +3141,13 @@ export function handleRequest(request) {
3086
3141
  if (fs.existsSync(gitignorePath)) {
3087
3142
  const existingGitignore = fs.readFileSync(gitignorePath, "utf-8");
3088
3143
  if (!existingGitignore.includes(".dev-logs/")) {
3089
- fs.appendFileSync(gitignorePath, `\n# GESF developer logs (not for remote)\n${devLogsIgnore}`);
3144
+ fs.appendFileSync(gitignorePath, `\n# GESF developer logs (developer-only, not for remote)\n${devLogsIgnore}`);
3090
3145
  }
3091
3146
  }
3092
3147
  else {
3093
- fs.writeFileSync(gitignorePath, `# GESF developer logs (not for remote)\n${devLogsIgnore}\n`);
3148
+ fs.writeFileSync(gitignorePath, `# GESF developer logs (developer-only, not for remote)\n${devLogsIgnore}\n`);
3094
3149
  }
3095
- fs.writeFileSync(path.join(projectPath, ".dev-logs", "README.md"), `# Developer Logs\n\nThis directory is for GESF development notes, session logs, AI recommendations, and release notes.\n\n**This directory is gitignored and intended for developers only. Do not submit to remote.**\n`);
3150
+ fs.writeFileSync(path.join(projectPath, ".dev-logs", "README.md"), `# Developer Logs\n\nThis directory is part of GESF — the Green Engineering Standard Framework.\n\nIt stores development notes, session logs, AI assistant recommendations, and release notes for your project.\n\n**This directory is gitignored and intended for developers only. Do not submit to remote.**\n`);
3096
3151
  const complianceDocs = generateComplianceDocs(projectName, projectType);
3097
3152
  for (const doc of complianceDocs) {
3098
3153
  const filePath = path.join(projectPath, COMPLIANCE_DIR, doc.filePath);
@@ -4157,6 +4212,96 @@ export function handleRequest(request) {
4157
4212
  resultText = `# Compliance Links Mapped\n\n**System**: ${updated.system_name}\n**Frameworks**: ${frameworks.join(", ") || "(none)"}\n**Controls**: ${controls.length}`;
4158
4213
  break;
4159
4214
  }
4215
+ case "assign_fix_to_governance": {
4216
+ const projectPath = resolveProjectPath(args.project_path);
4217
+ const fk = String(args.finding_key || "");
4218
+ const recordId = String(args.governance_record_id || "");
4219
+ const assignee = String(args.assignee || "");
4220
+ if (!fk || !recordId || !assignee) {
4221
+ resultText = "Error: finding_key, governance_record_id, and assignee are required.";
4222
+ break;
4223
+ }
4224
+ const record = findGovernanceRecord(projectPath, recordId);
4225
+ if (!record) {
4226
+ resultText = `Error: Governance record "${recordId}" not found.`;
4227
+ break;
4228
+ }
4229
+ const controlIds = args.finding_control_ids ? String(args.finding_control_ids).split(",").map((s) => s.trim()).filter(Boolean) : [];
4230
+ const assignment = createFixAssignment({
4231
+ finding_key: fk,
4232
+ finding_rule_id: String(args.finding_rule_id || ""),
4233
+ finding_title: String(args.finding_title || ""),
4234
+ finding_file: String(args.finding_file || ""),
4235
+ finding_line: args.finding_line ? Number(args.finding_line) : undefined,
4236
+ finding_severity: args.finding_severity || "medium",
4237
+ finding_control_ids: controlIds,
4238
+ governance_record_id: record.id,
4239
+ governance_system_name: record.system_name,
4240
+ assignee,
4241
+ assignee_role: String(args.assignee_role || ""),
4242
+ assigned_by: String(args.actor_name || "mcp"),
4243
+ notes: String(args.notes || ""),
4244
+ });
4245
+ addFixAssignment(projectPath, assignment);
4246
+ recordActivity(projectPath, {
4247
+ source: "mcp",
4248
+ action: "fix_assign",
4249
+ title: `Fix assigned: ${assignment.finding_rule_id} → ${record.system_name}`,
4250
+ description: `Assigned ${assignment.finding_rule_id} (${assignment.finding_title}) to ${assignee}, linked to ${record.system_name}.`,
4251
+ details: { finding_key: fk, governance_record_id: record.id, assignee },
4252
+ actor_name: args.actor_name,
4253
+ actor_role: args.actor_role,
4254
+ });
4255
+ resultText = `# Fix Assigned to Governance Record\n\n**Finding**: ${assignment.finding_rule_id} — ${assignment.finding_title}\n**Finding Key**: ${fk}\n**Governance Record**: ${record.system_name} (${record.id})\n**Assignee**: ${assignee}${args.assignee_role ? " (" + args.assignee_role + ")" : ""}\n**Status**: assigned\n\n## Provenance Chain\n- **System**: ${record.system_name}\n- **Approval**: ${record.approval ? record.approval.approver_name + " (" + record.approval.approval_authority + ")" : "No approval recorded"}\n- **Policy**: ${record.policy_basis ? record.policy_basis.policy_name : "No policy documented"}\n- **Risk**: ${record.risk_assessment ? record.risk_assessment.risk_score : "No risk assessment"}`;
4256
+ break;
4257
+ }
4258
+ case "list_fix_assignments": {
4259
+ const projectPath = resolveProjectPath(args.project_path);
4260
+ const all = loadFixAssignments(projectPath);
4261
+ const filtered = args.governance_record_id
4262
+ ? findFixAssignmentsForRecord(projectPath, String(args.governance_record_id))
4263
+ : all;
4264
+ if (filtered.length === 0) {
4265
+ resultText = "No fix assignments found.";
4266
+ break;
4267
+ }
4268
+ const lines = filtered.map((a) => {
4269
+ return `| ${a.status} | ${a.finding_rule_id} | ${a.finding_title} | ${a.governance_system_name} | ${a.assignee}${a.assignee_role ? " (" + a.assignee_role + ")" : ""} | ${a.finding_key} |`;
4270
+ });
4271
+ resultText = `# Fix Assignments (${filtered.length})\n\n| Status | Rule | Title | Governance Record | Assignee | Finding Key |\n|--------|------|-------|-------------------|----------|------------|\n${lines.join("\n")}`;
4272
+ break;
4273
+ }
4274
+ case "resolve_fix_assignment": {
4275
+ const projectPath = resolveProjectPath(args.project_path);
4276
+ const fk = String(args.finding_key || "");
4277
+ const resolver = String(args.resolved_by || "");
4278
+ if (!fk || !resolver) {
4279
+ resultText = "Error: finding_key and resolved_by are required.";
4280
+ break;
4281
+ }
4282
+ const method = args.method || "manual";
4283
+ const resolved = resolveFixAssignment(projectPath, fk, {
4284
+ resolved_by: resolver,
4285
+ resolved_by_role: String(args.resolved_by_role || ""),
4286
+ method,
4287
+ resolution_notes: String(args.resolution_notes || ""),
4288
+ });
4289
+ if (!resolved) {
4290
+ resultText = `Error: Fix assignment not found for finding_key: ${fk}`;
4291
+ break;
4292
+ }
4293
+ recordActivity(projectPath, {
4294
+ source: "mcp",
4295
+ action: "fix_resolve",
4296
+ title: `Fix resolved: ${resolved.finding_rule_id}`,
4297
+ description: `Resolved ${resolved.finding_rule_id} via ${method} by ${resolver}.`,
4298
+ details: { finding_key: fk, governance_record_id: resolved.governance_record_id, method },
4299
+ actor_name: args.actor_name,
4300
+ actor_role: args.actor_role,
4301
+ });
4302
+ resultText = `# Fix Resolved\n\n**Finding**: ${resolved.finding_rule_id} — ${resolved.finding_title}\n**Governance Record**: ${resolved.governance_system_name}\n**Resolved By**: ${resolver}\n**Method**: ${method}\n**Status**: fixed`;
4303
+ break;
4304
+ }
4160
4305
  default:
4161
4306
  return {
4162
4307
  jsonrpc: "2.0",
package/package.json CHANGED
@@ -3,17 +3,17 @@
3
3
  "ges-mcp": "dist/server.js"
4
4
  },
5
5
  "dependencies": {
6
- "@greenarmor/ges-audit-engine": "1.4.3",
7
- "@greenarmor/ges-cicd-generator": "1.4.3",
8
- "@greenarmor/ges-compliance-engine": "1.4.3",
9
- "@greenarmor/ges-core": "1.4.3",
10
- "@greenarmor/ges-doc-generator": "1.4.3",
11
- "@greenarmor/ges-policy-engine": "1.4.3",
12
- "@greenarmor/ges-report-generator": "1.4.3",
13
- "@greenarmor/ges-rules-engine": "1.4.3",
14
- "@greenarmor/ges-scanner-integration": "1.4.3",
15
- "@greenarmor/ges-scoring-engine": "1.4.3",
16
- "@greenarmor/ges-web-dashboard": "1.4.3"
6
+ "@greenarmor/ges-audit-engine": "1.5.1",
7
+ "@greenarmor/ges-cicd-generator": "1.5.1",
8
+ "@greenarmor/ges-compliance-engine": "1.5.1",
9
+ "@greenarmor/ges-core": "1.5.1",
10
+ "@greenarmor/ges-doc-generator": "1.5.1",
11
+ "@greenarmor/ges-policy-engine": "1.5.1",
12
+ "@greenarmor/ges-report-generator": "1.5.1",
13
+ "@greenarmor/ges-rules-engine": "1.5.1",
14
+ "@greenarmor/ges-scanner-integration": "1.5.1",
15
+ "@greenarmor/ges-scoring-engine": "1.5.1",
16
+ "@greenarmor/ges-web-dashboard": "1.5.1"
17
17
  },
18
18
  "description": "GESF MCP Server - AI Compliance Assistant for GDPR, OWASP, NIST, CIS. Check compliance, generate policies, assess risks via MCP protocol.",
19
19
  "devDependencies": {
@@ -67,7 +67,7 @@
67
67
  },
68
68
  "type": "module",
69
69
  "types": "./dist/index.d.ts",
70
- "version": "1.4.3",
70
+ "version": "1.5.1",
71
71
  "scripts": {
72
72
  "build": "tsc",
73
73
  "clean": "rm -rf dist bundle tsconfig.tsbuildinfo",