773 lines
No EOL
26 KiB
JSON
773 lines
No EOL
26 KiB
JSON
{
|
|
"name": "Genome: PR review",
|
|
"nodes": [
|
|
{
|
|
"parameters": {
|
|
"httpMethod": "POST",
|
|
"path": "forgejo-pr-review-23319ab8687b16f10e0f278fb920c112",
|
|
"options": {}
|
|
},
|
|
"id": "58df1ca9-e48e-4834-b231-d97c974cd01b",
|
|
"name": "Webhook PR Review",
|
|
"type": "n8n-nodes-base.webhook",
|
|
"typeVersion": 2.1,
|
|
"position": [
|
|
2272,
|
|
1344
|
|
],
|
|
"webhookId": "61ff3a5baa304571"
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForEachItem",
|
|
"jsCode": "// THE only parser of the review side: parse the directive, VALIDATE, prepare the rework payload.\n// Security: only allow-listed maintainers may drive the gate; destructive directives require a\n// feat/ai-ingest-* branch on the expected base; raw_source is recovered from a machine-readable\n// marker that run-ingest.sh writes into the PR body.\nconst ALLOWED_SENDERS = ['Keru']; // <-- maintainers allowed to issue directives\nconst BASE = 'develop';\n\n// n8n Run Once for Each Item: $json is the current webhook payload\nconst j = $json.body || $json;\nif (!j || typeof j !== 'object') {\n return { directive: 'INVALID', reason: 'malformed webhook payload' };\n}\n\nconst review = j.review || null;\nconst comment = j.comment || null;\nconst pr = j.pull_request || j.issue || null;\n\n// Extract directive text from review content or comment body\nconst body = String(\n (review && review.content) ||\n (comment && comment.body) ||\n ''\n);\nconst sender = String((j.sender && j.sender.login) || 'unknown');\n\n// Match directive at the start of the text (case-insensitive)\nconst m = body.match(/^\\s*(REWORK|RESTART|REVERT\\s+\\d+|SPLIT|REJECT|MERGE)\\s*:?/i);\nif (!m) return { directive: 'NONE' };\n\nconst headTok = m[1].toUpperCase().replace(/\\s+/g, ' ');\nconst directive = headTok.startsWith('REVERT') ? 'REVERT' : headTok;\nconst feedback = body.slice(m[0].length).trim() || '(nessun dettaglio fornito)';\n\n// Extract PR metadata safely\nconst prNumber = (pr && pr.number) || null;\nconst branch = (pr && pr.head && pr.head.ref) || null;\nconst base = (pr && pr.base && pr.base.ref) || null;\nconst repo = (pr && pr.base && pr.base.repo && pr.base.repo.name) ||\n (j.repository && j.repository.name) || null;\nconst owner = (pr && pr.base && pr.base.repo && pr.base.repo.owner && pr.base.repo.owner.login) ||\n (j.repository && j.repository.owner && j.repository.owner.login) || null;\nconst prBody = (pr && pr.body) || (j.issue && j.issue.body) || '';\n\n// Recover raw_source from machine-readable marker: <!-- kg:raw=path -->\n// Restricted to valid path characters, no spaces, no HTML breaking\nconst rawMatch = prBody.match(/<!--\\s*kg:raw=([^\\s>]+)\\s*-->/);\nconst raw = rawMatch ? rawMatch[1] : null;\n\n// REVERT is reserved for future Step 7 implementation\nif (directive === 'REVERT') {\n return { directive: 'NONE', note: 'REVERT reserved for Step 7' };\n}\n\n// Authorization gate\nif (!ALLOWED_SENDERS.includes(sender)) {\n return {\n directive: 'UNAUTHORIZED',\n attempted: directive,\n sender,\n prNumber,\n owner,\n repo\n };\n}\n\n// Validation rules\nconst okGenome = !!repo && /^[a-z0-9][a-z0-9-]{0,63}$/.test(repo);\nconst okPr = !!prNumber && /^[0-9]+$/.test(String(prNumber));\nconst okBranch = !!branch && /^feat\\/ai-ingest-[a-z0-9-]+$/.test(branch);\nconst okBase = base === BASE;\nconst okRaw = (directive === 'MERGE')\n ? true\n : (!!raw && raw.startsWith('raw/') && !raw.includes('..') && /^[A-Za-z0-9._\\/-]+$/.test(raw));\n\nif (!okGenome || !okPr || !okBase || (directive !== 'MERGE' && !okBranch) || !okRaw) {\n return {\n directive: 'INVALID',\n attempted: directive,\n prNumber,\n owner,\n repo,\n why: { okGenome, okPr, okBranch, okBase, okRaw }\n };\n}\n\n// Encode feedback for safe transport through SSH/scripts\nconst feedback_b64 = Buffer.from(feedback, 'utf8').toString('base64');\n\nreturn {\n directive,\n prNumber,\n branch,\n base,\n repo,\n owner,\n sender,\n raw,\n feedback,\n feedback_b64\n};"
|
|
},
|
|
"id": "c668f595-0a28-4bd3-9125-22fee9350d78",
|
|
"name": "Parse & validate",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
2496,
|
|
1344
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"rules": {
|
|
"values": [
|
|
{
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"typeValidation": "strict",
|
|
"version": 2
|
|
},
|
|
"conditions": [
|
|
{
|
|
"leftValue": "={{ $json.directive }}",
|
|
"rightValue": "MERGE",
|
|
"operator": {
|
|
"type": "string",
|
|
"operation": "equals"
|
|
},
|
|
"id": "4960f0868bc54687"
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
}
|
|
},
|
|
{
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"typeValidation": "strict",
|
|
"version": 2
|
|
},
|
|
"conditions": [
|
|
{
|
|
"leftValue": "={{ $json.directive }}",
|
|
"rightValue": "REWORK",
|
|
"operator": {
|
|
"type": "string",
|
|
"operation": "equals"
|
|
},
|
|
"id": "34002fdd92834d38"
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
}
|
|
},
|
|
{
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"typeValidation": "strict",
|
|
"version": 2
|
|
},
|
|
"conditions": [
|
|
{
|
|
"leftValue": "={{ $json.directive }}",
|
|
"rightValue": "RESTART",
|
|
"operator": {
|
|
"type": "string",
|
|
"operation": "equals"
|
|
},
|
|
"id": "d412a74e32ac4f0c"
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
}
|
|
},
|
|
{
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"typeValidation": "strict",
|
|
"version": 2
|
|
},
|
|
"conditions": [
|
|
{
|
|
"leftValue": "={{ $json.directive }}",
|
|
"rightValue": "SPLIT",
|
|
"operator": {
|
|
"type": "string",
|
|
"operation": "equals"
|
|
},
|
|
"id": "c0810b33fa474ca0"
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
}
|
|
},
|
|
{
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"typeValidation": "strict",
|
|
"version": 2
|
|
},
|
|
"conditions": [
|
|
{
|
|
"leftValue": "={{ $json.directive }}",
|
|
"rightValue": "REJECT",
|
|
"operator": {
|
|
"type": "string",
|
|
"operation": "equals"
|
|
},
|
|
"id": "531039e699c44cea"
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
}
|
|
},
|
|
{
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"typeValidation": "strict",
|
|
"version": 2
|
|
},
|
|
"conditions": [
|
|
{
|
|
"leftValue": "={{ $json.directive }}",
|
|
"rightValue": "UNAUTHORIZED",
|
|
"operator": {
|
|
"type": "string",
|
|
"operation": "equals"
|
|
},
|
|
"id": "cfbd691d2e9a4c2a"
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
}
|
|
},
|
|
{
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"typeValidation": "strict",
|
|
"version": 2
|
|
},
|
|
"conditions": [
|
|
{
|
|
"leftValue": "={{ $json.directive }}",
|
|
"rightValue": "INVALID",
|
|
"operator": {
|
|
"type": "string",
|
|
"operation": "equals"
|
|
},
|
|
"id": "251f5b7beea6424a"
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
}
|
|
}
|
|
]
|
|
},
|
|
"options": {
|
|
"fallbackOutput": "none"
|
|
}
|
|
},
|
|
"id": "489736cc-bab6-4664-8087-91b6d9ff31ad",
|
|
"name": "Switch",
|
|
"type": "n8n-nodes-base.switch",
|
|
"typeVersion": 3.4,
|
|
"position": [
|
|
2736,
|
|
1344
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "POST",
|
|
"url": "=https://git.keruhomelab.com/api/v1/repos/{{ $('Parse & validate').first().json.owner }}/{{ $('Parse & validate').first().json.repo }}/pulls/{{ $('Parse & validate').first().json.prNumber }}/merge",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"sendBody": true,
|
|
"specifyBody": "json",
|
|
"jsonBody": "={\n \"Do\": \"merge\"\n}",
|
|
"options": {
|
|
"timeout": 15000
|
|
}
|
|
},
|
|
"id": "3440cb8d-ae4c-4523-ae13-ee5667d24252",
|
|
"name": "Forgejo Merge PR",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.4,
|
|
"position": [
|
|
2976,
|
|
1104
|
|
],
|
|
"credentials": {
|
|
"httpHeaderAuth": {
|
|
"id": "TBPXSWOF63k9mvm8",
|
|
"name": "ntfy-token"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"typeValidation": "loose",
|
|
"version": 2
|
|
},
|
|
"conditions": [
|
|
{
|
|
"id": "cc369b5fc3d246a4",
|
|
"leftValue": "={{ $('Parse & validate').first().json.branch }}",
|
|
"rightValue": "feat/ai-ingest-",
|
|
"operator": {
|
|
"type": "string",
|
|
"operation": "startsWith"
|
|
}
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
},
|
|
"options": {}
|
|
},
|
|
"id": "e6d45fce-83d0-44ca-9fa4-86558fec1a0f",
|
|
"name": "Guardia feat/",
|
|
"type": "n8n-nodes-base.if",
|
|
"typeVersion": 2.2,
|
|
"position": [
|
|
2976,
|
|
1328
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "PATCH",
|
|
"url": "=https://git.keruhomelab.com/api/v1/repos/{{ $('Parse & validate').first().json.owner }}/{{ $('Parse & validate').first().json.repo }}/pulls/{{ $('Parse & validate').first().json.prNumber }}",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"sendBody": true,
|
|
"specifyBody": "json",
|
|
"jsonBody": "={\n \"state\": \"closed\"\n}",
|
|
"options": {
|
|
"timeout": 15000
|
|
}
|
|
},
|
|
"id": "1601f705-c758-4df6-a3bd-e3ac2e202c94",
|
|
"name": "Forgejo Close PR",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.4,
|
|
"position": [
|
|
3200,
|
|
1296
|
|
],
|
|
"credentials": {
|
|
"httpHeaderAuth": {
|
|
"id": "TBPXSWOF63k9mvm8",
|
|
"name": "ntfy-token"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "DELETE",
|
|
"url": "=https://git.keruhomelab.com/api/v1/repos/{{ $('Parse & validate').first().json.owner }}/{{ $('Parse & validate').first().json.repo }}/branches/{{ encodeURIComponent($('Parse & validate').first().json.branch) }}",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpHeaderAuth",
|
|
"options": {
|
|
"timeout": 15000
|
|
}
|
|
},
|
|
"id": "c2ff2247-efe1-4809-a435-9973188d61bb",
|
|
"name": "Forgejo Delete Branch",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.4,
|
|
"position": [
|
|
3424,
|
|
1296
|
|
],
|
|
"credentials": {
|
|
"httpHeaderAuth": {
|
|
"id": "TBPXSWOF63k9mvm8",
|
|
"name": "ntfy-token"
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"parameters": {
|
|
"conditions": {
|
|
"options": {
|
|
"caseSensitive": true,
|
|
"leftValue": "",
|
|
"typeValidation": "strict",
|
|
"version": 2
|
|
},
|
|
"conditions": [
|
|
{
|
|
"id": "55cf6c2a6c7d4d79",
|
|
"leftValue": "={{ $('Parse & validate').first().json.directive }}",
|
|
"rightValue": "REJECT",
|
|
"operator": {
|
|
"type": "string",
|
|
"operation": "equals"
|
|
}
|
|
}
|
|
],
|
|
"combinator": "and"
|
|
},
|
|
"options": {}
|
|
},
|
|
"id": "a1dbbc06-555d-4a1d-8fbf-ee75f617e98a",
|
|
"name": "E' REJECT?",
|
|
"type": "n8n-nodes-base.if",
|
|
"typeVersion": 2.2,
|
|
"position": [
|
|
3648,
|
|
1296
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"workflowId": {
|
|
"__rl": true,
|
|
"value": "zbtRXWsLt56nEIfz",
|
|
"mode": "list",
|
|
"cachedResultUrl": "/workflow/zbtRXWsLt56nEIfz",
|
|
"cachedResultName": "Power Manager"
|
|
},
|
|
"workflowInputs": {
|
|
"mappingMode": "defineBelow",
|
|
"value": {
|
|
"mode": "ensure-on"
|
|
},
|
|
"matchingColumns": [
|
|
"mode"
|
|
],
|
|
"schema": [
|
|
{
|
|
"id": "mode",
|
|
"displayName": "mode",
|
|
"required": false,
|
|
"defaultMatch": false,
|
|
"display": true,
|
|
"canBeUsedToMatch": true,
|
|
"type": "string",
|
|
"removed": false
|
|
}
|
|
],
|
|
"attemptToConvertTypes": false,
|
|
"convertFieldsToString": true
|
|
},
|
|
"options": {}
|
|
},
|
|
"id": "7fc3e648-4712-4eef-a6f3-12c8805ade1f",
|
|
"name": "Power Manager - ensure-on",
|
|
"type": "n8n-nodes-base.executeWorkflow",
|
|
"typeVersion": 1.3,
|
|
"position": [
|
|
3648,
|
|
1168
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"workflowId": {
|
|
"__rl": true,
|
|
"value": "VIi2ovb5gJxNJLbg",
|
|
"mode": "list",
|
|
"cachedResultUrl": "/workflow/VIi2ovb5gJxNJLbg",
|
|
"cachedResultName": "Genome: run-one-ingest"
|
|
},
|
|
"workflowInputs": {
|
|
"mappingMode": "defineBelow",
|
|
"value": {
|
|
"genome": "={{ $('Parse & validate').first().json.repo }}",
|
|
"raw": "={{ $('Parse & validate').first().json.raw }}",
|
|
"mode": "rework",
|
|
"feedback_b64": "={{ $('Parse & validate').first().json.feedback_b64 }}",
|
|
"reason": "={{ $('Parse & validate').first().json.directive }}",
|
|
"prevPr": "={{ String($('Parse & validate').first().json.prNumber || '') }}"
|
|
},
|
|
"matchingColumns": [],
|
|
"schema": [
|
|
{
|
|
"id": "genome",
|
|
"displayName": "genome",
|
|
"required": false,
|
|
"defaultMatch": false,
|
|
"display": true,
|
|
"canBeUsedToMatch": true,
|
|
"type": "string",
|
|
"removed": false
|
|
},
|
|
{
|
|
"id": "raw",
|
|
"displayName": "raw",
|
|
"required": false,
|
|
"defaultMatch": false,
|
|
"display": true,
|
|
"canBeUsedToMatch": true,
|
|
"type": "string",
|
|
"removed": false
|
|
},
|
|
{
|
|
"id": "mode",
|
|
"displayName": "mode",
|
|
"required": false,
|
|
"defaultMatch": false,
|
|
"display": true,
|
|
"canBeUsedToMatch": true,
|
|
"type": "string",
|
|
"removed": false
|
|
},
|
|
{
|
|
"id": "feedback_b64",
|
|
"displayName": "feedback_b64",
|
|
"required": false,
|
|
"defaultMatch": false,
|
|
"display": true,
|
|
"canBeUsedToMatch": true,
|
|
"type": "string",
|
|
"removed": false
|
|
},
|
|
{
|
|
"id": "reason",
|
|
"displayName": "reason",
|
|
"required": false,
|
|
"defaultMatch": false,
|
|
"display": true,
|
|
"canBeUsedToMatch": true,
|
|
"type": "string",
|
|
"removed": false
|
|
},
|
|
{
|
|
"id": "prevPr",
|
|
"displayName": "prevPr",
|
|
"required": false,
|
|
"defaultMatch": false,
|
|
"display": true,
|
|
"canBeUsedToMatch": true,
|
|
"type": "string",
|
|
"removed": false
|
|
}
|
|
],
|
|
"attemptToConvertTypes": false,
|
|
"convertFieldsToString": true
|
|
},
|
|
"options": {
|
|
"waitForSubWorkflow": false
|
|
}
|
|
},
|
|
"id": "9704c050-5c63-49fd-a26d-efbae9d92175",
|
|
"name": "Run one ingest (rework)",
|
|
"type": "n8n-nodes-base.executeWorkflow",
|
|
"typeVersion": 1.3,
|
|
"position": [
|
|
3856,
|
|
1168
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForEachItem",
|
|
"jsCode": "// merged (MERGE) / closed (REJECT). The HTTP node replaced $json with the API response,\n// so we read context from the parser via node reference (single review -> .first() is safe).\n// Fallback values prevent crashes if the parser node is unreachable.\nconst p = $('Parse & validate').first().json || {};\nconst repo = p.repo || 'unknown';\nconst owner = p.owner || 'unknown';\nconst prNumber = p.prNumber || '?';\nconst base = p.base || 'develop';\nconst branch = p.branch || 'unknown';\nconst sender = p.sender || 'unknown';\nconst directive = p.directive || 'UNKNOWN';\nconst feedback = p.feedback || '';\n\nconst repoUrl = (owner && repo && repo !== 'unknown')\n ? `https://git.keruhomelab.com/${owner}/${repo}`\n : '';\nconst prUrl = (repoUrl && prNumber !== '?')\n ? `${repoUrl}/pulls/${prNumber}`\n : '';\n\nlet n;\nif (directive === 'MERGE') {\n n = {\n topic: 'genome-ingest',\n title: `${repo} · PR #${prNumber} mergiata`,\n priority: 'default',\n tags: 'twisted_rightwards_arrows',\n click: prUrl,\n actions: `view, Vedi la PR, ${prUrl}`,\n body: `PR #${prNumber} mergiata su \\`${base}\\` da **${sender}**.`\n };\n} else {\n n = {\n topic: 'genome-ingest',\n title: `${repo} · PR #${prNumber} chiusa`,\n priority: 'default',\n tags: 'wastebasket',\n click: repoUrl,\n actions: '',\n body: `**REJECT** di **${sender}**: PR #${prNumber} chiusa e branch \\`${branch}\\` rimosso. Nessun nuovo tentativo.\\n> ${feedback}`\n };\n}\n\nreturn n;"
|
|
},
|
|
"id": "1ce634fd-d402-4a84-9ba1-04673ddffce9",
|
|
"name": "Build ntfy action",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
3856,
|
|
1344
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"mode": "runOnceForEachItem",
|
|
"jsCode": "// Security / near-miss: unauthorized sender, invalid directive, or the feat/ guard.\n// On all three paths Switch/Guardia pass the parser output through, so $json carries the directive + context.\nconst d = $json || {};\nconst directive = d.directive || 'UNKNOWN';\nconst attempted = d.attempted || directive;\nconst sender = d.sender || 'unknown';\nconst prNumber = d.prNumber || '?';\nconst branch = d.branch || 'unknown';\nconst owner = d.owner || '';\nconst repo = d.repo || '';\n\nconst repoUrl = (owner && repo) ? `https://git.keruhomelab.com/${owner}/${repo}` : '';\n\nlet n;\nif (directive === 'UNAUTHORIZED') {\n n = {\n topic: 'genome-ingest',\n title: `Sicurezza · direttiva non autorizzata`,\n priority: 'high',\n tags: 'no_entry',\n click: repoUrl,\n actions: '',\n body: `**${sender}** ha tentato \\`${attempted}\\` su PR #${prNumber}, ma non è tra i maintainer autorizzati. **Nessuna azione** eseguita.`\n };\n} else if (directive === 'INVALID') {\n n = {\n topic: 'genome-ingest',\n title: `Direttiva non applicata`,\n priority: 'low',\n tags: 'information_source',\n click: repoUrl,\n actions: '',\n body: `\\`${attempted}\\` su PR #${prNumber} ignorata: precondizioni non soddisfatte (branch / base / marker raw).`\n };\n} else {\n // Guardia feat/ false branch: destructive action on a non-feat/ai-ingest-* branch\n n = {\n topic: 'genome-ingest',\n title: `Sicurezza · branch protetto`,\n priority: 'high',\n tags: 'no_entry',\n click: repoUrl,\n actions: '',\n body: `Rifiutata azione distruttiva (\\`${attempted || directive}\\`) sul branch \\`${branch}\\`: non è un \\`feat/ai-ingest-*\\`. **Nessuna modifica.**`\n };\n}\n\nreturn n;"
|
|
},
|
|
"id": "32b16592-5126-4cc2-a3f2-d1bda58ac724",
|
|
"name": "Build ntfy sicurezza",
|
|
"type": "n8n-nodes-base.code",
|
|
"typeVersion": 2,
|
|
"position": [
|
|
3200,
|
|
1536
|
|
]
|
|
},
|
|
{
|
|
"parameters": {
|
|
"method": "POST",
|
|
"url": "=http://ntfy/{{ $json.topic }}",
|
|
"authentication": "genericCredentialType",
|
|
"genericAuthType": "httpBearerAuth",
|
|
"sendHeaders": true,
|
|
"headerParameters": {
|
|
"parameters": [
|
|
{
|
|
"name": "Title",
|
|
"value": "={{ $json.title }}"
|
|
},
|
|
{
|
|
"name": "Priority",
|
|
"value": "={{ $json.priority }}"
|
|
},
|
|
{
|
|
"name": "Tags",
|
|
"value": "={{ $json.tags }}"
|
|
},
|
|
{
|
|
"name": "Click",
|
|
"value": "={{ $json.click }}"
|
|
},
|
|
{
|
|
"name": "Actions",
|
|
"value": "={{ $json.actions }}"
|
|
},
|
|
{
|
|
"name": "Markdown",
|
|
"value": "yes"
|
|
}
|
|
]
|
|
},
|
|
"sendBody": true,
|
|
"contentType": "raw",
|
|
"rawContentType": "Raw / Text",
|
|
"body": "={{ $json.body }}",
|
|
"options": {
|
|
"timeout": 15000
|
|
}
|
|
},
|
|
"id": "4d45b486-de42-4c7f-be21-b5bfbc05fd44",
|
|
"name": "ntfy: send",
|
|
"type": "n8n-nodes-base.httpRequest",
|
|
"typeVersion": 4.4,
|
|
"position": [
|
|
4080,
|
|
1424
|
|
],
|
|
"credentials": {
|
|
"httpHeaderAuth": {
|
|
"id": "TBPXSWOF63k9mvm8",
|
|
"name": "ntfy-token"
|
|
},
|
|
"httpBearerAuth": {
|
|
"id": "nCv4CUN7Ef086Ewj",
|
|
"name": "Bearer Auth account"
|
|
}
|
|
}
|
|
}
|
|
],
|
|
"pinData": {},
|
|
"connections": {
|
|
"Webhook PR Review": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Parse & validate",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Parse & validate": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Switch",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Switch": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Forgejo Merge PR",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Power Manager - ensure-on",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Guardia feat/",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Guardia feat/",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Guardia feat/",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Build ntfy sicurezza",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Build ntfy sicurezza",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Forgejo Merge PR": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Build ntfy action",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Guardia feat/": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Forgejo Close PR",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Build ntfy sicurezza",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Forgejo Close PR": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Forgejo Delete Branch",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Forgejo Delete Branch": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "E' REJECT?",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"E' REJECT?": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Build ntfy action",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
],
|
|
[
|
|
{
|
|
"node": "Power Manager - ensure-on",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Power Manager - ensure-on": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "Run one ingest (rework)",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Build ntfy action": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "ntfy: send",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
},
|
|
"Build ntfy sicurezza": {
|
|
"main": [
|
|
[
|
|
{
|
|
"node": "ntfy: send",
|
|
"type": "main",
|
|
"index": 0
|
|
}
|
|
]
|
|
]
|
|
}
|
|
},
|
|
"active": true,
|
|
"settings": {
|
|
"executionOrder": "v1",
|
|
"binaryMode": "separate",
|
|
"timeSavedMode": "fixed",
|
|
"errorWorkflow": "7Vws3gCX3QnjM3oD",
|
|
"callerPolicy": "workflowsFromSameOwner",
|
|
"availableInMCP": false
|
|
},
|
|
"versionId": "22998a54-cd9a-4b57-9c80-df97085a997c",
|
|
"meta": {
|
|
"instanceId": "96b2f0ec76a4400bbd481c617b24b3b87024cc7a913efacccaf9fc85722e7417"
|
|
},
|
|
"id": "iho7kFQsXbGIxG7P",
|
|
"tags": []
|
|
} |