@kaademos/secure-sdlc 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/.claude/agents/ai-security-engineer.md +209 -0
  2. package/.claude/agents/appsec-engineer.md +131 -0
  3. package/.claude/agents/cloud-platform-engineer.md +119 -0
  4. package/.claude/agents/dev-lead.md +138 -0
  5. package/.claude/agents/grc-analyst.md +143 -0
  6. package/.claude/agents/product-manager.md +100 -0
  7. package/.claude/agents/release-manager.md +126 -0
  8. package/.claude/agents/security-champion.md +148 -0
  9. package/.cursor/rules/secure-sdlc.mdc +98 -0
  10. package/.github/workflows/secure-sdlc-gate.yml +325 -0
  11. package/CHANGELOG.md +49 -0
  12. package/CLAUDE.md +195 -0
  13. package/LICENSE +21 -0
  14. package/README.md +394 -0
  15. package/cli/bin/secure-sdlc.js +95 -0
  16. package/cli/src/commands/gate.js +129 -0
  17. package/cli/src/commands/init.js +219 -0
  18. package/cli/src/commands/install-mcp.js +121 -0
  19. package/cli/src/commands/kickoff.js +261 -0
  20. package/cli/src/commands/paths.js +33 -0
  21. package/cli/src/commands/review.js +53 -0
  22. package/cli/src/commands/status.js +122 -0
  23. package/cli/src/utils/banner.js +43 -0
  24. package/cli/src/utils/package-root.js +23 -0
  25. package/cli/src/utils/phase-detect.js +107 -0
  26. package/cli/src/utils/stack-detect.js +138 -0
  27. package/docs/templates/compliance-attestation.md +159 -0
  28. package/docs/templates/infra-security-review.md +133 -0
  29. package/docs/templates/release-sign-off.md +119 -0
  30. package/docs/templates/risk-register.md +72 -0
  31. package/docs/templates/sast-findings.md +110 -0
  32. package/docs/templates/security-requirements.md +98 -0
  33. package/docs/templates/test-security-report.md +143 -0
  34. package/docs/templates/threat-model.md +129 -0
  35. package/hooks/install.sh +37 -0
  36. package/hooks/pre-commit +208 -0
  37. package/hooks/pre-push +127 -0
  38. package/mcp/README.md +116 -0
  39. package/mcp/package.json +23 -0
  40. package/mcp/src/server.js +638 -0
  41. package/package.json +67 -0
  42. package/stacks/django.md +216 -0
  43. package/stacks/express.md +229 -0
  44. package/stacks/fastapi.md +247 -0
  45. package/stacks/nextjs.md +198 -0
  46. package/stacks/nodejs.md +28 -0
  47. package/stacks/rails.md +247 -0
  48. package/warp-workflows/README.md +25 -0
  49. package/warp-workflows/feature-kickoff.yaml +49 -0
  50. package/warp-workflows/pr-security-review.yaml +47 -0
  51. package/warp-workflows/release-gate.yaml +44 -0
  52. package/warp-workflows/sdlc-status.yaml +48 -0
  53. package/warp-workflows/threat-model.yaml +56 -0
