cyberaudit-skill 3.1.5 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. package/README.md +84 -25
  2. package/dist/cli.d.ts +10 -0
  3. package/dist/cli.js +552 -172
  4. package/dist/cli.test.d.ts +1 -0
  5. package/dist/cli.test.js +100 -0
  6. package/dist/mcp-server.d.ts +135 -1
  7. package/dist/mcp-server.js +185 -96
  8. package/dist/mcp-server.test.d.ts +1 -0
  9. package/dist/mcp-server.test.js +77 -0
  10. package/dist/report/generator.d.ts +2 -0
  11. package/dist/report/generator.js +260 -0
  12. package/dist/report/generator.test.d.ts +1 -0
  13. package/dist/report/generator.test.js +73 -0
  14. package/dist/report/types.d.ts +31 -0
  15. package/dist/report/types.js +1 -0
  16. package/dist/scanners/secrets.d.ts +32 -0
  17. package/dist/scanners/secrets.js +437 -0
  18. package/dist/scanners/secrets.test.d.ts +1 -0
  19. package/dist/scanners/secrets.test.js +96 -0
  20. package/dist/scanners/types.d.ts +22 -0
  21. package/dist/scanners/types.js +1 -0
  22. package/dist/scanners/web.d.ts +37 -0
  23. package/dist/scanners/web.js +327 -0
  24. package/dist/scanners/web.test.d.ts +1 -0
  25. package/dist/scanners/web.test.js +67 -0
  26. package/package.json +15 -3
  27. package/skills/cyberaudit/AGENT-BOOT.md +1 -1
  28. package/skills/cyberaudit/COMMANDS.md +11 -1
  29. package/skills/cyberaudit/INSTALL.md +7 -6
  30. package/skills/cyberaudit/README.md +20 -5
  31. package/skills/cyberaudit/SKILL.md +20 -5
  32. package/skills/cyberaudit/cloud/CLOUD-CHECKLIST.md +85 -0
  33. package/skills/cyberaudit/cloud/CLOUD-PHILOSOPHY.md +91 -0
  34. package/skills/cyberaudit/cloud/CLOUD-REMEDIATION-LIBRARY.md +145 -0
  35. package/skills/cyberaudit/commands/audit-angular.md +11 -0
  36. package/skills/cyberaudit/commands/audit-api-bola.md +11 -0
  37. package/skills/cyberaudit/commands/audit-api-bopla.md +11 -0
  38. package/skills/cyberaudit/commands/audit-api-graphql.md +11 -0
  39. package/skills/cyberaudit/commands/audit-api-inventory.md +11 -0
  40. package/skills/cyberaudit/commands/audit-api-rate-limit.md +11 -0
  41. package/skills/cyberaudit/commands/audit-api-rest.md +11 -0
  42. package/skills/cyberaudit/commands/audit-api-third-party.md +11 -0
  43. package/skills/cyberaudit/commands/audit-api-ws.md +11 -0
  44. package/skills/cyberaudit/commands/audit-auth-api.md +11 -0
  45. package/skills/cyberaudit/commands/audit-auth-mobile.md +11 -0
  46. package/skills/cyberaudit/commands/audit-auth.md +12 -0
  47. package/skills/cyberaudit/commands/audit-binary.md +11 -0
  48. package/skills/cyberaudit/commands/audit-cis.md +11 -0
  49. package/skills/cyberaudit/commands/audit-cloud-iam.md +11 -0
  50. package/skills/cyberaudit/commands/audit-cloud-network.md +11 -0
  51. package/skills/cyberaudit/commands/audit-cloud-s3.md +11 -0
  52. package/skills/cyberaudit/commands/audit-cloud.md +10 -0
  53. package/skills/cyberaudit/commands/audit-cors.md +11 -0
  54. package/skills/cyberaudit/commands/audit-crypto-mobile.md +11 -0
  55. package/skills/cyberaudit/commands/audit-crypto.md +10 -0
  56. package/skills/cyberaudit/commands/audit-csrf.md +11 -0
  57. package/skills/cyberaudit/commands/audit-deeplinks.md +11 -0
  58. package/skills/cyberaudit/commands/audit-deps.md +11 -0
  59. package/skills/cyberaudit/commands/audit-deserial.md +11 -0
  60. package/skills/cyberaudit/commands/audit-exec.md +11 -0
  61. package/skills/cyberaudit/commands/audit-expo.md +11 -0
  62. package/skills/cyberaudit/commands/audit-express.md +11 -0
  63. package/skills/cyberaudit/commands/audit-flutter.md +11 -0
  64. package/skills/cyberaudit/commands/audit-headers.md +11 -0
  65. package/skills/cyberaudit/commands/audit-hipaa.md +11 -0
  66. package/skills/cyberaudit/commands/audit-idor.md +11 -0
  67. package/skills/cyberaudit/commands/audit-injection.md +12 -0
  68. package/skills/cyberaudit/commands/audit-ionic.md +11 -0
  69. package/skills/cyberaudit/commands/audit-laravel.md +11 -0
  70. package/skills/cyberaudit/commands/audit-logic.md +11 -0
  71. package/skills/cyberaudit/commands/audit-masvs.md +11 -0
  72. package/skills/cyberaudit/commands/audit-nestjs.md +11 -0
  73. package/skills/cyberaudit/commands/audit-network.md +11 -0
  74. package/skills/cyberaudit/commands/audit-nextjs.md +11 -0
  75. package/skills/cyberaudit/commands/audit-owasp.md +11 -0
  76. package/skills/cyberaudit/commands/audit-pci.md +11 -0
  77. package/skills/cyberaudit/commands/audit-permissions.md +11 -0
  78. package/skills/cyberaudit/commands/audit-react-native.md +11 -0
  79. package/skills/cyberaudit/commands/audit-react.md +11 -0
  80. package/skills/cyberaudit/commands/audit-rgpd.md +11 -0
  81. package/skills/cyberaudit/commands/audit-runtime.md +11 -0
  82. package/skills/cyberaudit/commands/audit-secrets.md +11 -0
  83. package/skills/cyberaudit/commands/audit-ssrf.md +11 -0
  84. package/skills/cyberaudit/commands/audit-storage.md +11 -0
  85. package/skills/cyberaudit/commands/audit-vue.md +11 -0
  86. package/skills/cyberaudit/commands/audit-xss.md +11 -0
  87. package/skills/cyberaudit/commands/audit-xxe.md +11 -0
  88. package/skills/cyberaudit/reports/EXECUTIVE-SUMMARY-TEMPLATE.md +1 -1
  89. package/skills/cyberaudit/reports/REPORT-TEMPLATE-CLOUD.md +103 -0
  90. package/skills/cyberaudit/reports/REPORT-TEMPLATE-MOBILE.md +2 -2
  91. package/skills/cyberaudit/reports/REPORT-TEMPLATE-WEB.md +2 -2
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,100 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import { existsSync, rmSync, readFileSync } from 'fs';
3
+ import { join } from 'path';
4
+ import { tmpdir } from 'os';
5
+ import { mkdtempSync } from 'fs';
6
+ describe('CLI Installer Safety', () => {
7
+ let tmp;
8
+ beforeEach(() => {
9
+ tmp = mkdtempSync(join(tmpdir(), 'cyberaudit-test-'));
10
+ });
11
+ afterEach(() => {
12
+ rmSync(tmp, { recursive: true, force: true });
13
+ });
14
+ it('isSafePath should block paths outside HOME containing cyberaudit', async () => {
15
+ const cliPath = join(process.cwd(), 'src', 'cli.ts');
16
+ const content = readFileSync(cliPath, 'utf-8');
17
+ // New version uses isSafeInsideHome, isSafeSkillPath, isSafeCommandPath
18
+ expect(content).toMatch(/isSafe.*Path/);
19
+ expect(content).toContain('homedir');
20
+ expect(content).toContain('cyberaudit');
21
+ expect(content).toContain('isSafeInsideHome');
22
+ });
23
+ it('installDir should exist as function', () => {
24
+ const content = readFileSync(join(process.cwd(), 'src', 'cli.ts'), 'utf-8');
25
+ expect(content).toContain('function installDir');
26
+ });
27
+ it('installForCursor handles corrupted mcp.json with backup', () => {
28
+ const cliContent = readFileSync(join(process.cwd(), 'src/cli.ts'), 'utf-8');
29
+ expect(cliContent).toContain('mcp.json is corrupted');
30
+ expect(cliContent).toContain('.bak');
31
+ expect(cliContent).toContain('copyFileSync');
32
+ });
33
+ it('version comes from package.json not hardcoded', () => {
34
+ const cliContent = readFileSync(join(process.cwd(), 'src/cli.ts'), 'utf-8');
35
+ expect(cliContent).toContain('PKG.version');
36
+ expect(cliContent).not.toMatch(/version:\s*\"3\.0\.0\"/);
37
+ });
38
+ });
39
+ describe('Command files completeness', () => {
40
+ it('should have at least 50 command files', () => {
41
+ const fs = require('fs');
42
+ const files = fs.readdirSync(join(process.cwd(), 'skills', 'cyberaudit', 'commands'));
43
+ expect(files.length).toBeGreaterThanOrEqual(50);
44
+ });
45
+ it('should have audit-cloud file', () => {
46
+ const fs = require('fs');
47
+ const files = fs.readdirSync(join(process.cwd(), 'skills', 'cyberaudit', 'commands'));
48
+ expect(files).toContain('audit-cloud.md');
49
+ expect(files).toContain('audit-cloud-s3.md');
50
+ expect(files).toContain('audit-cloud-iam.md');
51
+ });
52
+ });
53
+ describe('Cloud module completeness', () => {
54
+ it('cloud checklist exists', () => {
55
+ expect(existsSync(join(process.cwd(), 'skills', 'cyberaudit', 'cloud', 'CLOUD-CHECKLIST.md'))).toBe(true);
56
+ });
57
+ it('cloud philosophy exists', () => {
58
+ expect(existsSync(join(process.cwd(), 'skills', 'cyberaudit', 'cloud', 'CLOUD-PHILOSOPHY.md'))).toBe(true);
59
+ });
60
+ it('cloud remediation exists', () => {
61
+ expect(existsSync(join(process.cwd(), 'skills', 'cyberaudit', 'cloud', 'CLOUD-REMEDIATION-LIBRARY.md'))).toBe(true);
62
+ });
63
+ it('cloud report template exists', () => {
64
+ expect(existsSync(join(process.cwd(), 'skills', 'cyberaudit', 'reports', 'REPORT-TEMPLATE-CLOUD.md'))).toBe(true);
65
+ });
66
+ });
67
+ describe('Multi-agent support (like ui-ux-pro)', () => {
68
+ it('should support at least 15 agents', () => {
69
+ const content = readFileSync(join(process.cwd(), 'src', 'cli.ts'), 'utf-8');
70
+ // Count Agent union type entries
71
+ const match = content.match(/type Agent =([\s\S]*?);/);
72
+ expect(match).toBeTruthy();
73
+ const agents = match[1].split('|').map(s => s.trim()).filter(Boolean);
74
+ expect(agents.length).toBeGreaterThanOrEqual(15);
75
+ });
76
+ it('should have MAIN_COMMANDS 8 for \"/\" menu', () => {
77
+ const content = readFileSync(join(process.cwd(), 'src', 'cli.ts'), 'utf-8');
78
+ expect(content).toContain('MAIN_COMMANDS');
79
+ // Should contain 8 entries
80
+ const mainMatch = content.match(/const MAIN_COMMANDS = \[([\s\S]*?)\];/);
81
+ expect(mainMatch).toBeTruthy();
82
+ const count = (mainMatch[1].match(/\.md/g) || []).length;
83
+ expect(count).toBe(8);
84
+ });
85
+ it('should define AGENT_CONFIG for many agents', () => {
86
+ const content = readFileSync(join(process.cwd(), 'src', 'cli.ts'), 'utf-8');
87
+ expect(content).toContain('AGENT_CONFIG');
88
+ expect(content).toContain('claude-code');
89
+ expect(content).toContain('cursor');
90
+ expect(content).toContain('windsurf');
91
+ expect(content).toContain('copilot');
92
+ expect(content).toContain('codex');
93
+ expect(content).toContain('continue');
94
+ });
95
+ it('should install commands for \"/\" menu', () => {
96
+ const content = readFileSync(join(process.cwd(), 'src', 'cli.ts'), 'utf-8');
97
+ expect(content).toContain('installCommands');
98
+ expect(content).toContain('"/" will show');
99
+ });
100
+ });
@@ -1,2 +1,136 @@
1
1
  #!/usr/bin/env node
2
- export {};
2
+ export declare const MCP_TOOLS: ({
3
+ name: string;
4
+ description: string;
5
+ inputSchema: {
6
+ type: string;
7
+ properties: {
8
+ target: {
9
+ type: string;
10
+ description: string;
11
+ };
12
+ depth: {
13
+ type: string;
14
+ enum: string[];
15
+ default: string;
16
+ };
17
+ platform?: undefined;
18
+ };
19
+ required: string[];
20
+ };
21
+ } | {
22
+ name: string;
23
+ description: string;
24
+ inputSchema: {
25
+ type: string;
26
+ properties: {
27
+ target: {
28
+ type: string;
29
+ description: string;
30
+ };
31
+ platform: {
32
+ type: string;
33
+ enum: string[];
34
+ default: string;
35
+ };
36
+ depth?: undefined;
37
+ };
38
+ required: string[];
39
+ };
40
+ } | {
41
+ name: string;
42
+ description: string;
43
+ inputSchema: {
44
+ type: string;
45
+ properties: {
46
+ target: {
47
+ type: string;
48
+ description: string;
49
+ };
50
+ depth?: undefined;
51
+ platform?: undefined;
52
+ };
53
+ required: string[];
54
+ };
55
+ } | {
56
+ name: string;
57
+ description: string;
58
+ inputSchema: {
59
+ type: string;
60
+ properties: {
61
+ target?: undefined;
62
+ depth?: undefined;
63
+ platform?: undefined;
64
+ };
65
+ required?: undefined;
66
+ };
67
+ })[];
68
+ export declare const capabilities: {
69
+ tools: ({
70
+ name: string;
71
+ description: string;
72
+ inputSchema: {
73
+ type: string;
74
+ properties: {
75
+ target: {
76
+ type: string;
77
+ description: string;
78
+ };
79
+ depth: {
80
+ type: string;
81
+ enum: string[];
82
+ default: string;
83
+ };
84
+ platform?: undefined;
85
+ };
86
+ required: string[];
87
+ };
88
+ } | {
89
+ name: string;
90
+ description: string;
91
+ inputSchema: {
92
+ type: string;
93
+ properties: {
94
+ target: {
95
+ type: string;
96
+ description: string;
97
+ };
98
+ platform: {
99
+ type: string;
100
+ enum: string[];
101
+ default: string;
102
+ };
103
+ depth?: undefined;
104
+ };
105
+ required: string[];
106
+ };
107
+ } | {
108
+ name: string;
109
+ description: string;
110
+ inputSchema: {
111
+ type: string;
112
+ properties: {
113
+ target: {
114
+ type: string;
115
+ description: string;
116
+ };
117
+ depth?: undefined;
118
+ platform?: undefined;
119
+ };
120
+ required: string[];
121
+ };
122
+ } | {
123
+ name: string;
124
+ description: string;
125
+ inputSchema: {
126
+ type: string;
127
+ properties: {
128
+ target?: undefined;
129
+ depth?: undefined;
130
+ platform?: undefined;
131
+ };
132
+ required?: undefined;
133
+ };
134
+ })[];
135
+ };
136
+ export declare function startMcpServer(): void;
@@ -1,126 +1,215 @@
1
1
  #!/usr/bin/env node
2
2
  import { createInterface } from "readline";
3
- import { join, dirname } from "path";
3
+ import { readFileSync, existsSync, statSync } from "fs";
4
+ import { join, dirname, resolve } from "path";
4
5
  import { fileURLToPath } from "url";
6
+ import { scanSecrets, formatFindingsText } from "./scanners/secrets.js";
7
+ import { scanWeb, formatWebFindingsText } from "./scanners/web.js";
5
8
  const __dirname = dirname(fileURLToPath(import.meta.url));
6
- const SKILL_DIR = join(__dirname, "..", "skills", "cyberaudit");
7
- const capabilities = {
8
- tools: [
9
- {
10
- name: "cyberaudit-web",
11
- description: "Run a web application security audit (OWASP Top 10)",
12
- inputSchema: {
13
- type: "object",
14
- properties: {
15
- target: { type: "string", description: "URL, domain, or project path to audit" },
16
- depth: { type: "string", enum: ["quick", "standard", "deep"], default: "standard" },
17
- },
18
- required: ["target"],
9
+ const PKG_ROOT = join(__dirname, "..");
10
+ const SKILL_DIR = join(PKG_ROOT, "skills", "cyberaudit");
11
+ function getVersion() {
12
+ try {
13
+ const pkgPath = join(PKG_ROOT, "package.json");
14
+ if (existsSync(pkgPath)) {
15
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
16
+ return pkg.version || "3.1.5";
17
+ }
18
+ }
19
+ catch { }
20
+ return "3.1.5";
21
+ }
22
+ const VERSION = getVersion();
23
+ export const MCP_TOOLS = [
24
+ {
25
+ name: "cyberaudit-web",
26
+ description: "Run a web application security audit (OWASP Top 10)",
27
+ inputSchema: {
28
+ type: "object",
29
+ properties: {
30
+ target: { type: "string", description: "URL, domain, or project path to audit" },
31
+ depth: { type: "string", enum: ["quick", "standard", "deep"], default: "standard" },
19
32
  },
33
+ required: ["target"],
20
34
  },
21
- {
22
- name: "cyberaudit-mobile",
23
- description: "Run a mobile application security audit (OWASP MASVS)",
24
- inputSchema: {
25
- type: "object",
26
- properties: {
27
- target: { type: "string", description: "App identifier, APK/IPA path, or project path" },
28
- platform: { type: "string", enum: ["android", "ios", "both"], default: "both" },
29
- },
30
- required: ["target"],
35
+ },
36
+ {
37
+ name: "cyberaudit-mobile",
38
+ description: "Run a mobile application security audit (OWASP MASVS)",
39
+ inputSchema: {
40
+ type: "object",
41
+ properties: {
42
+ target: { type: "string", description: "App identifier, APK/IPA path, or project path" },
43
+ platform: { type: "string", enum: ["android", "ios", "both"], default: "both" },
31
44
  },
45
+ required: ["target"],
32
46
  },
33
- {
34
- name: "cyberaudit-api",
35
- description: "Run an API security audit",
36
- inputSchema: {
37
- type: "object",
38
- properties: {
39
- target: { type: "string", description: "API base URL, OpenAPI spec path, or project directory" },
40
- },
41
- required: ["target"],
47
+ },
48
+ {
49
+ name: "cyberaudit-api",
50
+ description: "Run an API security audit (OWASP API Top 10)",
51
+ inputSchema: {
52
+ type: "object",
53
+ properties: {
54
+ target: { type: "string", description: "API base URL, OpenAPI spec path, or project directory" },
42
55
  },
56
+ required: ["target"],
43
57
  },
44
- {
45
- name: "cyberaudit-cloud",
46
- description: "Run a cloud configuration security audit",
47
- inputSchema: {
48
- type: "object",
49
- properties: {
50
- target: { type: "string", description: "Cloud provider or config file path" },
51
- },
52
- required: ["target"],
58
+ },
59
+ {
60
+ name: "cyberaudit-cloud",
61
+ description: "Run a cloud configuration security audit (AWS/GCP/Azure S3, IAM, SG, storage)",
62
+ inputSchema: {
63
+ type: "object",
64
+ properties: {
65
+ target: { type: "string", description: "Cloud provider, IaC path (terraform/cloudformation), or config file path" },
53
66
  },
67
+ required: ["target"],
54
68
  },
55
- {
56
- name: "cyberaudit-quick",
57
- description: "Run a quick vulnerability scan (5-minute assessment)",
58
- inputSchema: {
59
- type: "object",
60
- properties: {
61
- target: { type: "string", description: "URL, domain, or project path" },
62
- },
63
- required: ["target"],
69
+ },
70
+ {
71
+ name: "cyberaudit-quick",
72
+ description: "Run a quick vulnerability scan (5-minute assessment, secrets + criticals) — deterministic scanner included",
73
+ inputSchema: {
74
+ type: "object",
75
+ properties: {
76
+ target: { type: "string", description: "URL, domain, or project path" },
64
77
  },
78
+ required: ["target"],
65
79
  },
66
- ],
80
+ },
81
+ {
82
+ name: "cyberaudit-list",
83
+ description: "List all available audit types and check installation",
84
+ inputSchema: { type: "object", properties: {} },
85
+ },
86
+ ];
87
+ export const capabilities = {
88
+ tools: MCP_TOOLS,
67
89
  };
68
90
  function write(id, result) {
69
91
  process.stdout.write(JSON.stringify({ jsonrpc: "2.0", id, ...result }) + "\n");
70
92
  }
71
93
  function handleToolCall(id, name, args) {
72
94
  const auditType = name.replace("cyberaudit-", "");
73
- write(id, {
74
- content: [
75
- {
76
- type: "text",
77
- text: `▶ CyberAudit: ${auditType.toUpperCase()} audit requested
95
+ if (name === "cyberaudit-list") {
96
+ write(id, {
97
+ result: {
98
+ content: [
99
+ {
100
+ type: "text",
101
+ text: `═══ CyberAudit ${VERSION} — Available Audits ═══
78
102
 
79
- Target: ${args.target}
80
- ${args.depth ? `Depth: ${args.depth}` : ""}
81
- ${args.platform ? `Platform: ${args.platform}` : ""}
103
+ • cyberaudit-web: OWASP Top 10 web app audit
104
+ cyberaudit-mobile: OWASP MASVS mobile audit
105
+ cyberaudit-api: OWASP API Top 10 audit
106
+ • cyberaudit-cloud: Cloud config audit (S3, IAM, SG, storage)
107
+ • cyberaudit-quick: Quick 5-minute scan (secrets + criticals) — DETERMINISTIC SCANNER
108
+ • cyberaudit-full: Full stack (web + api + cloud) via /audit
82
109
 
110
+ Skill location: ${SKILL_DIR}
111
+ Docs: https://github.com/ArisRoman/cyberaudit-skill
112
+ Scanner: deterministic secrets detection 15 patterns`,
113
+ },
114
+ ],
115
+ },
116
+ });
117
+ return;
118
+ }
119
+ if (name === "cyberaudit-quick" && args.target) {
120
+ try {
121
+ const targetPath = resolve(args.target);
122
+ if (existsSync(targetPath)) {
123
+ const stat = statSync(targetPath);
124
+ if (stat.isDirectory() || stat.isFile()) {
125
+ const secretFindings = scanSecrets(targetPath);
126
+ const webFindings = scanWeb(targetPath);
127
+ const secretReport = formatFindingsText(secretFindings, args.target);
128
+ const webReport = formatWebFindingsText(webFindings, args.target);
129
+ write(id, {
130
+ result: {
131
+ content: [
132
+ {
133
+ type: "text",
134
+ text: `▶ CyberAudit ${VERSION}: QUICK deterministic scan completed\n\n${secretReport}\n${webReport}\n---\nTotal: ${secretFindings.length + webFindings.length} findings (secrets:${secretFindings.length} web:${webFindings.length})\nFor full context-aware audit, load skill and run:\n/${name} "${args.target}"\n\nSkill location: ${SKILL_DIR}\nChecklist: ${SKILL_DIR}/cloud/CLOUD-CHECKLIST.md\nCLI: npx cyberaudit-skill scan "${args.target}" --json`,
135
+ },
136
+ ],
137
+ },
138
+ });
139
+ return;
140
+ }
141
+ }
142
+ }
143
+ catch (e) {
144
+ console.error(`[CyberAudit] Quick scan failed for ${args.target}: ${e.message}`);
145
+ }
146
+ }
147
+ write(id, {
148
+ result: {
149
+ content: [
150
+ {
151
+ type: "text",
152
+ text: `▶ CyberAudit ${VERSION}: ${auditType.toUpperCase()} audit requested
153
+
154
+ Target: ${args.target || "not provided"}
155
+ ${args.depth ? `Depth: ${args.depth}\n` : ""}${args.platform ? `Platform: ${args.platform}\n` : ""}
83
156
  To execute the full audit, load the CyberAudit Skill and run:
84
157
 
85
- /${name} "${args.target}"
158
+ /${name} "${args.target || "."}"
86
159
 
87
160
  The skill will guide you through all checks, scoring, and report generation.
88
161
 
89
- Skill location: ${SKILL_DIR}`,
90
- },
91
- ],
162
+ Skill location: ${SKILL_DIR}
163
+ Cloud checklist: ${SKILL_DIR}/cloud/CLOUD-CHECKLIST.md
164
+ Secrets scanner: npx cyberaudit-skill scan "${args.target || "."}"`,
165
+ },
166
+ ],
167
+ },
92
168
  });
93
169
  }
94
- const rl = createInterface({ input: process.stdin });
95
- rl.on("line", (line) => {
96
- try {
97
- const msg = JSON.parse(line.trim());
98
- const id = msg.id;
99
- switch (msg.method) {
100
- case "initialize":
101
- write(id, {
102
- protocolVersion: "2024-11-05",
103
- capabilities,
104
- serverInfo: { name: "cyberaudit-skill", version: "3.0.0" },
105
- });
106
- break;
107
- case "tools/list":
108
- write(id, capabilities);
109
- break;
110
- case "tools/call":
111
- handleToolCall(id, msg.params.name, msg.params.arguments || {});
112
- break;
113
- case "notifications/initialized":
114
- // no response expected
115
- break;
116
- default:
117
- write(id, { error: { code: -32601, message: `Method not found: ${msg.method}` } });
170
+ export function startMcpServer() {
171
+ const rl = createInterface({ input: process.stdin });
172
+ rl.on("line", (line) => {
173
+ try {
174
+ const trimmed = line.trim();
175
+ if (!trimmed)
176
+ return;
177
+ const msg = JSON.parse(trimmed);
178
+ const id = msg.id;
179
+ switch (msg.method) {
180
+ case "initialize":
181
+ write(id, {
182
+ result: {
183
+ protocolVersion: "2024-11-05",
184
+ capabilities,
185
+ serverInfo: { name: "cyberaudit-skill", version: VERSION },
186
+ },
187
+ });
188
+ break;
189
+ case "tools/list":
190
+ write(id, {
191
+ result: capabilities,
192
+ });
193
+ break;
194
+ case "tools/call":
195
+ handleToolCall(id, msg.params?.name, msg.params?.arguments || {});
196
+ break;
197
+ case "notifications/initialized":
198
+ break;
199
+ default:
200
+ if (id !== undefined) {
201
+ write(id, { error: { code: -32601, message: `Method not found: ${msg.method}` } });
202
+ }
203
+ }
118
204
  }
119
- }
120
- catch (e) {
121
- // ignore malformed input
122
- }
123
- });
124
- process.on("SIGINT", () => process.exit(0));
125
- process.on("SIGTERM", () => process.exit(0));
126
- console.error(`[CyberAudit] MCP server ready | Skill: ${SKILL_DIR}`);
205
+ catch {
206
+ // ignore malformed
207
+ }
208
+ });
209
+ process.on("SIGINT", () => process.exit(0));
210
+ process.on("SIGTERM", () => process.exit(0));
211
+ console.error(`[CyberAudit] MCP server ready v${VERSION} | Skill: ${SKILL_DIR}`);
212
+ }
213
+ if (import.meta.url === `file://${process.argv[1]}` || process.argv[1]?.endsWith("mcp-server.js") || process.argv[1]?.endsWith("mcp-server.ts")) {
214
+ startMcpServer();
215
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,77 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { spawn } from 'child_process';
3
+ import { join } from 'path';
4
+ function runMcp(inputLines) {
5
+ return new Promise((resolve, reject) => {
6
+ const proc = spawn('node', [join(process.cwd(), 'dist', 'mcp-server.js')], {
7
+ stdio: ['pipe', 'pipe', 'pipe'],
8
+ });
9
+ let stdout = '';
10
+ let stderr = '';
11
+ proc.stdout.on('data', (d) => (stdout += d.toString()));
12
+ proc.stderr.on('data', (d) => (stderr += d.toString()));
13
+ proc.on('error', reject);
14
+ // Write lines
15
+ for (const line of inputLines) {
16
+ proc.stdin.write(line + '\n');
17
+ }
18
+ setTimeout(() => {
19
+ proc.kill();
20
+ resolve({ stdout, stderr });
21
+ }, 800);
22
+ });
23
+ }
24
+ describe('MCP Server', () => {
25
+ it('should respond to initialize', async () => {
26
+ const { stdout, stderr } = await runMcp([
27
+ JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'initialize', params: {} }),
28
+ ]);
29
+ expect(stdout).toContain('protocolVersion');
30
+ expect(stdout).toContain('cyberaudit-skill');
31
+ expect(stderr).toContain('MCP server ready');
32
+ const lines = stdout.trim().split('\n').filter(Boolean);
33
+ const first = JSON.parse(lines[0]);
34
+ expect(first.result.serverInfo.version).toMatch(/\d+\.\d+\.\d+/);
35
+ // Should read version from package.json (3.1.5)
36
+ expect(first.result.serverInfo.version).toBe('3.1.5');
37
+ });
38
+ it('should list 6 tools including cloud', async () => {
39
+ const { stdout } = await runMcp([
40
+ JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'initialize', params: {} }),
41
+ JSON.stringify({ jsonrpc: '2.0', id: 2, method: 'tools/list', params: {} }),
42
+ ]);
43
+ const lines = stdout.trim().split('\n').filter(Boolean).map(l => JSON.parse(l));
44
+ const listResp = lines.find(r => r.id === 2);
45
+ expect(listResp).toBeDefined();
46
+ const toolNames = listResp.result.tools.map((t) => t.name);
47
+ expect(toolNames).toContain('cyberaudit-web');
48
+ expect(toolNames).toContain('cyberaudit-cloud');
49
+ expect(toolNames).toContain('cyberaudit-quick');
50
+ expect(toolNames.length).toBeGreaterThanOrEqual(6);
51
+ });
52
+ it('should handle cloud tool call', async () => {
53
+ const { stdout } = await runMcp([
54
+ JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'initialize', params: {} }),
55
+ JSON.stringify({
56
+ jsonrpc: '2.0',
57
+ id: 2,
58
+ method: 'tools/call',
59
+ params: { name: 'cyberaudit-cloud', arguments: { target: 'terraform/' } },
60
+ }),
61
+ ]);
62
+ const lines = stdout.trim().split('\n').filter(Boolean).map(l => JSON.parse(l));
63
+ const callResp = lines.find(r => r.id === 2);
64
+ expect(callResp).toBeDefined();
65
+ const text = callResp.result.content[0].text;
66
+ expect(text).toContain('CLOUD');
67
+ expect(text).toContain('terraform/');
68
+ expect(text).toContain('CLOUD-CHECKLIST.md');
69
+ });
70
+ it('should use single source of truth (no duplicate implementation in cli)', async () => {
71
+ // cli.ts should import from mcp-server.js
72
+ const fs = await import('fs');
73
+ const cliContent = fs.readFileSync(join(process.cwd(), 'src', 'cli.ts'), 'utf-8');
74
+ expect(cliContent).toContain('from "./mcp-server.js"');
75
+ expect(cliContent).not.toContain('msg.para'); // old buggy truncation
76
+ });
77
+ });
@@ -0,0 +1,2 @@
1
+ import { ReportInput, ReportOutput } from './types.js';
2
+ export declare function generateReport(input: ReportInput): ReportOutput;