{
  "name": "🧩#152 - AI Code Reviewer",
  "nodes": [
    {
      "parameters": {},
      "id": "15200000-0000-4000-8000-000000000001",
      "name": "When clicking 'Execute workflow'",
      "type": "n8n-nodes-base.manualTrigger",
      "typeVersion": 1,
      "position": [
        0,
        0
      ]
    },
    {
      "parameters": {
        "jsCode": "return [\n  {\n    json: {\n      language: \"javascript\",\n      codeToReview: `\nfunction getUserData(userId) {\n  const query = \"SELECT * FROM users WHERE id = \" + userId;\n  db.query(query, function(err, result) {\n    if (err) {\n      console.log(err);\n    }\n    return result;\n  });\n}\nfunction calculateTotal(items) {\n  let total = 0;\n  for (let i = 0; i <= items.length; i++) {\n    total += items[i].price * items[i].qty;\n  }\n  return total;\n}\nfunction login(username, password) {\n  if (username == \"admin\" && password == \"password123\") {\n    return true;\n  }\n  return false;\n}\n`\n    }\n  }\n];"
      },
      "id": "15200000-0000-4000-8000-000000000002",
      "name": "Code in JavaScript",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        224,
        0
      ]
    },
    {
      "parameters": {
        "modelId": {
          "__rl": true,
          "value": "gpt-4o-mini",
          "mode": "list",
          "cachedResultName": "gpt-4o-mini"
        },
        "messages": {
          "values": [
            {
              "content": "You are an expert senior software engineer performing a rigorous, structured code review.\nYour task is to analyze the provided code for bugs, logic errors, security vulnerabilities, performance bottlenecks, and code readability issues.\n\nYou MUST respond with a single, valid JSON object following EXACTLY this schema (no markdown formatting, no commentary outside JSON):\n{\n  \"summary\": string,\n  \"bugs\": [\n    {\n      \"issue\": string,\n      \"severity\": \"Critical\" | \"High\" | \"Medium\" | \"Low\",\n      \"lineHint\": string,\n      \"fix\": string\n    }\n  ],\n  \"improvements\": string[],\n  \"securityScore\": number (0 to 100),\n  \"performanceScore\": number (0 to 100),\n  \"readabilityScore\": number (0 to 100),\n  \"finalVerdict\": string\n}\n\nRules:\n- Be critical, objective, and precise.\n- For each bug, pinpoint the exact risky logic or code snippet in lineHint and provide concrete remediation in fix.\n- Give realistic scores between 0 and 100 based on severity of flaws.\n- Final verdict should clearly summarize whether the code is production-ready, needs minor polish, or requires major revision.\n- Output ONLY valid JSON.",
              "role": "system"
            },
            {
              "content": "=Code to review (Language: {{ $json.language || 'javascript' }}):\n\n{{ $json.codeToReview }}"
            }
          ]
        },
        "jsonOutput": true,
        "options": {}
      },
      "id": "15200000-0000-4000-8000-000000000003",
      "name": "Message a model",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "typeVersion": 1.8,
      "position": [
        448,
        0
      ]
    },
    {
      "parameters": {
        "jsCode": "// Parse the AI Review JSON (handles raw object or string/fenced output)\nconst raw = $json.text ?? $json.message?.content ?? $json.content ?? $json;\nlet review;\n\nif (raw && typeof raw === \"object\" && raw.summary && (raw.bugs || raw.securityScore !== undefined)) {\n  review = raw;\n} else {\n  let txt = (raw ?? \"\").toString().trim();\n  const fence = txt.match(/```(?:json)?\\s*([\\s\\S]*?)```/i);\n  if (fence) txt = fence[1].trim();\n  const s = txt.indexOf(\"{\"), e = txt.lastIndexOf(\"}\");\n  if (s !== -1 && e !== -1) txt = txt.slice(s, e + 1);\n  try {\n    review = JSON.parse(txt);\n  } catch (err) {\n    return [{\n      json: {\n        error: \"Failed to parse AI review output as JSON\",\n        rawOutput: raw\n      }\n    }];\n  }\n}\n\n// Format bugs list\nlet bugsList = \"\";\nif (Array.isArray(review.bugs) && review.bugs.length > 0) {\n  bugsList = review.bugs.map((b, idx) => {\n    return `${idx + 1}. [${b.severity || 'Notice'}] ${b.issue}\n   • Line: ${b.lineHint || 'N/A'}\n   • Fix: ${b.fix || 'N/A'}`;\n  }).join(\"\\n\\n\");\n} else {\n  bugsList = \"• No critical bugs detected.\";\n}\n\n// Format improvements list\nlet improvementsList = \"\";\nif (Array.isArray(review.improvements) && review.improvements.length > 0) {\n  improvementsList = review.improvements.map(imp => `• ${imp}`).join(\"\\n\");\n} else {\n  improvementsList = \"• No additional improvements suggested.\";\n}\n\n// Generate formatted clean report\nconst telegramMessage = `🛠️ AI Senior Developer Code Review\n\n📋 Summary:\n${review.summary || 'Code review completed.'}\n\n🐛 Detected Bugs & Vulnerabilities:\n${bugsList}\n\n💡 Improvements Suggested:\n${improvementsList}\n\n📊 Scores:\nSecurity: ${review.securityScore}/100\nPerformance: ${review.performanceScore}/100\nReadability: ${review.readabilityScore}/100\n\n⚖️ Final Verdict:\n${review.finalVerdict}`;\n\nreturn [\n  {\n    json: {\n      ...review,\n      telegramMessage\n    }\n  }\n];"
      },
      "id": "15200000-0000-4000-8000-000000000004",
      "name": "Code in JavaScript1",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [
        672,
        0
      ]
    }
  ],
  "connections": {
    "When clicking 'Execute workflow'": {
      "main": [
        [
          {
            "node": "Code in JavaScript",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Code in JavaScript": {
      "main": [
        [
          {
            "node": "Message a model",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Message a model": {
      "main": [
        [
          {
            "node": "Code in JavaScript1",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  },
  "pinData": {
    "When clicking 'Execute workflow'": [
      {
        "json": {},
        "pairedItem": {
          "item": 0
        }
      }
    ],
    "Code in JavaScript": [
      {
        "json": {
          "language": "javascript",
          "codeToReview": "\nfunction getUserData(userId) {\n  const query = \"SELECT * FROM users WHERE id = \" + userId;\n  db.query(query, function(err, result) {\n    if (err) {\n      console.log(err);\n    }\n    return result;\n  });\n}\nfunction calculateTotal(items) {\n  let total = 0;\n  for (let i = 0; i <= items.length; i++) {\n    total += items[i].price * items[i].qty;\n  }\n  return total;\n}\nfunction login(username, password) {\n  if (username == \"admin\" && password == \"password123\") {\n    return true;\n  }\n  return false;\n}\n"
        },
        "pairedItem": {
          "item": 0
        }
      }
    ],
    "Message a model": [
      {
        "json": {
          "index": 0,
          "message": {
            "role": "assistant",
            "content": {
              "summary": "The code has a major SQL injection vulnerability, incorrect async return handling, and an off-by-one bug in the total calculation that can cause runtime errors. Authentication is hardcoded and insecure. Several maintainability and readability issues are present (loose equality, weak error handling, and missing input validation).",
              "bugs": [
                {
                  "issue": "SQL injection due to string concatenation of userId into the SQL query.",
                  "severity": "Critical",
                  "lineHint": "getUserData: const query = \"SELECT * FROM users WHERE id = \" + userId;",
                  "fix": "Use parameterized queries/prepared statements (e.g., db.query('SELECT * FROM users WHERE id = ?', [userId], ...)) and validate userId type/range."
                },
                {
                  "issue": "Incorrect async behavior: function does not return the query result to the caller; `return result;` inside the callback only returns from the callback.",
                  "severity": "High",
                  "lineHint": "getUserData: db.query(query, function(err, result) { ... return result; });",
                  "fix": "Use Promises, async/await, or pass a callback function to return results to callers."
                },
                {
                  "issue": "Off-by-one error in loop condition (i <= items.length) causes items[items.length] to be undefined and throw a TypeError when accessing .price.",
                  "severity": "Critical",
                  "lineHint": "calculateTotal: for (let i = 0; i <= items.length; i++)",
                  "fix": "Change condition to i < items.length or use items.reduce((sum, item) => sum + (item.price * item.qty), 0)."
                },
                {
                  "issue": "Hardcoded credentials and plain-text comparison using loose equality (==).",
                  "severity": "Critical",
                  "lineHint": "login: if (username == \"admin\" && password == \"password123\")",
                  "fix": "Authenticate against a secure user database using hashed passwords (e.g. bcrypt/argon2) and constant-time string comparison, or leverage OAuth/JWT."
                }
              ],
              "improvements": [
                "Use strict equality (===) instead of loose equality (==) to prevent unexpected type coercion.",
                "Add proper error propagation and logging rather than silently logging with console.log and returning undefined.",
                "Validate inputs (e.g., check items array is non-empty and contains valid price/qty numbers).",
                "Modernize JavaScript syntax: adopt async/await, Array.prototype.reduce, and const/let best practices."
              ],
              "securityScore": 15,
              "performanceScore": 65,
              "readabilityScore": 60,
              "finalVerdict": "Needs Major Revision"
            }
          }
        },
        "pairedItem": {
          "item": 0
        }
      }
    ],
    "Code in JavaScript1": [
      {
        "json": {
          "summary": "The code has a major SQL injection vulnerability, incorrect async return handling, and an off-by-one bug in the total calculation that can cause runtime errors. Authentication is hardcoded and insecure. Several maintainability and readability issues are present (loose equality, weak error handling, and missing input validation).",
          "bugs": [
            {
              "issue": "SQL injection due to string concatenation of userId into the SQL query.",
              "severity": "Critical",
              "lineHint": "getUserData: const query = \"SELECT * FROM users WHERE id = \" + userId;",
              "fix": "Use parameterized queries/prepared statements (e.g., db.query('SELECT * FROM users WHERE id = ?', [userId], ...)) and validate userId type/range."
            },
            {
              "issue": "Incorrect async behavior: function does not return the query result to the caller; `return result;` inside the callback only returns from the callback.",
              "severity": "High",
              "lineHint": "getUserData: db.query(query, function(err, result) { ... return result; });",
              "fix": "Use Promises, async/await, or pass a callback function to return results to callers."
            },
            {
              "issue": "Off-by-one error in loop condition (i <= items.length) causes items[items.length] to be undefined and throw a TypeError when accessing .price.",
              "severity": "Critical",
              "lineHint": "calculateTotal: for (let i = 0; i <= items.length; i++)",
              "fix": "Change condition to i < items.length or use items.reduce((sum, item) => sum + (item.price * item.qty), 0)."
            },
            {
              "issue": "Hardcoded credentials and plain-text comparison using loose equality (==).",
              "severity": "Critical",
              "lineHint": "login: if (username == \"admin\" && password == \"password123\")",
              "fix": "Authenticate against a secure user database using hashed passwords (e.g. bcrypt/argon2) and constant-time string comparison, or leverage OAuth/JWT."
            }
          ],
          "improvements": [
            "Use strict equality (===) instead of loose equality (==) to prevent unexpected type coercion.",
            "Add proper error propagation and logging rather than silently logging with console.log and returning undefined.",
            "Validate inputs (e.g., check items array is non-empty and contains valid price/qty numbers).",
            "Modernize JavaScript syntax: adopt async/await, Array.prototype.reduce, and const/let best practices."
          ],
          "securityScore": 15,
          "performanceScore": 65,
          "readabilityScore": 60,
          "finalVerdict": "Needs Major Revision",
          "telegramMessage": "🛠️ AI Senior Developer Code Review\n\n📋 Summary:\nThe code has a major SQL injection vulnerability, incorrect async return handling, and an off-by-one bug in the total calculation that can cause runtime errors. Authentication is hardcoded and insecure. Several maintainability and readability issues are present (loose equality, weak error handling, and missing input validation).\n\n🐛 Detected Bugs & Vulnerabilities:\n1. [Critical] SQL injection due to string concatenation of userId into the SQL query.\n   • Line: getUserData: const query = \"SELECT * FROM users WHERE id = \" + userId;\n   • Fix: Use parameterized queries/prepared statements (e.g., db.query('SELECT * FROM users WHERE id = ?', [userId], ...)) and validate userId type/range.\n\n2. [High] Incorrect async behavior: function does not return the query result to the caller; `return result;` inside the callback only returns from the callback.\n   • Line: getUserData: db.query(query, function(err, result) { ... return result; });\n   • Fix: Use Promises, async/await, or pass a callback function to return results to callers.\n\n3. [Critical] Off-by-one error in loop condition (i <= items.length) causes items[items.length] to be undefined and throw a TypeError when accessing .price.\n   • Line: calculateTotal: for (let i = 0; i <= items.length; i++)\n   • Fix: Change condition to i < items.length or use items.reduce((sum, item) => sum + (item.price * item.qty), 0).\n\n4. [Critical] Hardcoded credentials and plain-text comparison using loose equality (==).\n   • Line: login: if (username == \"admin\" && password == \"password123\")\n   • Fix: Authenticate against a secure user database using hashed passwords (e.g. bcrypt/argon2) and constant-time string comparison, or leverage OAuth/JWT.\n\n💡 Improvements Suggested:\n• Use strict equality (===) instead of loose equality (==) to prevent unexpected type coercion.\n• Add proper error propagation and logging rather than silently logging with console.log and returning undefined.\n• Validate inputs (e.g., check items array is non-empty and contains valid price/qty numbers).\n• Modernize JavaScript syntax: adopt async/await, Array.prototype.reduce, and const/let best practices.\n\n📊 Scores:\nSecurity: 15/100\nPerformance: 65/100\nReadability: 60/100\n\n⚖️ Final Verdict:\nNeeds Major Revision"
        },
        "pairedItem": {
          "item": 0
        }
      }
    ]
  },
  "active": false,
  "settings": {
    "executionOrder": "v1",
    "binaryMode": "separate"
  }
}