@@ -0,0 +1,638 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * Secure SDLC MCP Server
4
+ *
5
+ * Exposes the full Secure SDLC agent team as MCP tools, compatible with:
6
+ * - Cursor (via MCP settings)
7
+ * - Claude Code (via mcp__* tools)
8
+ * - Windsurf, Zed, Continue, and any MCP-compliant host
9
+ *
10
+ * Each tool invokes the appropriate specialist agent with the right context
11
+ * and returns structured, actionable guidance.
12
+ */
13
+
14
+ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
15
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
16
+ import {
17
+ CallToolRequestSchema,
18
+ ListToolsRequestSchema,
19
+ } from "@modelcontextprotocol/sdk/types.js";
20
+ import { readFileSync, existsSync, mkdirSync, writeFileSync } from "fs";
21
+ import { join, dirname } from "path";
22
+ import { fileURLToPath } from "url";
23
+
24
+ const __dirname = dirname(fileURLToPath(import.meta.url));
25
+ const AGENTS_DIR = join(__dirname, "../../.claude/agents");
26
+ const TEMPLATES_DIR = join(__dirname, "../../docs/templates");
27
+
28
+ function readAgentPrompt(agentName) {
29
+ const path = join(AGENTS_DIR, `${agentName}.md`);
30
+ if (!existsSync(path)) return null;
31
+ const raw = readFileSync(path, "utf-8");
32
+ // Strip YAML frontmatter
33
+ return raw.replace(/^---[\s\S]*?---\n/, "").trim();
34
+ }
35
+
36
+ function readTemplate(templateName) {
37
+ const path = join(TEMPLATES_DIR, `${templateName}.md`);
38
+ if (!existsSync(path)) return null;
39
+ return readFileSync(path, "utf-8");
40
+ }
41
+
42
+ function ensureDocsDir(projectRoot) {
43
+ const docsDir = join(projectRoot, "docs", "audit-evidence");
44
+ mkdirSync(docsDir, { recursive: true });
45
+ return join(projectRoot, "docs");
46
+ }
47
+
48
+ // ──────────────────────────────────────────────────────────────────────────────
49
+ // Tool definitions
50
+ // ──────────────────────────────────────────────────────────────────────────────
51
+
52
+ const TOOLS = [
53
+ {
54
+ name: "sdlc_plan_feature",
55
+ description:
56
+ "Start a new feature or project with secure requirements and compliance mapping. " +
57
+ "Invokes the product-manager (ASVS requirements) and grc-analyst (risk register, framework mapping) agents. " +
58
+ "Use this at the very beginning of any new feature, sprint, or project.",
59
+ inputSchema: {
60
+ type: "object",
61
+ properties: {
62
+ feature_description: {
63
+ type: "string",
64
+ description:
65
+ "What you are building — be specific about actors, data handled, and integrations",
66
+ },
67
+ stack: {
68
+ type: "string",
69
+ description:
70
+ "Technology stack (e.g. 'Next.js + PostgreSQL + Vercel', 'Python FastAPI + AWS')",
71
+ },
72
+ asvs_level: {
73
+ type: "string",
74
+ enum: ["L1", "L2", "L3"],
75
+ default: "L2",
76
+ description:
77
+ "OWASP ASVS assurance level. L1=basic, L2=standard (default), L3=high-assurance/regulated",
78
+ },
79
+ compliance_frameworks: {
80
+ type: "array",
81
+ items: { type: "string" },
82
+ description:
83
+ "Applicable compliance frameworks (e.g. ['SOC2', 'GDPR', 'PCI-DSS', 'HIPAA'])",
84
+ },
85
+ project_root: {
86
+ type: "string",
87
+ description: "Absolute path to the project root directory",
88
+ },
89
+ },
90
+ required: ["feature_description"],
91
+ },
92
+ },
93
+ {
94
+ name: "sdlc_threat_model",
95
+ description:
96
+ "Run a structured STRIDE (and optionally LINDDUN) threat model against a proposed architecture. " +
97
+ "Invokes the appsec-engineer agent. Use after requirements are written, before implementation begins.",
98
+ inputSchema: {
99
+ type: "object",
100
+ properties: {
101
+ architecture_description: {
102
+ type: "string",
103
+ description:
104
+ "Description of the architecture: components, data flows, trust boundaries, protocols, auth mechanisms",
105
+ },
106
+ pii_in_scope: {
107
+ type: "boolean",
108
+ default: false,
109
+ description: "Set true to also run LINDDUN privacy threat modelling",
110
+ },
111
+ security_requirements_path: {
112
+ type: "string",
113
+ description:
114
+ "Optional path to docs/security-requirements.md to anchor the model to requirements",
115
+ },
116
+ project_root: {
117
+ type: "string",
118
+ description: "Absolute path to the project root directory",
119
+ },
120
+ },
121
+ required: ["architecture_description"],
122
+ },
123
+ },
124
+ {
125
+ name: "sdlc_review_pr",
126
+ description:
127
+ "Security review a pull request or code diff. Runs the dev-lead (secure coding, SCA) " +
128
+ "and appsec-engineer (vulnerability triage) agents. Use before merging any PR.",
129
+ inputSchema: {
130
+ type: "object",
131
+ properties: {
132
+ pr_description: {
133
+ type: "string",
134
+ description: "What the PR does — describe the change",
135
+ },
136
+ code_diff: {
137
+ type: "string",
138
+ description:
139
+ "The actual code diff or the most security-relevant changed files/functions",
140
+ },
141
+ pr_number: {
142
+ type: "string",
143
+ description: "PR number or identifier (e.g. '#42')",
144
+ },
145
+ language_stack: {
146
+ type: "string",
147
+ description:
148
+ "Language and framework (e.g. 'TypeScript/Next.js', 'Python/FastAPI')",
149
+ },
150
+ new_dependencies: {
151
+ type: "array",
152
+ items: { type: "string" },
153
+ description:
154
+ "List of new packages added (e.g. ['express@4.18.2', 'jsonwebtoken@9.0.0'])",
155
+ },
156
+ },
157
+ required: ["pr_description"],
158
+ },
159
+ },
160
+ {
161
+ name: "sdlc_review_infra",
162
+ description:
163
+ "Security review infrastructure-as-code (Terraform, Pulumi, CloudFormation, Helm, Kubernetes manifests). " +
164
+ "Invokes the cloud-platform-engineer agent. Checks for misconfigurations, IAM issues, secrets, and hardening gaps.",
165
+ inputSchema: {
166
+ type: "object",
167
+ properties: {
168
+ iac_description: {
169
+ type: "string",
170
+ description: "What infrastructure is being provisioned or changed",
171
+ },
172
+ iac_content: {
173
+ type: "string",
174
+ description:
175
+ "The IaC code to review (Terraform HCL, YAML manifests, etc.)",
176
+ },
177
+ cloud_provider: {
178
+ type: "string",
179
+ enum: ["AWS", "GCP", "Azure", "Multi-cloud", "On-prem", "Other"],
180
+ description: "Cloud provider or deployment target",
181
+ },
182
+ environment: {
183
+ type: "string",
184
+ enum: ["development", "staging", "production"],
185
+ description: "Target environment",
186
+ },
187
+ },
188
+ required: ["iac_description"],
189
+ },
190
+ },
191
+ {
192
+ name: "sdlc_triage_sast",
193
+ description:
194
+ "Triage SAST (static analysis) findings from any tool — Semgrep, Snyk Code, CodeQL, Checkmarx, Bandit, etc. " +
195
+ "Invokes the appsec-engineer agent to confirm, rate severity, and provide developer-friendly remediation.",
196
+ inputSchema: {
197
+ type: "object",
198
+ properties: {
199
+ findings: {
200
+ type: "string",
201
+ description:
202
+ "The raw SAST output or a description of the findings to triage",
203
+ },
204
+ tool: {
205
+ type: "string",
206
+ description: "SAST tool that produced the findings (e.g. 'Semgrep', 'Snyk Code')",
207
+ },
208
+ language: {
209
+ type: "string",
210
+ description: "Language of the scanned code",
211
+ },
212
+ },
213
+ required: ["findings"],
214
+ },
215
+ },
216
+ {
217
+ name: "sdlc_release_gate",
218
+ description:
219
+ "Run the pre-release security gate. Aggregates all phase artefacts, applies severity thresholds, " +
220
+ "and produces a formal go/no-go decision. Invokes the release-manager agent. " +
221
+ "Must be run before any production deployment.",
222
+ inputSchema: {
223
+ type: "object",
224
+ properties: {
225
+ version: {
226
+ type: "string",
227
+ description: "Release version (e.g. 'v1.2.0', 'v2024-10-sprint-3')",
228
+ },
229
+ docs_path: {
230
+ type: "string",
231
+ description: "Path to the docs/ directory containing all phase artefacts",
232
+ },
233
+ open_findings_summary: {
234
+ type: "string",
235
+ description:
236
+ "Optional summary of any outstanding findings that require gate evaluation",
237
+ },
238
+ },
239
+ required: ["version"],
240
+ },
241
+ },
242
+ {
243
+ name: "sdlc_check_compliance",
244
+ description:
245
+ "Map technical security controls to compliance framework requirements and identify gaps. " +
246
+ "Invokes the grc-analyst agent. Use when preparing for audits or assessing compliance posture.",
247
+ inputSchema: {
248
+ type: "object",
249
+ properties: {
250
+ controls_implemented: {
251
+ type: "string",
252
+ description:
253
+ "Description of security controls currently in place (or reference to docs/)",
254
+ },
255
+ frameworks: {
256
+ type: "array",
257
+ items: { type: "string" },
258
+ description: "Frameworks to map against (e.g. ['SOC2', 'ISO27001', 'GDPR'])",
259
+ },
260
+ data_types: {
261
+ type: "string",
262
+ description:
263
+ "Types of data processed (PII, PHI, PCI, IP, etc.) to scope framework applicability",
264
+ },
265
+ },
266
+ required: ["controls_implemented", "frameworks"],
267
+ },
268
+ },
269
+ {
270
+ name: "sdlc_init_project",
271
+ description:
272
+ "Initialise a new project with the full Secure SDLC scaffold: docs directory, templates, " +
273
+ "and a project security config. Returns setup instructions tailored to the detected stack.",
274
+ inputSchema: {
275
+ type: "object",
276
+ properties: {
277
+ project_root: {
278
+ type: "string",
279
+ description: "Absolute path to the project root directory",
280
+ },
281
+ project_name: {
282
+ type: "string",
283
+ description: "Name of the project or application",
284
+ },
285
+ stack: {
286
+ type: "string",
287
+ description: "Technology stack description",
288
+ },
289
+ team_size: {
290
+ type: "string",
291
+ enum: ["solo", "small (2-5)", "medium (6-20)", "large (20+)"],
292
+ description: "Team size to calibrate process overhead",
293
+ },
294
+ },
295
+ required: ["project_root", "project_name"],
296
+ },
297
+ },
298
+ {
299
+ name: "sdlc_security_champion",
300
+ description:
301
+ "First-line security review and developer coaching from the security champion perspective. " +
302
+ "Lower friction than a full appsec review — use for quick security questions, " +
303
+ "reviewing small changes, or when learning secure coding patterns.",
304
+ inputSchema: {
305
+ type: "object",
306
+ properties: {
307
+ question_or_code: {
308
+ type: "string",
309
+ description:
310
+ "Security question to answer, or code/implementation to quickly review",
311
+ },
312
+ context: {
313
+ type: "string",
314
+ description:
315
+ "What you are building and why — helps the champion give relevant advice",
316
+ },
317
+ },
318
+ required: ["question_or_code"],
319
+ },
320
+ },
321
+ {
322
+ name: "sdlc_ai_security_review",
323
+ description:
324
+ "Security review for AI/LLM features: prompt injection, model poisoning, data leakage, " +
325
+ "agent trust boundaries, and AI supply chain risks. Invokes the ai-security-engineer agent.",
326
+ inputSchema: {
327
+ type: "object",
328
+ properties: {
329
+ ai_feature_description: {
330
+ type: "string",
331
+ description:
332
+ "Describe the AI/LLM feature: what model, what inputs it accepts, what it outputs, " +
333
+ "what tools/functions it can call, and what data it accesses",
334
+ },
335
+ attack_surface: {
336
+ type: "string",
337
+ description:
338
+ "Who can send input to the AI feature? (public users, authenticated users, internal services, etc.)",
339
+ },
340
+ },
341
+ required: ["ai_feature_description"],
342
+ },
343
+ },
344
+ ];
345
+
346
+ // ──────────────────────────────────────────────────────────────────────────────
347
+ // Tool handlers
348
+ // ──────────────────────────────────────────────────────────────────────────────
349
+
350
+ function buildPromptPrefix(agentName) {
351
+ const prompt = readAgentPrompt(agentName);
352
+ return prompt
353
+ ? `You are operating as the ${agentName} agent in the Secure SDLC team.\n\n${prompt}\n\n---\n\n`
354
+ : "";
355
+ }
356
+
357
+ function handlePlanFeature(args) {
358
+ const { feature_description, stack, asvs_level = "L2", compliance_frameworks = [], project_root } = args;
359
+
360
+ const pmPrompt = buildPromptPrefix("product-manager");
361
+ const grcPrompt = buildPromptPrefix("grc-analyst");
362
+ const template = readTemplate("security-requirements");
363
+
364
+ let output = `${pmPrompt}`;
365
+ output += `## Task: Produce Security Requirements + Risk Register\n\n`;
366
+ output += `**Feature:** ${feature_description}\n`;
367
+ if (stack) output += `**Stack:** ${stack}\n`;
368
+ output += `**ASVS Target Level:** ${asvs_level}\n`;
369
+ if (compliance_frameworks.length) {
370
+ output += `**Compliance Frameworks:** ${compliance_frameworks.join(", ")}\n`;
371
+ }
372
+ output += `\n### Step 1 — Product Manager: Security Requirements\n\n`;
373
+ output += `Using the elicitation checklist in your agent instructions, produce a complete `;
374
+ output += `security-requirements.md for this feature. Map every requirement to ASVS ${asvs_level} controls.\n\n`;
375
+ output += `Then, acting as the GRC Analyst:\n\n${grcPrompt}\n\n`;
376
+ output += `### Step 2 — GRC Analyst: Risk Register + Compliance Mapping\n\n`;
377
+ output += `Initialise the risk register for this feature. Identify the top 5-8 risks. `;
378
+ if (compliance_frameworks.length) {
379
+ output += `Map ASVS requirements to these frameworks: ${compliance_frameworks.join(", ")}. `;
380
+ }
381
+ output += `Produce the control mapping table.\n\n`;
382
+ if (project_root) {
383
+ output += `Save outputs to:\n- ${project_root}/docs/security-requirements.md\n- ${project_root}/docs/risk-register.md\n\n`;
384
+ }
385
+ if (template) {
386
+ output += `Use this template for security-requirements.md:\n\n${template}\n`;
387
+ }
388
+
389
+ return {
390
+ content: [{ type: "text", text: output }],
391
+ };
392
+ }
393
+
394
+ function handleThreatModel(args) {
395
+ const { architecture_description, pii_in_scope = false, security_requirements_path, project_root } = args;
396
+
397
+ const prompt = buildPromptPrefix("appsec-engineer");
398
+ const template = readTemplate("threat-model");
399
+
400
+ let output = `${prompt}## Task: Threat Model\n\n`;
401
+ output += `**Architecture:**\n${architecture_description}\n\n`;
402
+ output += `Perform a complete STRIDE threat model. For each component and data flow:\n`;
403
+ output += `1. Enumerate all STRIDE threats (Spoofing, Tampering, Repudiation, Info Disclosure, DoS, Elevation of Privilege)\n`;
404
+ output += `2. Rate Likelihood (Low/Medium/High) and Impact (Medium/High/Critical)\n`;
405
+ output += `3. Derive a Risk Rating (LOW/MEDIUM/HIGH/CRITICAL)\n`;
406
+ output += `4. Specify a concrete mitigation\n\n`;
407
+ if (pii_in_scope) {
408
+ output += `Also perform **LINDDUN privacy threat modelling** — this feature handles personal data.\n\n`;
409
+ }
410
+ if (security_requirements_path) {
411
+ output += `Reference the security requirements at: ${security_requirements_path}\n\n`;
412
+ }
413
+ output += `Produce a threat summary table and a prioritised list of mitigations for the dev team.\n\n`;
414
+ if (project_root) {
415
+ output += `Save output to: ${project_root}/docs/threat-model.md\n\n`;
416
+ }
417
+ if (template) {
418
+ output += `Use this template:\n\n${template}\n`;
419
+ }
420
+
421
+ return { content: [{ type: "text", text: output }] };
422
+ }
423
+
424
+ function handleReviewPR(args) {
425
+ const { pr_description, code_diff, pr_number, language_stack, new_dependencies = [] } = args;
426
+
427
+ const devLeadPrompt = buildPromptPrefix("dev-lead");
428
+ const appsecPrompt = buildPromptPrefix("appsec-engineer");
429
+
430
+ let output = `${devLeadPrompt}## Task: Security Review${pr_number ? ` — PR ${pr_number}` : ""}\n\n`;
431
+ output += `**Change description:** ${pr_description}\n`;
432
+ if (language_stack) output += `**Stack:** ${language_stack}\n`;
433
+ if (new_dependencies.length) {
434
+ output += `**New dependencies:** ${new_dependencies.join(", ")}\n`;
435
+ }
436
+ output += `\n`;
437
+ if (code_diff) {
438
+ output += `**Code to review:**\n\`\`\`\n${code_diff}\n\`\`\`\n\n`;
439
+ }
440
+ output += `Using the PR checklist in your agent instructions, review this change for security issues.\n`;
441
+ output += `Structure your feedback as: Critical/High (block merge) → Medium (should fix) → Low/Info → Positive observations.\n\n`;
442
+ if (new_dependencies.length) {
443
+ output += `${appsecPrompt}Also review the new dependencies for CVEs, maintenance status, and supply chain risk.\n\n`;
444
+ }
445
+ output += `Reference docs/security-requirements.md if it exists in the project.\n`;
446
+
447
+ return { content: [{ type: "text", text: output }] };
448
+ }
449
+
450
+ function handleReviewInfra(args) {
451
+ const { iac_description, iac_content, cloud_provider, environment } = args;
452
+
453
+ const prompt = buildPromptPrefix("cloud-platform-engineer");
454
+ const template = readTemplate("infra-security-review");
455
+
456
+ let output = `${prompt}## Task: Infrastructure Security Review\n\n`;
457
+ output += `**Change:** ${iac_description}\n`;
458
+ if (cloud_provider) output += `**Cloud:** ${cloud_provider}\n`;
459
+ if (environment) output += `**Environment:** ${environment}\n\n`;
460
+ if (iac_content) {
461
+ output += `**IaC to review:**\n\`\`\`\n${iac_content}\n\`\`\`\n\n`;
462
+ }
463
+ output += `Using the CSPM-style checklist in your agent instructions, review for:\n`;
464
+ output += `- IAM over-privilege and least-privilege violations\n`;
465
+ output += `- Hardcoded secrets, credentials, or sensitive values\n`;
466
+ output += `- Network exposure and security group / NACL issues\n`;
467
+ output += `- Unencrypted storage or data in transit\n`;
468
+ output += `- Container/compute hardening gaps\n`;
469
+ output += `- Dependency pinning (no 'latest' tags)\n\n`;
470
+ if (environment === "production") {
471
+ output += `This is a **PRODUCTION** change — apply heightened scrutiny.\n\n`;
472
+ }
473
+ if (template) {
474
+ output += `Produce output using this template:\n\n${template}\n`;
475
+ }
476
+
477
+ return { content: [{ type: "text", text: output }] };
478
+ }
479
+
480
+ function handleTriageSAST(args) {
481
+ const { findings, tool, language } = args;
482
+
483
+ const prompt = buildPromptPrefix("appsec-engineer");
484
+
485
+ let output = `${prompt}## Task: SAST Triage\n\n`;
486
+ if (tool) output += `**Tool:** ${tool}\n`;
487
+ if (language) output += `**Language:** ${language}\n\n`;
488
+ output += `**Findings to triage:**\n\n${findings}\n\n`;
489
+ output += `For each finding:\n`;
490
+ output += `1. Confirm (true positive) or dismiss (false positive) with reasoning\n`;
491
+ output += `2. Rate severity using CVSS 3.1 + contextual adjustments\n`;
492
+ output += `3. Map to CWE and relevant OWASP/ASVS control\n`;
493
+ output += `4. Provide a concrete, copy-pasteable code fix — not just "use parameterised queries"\n`;
494
+ output += `5. Note if this blocks the Build→Test gate (CRITICAL/HIGH = block)\n`;
495
+
496
+ return { content: [{ type: "text", text: output }] };
497
+ }
498
+
499
+ function handleReleaseGate(args) {
500
+ const { version, docs_path, open_findings_summary } = args;
501
+
502
+ const prompt = buildPromptPrefix("release-manager");
503
+ const template = readTemplate("release-sign-off");
504
+
505
+ let output = `${prompt}## Task: Pre-Release Security Gate — ${version}\n\n`;
506
+ if (docs_path) {
507
+ output += `**Artefacts location:** ${docs_path}\n\n`;
508
+ output += `Review artefacts at that path. For each required document, confirm it exists and is not a blank template.\n\n`;
509
+ }
510
+ if (open_findings_summary) {
511
+ output += `**Open findings requiring gate evaluation:**\n${open_findings_summary}\n\n`;
512
+ }
513
+ output += `Run the full pre-release security checklist from your agent instructions. `;
514
+ output += `Produce a formal go/no-go decision with documented rationale.\n\n`;
515
+ output += `**Severity gate rules:**\n`;
516
+ output += `- CRITICAL unmitigated → NO-GO, no exceptions\n`;
517
+ output += `- HIGH unmitigated without documented accepted risk → NO-GO\n`;
518
+ output += `- MEDIUM without remediation plan or accepted risk → NO-GO\n`;
519
+ output += `- LOW → track in risk register, does not block\n\n`;
520
+ if (template) {
521
+ output += `Produce output using this template:\n\n${template}\n`;
522
+ }
523
+
524
+ return { content: [{ type: "text", text: output }] };
525
+ }
526
+
527
+ function handleCheckCompliance(args) {
528
+ const { controls_implemented, frameworks, data_types } = args;
529
+
530
+ const prompt = buildPromptPrefix("grc-analyst");
531
+
532
+ let output = `${prompt}## Task: Compliance Gap Analysis\n\n`;
533
+ output += `**Frameworks in scope:** ${frameworks.join(", ")}\n`;
534
+ if (data_types) output += `**Data types processed:** ${data_types}\n\n`;
535
+ output += `**Controls currently implemented:**\n${controls_implemented}\n\n`;
536
+ output += `Produce:\n`;
537
+ output += `1. A control mapping table: for each ASVS requirement, map to applicable controls in the requested frameworks\n`;
538
+ output += `2. A gap analysis: which framework controls are not satisfied by current controls\n`;
539
+ output += `3. Risk rating for each gap\n`;
540
+ output += `4. Recommended remediation priority order\n`;
541
+
542
+ return { content: [{ type: "text", text: output }] };
543
+ }
544
+
545
+ function handleInitProject(args) {
546
+ const { project_root, project_name, stack, team_size = "small (2-5)" } = args;
547
+
548
+ let output = `# Secure SDLC Initialisation — ${project_name}\n\n`;
549
+ output += `Project: \`${project_root}\`\n`;
550
+ if (stack) output += `Stack: ${stack}\n`;
551
+ output += `Team size: ${team_size}\n\n`;
552
+
553
+ output += `## What to do next\n\n`;
554
+ output += `### 1. Create your docs directory\n\`\`\`bash\nmkdir -p ${project_root}/docs/audit-evidence\n\`\`\`\n\n`;
555
+ output += `### 2. Copy templates\n\`\`\`bash\ncp /path/to/secure-sdlc-agents/docs/templates/* ${project_root}/docs/\n\`\`\`\n\n`;
556
+ output += `### 3. Install git hooks\n\`\`\`bash\ncp /path/to/secure-sdlc-agents/hooks/pre-commit ${project_root}/.git/hooks/\nchmod +x ${project_root}/.git/hooks/pre-commit\n\`\`\`\n\n`;
557
+ output += `### 4. Start the Plan phase\n`;
558
+ output += `Use the \`sdlc_plan_feature\` tool with your first feature description.\n\n`;
559
+ output += `### 5. Phase sequence\n`;
560
+ output += `PLAN → DESIGN → BUILD → TEST → RELEASE\n\n`;
561
+ output += `Each phase gate must be passed before proceeding. See CLAUDE.md for orchestration rules.\n`;
562
+
563
+ return { content: [{ type: "text", text: output }] };
564
+ }
565
+
566
+ function handleSecurityChampion(args) {
567
+ const { question_or_code, context } = args;
568
+
569
+ const prompt = readAgentPrompt("security-champion");
570
+ const champPrompt = prompt
571
+ ? `You are a Security Champion — a developer who champions security within the team without being a blocker.\n\n${prompt}\n\n---\n\n`
572
+ : `You are a Security Champion — a developer-friendly security advocate. Give practical, actionable security advice. `;
573
+
574
+ let output = `${champPrompt}## Question / Review Request\n\n`;
575
+ if (context) output += `**Context:** ${context}\n\n`;
576
+ output += `${question_or_code}\n\n`;
577
+ output += `Respond with:\n- A direct answer / assessment\n- Concrete recommendations with code examples where helpful\n- Links to OWASP or relevant standards if applicable\n- Severity if this is a finding (and whether it blocks or warns)\n`;
578
+
579
+ return { content: [{ type: "text", text: output }] };
580
+ }
581
+
582
+ function handleAISecurityReview(args) {
583
+ const { ai_feature_description, attack_surface } = args;
584
+
585
+ const prompt = readAgentPrompt("ai-security-engineer");
586
+ const agentPrompt = prompt
587
+ ? `You are the AI Security Engineer agent.\n\n${prompt}\n\n---\n\n`
588
+ : `You are an AI/LLM Security Engineer specialising in 2026-era AI application security.\n\n`;
589
+
590
+ let output = `${agentPrompt}## Task: AI Feature Security Review\n\n`;
591
+ output += `**Feature:** ${ai_feature_description}\n`;
592
+ if (attack_surface) output += `**Attack surface / who can send input:** ${attack_surface}\n\n`;
593
+ output += `Review for:\n`;
594
+ output += `1. **Prompt injection** — can an attacker manipulate the model's behaviour via user input?\n`;
595
+ output += `2. **Indirect prompt injection** — can retrieved documents/web content contain injected instructions?\n`;
596
+ output += `3. **Data exfiltration** — can the model be made to leak training data or system prompts?\n`;
597
+ output += `4. **Agentic trust boundaries** — if the AI can call tools/functions, what can it be tricked into doing?\n`;
598
+ output += `5. **Model supply chain** — is the model from a trusted, verified source with known provenance?\n`;
599
+ output += `6. **Output validation** — are AI outputs validated before being used in downstream systems?\n`;
600
+ output += `7. **PII leakage** — is user data being sent to external model APIs without consent?\n`;
601
+ output += `8. **Rate limiting and abuse** — can the AI feature be abused for SSRF, data scraping, etc.?\n\n`;
602
+ output += `Map findings to OWASP Top 10 for LLMs 2025 where applicable.\n`;
603
+
604
+ return { content: [{ type: "text", text: output }] };
605
+ }
606
+
607
+ // ──────────────────────────────────────────────────────────────────────────────
608
+ // Server setup
609
+ // ──────────────────────────────────────────────────────────────────────────────
610
+
611
+ const server = new Server(
612
+ { name: "secure-sdlc", version: "1.0.0" },
613
+ { capabilities: { tools: {} } }
614
+ );
615
+
616
+ server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
617
+
618
+ server.setRequestHandler(CallToolRequestSchema, async (request) => {
619
+ const { name, arguments: args } = request.params;
620
+
621
+ switch (name) {
622
+ case "sdlc_plan_feature": return handlePlanFeature(args);
623
+ case "sdlc_threat_model": return handleThreatModel(args);
624
+ case "sdlc_review_pr": return handleReviewPR(args);
625
+ case "sdlc_review_infra": return handleReviewInfra(args);
626
+ case "sdlc_triage_sast": return handleTriageSAST(args);
627
+ case "sdlc_release_gate": return handleReleaseGate(args);
628
+ case "sdlc_check_compliance": return handleCheckCompliance(args);
629
+ case "sdlc_init_project": return handleInitProject(args);
630
+ case "sdlc_security_champion": return handleSecurityChampion(args);
631
+ case "sdlc_ai_security_review": return handleAISecurityReview(args);
632
+ default:
633
+ throw new Error(`Unknown tool: ${name}`);
634
+ }
635
+ });
636
+
637
+ const transport = new StdioServerTransport();
638
+ await server.connect(transport);