CyberPulse-Konformität – v2 Batch-Verarbeitungs-Pipeline

Experte

Dies ist ein Automatisierungsworkflow mit 18 Nodes. Hauptsächlich werden Set, Code, Merge, GoogleSheets, ManualTrigger und andere Nodes verwendet. Automatisierte Bewertung von Kontrollen für die Einhaltung von Vorschriften mit CyberPulse, GPT-4o und Google Sheets

Voraussetzungen
  • Google Sheets API-Anmeldedaten
  • OpenAI API Key

Kategorie

-
Workflow-Vorschau
Visualisierung der Node-Verbindungen, mit Zoom und Pan
Workflow exportieren
Kopieren Sie die folgende JSON-Konfiguration und importieren Sie sie in n8n
{
  "id": "6yJ0KXSSGqSb9FY6",
  "meta": {
    "instanceId": "6feff41aadeb8409737e26476f9d0a45f95eec6a9c16afff8ef87a662455b6df",
    "templateCredsSetupCompleted": true
  },
  "name": "CyberPulse Compliance – v2 batch pipeline",
  "tags": [],
  "nodes": [
    {
      "id": "1ae2a107-6515-4dbe-a3b8-4c3fd5d64cce",
      "name": "Manueller Auslöser",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -1008,
        -608
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "2360ade2-1686-4554-beb3-76ba59e16408",
      "name": "Zeile in Tabelle anhängen",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        2208,
        -336
      ],
      "parameters": {
        "columns": {
          "value": {
            "score": "={{ $json.score }}",
            "status": "={{ $json.status }}",
            "rationale": "={{ $json.rationale }}",
            "timestamp": "={{ $json.timestamp }}",
            "ai_summary": "={{ $json.ai_summary }}",
            "categories": "={{ $json.categories }}",
            "confidence": "={{ $json.confidence }}",
            "control_id": "={{ $json.control_id }}",
            "evaluation": "={{ $json.evaluation }}",
            "ai_findings": "={{ $json.ai_findings }}",
            "mapped_count": "={{ $json.mapped_count }}",
            "mapping_flat": "={{ $json.mapping_flat }}",
            "response_text": "={{ $json.response_text }}",
            "engine_version": "={{ $json.engine_version }}",
            "evidence_count": "={{ $json.evidence_count }}",
            "evidence_url_1": "={{ $json.evidence_url_1 }}",
            "evidence_url_2": "={{ $json.evidence_url_2 }}",
            "evidence_url_3": "={{ $json.evidence_url_3 }}",
            "evidence_url_4": "={{ $json.evidence_url_4 }}",
            "ai_recommendations": "={{ $json.ai_recommendations }}",
            "control_description": "={{ $json.control_description }}",
            "frameworks_selected": "={{ $json.frameworks_selected }}",
            "implementation_notes": "={{ $json.implementation_notes }}"
          },
          "schema": [
            {
              "id": "timestamp",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "timestamp",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "control_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "control_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "control_description",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "control_description",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "response_text",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "response_text",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "implementation_notes",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "implementation_notes",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "evidence_url_1",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "evidence_url_1",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "evidence_url_2",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "evidence_url_2",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "evidence_url_3",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "evidence_url_3",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "evidence_url_4",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "evidence_url_4",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "status",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "status",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "evaluation",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "evaluation",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "score",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "score",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "confidence",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "confidence",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "rationale",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "rationale",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "categories",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "categories",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "evidence_count",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "evidence_count",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "mapped_count",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "mapped_count",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "mapping_flat",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "mapping_flat",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "frameworks_selected",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "frameworks_selected",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "engine_version",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "engine_version",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "ai_summary",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "ai_summary",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "ai_findings",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "ai_findings",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "ai_recommendations",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "ai_recommendations",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "priority",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "priority",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "owner",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "owner",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "due_date",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "due_date",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "ticket_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "ticket_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "next_action",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "next_action",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "evidence_gap_flag",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "evidence_gap_flag",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "policy_gap_flag",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "policy_gap_flag",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "last_run_id",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "last_run_id",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            },
            {
              "id": "source_sheet_row",
              "type": "string",
              "display": true,
              "required": false,
              "displayName": "source_sheet_row",
              "defaultMatch": false,
              "canBeUsedToMatch": true
            }
          ],
          "mappingMode": "defineBelow",
          "matchingColumns": [],
          "attemptToConvertTypes": false,
          "convertFieldsToString": false
        },
        "options": {},
        "operation": "append",
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1117838353,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1owd3qVXCO34EhvBO5Vr3d2Pn2_QQXt0rNl_kroSmf0I/edit#gid=1117838353",
          "cachedResultName": "controls_results_template.csv"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1owd3qVXCO34EhvBO5Vr3d2Pn2_QQXt0rNl_kroSmf0I",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1owd3qVXCO34EhvBO5Vr3d2Pn2_QQXt0rNl_kroSmf0I/edit?usp=drivesdk",
          "cachedResultName": "controls_results_template"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "SHFVDGHEaA6jzLc4",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "46fe1437-f8b0-4ede-9cc6-23958351755a",
      "name": "Zeile(n) in Tabelle abrufen",
      "type": "n8n-nodes-base.googleSheets",
      "position": [
        -992,
        -368
      ],
      "parameters": {
        "options": {},
        "sheetName": {
          "__rl": true,
          "mode": "list",
          "value": 1182991363,
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1Gcak2OCpo2vnDkB2W49xz4TD762DGCY3ZA6Pkfv82nM/edit#gid=1182991363",
          "cachedResultName": "Sheet1"
        },
        "documentId": {
          "__rl": true,
          "mode": "list",
          "value": "1Gcak2OCpo2vnDkB2W49xz4TD762DGCY3ZA6Pkfv82nM",
          "cachedResultUrl": "https://docs.google.com/spreadsheets/d/1Gcak2OCpo2vnDkB2W49xz4TD762DGCY3ZA6Pkfv82nM/edit?usp=drivesdk",
          "cachedResultName": "controls_input_mock_100_rows"
        }
      },
      "credentials": {
        "googleSheetsOAuth2Api": {
          "id": "SHFVDGHEaA6jzLc4",
          "name": "Google Sheets account"
        }
      },
      "typeVersion": 4.7
    },
    {
      "id": "2f4910f6-3fdf-4133-b714-b6752d5bdb94",
      "name": "Erklären & Empfehlen",
      "type": "@n8n/n8n-nodes-langchain.openAi",
      "position": [
        640,
        -288
      ],
      "parameters": {
        "modelId": {
          "__rl": true,
          "mode": "list",
          "value": "gpt-4o-mini",
          "cachedResultName": "GPT-4O-MINI"
        },
        "options": {},
        "messages": {
          "values": [
            {
              "role": "system",
              "content": "=Use only the provided fields. Do not invent evidence, numbers, or frameworks.\nReturn a JSON object with keys exactly:\n- ai_summary (string)\n- ai_findings (array of 3 short strings), no bullets, no dashes, no numbering, no checkboxes.\n- ai_recommendations (array of 3 short, actionable strings), no bullets, no dashes, no numbering, no checkboxes.\nNo other keys.\n"
            },
            {
              "content": "={\n  \"timestamp\": \"{{ $('Edit Fields').item.json.timestamp }}\",\n  \"control_id\": \"{{ $('Edit Fields').item.json.control_id }}\",\n  \"control_description\": \"{{ $('Edit Fields').item.json.control_description }}\",\n  \"response_text\": \"{{ $('Edit Fields').item.json.response_text }}\",\n  \"implementation_notes\": \"{{$json.implementation_notes || ''}}\",\n\n  \"status\": \"{{$json.status}}\",\n  \"evaluation\": \"{{$json.evaluation}}\",\n  \"score\": {{ +$json.score }},\n  \"confidence\": {{ +$json.confidence }},\n  \"rationale\": \"{{$json.rationale}}\",\n\n  \"evidence_count\": {{\n  Array.isArray($json.evidence)\n    ? $json.evidence.filter(u => u && String(u).trim()).length\n    : ([\n        $json.evidence_url_1,\n        $json.evidence_url_2,\n        $json.evidence_url_3,\n        $json.evidence_url_4\n      ].filter(u => u && String(u).trim()).length || ($json.evidence_count ?? 0))\n}},\n\n  \"mapped_count\": {{ Array.isArray($json.mapped_requirements) ? $json.mapped_requirements.length : ($json.mapped_count ?? 0) }},\n  \"mapping_flat\": \"{{ Array.isArray($json.mapped_requirements) ? $json.mapped_requirements.map(m => [m.framework, m.clause, m.title].filter(Boolean).join(': ')).join(' | ') : ($json.mapping_flat || '') }}\",\n  \"categories\": \"{{ Array.isArray($json.categories) ? $json.categories.join(', ') : ($json.categories || '') }}\",\n  \"frameworks_selected\": \"{{ Array.isArray($json.mapped_requirements) ? [...new Set($json.mapped_requirements.map(m => m.framework).filter(Boolean))].join(', ') : ($json.frameworks_selected || '') }}\",\n  \"engine_version\": \"{{$json.engine_version || ''}}\",\n\n  \"format_instructions\": \"Return ai_summary exactly as: 'Status: {status}. Evaluation: {evaluation}. Score: {score}. Confidence: {confidence}. Evidence items: {evidence_count}. Categories: {categories}. Mappings: {mapping_flat}'. Then return ai_findings as a single string with 3 short bullets (prefix each with '• ') grounded in rationale/categories. Then return ai_recommendations as a single string with 3 short, actionable bullets (prefix each with '• ') tied to mapping_flat and evidence_count. Also compute priority, next_action, evidence_gap_flag, policy_gap_flag using the rules below.\\n\\nRules:\\n- priority:\\n  - P1 if (status == 'Non-Compliant' && mapped_count >= 3) OR (score < 50 && evidence_count == 0)\\n  - P2 if (status in ['Non-Compliant','Partial'] && (score >= 50 && score < 75)) OR (evidence_count <= 1)\\n  - P3 if (status == 'Compliant' && (confidence < 60 || evidence_count < 2))\\n  - else P4\\n- next_action:\\n  - 'implement' if status == 'Non-Compliant'\\n  - 'remediate' if status == 'Partial'\\n  - 'monitor' if status == 'Compliant' and (confidence < 60 || evidence_count < 2)\\n  - else 'review'\\n- evidence_gap_flag: 'yes' if evidence_count == 0 OR evidence_count == 1, else 'no'\\n- policy_gap_flag: 'yes' if ('policy' appears in (response_text or rationale) case-insensitive) OR categories contains 'policy', else 'no'\"\n}\n"
            }
          ]
        },
        "jsonOutput": true
      },
      "credentials": {
        "openAiApi": {
          "id": "gcqJ07oLkr9oSi82",
          "name": "OpenAi account"
        }
      },
      "typeVersion": 1.8
    },
    {
      "id": "1920b78c-97ac-4303-a055-e2541cf12f29",
      "name": "Parsen + an jedes Element anhängen",
      "type": "n8n-nodes-base.code",
      "position": [
        1696,
        -336
      ],
      "parameters": {
        "mode": "runOnceForEachItem",
        "jsCode": "// Helpers\nfunction isNonEmpty(x){ if(x===undefined||x===null) return false; if(typeof x==='number') return true; return String(x).trim()!==''; }\nfunction prefer(...vals){ for(const v of vals){ if(isNonEmpty(v)) return v; } return ''; }\nfunction safeNum(x, def=''){ const n = Number(x); return Number.isFinite(n) ? n : def; }\n\n// Strip any leading bullets / dashes / numbers / checkboxes before we add our own bullets\nfunction stripLeadingMarkers(s){\n  return String(s).replace(/^\\s*(?:[-*•\\u2022]+|\\d+[.)]|[✓✔✗✘xX\\[\\]\\(\\)])\\s*/u, '');\n}\nfunction asArray(x){\n  if(!x) return [];\n  if(Array.isArray(x)) return x.filter(Boolean).map(v => stripLeadingMarkers(v));\n  return String(x).split(/\\r?\\n+/).map(v => stripLeadingMarkers(v)).filter(Boolean);\n}\nfunction bullets(x){\n  const a = asArray(x);\n  return a.length ? a.map(s => `• ${s}`).join('\\n') : '';\n}\n\n// Current item from Merge\nconst i = $json;\n// Originals straight from \"Edit Fields\" (for fields the merge might not include)\nconst src = $(\"Edit Fields\").item?.json ?? {};\n\n// ---- Ingest (preserve originals)\nconst timestamp           = prefer(i.timestamp, src.timestamp, new Date().toISOString());\nconst control_id          = prefer(i.control_id, src.control_id);\nconst control_description = prefer(i.control_description, src.control_description);\nconst response_text       = prefer(i.response_text, src.response_text);\nconst implementation_notes= prefer(i.implementation_notes, src.implementation_notes);\nconst evidence_url_1      = prefer(i.evidence_url_1, src.evidence_url_1);\nconst evidence_url_2      = prefer(i.evidence_url_2, src.evidence_url_2);\nconst evidence_url_3      = prefer(i.evidence_url_3, src.evidence_url_3);\nconst evidence_url_4      = prefer(i.evidence_url_4, src.evidence_url_4);\n\n// ---- Scoring & mapping\nconst status       = prefer(i.status, 'Unknown');\nconst evaluation   = prefer(i.evaluation, status);\nconst score        = safeNum(i.score);\nconst confidence   = safeNum(i.confidence);\nconst rationaleIn  = prefer(i.rationale, i.reason);\n\n// categories may be array or string\nconst categoriesStr = Array.isArray(i.categories) ? i.categories.join(', ') : prefer(i.categories);\n\n// evidence: prefer i.evidence (array), else derive from URL fields, then filter empties\nlet evidenceArr = [];\nif (Array.isArray(i.evidence)) {\n  evidenceArr = i.evidence.filter(u => u && String(u).trim());\n} else {\n  evidenceArr = [evidence_url_1, evidence_url_2, evidence_url_3, evidence_url_4]\n    .filter(u => u && String(u).trim());\n}\nconst evidence_count = isNonEmpty(i.evidence_count) ? safeNum(i.evidence_count, evidenceArr.length) : evidenceArr.length;\n\n// mapped requirements\nconst mappedReqs   = Array.isArray(i.mapped_requirements) ? i.mapped_requirements : [];\nconst mapped_count = isNonEmpty(i.mapped_count) ? safeNum(i.mapped_count, mappedReqs.length) : mappedReqs.length;\nconst mapping_flat = isNonEmpty(i.mapping_flat)\n  ? String(i.mapping_flat)\n  : mappedReqs.map(m => [m.framework, m.clause, m.title].filter(Boolean).join(': ')).join(' | ');\n\n// frameworks selected (pretty commas)\nconst frameworks_selected = (isNonEmpty(i.frameworks_selected)\n  ? String(i.frameworks_selected)\n  : [...new Set(mappedReqs.map(m => m.framework).filter(Boolean))].join(', ')\n).replace(/,\\s*/g, ', ');\n\nconst engine_version = prefer(i.engine_version, i.version);\n\n// ---- AI outputs (handle message.content object OR JSON string; also accept top-level)\nlet ai_summary = i.ai_summary;\nlet ai_findings_any = i.ai_findings;\nlet ai_recommendations_any = i.ai_recommendations;\n\nif ((!ai_summary || (!ai_findings_any && !ai_recommendations_any)) && i.message?.content) {\n  if (typeof i.message.content === 'object') {\n    const c = i.message.content;\n    ai_summary = ai_summary ?? c.ai_summary;\n    ai_findings_any = ai_findings_any ?? c.ai_findings;\n    ai_recommendations_any = ai_recommendations_any ?? c.ai_recommendations;\n  } else {\n    try {\n      const parsed = JSON.parse(i.message.content);\n      ai_summary = ai_summary ?? parsed.ai_summary;\n      ai_findings_any = ai_findings_any ?? parsed.ai_findings;\n      ai_recommendations_any = ai_recommendations_any ?? parsed.ai_recommendations;\n    } catch {}\n  }\n}\n\n// Normalize to single strings for the sheet (no double bullets)\nconst ai_findings        = bullets(ai_findings_any);\nconst ai_recommendations = bullets(ai_recommendations_any);\n\n// Sync the item count inside rationale (e.g., replace \"(4 items)\" with \"(3 items)\")\nlet rationale = rationaleIn;\nif (isNonEmpty(rationale)) {\n  rationale = rationale.replace(/\\(\\s*\\d+\\s*items?\\s*\\)/i, `(${evidence_count} items)`);\n}\n\n// Synthesize summary if missing (deterministic)\nif (!isNonEmpty(ai_summary)) {\n  ai_summary = `Status: ${status}. Evaluation: ${evaluation}. Score: ${score}. `\n             + `Confidence: ${confidence}. Evidence items: ${evidence_count}. `\n             + `Categories: ${categoriesStr}. Mappings: ${mapping_flat}`;\n}\n\n// Return final row payload\nreturn {\n  json: {\n    // Ingest\n    timestamp,\n    control_id,\n    control_description,\n    response_text,\n    implementation_notes,\n    evidence_url_1,\n    evidence_url_2,\n    evidence_url_3,\n    evidence_url_4,\n\n    // Scoring & mapping\n    status,\n    evaluation,\n    score,\n    confidence,\n    rationale,\n    categories: categoriesStr,\n    evidence_count,\n    mapped_count,\n    mapping_flat,\n    frameworks_selected,\n    engine_version,\n\n    // AI (strings)\n    ai_summary,\n    ai_findings,\n    ai_recommendations\n  }\n};"
      },
      "typeVersion": 2
    },
    {
      "id": "23954e15-29e1-49d3-9614-772e33562fc4",
      "name": "Über Elemente iterieren",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        160,
        -368
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "1f2dda49-fde7-44f8-8efd-e6ffd73e4e96",
      "name": "Felder bearbeiten",
      "type": "n8n-nodes-base.set",
      "position": [
        -672,
        -368
      ],
      "parameters": {
        "options": {},
        "assignments": {
          "assignments": [
            {
              "id": "87318d44-cd2c-47d8-850a-c0b152d6b455",
              "name": "row_number",
              "type": "string",
              "value": "={{ $json.row_number }}"
            },
            {
              "id": "9eab7a02-e58e-46a8-85cb-d2a41693759c",
              "name": "timestamp",
              "type": "string",
              "value": "={{ $json.timestamp }}"
            },
            {
              "id": "6d3fa2f3-5e8b-45c6-80f6-e9b713fd82e4",
              "name": "control_description",
              "type": "string",
              "value": "={{ $json.control_description }}"
            },
            {
              "id": "e0b7a487-bc52-40d9-80a6-5bc2a13c19a0",
              "name": "response_text",
              "type": "string",
              "value": "={{ $json.response_text }}"
            },
            {
              "id": "b6347812-76af-454b-8869-81c47f4c90a8",
              "name": "evidence_url_1",
              "type": "string",
              "value": "={{ $json.evidence_url_1 }}"
            },
            {
              "id": "f8784a98-ead8-4af2-a1ca-42aa2fcc6032",
              "name": "evidence_url_2",
              "type": "string",
              "value": "={{ $json.evidence_url_2 }}"
            },
            {
              "id": "d91dceb0-e1a7-4322-89a9-041a34e00f52",
              "name": "evidence_url_3",
              "type": "string",
              "value": "={{ $json.evidence_url_3 }}"
            },
            {
              "id": "14d6374b-5191-4f4f-85b0-d443a9e404ee",
              "name": "evidence_url_4",
              "type": "string",
              "value": "={{ $json.evidence_url_4 }}"
            },
            {
              "id": "b8bd82a7-c19c-458b-a0cb-5cf2941efc0c",
              "name": "implementation_notes",
              "type": "string",
              "value": "={{ $json.implementation_notes }}"
            }
          ]
        },
        "includeOtherFields": true
      },
      "typeVersion": 3.4
    },
    {
      "id": "af2a5b70-b8e7-4ab4-b9cb-29da669d1474",
      "name": "Zusammenführen1",
      "type": "n8n-nodes-base.merge",
      "position": [
        1216,
        -336
      ],
      "parameters": {
        "mode": "combine",
        "options": {
          "includeUnpaired": true
        },
        "combineBy": "combineByPosition"
      },
      "typeVersion": 3.2
    },
    {
      "id": "d2232908-5186-4e0a-b771-7230028b8b43",
      "name": "CyberPulse Compliance (Dev)",
      "type": "n8n-nodes-cyberpulse-compliance-dev.cyberPulseCompliance",
      "position": [
        -288,
        -368
      ],
      "parameters": {
        "controlText": "=={{ $json.response_text + ($json.implementation_notes ? (' ' + $json.implementation_notes) : '') }}",
        "crosswalkUrl": "https://gist.githubusercontent.com/gitadta/c6b7b69ae2a00f2a67e3bbac4b6648d4/raw/238ce80b0252702d4e6e9c19015bf958d0a0bad6/crosswalk.json",
        "evidenceUrls": [
          "={{ $json.evidence_url_1 }}",
          "={{ $json.evidence_url_2 }}",
          "={{ $json.evidence_url_3 }}",
          "={{ $json.evidence_url_4 }}"
        ]
      },
      "credentials": {
        "cyberPulseHttpHeaderAuthApi": {
          "id": "s8WtV23qQ1z0bVTT",
          "name": "CyberPulse HTTP Header Auth account"
        }
      },
      "typeVersion": 6
    },
    {
      "id": "a7a4f9e1-df82-4776-827b-e89177d9c935",
      "name": "Haftnotiz",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -1328,
        -704
      ],
      "parameters": {
        "color": 4,
        "width": 528,
        "height": 512,
        "content": "\n\n🟢 Manual Trigger — Start/diagnostics\n\nReceives POST and starts the run; echoes runId for tracing\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n🟩 Get row(s) in sheet — Read inputs\n\nLoads model/routing settings from\n the config sheet."
      },
      "typeVersion": 1
    },
    {
      "id": "95cc8cf7-0b2b-4e33-974c-bcb23d07c265",
      "name": "Haftnotiz1",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -784,
        -576
      ],
      "parameters": {
        "color": 5,
        "width": 400,
        "height": 384,
        "content": "\n\n\n\n\n🟦 Edit Fields — Normalize columns\n\nMaps incoming keys, trims text, and sets safe defaults."
      },
      "typeVersion": 1
    },
    {
      "id": "f98d67c1-31e3-4274-a0b0-41812290b18a",
      "name": "Haftnotiz2",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        -368,
        -576
      ],
      "parameters": {
        "width": 432,
        "height": 384,
        "content": "\n\n🟨 CyberPulse Compliance (Dev) — Score + map\n\nScores and maps each control using control text + implementation notes + up to 4 evidence URLs and selected frameworks.\nOutputs score (0–100), status, confidence, binary evaluation, categories, crosswalk mappings, and adds gaps/actions when evidence is weak or missing."
      },
      "typeVersion": 1
    },
    {
      "id": "0777506c-4b63-45ae-a27e-2c4fa519947c",
      "name": "Haftnotiz3",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        80,
        -576
      ],
      "parameters": {
        "color": 6,
        "width": 432,
        "height": 384,
        "content": "\n\n🟪 Loop Over Items — Iterate per control\n\nIterates each control independently to run LLM → parse → append, preserving per-row context and emitting one result per input."
      },
      "typeVersion": 1
    },
    {
      "id": "f5161050-7010-43d6-aadc-eec7daae85d0",
      "name": "Haftnotiz4",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        528,
        -576
      ],
      "parameters": {
        "color": 5,
        "width": 512,
        "height": 384,
        "content": "\n\n🟦 Explain & Recommend (Message Model) — Exec summary\n\nGenerates a strict-JSON executive summary—ai_summary, three ai_findings, and three ai_recommendations—from the control’s status, score, confidence, categories, evidence, and framework mappings."
      },
      "typeVersion": 1
    },
    {
      "id": "ed04125f-e8d8-4a05-afe0-3f8844f07f5e",
      "name": "Haftnotiz5",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1056,
        -576
      ],
      "parameters": {
        "color": 3,
        "width": 464,
        "height": 384,
        "content": "\n\n🟧 Merge1 — Combine model + original\n\nCombines CyberPulse scoring/mapping with the LLM summary by position, producing one merged item per row."
      },
      "typeVersion": 1
    },
    {
      "id": "16c54ee5-0dc1-4374-b2f9-ca831de1c1a4",
      "name": "Haftnotiz6",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        1536,
        -576
      ],
      "parameters": {
        "width": 464,
        "height": 384,
        "content": "\n\n🟨 Parse + attach to each item — Final shaping\n\nMerges CyberPulse scores/mappings with the LLM output by index into a single unified row."
      },
      "typeVersion": 1
    },
    {
      "id": "b4e8b1ee-95ad-4a8b-bd3b-2c07ecab42b3",
      "name": "Haftnotiz7",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        2016,
        -576
      ],
      "parameters": {
        "color": 4,
        "width": 496,
        "height": 384,
        "content": "\n\n🟩 Append row in sheet — Write results\n\nAppends one result row per item to the results sheet with core, scoring, mapping, and AI fields, leaving future columns blank."
      },
      "typeVersion": 1
    },
    {
      "id": "297e3ea4-35bd-4bc5-a851-ecf0f8dda5bc",
      "name": "Haftnotiz8",
      "type": "n8n-nodes-base.stickyNote",
      "position": [
        192,
        -912
      ],
      "parameters": {
        "color": 7,
        "width": 784,
        "height": 288,
        "content": "\n\nWhat is CyberPulse Agent workflow ?\n\nAutomates evidence-aware control scoring (0–100) with deterministic gates and confidence from evidence/text quality.\nReads controls from Google Sheets (text, up to 4 evidence URLs, notes) and classifies, scores, and maps via the CyberPulse node.\nGenerates board-ready AI outputs per control: one-paragraph summary, 3 findings, and 3 actionable recommendations.\nWrites normalized, analytics-ready rows back to a results sheet with flattened framework mappings and detected categories.\nCovers ISO 27001, NIST CSF, SOC 2, PCI DSS, Essential Eight, GDPR; secure, scalable in n8n with tunable weights/thresholds."
      },
      "typeVersion": 1
    }
  ],
  "active": false,
  "pinData": {},
  "settings": {
    "executionOrder": "v1"
  },
  "versionId": "8a012f28-964c-4087-9b74-7c24a4d8f76e",
  "connections": {
    "af2a5b70-b8e7-4ab4-b9cb-29da669d1474": {
      "main": [
        [
          {
            "node": "1920b78c-97ac-4303-a055-e2541cf12f29",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "1f2dda49-fde7-44f8-8efd-e6ffd73e4e96": {
      "main": [
        [
          {
            "node": "d2232908-5186-4e0a-b771-7230028b8b43",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "1ae2a107-6515-4dbe-a3b8-4c3fd5d64cce": {
      "main": [
        [
          {
            "node": "46fe1437-f8b0-4ede-9cc6-23958351755a",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "23954e15-29e1-49d3-9614-772e33562fc4": {
      "main": [
        [],
        [
          {
            "node": "2f4910f6-3fdf-4133-b714-b6752d5bdb94",
            "type": "main",
            "index": 0
          },
          {
            "node": "af2a5b70-b8e7-4ab4-b9cb-29da669d1474",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "2360ade2-1686-4554-beb3-76ba59e16408": {
      "main": [
        [
          {
            "node": "23954e15-29e1-49d3-9614-772e33562fc4",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "2f4910f6-3fdf-4133-b714-b6752d5bdb94": {
      "main": [
        [
          {
            "node": "af2a5b70-b8e7-4ab4-b9cb-29da669d1474",
            "type": "main",
            "index": 1
          }
        ]
      ]
    },
    "46fe1437-f8b0-4ede-9cc6-23958351755a": {
      "main": [
        [
          {
            "node": "1f2dda49-fde7-44f8-8efd-e6ffd73e4e96",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "d2232908-5186-4e0a-b771-7230028b8b43": {
      "main": [
        [
          {
            "node": "23954e15-29e1-49d3-9614-772e33562fc4",
            "type": "main",
            "index": 0
          }
        ]
      ]
    },
    "1920b78c-97ac-4303-a055-e2541cf12f29": {
      "main": [
        [
          {
            "node": "2360ade2-1686-4554-beb3-76ba59e16408",
            "type": "main",
            "index": 0
          }
        ]
      ]
    }
  }
}
Häufig gestellte Fragen

Wie verwende ich diesen Workflow?

Kopieren Sie den obigen JSON-Code, erstellen Sie einen neuen Workflow in Ihrer n8n-Instanz und wählen Sie "Aus JSON importieren". Fügen Sie die Konfiguration ein und passen Sie die Anmeldedaten nach Bedarf an.

Für welche Szenarien ist dieser Workflow geeignet?

Experte

Ist es kostenpflichtig?

Dieser Workflow ist völlig kostenlos. Beachten Sie jedoch, dass Drittanbieterdienste (wie OpenAI API), die im Workflow verwendet werden, möglicherweise kostenpflichtig sind.

Workflow-Informationen
Schwierigkeitsgrad
Experte
Anzahl der Nodes18
Kategorie-
Node-Typen9
Schwierigkeitsbeschreibung

Für fortgeschrittene Benutzer, komplexe Workflows mit 16+ Nodes

Autor
Adnan Tariq

Adnan Tariq

@adnantariq

Founder of CYBERPULSE AI — helping security teams and SMEs eliminate repetitive tasks through modular n8n automations. I build workflows for vulnerability triage, compliance reporting, threat intel, and Red/Blue/GRC ops. Book a session if you'd like custom automation for your use case. https://linkedin.com/in/adnan-tariq-4b2a1a47

Externe Links
Auf n8n.io ansehen

Diesen Workflow teilen

Kategorien

Kategorien: 34