CyberPulseコンプライアンス – v2 バッチパイプライン

上級

これは自動化ワークフローで、18個のノードを含みます。主にSet, Code, Merge, GoogleSheets, ManualTriggerなどのノードを使用。 CyberPulse、GPT-4o、Google Sheetsを使用した自動コンプライアンスコントロールスコアリング

前提条件
  • Google Sheets API認証情報
  • OpenAI API Key

カテゴリー

-
ワークフロープレビュー
ノード接続関係を可視化、ズームとパンをサポート
ワークフローをエクスポート
以下のJSON設定をn8nにインポートして、このワークフローを使用できます
{
  "id": "6yJ0KXSSGqSb9FY6",
  "meta": {
    "instanceId": "6feff41aadeb8409737e26476f9d0a45f95eec6a9c16afff8ef87a662455b6df",
    "templateCredsSetupCompleted": true
  },
  "name": "CyberPulse Compliance – v2 batch pipeline",
  "tags": [],
  "nodes": [
    {
      "id": "1ae2a107-6515-4dbe-a3b8-4c3fd5d64cce",
      "name": "手動トリガー",
      "type": "n8n-nodes-base.manualTrigger",
      "position": [
        -1008,
        -608
      ],
      "parameters": {},
      "typeVersion": 1
    },
    {
      "id": "2360ade2-1686-4554-beb3-76ba59e16408",
      "name": "シートに行を追加",
      "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": "シートの行を取得",
      "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": "説明と推奨",
      "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": "解析 + 各項目に添付",
      "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": "項目をループ処理",
      "type": "n8n-nodes-base.splitInBatches",
      "position": [
        160,
        -368
      ],
      "parameters": {
        "options": {}
      },
      "typeVersion": 3
    },
    {
      "id": "1f2dda49-fde7-44f8-8efd-e6ffd73e4e96",
      "name": "フィールドを編集",
      "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": "マージ1",
      "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": "付箋",
      "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": "付箋1",
      "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": "付箋2",
      "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": "付箋3",
      "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": "付箋4",
      "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": "付箋5",
      "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": "付箋6",
      "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": "付箋7",
      "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": "付箋8",
      "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
          }
        ]
      ]
    }
  }
}
よくある質問

このワークフローの使い方は?

上記のJSON設定コードをコピーし、n8nインスタンスで新しいワークフローを作成して「JSONからインポート」を選択、設定を貼り付けて認証情報を必要に応じて変更してください。

このワークフローはどんな場面に適していますか?

上級

有料ですか?

このワークフローは完全無料です。ただし、ワークフローで使用するサードパーティサービス(OpenAI APIなど)は別途料金が発生する場合があります。

ワークフロー情報
難易度
上級
ノード数18
カテゴリー-
ノードタイプ9
難易度説明

上級者向け、16ノード以上の複雑なワークフロー

作成者
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

外部リンク
n8n.ioで表示

このワークフローを共有

カテゴリー

カテゴリー: 34