secufusion-mcp 1.2.7 → 2.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.
@@ -0,0 +1,40 @@
1
+ export function parseDatabase(filePath, fileContent, repository) {
2
+ const entities = [];
3
+ if (filePath.endsWith('.sql')) {
4
+ const tableRegex = /CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?([^\s\(]+)/gi;
5
+ let match;
6
+ while ((match = tableRegex.exec(fileContent)) !== null) {
7
+ entities.push({
8
+ tableName: match[1],
9
+ filePath,
10
+ repository,
11
+ schemaType: 'SQL'
12
+ });
13
+ }
14
+ }
15
+ else if (filePath.endsWith('.prisma')) {
16
+ const modelRegex = /model\s+(\w+)\s+\{/g;
17
+ let match;
18
+ while ((match = modelRegex.exec(fileContent)) !== null) {
19
+ entities.push({
20
+ tableName: match[1],
21
+ filePath,
22
+ repository,
23
+ schemaType: 'Prisma'
24
+ });
25
+ }
26
+ }
27
+ else if (fileContent.includes('new mongoose.Schema')) {
28
+ const modelRegex = /mongoose\.model\s*\(\s*['"]([^'"]+)['"]/g;
29
+ let match;
30
+ while ((match = modelRegex.exec(fileContent)) !== null) {
31
+ entities.push({
32
+ tableName: match[1],
33
+ filePath,
34
+ repository,
35
+ schemaType: 'Mongoose'
36
+ });
37
+ }
38
+ }
39
+ return entities;
40
+ }
@@ -0,0 +1,21 @@
1
+ export function parseDomainModels(filePath, fileContent, repository) {
2
+ const models = [];
3
+ const classMatch = fileContent.match(/public\s+class\s+(\w+)/);
4
+ if (!classMatch)
5
+ return models;
6
+ const className = classMatch[1];
7
+ const violations = [];
8
+ if (fileContent.includes("@Entity")) {
9
+ if (!fileContent.includes("tenantId") && !fileContent.includes("TenantId")) {
10
+ violations.push("P1 Violation: Entity is missing 'tenantId' field for tenant isolation.");
11
+ }
12
+ models.push({ name: className, type: "Entity", filePath, repository, violations });
13
+ }
14
+ if (className.endsWith("DTO") || className.endsWith("Dto") || className.endsWith("Request") || className.endsWith("Response")) {
15
+ if (!fileContent.includes("@Data") || !fileContent.includes("@Builder")) {
16
+ violations.push("Warning: DTO is missing @Data or @Builder Lombok annotations.");
17
+ }
18
+ models.push({ name: className, type: "DTO", filePath, repository, violations });
19
+ }
20
+ return models;
21
+ }
@@ -0,0 +1,36 @@
1
+ export function parseEventTopics(filePath, fileContent, repository) {
2
+ const events = [];
3
+ const classMatch = fileContent.match(/public\s+class\s+(\w+)/);
4
+ if (!classMatch)
5
+ return events;
6
+ const className = classMatch[1];
7
+ const topicsConsumed = [];
8
+ const topicsProduced = [];
9
+ const violations = [];
10
+ const listenerRegex = /@KafkaListener\s*\(\s*topics\s*=\s*["']([^"']+)["']/g;
11
+ let match;
12
+ while ((match = listenerRegex.exec(fileContent)) !== null) {
13
+ topicsConsumed.push(match[1]);
14
+ }
15
+ const producerRegex = /KafkaTemplate.*\.send\(\s*["']([^"']+)["']/g;
16
+ while ((match = producerRegex.exec(fileContent)) !== null) {
17
+ topicsProduced.push(match[1]);
18
+ }
19
+ if (topicsConsumed.length === 0 && topicsProduced.length === 0) {
20
+ return events;
21
+ }
22
+ if (topicsConsumed.length > 0) {
23
+ if (fileContent.includes("RestTemplate") || fileContent.includes("FeignClient") || fileContent.includes("HttpClient")) {
24
+ violations.push("P4 Violation (KAFKA_SYNC): Potential synchronous blocking call detected inside or near @KafkaListener.");
25
+ }
26
+ }
27
+ events.push({
28
+ className,
29
+ topicsConsumed,
30
+ topicsProduced,
31
+ filePath,
32
+ repository,
33
+ violations
34
+ });
35
+ return events;
36
+ }
@@ -0,0 +1,34 @@
1
+ export function parseFrontend(filePath, fileContent, repository) {
2
+ const components = [];
3
+ if (filePath.endsWith('.tsx') || filePath.endsWith('.jsx')) {
4
+ const match = fileContent.match(/(?:export\s+)?(?:default\s+)?(?:function|const)\s+([A-Z]\w+)/);
5
+ if (match) {
6
+ components.push({
7
+ componentName: match[1],
8
+ type: 'React',
9
+ filePath,
10
+ repository
11
+ });
12
+ }
13
+ }
14
+ else if (filePath.endsWith('.vue')) {
15
+ components.push({
16
+ componentName: filePath.split('/').pop()?.replace('.vue', '') || 'VueComponent',
17
+ type: 'Vue',
18
+ filePath,
19
+ repository
20
+ });
21
+ }
22
+ else if (filePath.endsWith('.ts') && fileContent.includes('@Component')) {
23
+ const match = fileContent.match(/export\s+class\s+(\w+Component)/);
24
+ if (match) {
25
+ components.push({
26
+ componentName: match[1],
27
+ type: 'Angular',
28
+ filePath,
29
+ repository
30
+ });
31
+ }
32
+ }
33
+ return components;
34
+ }
@@ -0,0 +1,42 @@
1
+ export function parseInfra(filePath, fileContent, repository) {
2
+ const resources = [];
3
+ if (filePath.endsWith('docker-compose.yml') || filePath.endsWith('docker-compose.yaml')) {
4
+ const servicesRegex = /services:\s*\n((\s+[\w-]+:\s*\n)+)/;
5
+ const match = fileContent.match(servicesRegex);
6
+ if (match) {
7
+ resources.push({
8
+ type: 'DockerCompose',
9
+ name: 'Compose-Services',
10
+ filePath,
11
+ repository
12
+ });
13
+ }
14
+ }
15
+ else if (filePath.endsWith('.yaml') || filePath.endsWith('.yml')) {
16
+ if (fileContent.includes('apiVersion:') && fileContent.includes('kind:')) {
17
+ const kindMatch = fileContent.match(/kind:\s*(\w+)/);
18
+ const nameMatch = fileContent.match(/name:\s*([^\n]+)/);
19
+ if (kindMatch && nameMatch) {
20
+ resources.push({
21
+ type: `Kubernetes-${kindMatch[1]}`,
22
+ name: nameMatch[1],
23
+ filePath,
24
+ repository
25
+ });
26
+ }
27
+ }
28
+ }
29
+ else if (filePath.endsWith('.tf')) {
30
+ const resourceRegex = /resource\s+"([^"]+)"\s+"([^"]+)"/g;
31
+ let match;
32
+ while ((match = resourceRegex.exec(fileContent)) !== null) {
33
+ resources.push({
34
+ type: `Terraform-${match[1]}`,
35
+ name: match[2],
36
+ filePath,
37
+ repository
38
+ });
39
+ }
40
+ }
41
+ return resources;
42
+ }
@@ -0,0 +1,49 @@
1
+ export function inferPatterns(dna) {
2
+ const inferredPatterns = [];
3
+ // Infer DTO naming patterns
4
+ const domains = dna.domains || [];
5
+ if (domains.length > 0) {
6
+ const dtos = domains.filter((d) => d.type === "DTO");
7
+ if (dtos.length > 0) {
8
+ let suffixDTO = 0;
9
+ let suffixRequest = 0;
10
+ let suffixResponse = 0;
11
+ dtos.forEach((d) => {
12
+ if (d.name.endsWith("DTO"))
13
+ suffixDTO++;
14
+ else if (d.name.endsWith("Request"))
15
+ suffixRequest++;
16
+ else if (d.name.endsWith("Response"))
17
+ suffixResponse++;
18
+ });
19
+ const max = Math.max(suffixDTO, suffixRequest, suffixResponse);
20
+ const total = dtos.length;
21
+ if (max / total > 0.7) {
22
+ if (max === suffixDTO)
23
+ inferredPatterns.push("Inferred Pattern: 70%+ of data models use 'DTO' suffix.");
24
+ if (max === suffixRequest)
25
+ inferredPatterns.push("Inferred Pattern: 70%+ of data models use 'Request' suffix.");
26
+ if (max === suffixResponse)
27
+ inferredPatterns.push("Inferred Pattern: 70%+ of data models use 'Response' suffix.");
28
+ }
29
+ }
30
+ }
31
+ // Infer API Path Versioning
32
+ const apis = dna.apis || [];
33
+ if (apis.length > 0) {
34
+ let versioned = 0;
35
+ apis.forEach((a) => {
36
+ const paths = a.endpoints.join(" ");
37
+ if (paths.includes("/v1/") || paths.includes("/v2/")) {
38
+ versioned++;
39
+ }
40
+ });
41
+ if (versioned / apis.length < 0.1) {
42
+ inferredPatterns.push("Inferred Pattern: Codebase does not heavily use URL path versioning (e.g., /v1/).");
43
+ }
44
+ else if (versioned / apis.length > 0.8) {
45
+ inferredPatterns.push("Inferred Pattern: Codebase strictly enforces URL path versioning (e.g., /v1/).");
46
+ }
47
+ }
48
+ return inferredPatterns;
49
+ }
@@ -0,0 +1,16 @@
1
+ export function parseSecurity(filePath, fileContent, repository) {
2
+ const contexts = [];
3
+ if (fileContent.includes('KeycloakWebSecurityConfigurerAdapter') || fileContent.includes('keycloak.json')) {
4
+ contexts.push({ authType: 'Keycloak', filePath, repository });
5
+ }
6
+ if (fileContent.includes('@PreAuthorize') || fileContent.includes('@RolesAllowed')) {
7
+ contexts.push({ authType: 'SpringSecurity-RBAC', filePath, repository });
8
+ }
9
+ if (fileContent.includes('jwt') || fileContent.includes('jsonwebtoken') || fileContent.includes('JwtDecoder')) {
10
+ contexts.push({ authType: 'JWT', filePath, repository });
11
+ }
12
+ if (fileContent.includes('passport.use')) {
13
+ contexts.push({ authType: 'PassportJS', filePath, repository });
14
+ }
15
+ return contexts;
16
+ }