{
  "id": "PG84Tipt74DfpUvh",
  "meta": {
    "templateCredsSetupCompleted": true
  },
  "name": "Cybersecurity Compliance Monitoring & Reporting",
  "tags": [],
  "nodes": [
    {
      "id": "9724511a-114a-4e93-a57b-fdc020723868",
      "name": "Sticky Note",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1456,
        144
      ],
      "parameters": {
        "width": 820,
        "height": 720,
        "content": "## Cybersecurity compliance monitoring & reporting\n\nAutomates weekly compliance monitoring across IT, OT, and cloud environments. Validates security controls against ISO 27001, NIST, GDPR, and SOC2, analyzes SIEM logs for anomalies, scores overall compliance, and delivers audit-ready reports with remediation tickets.\n\n## How it works\n\n1. **Trigger** \u2014 Runs every Monday at 9 AM\n2. **Scan & collect** \u2014 Initiates full security scan and fetches 7 days of SIEM logs in parallel\n3. **Analyze** \u2014 Detects log anomalies, scores policy controls, classifies as COMPLIANT / WARNING / NON-COMPLIANT\n4. **Remediate** \u2014 Creates Jira tickets for findings; sends critical alerts for non-compliant status\n5. **Store** \u2014 Saves report to PostgreSQL for historical trend tracking\n6. **Report** \u2014 Generates HTML compliance scorecard and delivers via Email + Slack\n\n## Setup steps\n\n1. **Security APIs** \u2014 Replace placeholder URLs with your SIEM, vulnerability scanner, and policy engine\n2. **PostgreSQL** \u2014 Create a `compliance_reports` table to store weekly results\n3. **Jira** \u2014 Update the ticket API URL with your Jira or ServiceNow instance\n4. **Slack** \u2014 Add your incoming webhook URL to the Slack node\n5. **Email** \u2014 Configure SMTP credentials and set `from` / `to` addresses\n6. **Test** \u2014 Run manually to verify all connections, then activate"
      },
      "typeVersion": 1
    },
    {
      "id": "879c86d6-c0e9-49bf-b6f5-3463c03323f5",
      "name": "Sticky Note1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -528,
        352
      ],
      "parameters": {
        "color": 5,
        "width": 468,
        "height": 465,
        "content": "## 1. Trigger compliance check\n\nRuns every Monday at 9 AM to initiate the weekly security audit cycle"
      },
      "typeVersion": 1
    },
    {
      "id": "b37965a2-b108-475b-b99d-24cf4c231ae2",
      "name": "Sticky Note2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -30,
        351
      ],
      "parameters": {
        "color": 5,
        "width": 668,
        "height": 353,
        "content": "## 2. Scan, collect & analyze\n\nRuns security scans, fetches SIEM logs, validates policies, and detects anomalies in parallel"
      },
      "typeVersion": 1
    },
    {
      "id": "e9050345-47ef-428c-9101-88bb2e38cddc",
      "name": "Sticky Note3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        672,
        96
      ],
      "parameters": {
        "color": 5,
        "width": 476,
        "height": 905,
        "content": "## 3. Score, alert & remediate\n\nCalculates compliance score, creates tickets, sends critical alerts, and stores results to database"
      },
      "typeVersion": 1
    },
    {
      "id": "d708d76c-63c9-46d9-8c9c-8e50bf01aed7",
      "name": "Sticky Note4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1184,
        256
      ],
      "parameters": {
        "color": 5,
        "width": 960,
        "height": 553,
        "content": "## 4. Report & notify\n\nGenerates audit-ready HTML compliance report and delivers to team via Email and Slack"
      },
      "typeVersion": 1
    },
    {
      "id": "0ed7197c-e590-41b9-9658-c7b80ad118b9",
      "name": "Weekly compliance check every Monday 9 AM",
      "type": "n8n-nodes-base.scheduleTrigger",
      "position": [
        -416,
        544
      ],
      "parameters": {
        "rule": {
          "interval": [
            {
              "field": "cronExpression",
              "expression": "0 9 * * 1"
            }
          ]
        }
      },
      "typeVersion": 1.2
    },
    {
      "id": "d7137554-b81d-417b-ba61-6f2025e5db56",
      "name": "Initiate full security scan across environments",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -192,
        448
      ],
      "parameters": {
        "url": "https://api.example.com/security/scan",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "sendHeaders": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "scan_type",
              "value": "full_compliance"
            },
            {
              "name": "environments",
              "value": "IT,OT,cloud"
            },
            {
              "name": "frameworks",
              "value": "ISO27001,NIST,GDPR,SOC2"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "bd6b07d3-3857-4994-98c7-d1d67b47e7c0",
      "name": "Fetch 7 days of SIEM security logs",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        -192,
        640
      ],
      "parameters": {
        "url": "https://api.example.com/logs/security?days=7",
        "options": {}
      },
      "typeVersion": 4.2
    },
    {
      "id": "361e37b6-7887-4e80-b6d8-df53881233c5",
      "name": "Merge scan results and log data",
      "type": "n8n-nodes-base.merge",
      "position": [
        32,
        544
      ],
      "parameters": {
        "mode": "combine",
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "9a5cdde8-cf35-4789-bcd4-c8dc42d9631a",
      "name": "Analyze scan results and detect log anomalies",
      "type": "n8n-nodes-base.code",
      "position": [
        256,
        544
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Analyze security scan results and SIEM logs for anomalies\nconst data = $input.item.json;\n\n// --- Policy compliance validation ---\nconst frameworks = ['ISO27001', 'NIST', 'GDPR', 'SOC2'];\nconst policyResults = data.policy_results || {};\nconst controlsPassed = policyResults.controls_passed || 0;\nconst controlsTotal = policyResults.controls_total || 100;\nconst compliancePercentage = controlsTotal > 0 ? Math.round((controlsPassed / controlsTotal) * 100) : 0;\n\n// --- Log anomaly detection ---\nconst logs = data.logs || [];\nlet anomaliesDetected = 0;\nlet suspiciousActivities = [];\nconst failedLoginThreshold = 3;\n\nlogs.forEach(log => {\n  if (log.severity === 'high' || (log.failed_attempts && log.failed_attempts > failedLoginThreshold)) {\n    anomaliesDetected++;\n    suspiciousActivities.push({\n      timestamp: log.timestamp,\n      type: log.event_type || 'Unknown',\n      user: log.user_id || 'Anonymous',\n      severity: log.severity || 'high',\n      source_ip: log.source_ip || 'N/A'\n    });\n  }\n});\n\n// --- Risk level from logs ---\nconst logRiskLevel = anomaliesDetected > 10 ? 'HIGH' : anomaliesDetected > 5 ? 'MEDIUM' : 'LOW';\n\n// --- Vulnerability findings ---\nconst scanFindings = data.scan_results || {};\nconst criticalFindings = scanFindings.critical || 0;\nconst highFindings = scanFindings.high || 0;\nconst mediumFindings = scanFindings.medium || 0;\nconst lowFindings = scanFindings.low || 0;\n\n// --- Overall compliance status ---\nlet complianceStatus = 'COMPLIANT';\nif (compliancePercentage < 80 || criticalFindings > 0) complianceStatus = 'NON-COMPLIANT';\nelse if (compliancePercentage < 95 || highFindings > 0) complianceStatus = 'WARNING';\n\n// --- Risk score calculation (0-100) ---\nlet riskScore = 100 - compliancePercentage;\nriskScore += criticalFindings * 5;\nriskScore += highFindings * 2;\nriskScore += anomaliesDetected * 1;\nriskScore = Math.min(riskScore, 100);\n\n// --- Frameworks assessed ---\nconst frameworkStatuses = {};\nframeworks.forEach(fw => {\n  frameworkStatuses[fw] = policyResults[fw.toLowerCase()] || { compliant: false, score: 0 };\n});\n\n// --- Timestamp ---\nconst timestamp = new Date().toISOString();\nconst reportDate = new Date().toLocaleDateString('en-US', { year: 'numeric', month: 'long', day: 'numeric' });\nconst weekNumber = Math.ceil(new Date().getDate() / 7);\nconst reportId = `RPT-${new Date().getFullYear()}-W${String(weekNumber).padStart(2, '0')}`;\n\n// --- Determine remediation priority ---\nlet remediationPriority = 'low';\nif (criticalFindings > 0) remediationPriority = 'critical';\nelse if (highFindings > 0 || anomaliesDetected > 5) remediationPriority = 'high';\nelse if (mediumFindings > 0) remediationPriority = 'medium';\n\nreturn {\n  json: {\n    // Report Identity\n    reportId,\n    reportDate,\n    timestamp,\n    lastUpdated: timestamp,\n\n    // Compliance Scores\n    complianceScore: compliancePercentage,\n    complianceStatus,\n    riskScore,\n    logRiskLevel,\n\n    // Vulnerability Findings\n    criticalFindings,\n    highFindings,\n    mediumFindings,\n    lowFindings,\n    totalFindings: criticalFindings + highFindings + mediumFindings + lowFindings,\n\n    // Log Analysis\n    totalLogsAnalyzed: logs.length,\n    anomaliesDetected,\n    suspiciousActivities,\n\n    // Framework Compliance\n    frameworkStatuses,\n    frameworksAssessed: frameworks,\n\n    // Controls\n    controlsPassed,\n    controlsTotal,\n    controlsFailed: controlsTotal - controlsPassed,\n\n    // Remediation\n    remediationPriority,\n    requiresImmediateAction: criticalFindings > 0 || complianceStatus === 'NON-COMPLIANT',\n    requiresAlert: criticalFindings > 0 || highFindings > 0,\n\n    // Original data for reference\n    originalData: data\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "139d56f5-3e30-4a36-bf9e-d8236b533b66",
      "name": "Check for duplicate compliance reports",
      "type": "n8n-nodes-base.code",
      "position": [
        480,
        544
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Check for prior compliance run in same week to avoid duplicate reports\nconst reportId = $input.item.json.reportId;\nconst complianceStatus = $input.item.json.complianceStatus;\n\n// Use workflow static data to track processed reports\nconst processedReports = $getWorkflowStaticData('global').processedReports || {};\n\nif (processedReports[reportId]) {\n  const existing = processedReports[reportId];\n\n  return {\n    json: {\n      ...$input.item.json,\n      isDuplicate: true,\n      isUpdate: true,\n      existingData: existing,\n      action: 'update'\n    }\n  };\n}\n\n// New report \u2014 register it\nprocessedReports[reportId] = {\n  timestamp: new Date().toISOString(),\n  reportId,\n  complianceStatus,\n  complianceScore: $input.item.json.complianceScore\n};\n\n// Clean up reports older than 365 days\nconst oneYearAgo = Date.now() - (365 * 24 * 60 * 60 * 1000);\nfor (const key in processedReports) {\n  const entryTime = new Date(processedReports[key].timestamp).getTime();\n  if (entryTime < oneYearAgo) {\n    delete processedReports[key];\n  }\n}\n\n$getWorkflowStaticData('global').processedReports = processedReports;\n\nreturn {\n  json: {\n    ...$input.item.json,\n    isDuplicate: false,\n    isUpdate: false,\n    action: 'create'\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "5c9cd279-d61b-4550-b26c-8f3bdc01efaa",
      "name": "Route by compliance status",
      "type": "n8n-nodes-base.switch",
      "position": [
        704,
        528
      ],
      "parameters": {
        "rules": {
          "values": [
            {
              "outputKey": "Critical \u2014 Non-Compliant",
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.complianceStatus }}",
                    "rightValue": "NON-COMPLIANT"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Warning",
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.complianceStatus }}",
                    "rightValue": "WARNING"
                  }
                ]
              },
              "renameOutput": true
            },
            {
              "outputKey": "Compliant",
              "conditions": {
                "options": {
                  "leftValue": "",
                  "caseSensitive": true,
                  "typeValidation": "strict"
                },
                "combinator": "and",
                "conditions": [
                  {
                    "operator": {
                      "type": "string",
                      "operation": "equals"
                    },
                    "leftValue": "={{ $json.complianceStatus }}",
                    "rightValue": "COMPLIANT"
                  }
                ]
              },
              "renameOutput": true
            }
          ]
        },
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "3058a9cb-b31a-48e7-85a8-f0f0133b004a",
      "name": "Send critical compliance alert",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        928,
        256
      ],
      "parameters": {
        "url": "https://api.example.com/alerts/send",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "sendHeaders": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "alert_type",
              "value": "CRITICAL_COMPLIANCE_FAILURE"
            },
            {
              "name": "severity",
              "value": "critical"
            },
            {
              "name": "report_id",
              "value": "={{ $json.reportId }}"
            },
            {
              "name": "compliance_score",
              "value": "={{ $json.complianceScore }}"
            },
            {
              "name": "critical_findings",
              "value": "={{ $json.criticalFindings }}"
            },
            {
              "name": "anomalies_detected",
              "value": "={{ $json.anomaliesDetected }}"
            },
            {
              "name": "message",
              "value": "={{ 'CRITICAL: System is NON-COMPLIANT. Score: ' + $json.complianceScore + '%. Critical findings: ' + $json.criticalFindings + '. Immediate remediation required.' }}"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "0131735a-c60a-4d15-8b0a-6be6a298a5c9",
      "name": "Create remediation tickets in Jira",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        928,
        448
      ],
      "parameters": {
        "url": "https://api.example.com/tickets/create",
        "method": "POST",
        "options": {},
        "sendBody": true,
        "sendHeaders": true,
        "bodyParameters": {
          "parameters": [
            {
              "name": "title",
              "value": "={{ '[' + $json.reportId + '] Compliance Remediation Required \u2014 ' + $json.complianceStatus }}"
            },
            {
              "name": "priority",
              "value": "={{ $json.remediationPriority }}"
            },
            {
              "name": "project",
              "value": "SEC"
            },
            {
              "name": "issue_type",
              "value": "Security"
            },
            {
              "name": "description",
              "value": "={{ 'Report: ' + $json.reportId + '\\nStatus: ' + $json.complianceStatus + '\\nScore: ' + $json.complianceScore + '%\\nCritical Findings: ' + $json.criticalFindings + '\\nHigh Findings: ' + $json.highFindings + '\\nAnomalies Detected: ' + $json.anomaliesDetected + '\\nFrameworks: ' + $json.frameworksAssessed.join(', ') }}"
            },
            {
              "name": "labels",
              "value": "compliance,security,automated"
            }
          ]
        },
        "headerParameters": {
          "parameters": [
            {
              "name": "Content-Type",
              "value": "application/json"
            }
          ]
        }
      },
      "typeVersion": 4.2
    },
    {
      "id": "c659bc88-765a-4654-a5ec-49c51b05ff03",
      "name": "Store compliance report in PostgreSQL",
      "type": "n8n-nodes-base.postgres",
      "position": [
        928,
        640
      ],
      "parameters": {
        "table": "compliance_reports",
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "columns": {
          "value": {
            "report_id": "={{ $json.reportId }}",
            "timestamp": "={{ $json.timestamp }}",
            "risk_score": "={{ $json.riskScore }}",
            "report_date": "={{ $json.reportDate }}",
            "low_findings": "={{ $json.lowFindings }}",
            "high_findings": "={{ $json.highFindings }}",
            "controls_total": "={{ $json.controlsTotal }}",
            "log_risk_level": "={{ $json.logRiskLevel }}",
            "total_findings": "={{ $json.totalFindings }}",
            "controls_failed": "={{ $json.controlsFailed }}",
            "controls_passed": "={{ $json.controlsPassed }}",
            "medium_findings": "={{ $json.mediumFindings }}",
            "compliance_score": "={{ $json.complianceScore }}",
            "compliance_status": "={{ $json.complianceStatus }}",
            "critical_findings": "={{ $json.criticalFindings }}",
            "anomalies_detected": "={{ $json.anomaliesDetected }}",
            "frameworks_assessed": "={{ $json.frameworksAssessed.join(', ') }}",
            "total_logs_analyzed": "={{ $json.totalLogsAnalyzed }}",
            "remediation_priority": "={{ $json.remediationPriority }}"
          },
          "mappingMode": "defineBelow"
        },
        "options": {}
      },
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.5
    },
    {
      "id": "b4261796-048e-4a39-9ee3-f1702c6408b5",
      "name": "Update existing report in PostgreSQL",
      "type": "n8n-nodes-base.postgres",
      "position": [
        928,
        832
      ],
      "parameters": {
        "table": "compliance_reports",
        "schema": {
          "__rl": true,
          "mode": "list",
          "value": "public"
        },
        "columns": {
          "value": {},
          "schema": [],
          "mappingMode": "autoMapInputData",
          "matchingColumns": [
            "report_id"
          ],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {}
      },
      "credentials": {
        "postgres": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.5
    },
    {
      "id": "503ae646-8970-4b01-9f8b-b3c54c87cd57",
      "name": "Generate audit-ready HTML compliance report",
      "type": "n8n-nodes-base.code",
      "position": [
        1216,
        544
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Generate audit-ready HTML compliance report with scorecards and evidence logs\nconst report = $input.item.json;\n\nconst statusColor = report.complianceStatus === 'COMPLIANT' ? '#22c55e' \n  : report.complianceStatus === 'WARNING' ? '#f59e0b' \n  : '#ef4444';\n\nconst statusIcon = report.complianceStatus === 'COMPLIANT' ? '\u2705' \n  : report.complianceStatus === 'WARNING' ? '\u26a0\ufe0f' \n  : '\ud83d\udea8';\n\nconst riskLevelColor = report.logRiskLevel === 'HIGH' ? '#ef4444' \n  : report.logRiskLevel === 'MEDIUM' ? '#f59e0b' \n  : '#22c55e';\n\n// Build framework rows\nconst frameworkRows = report.frameworksAssessed.map(fw => {\n  const fwData = report.frameworkStatuses[fw] || {};\n  const score = fwData.score || 'N/A';\n  const compliant = fwData.compliant ? '\u2705 Compliant' : '\u274c Non-Compliant';\n  return `<tr><td>${fw}</td><td>${compliant}</td><td>${score}</td></tr>`;\n}).join('');\n\n// Build suspicious activity rows\nconst activityRows = (report.suspiciousActivities || []).slice(0, 10).map(a => {\n  return `<tr><td>${a.timestamp || 'N/A'}</td><td>${a.type || 'N/A'}</td><td>${a.user || 'N/A'}</td><td>${a.severity || 'N/A'}</td><td>${a.source_ip || 'N/A'}</td></tr>`;\n}).join('') || '<tr><td colspan=\"5\">No suspicious activities detected</td></tr>';\n\nconst reportHtml = `\n<!DOCTYPE html>\n<html>\n<head>\n  <meta charset=\"UTF-8\">\n  <title>Compliance Report ${report.reportId}</title>\n  <style>\n    body { font-family: Arial, sans-serif; color: #1e293b; margin: 0; padding: 24px; background: #f8fafc; }\n    .header { background: #0f172a; color: white; padding: 24px; border-radius: 8px; margin-bottom: 24px; }\n    .header h1 { margin: 0 0 8px 0; font-size: 22px; }\n    .header p { margin: 0; opacity: 0.7; font-size: 13px; }\n    .status-badge { display: inline-block; padding: 6px 16px; border-radius: 20px; font-weight: bold; font-size: 14px; background: ${statusColor}; color: white; margin-top: 12px; }\n    .cards { display: grid; grid-template-columns: repeat(4, 1fr); gap: 16px; margin-bottom: 24px; }\n    .card { background: white; border-radius: 8px; padding: 16px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n    .card .value { font-size: 28px; font-weight: bold; }\n    .card .label { font-size: 12px; color: #64748b; margin-top: 4px; }\n    .section { background: white; border-radius: 8px; padding: 20px; margin-bottom: 20px; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }\n    .section h2 { margin: 0 0 16px 0; font-size: 16px; border-bottom: 2px solid #e2e8f0; padding-bottom: 8px; }\n    table { width: 100%; border-collapse: collapse; font-size: 13px; }\n    th { background: #f1f5f9; text-align: left; padding: 8px 12px; }\n    td { padding: 8px 12px; border-bottom: 1px solid #e2e8f0; }\n    .footer { text-align: center; font-size: 11px; color: #94a3b8; margin-top: 24px; }\n  </style>\n</head>\n<body>\n  <div class=\"header\">\n    <h1>${statusIcon} Cybersecurity Compliance Report</h1>\n    <p>Report ID: ${report.reportId} &nbsp;|&nbsp; Generated: ${report.reportDate} &nbsp;|&nbsp; Frameworks: ${report.frameworksAssessed.join(', ')}</p>\n    <div class=\"status-badge\">${report.complianceStatus}</div>\n  </div>\n\n  <div class=\"cards\">\n    <div class=\"card\"><div class=\"value\" style=\"color: ${statusColor}\">${report.complianceScore}%</div><div class=\"label\">Compliance Score</div></div>\n    <div class=\"card\"><div class=\"value\" style=\"color: #ef4444\">${report.criticalFindings}</div><div class=\"label\">Critical Findings</div></div>\n    <div class=\"card\"><div class=\"value\" style=\"color: ${riskLevelColor}\">${report.anomaliesDetected}</div><div class=\"label\">Log Anomalies</div></div>\n    <div class=\"card\"><div class=\"value\">${report.controlsPassed}/${report.controlsTotal}</div><div class=\"label\">Controls Passed</div></div>\n  </div>\n\n  <div class=\"section\">\n    <h2>\ud83d\udccb Framework Compliance Status</h2>\n    <table><thead><tr><th>Framework</th><th>Status</th><th>Score</th></tr></thead><tbody>${frameworkRows}</tbody></table>\n  </div>\n\n  <div class=\"section\">\n    <h2>\ud83d\udd0d Vulnerability Summary</h2>\n    <table><thead><tr><th>Severity</th><th>Count</th></tr></thead><tbody>\n      <tr><td>Critical</td><td style=\"color:#ef4444;font-weight:bold\">${report.criticalFindings}</td></tr>\n      <tr><td>High</td><td style=\"color:#f97316;font-weight:bold\">${report.highFindings}</td></tr>\n      <tr><td>Medium</td><td style=\"color:#f59e0b\">${report.mediumFindings}</td></tr>\n      <tr><td>Low</td><td>${report.lowFindings}</td></tr>\n      <tr><td><strong>Total</strong></td><td><strong>${report.totalFindings}</strong></td></tr>\n    </tbody></table>\n  </div>\n\n  <div class=\"section\">\n    <h2>\ud83d\udd2c Suspicious Activity Evidence Log</h2>\n    <p style=\"font-size:12px;color:#64748b\">Showing up to 10 most recent suspicious events from ${report.totalLogsAnalyzed} logs analyzed. Log Risk Level: <strong style=\"color:${riskLevelColor}\">${report.logRiskLevel}</strong></p>\n    <table><thead><tr><th>Timestamp</th><th>Event Type</th><th>User</th><th>Severity</th><th>Source IP</th></tr></thead><tbody>${activityRows}</tbody></table>\n  </div>\n\n  <div class=\"footer\">Automated report generated by Cybersecurity Compliance Monitoring Workflow &nbsp;|&nbsp; ${report.timestamp}</div>\n</body>\n</html>`;\n\nconst notificationMessage = `${statusIcon} *WEEKLY COMPLIANCE REPORT \u2014 ${report.reportId}*\\n\\n` +\n  `*Status:* ${report.complianceStatus}\\n` +\n  `*Compliance Score:* ${report.complianceScore}%\\n` +\n  `*Risk Score:* ${report.riskScore}/100\\n` +\n  `*Log Risk Level:* ${report.logRiskLevel}\\n\\n` +\n  `*Findings:* Critical: ${report.criticalFindings} | High: ${report.highFindings} | Medium: ${report.mediumFindings}\\n` +\n  `*Anomalies Detected:* ${report.anomaliesDetected} from ${report.totalLogsAnalyzed} logs\\n` +\n  `*Controls:* ${report.controlsPassed}/${report.controlsTotal} passed\\n\\n` +\n  `*Frameworks Assessed:* ${report.frameworksAssessed.join(', ')}\\n` +\n  `*Report Date:* ${report.reportDate}\\n` +\n  `*Remediation Priority:* ${report.remediationPriority.toUpperCase()}`;\n\nreturn {\n  json: {\n    ...report,\n    reportHtml,\n    notificationMessage,\n    notificationTitle: `${statusIcon} [${report.reportId}] Compliance ${report.complianceStatus} \u2014 Score: ${report.complianceScore}%`,\n    shouldNotify: report.complianceStatus === 'NON-COMPLIANT' || report.complianceStatus === 'WARNING',\n    shouldNotifyAll: true\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "bad858d6-007e-441d-9071-5c83da6ba2a9",
      "name": "Filter for non-compliant and warning reports",
      "type": "n8n-nodes-base.filter",
      "position": [
        1376,
        544
      ],
      "parameters": {
        "options": {},
        "conditions": {
          "options": {
            "leftValue": "",
            "caseSensitive": false,
            "typeValidation": "strict"
          },
          "combinator": "and",
          "conditions": [
            {
              "id": "notify-condition",
              "operator": {
                "type": "boolean",
                "operation": "true"
              },
              "leftValue": "={{ $json.shouldNotifyAll }}"
            }
          ]
        }
      },
      "typeVersion": 2
    },
    {
      "id": "f89a8f4b-dbd8-4843-bff3-2217b3fd1b08",
      "name": "Post compliance summary to Slack",
      "type": "n8n-nodes-base.httpRequest",
      "position": [
        1600,
        448
      ],
      "parameters": {
        "url": "YOUR_SLACK_WEBHOOK_URL",
        "method": "POST",
        "options": {},
        "jsonBody": "={\n  \"text\": \"{{ $json.notificationTitle }}\",\n  \"blocks\": [\n    {\n      \"type\": \"section\",\n      \"text\": {\n        \"type\": \"mrkdwn\",\n        \"text\": \"{{ $json.notificationMessage }}\"\n      }\n    }\n  ]\n}",
        "sendBody": true,
        "specifyBody": "json"
      },
      "typeVersion": 4.2
    },
    {
      "id": "4174b783-2d40-4b6f-9bf6-9a71de1657d2",
      "name": "Email audit-ready report to team",
      "type": "n8n-nodes-base.emailSend",
      "position": [
        1600,
        640
      ],
      "parameters": {
        "html": "={{ $json.reportHtml }}",
        "options": {},
        "subject": "={{ $json.notificationTitle }}",
        "toEmail": "user@example.com",
        "fromEmail": "user@example.com"
      },
      "credentials": {
        "smtp": {
          "name": "<your credential>"
        }
      },
      "typeVersion": 2.1
    },
    {
      "id": "2198e4d1-26ac-419e-851a-10cbd7365144",
      "name": "Log success and track compliance statistics",
      "type": "n8n-nodes-base.code",
      "position": [
        1824,
        544
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Log successful compliance cycle and track statistics\nconst timestamp = new Date().toISOString();\nconst report = $input.item.json;\n\nconsole.log(`\u2705 SUCCESS: Compliance report ${report.reportId} | Status: ${report.complianceStatus} | Score: ${report.complianceScore}% | Critical: ${report.criticalFindings} | Anomalies: ${report.anomaliesDetected} | Time: ${timestamp}`);\n\n// Cumulative statistics\nconst stats = $getWorkflowStaticData('global').stats || {\n  totalReports: 0,\n  compliantCount: 0,\n  warningCount: 0,\n  nonCompliantCount: 0,\n  totalCriticalFindings: 0,\n  totalAnomalies: 0,\n  lastProcessed: null\n};\n\nif (report.action === 'create') {\n  stats.totalReports++;\n  if (report.complianceStatus === 'COMPLIANT') stats.compliantCount++;\n  else if (report.complianceStatus === 'WARNING') stats.warningCount++;\n  else stats.nonCompliantCount++;\n  stats.totalCriticalFindings += report.criticalFindings || 0;\n  stats.totalAnomalies += report.anomaliesDetected || 0;\n}\n\nstats.lastProcessed = timestamp;\n$getWorkflowStaticData('global').stats = stats;\n\nreturn {\n  json: {\n    success: true,\n    action: report.action,\n    reportId: report.reportId,\n    complianceStatus: report.complianceStatus,\n    complianceScore: report.complianceScore,\n    criticalFindings: report.criticalFindings,\n    anomaliesDetected: report.anomaliesDetected,\n    timestamp,\n    cumulativeStats: stats\n  }\n};"
      },
      "typeVersion": 2
    }
  ],
  "active": false,
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "8270314b-ccbb-4eb9-bbf8-795b9245cda2",
  "connections": {
    "Route by compliance status": {
      "main": [
        [
          {
            "node": "Send critical compliance alert",
            "type": "main",
            "index": 0
          },
          {
            "node": "Create remediation tickets in Jira",
            "type": "main",
            "index": 0
          },
          {
            "node": "Store compliance report in PostgreSQL",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Create remediation tickets in Jira",
            "type": "main",
            "index": 0
          },
          {
            "node": "Store compliance report in PostgreSQL",
            "type": "main",
            "index": 0
          }
        ],
        [
          {
            "node": "Store compliance report in PostgreSQL",
            "type": "main",
            "index": 0
          },
          {
            "node": "Update existing report in PostgreSQL",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Send critical compliance alert": {
      "main": [
        [
          {
            "node": "Generate audit-ready HTML compliance report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Merge scan results and log data": {
      "main": [
        [
          {
            "node": "Analyze scan results and detect log anomalies",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Email audit-ready report to team": {
      "main": [
        [
          {
            "node": "Log success and track compliance statistics",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Post compliance summary to Slack": {
      "main": [
        [
          {
            "node": "Log success and track compliance statistics",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Create remediation tickets in Jira": {
      "main": [
        [
          {
            "node": "Generate audit-ready HTML compliance report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Fetch 7 days of SIEM security logs": {
      "main": [
        [
          {
            "node": "Merge scan results and log data",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "Update existing report in PostgreSQL": {
      "main": [
        [
          {
            "node": "Generate audit-ready HTML compliance report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Store compliance report in PostgreSQL": {
      "main": [
        [
          {
            "node": "Generate audit-ready HTML compliance report",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Check for duplicate compliance reports": {
      "main": [
        [
          {
            "node": "Route by compliance status",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Weekly compliance check every Monday 9 AM": {
      "main": [
        [
          {
            "node": "Initiate full security scan across environments",
            "type": "main",
            "index": 0
          },
          {
            "node": "Fetch 7 days of SIEM security logs",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Generate audit-ready HTML compliance report": {
      "main": [
        [
          {
            "node": "Filter for non-compliant and warning reports",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Filter for non-compliant and warning reports": {
      "main": [
        [
          {
            "node": "Post compliance summary to Slack",
            "type": "main",
            "index": 0
          },
          {
            "node": "Email audit-ready report to team",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Analyze scan results and detect log anomalies": {
      "main": [
        [
          {
            "node": "Check for duplicate compliance reports",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "Initiate full security scan across environments": {
      "main": [
        [
          {
            "node": "Merge scan results and log data",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}