M44: harden release integrity and assurance
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
# n8n workflow manifest
|
||||
|
||||
Source of truth for the four canonical Fleet Ops n8n workflows. Definitions in this
|
||||
Source of truth for the five canonical Fleet Ops n8n workflows. Definitions in this
|
||||
directory are cleaned exports of the live workflows on `https://n8n.itworx.tech` —
|
||||
credential values are never embedded; nodes reference named n8n credentials instead. Run
|
||||
`n8n/workflows/check_drift.py` to compare a live workflow against its repo definition.
|
||||
@@ -108,3 +108,17 @@ runs from the editor. This is a known limitation of the live-validation evidence
|
||||
round: the mock-data path exercises the same nodes/logic and the real Fleet Ops
|
||||
endpoint, but a fully automatic (schedule- or webhook-triggered) failure cascading into
|
||||
this handler was not observed live.
|
||||
|
||||
## 5. Fleet Ops — Alert Receiver
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| File | `fleet-ops-alert-receiver.json` |
|
||||
| Purpose | Receive validated Alertmanager firing/resolved notifications and route them to the watched owner mailbox. |
|
||||
| Trigger | Production webhook, `POST /webhook/mobilityops-alerts`, Header Auth (`Fleet Ops Webhook Trigger Token`) |
|
||||
| Required credentials | `Fleet Ops Webhook Trigger Token` (Header Auth); `M365 n8n Shared Mailbox` (Microsoft Outlook OAuth2) |
|
||||
| Live workflow ID | `mobilityops-alert-receiver` |
|
||||
| Active status | Imported inactive by default; production deployment must publish it before enabling Alertmanager. |
|
||||
| Error Workflow | `Fleet Ops — Workflow Error Handler` (wired) |
|
||||
| Safety | Strict Alertmanager payload shape, bounded to 25 alerts and bounded text fields. |
|
||||
| Checksum (sha256) | `3672ad3d14b65c603c8c3f2067197cc50372e9d4c2fc314d1c9b6aaf3ecef444` |
|
||||
|
||||
@@ -34,6 +34,7 @@ KNOWN_WORKFLOWS = [
|
||||
("fleet-ops-data-quality-scan.json", "mobilityops-scheduled-quality-scan"),
|
||||
("fleet-ops-error-handler.json", "Xppn2rAEqUuyiCJF"),
|
||||
("fleet-ops-ragcore-procedure-sync.json", "6wbkc4d1AouGpmWT"),
|
||||
("fleet-ops-alert-receiver.json", "mobilityops-alert-receiver"),
|
||||
]
|
||||
|
||||
# Fields that legitimately differ between a committed definition and the live instance
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
{
|
||||
"id": "mobilityops-alert-receiver",
|
||||
"name": "Fleet Ops — Alert Receiver",
|
||||
"active": false,
|
||||
"nodes": [
|
||||
{
|
||||
"parameters": {"httpMethod": "POST", "path": "mobilityops-alerts", "authentication": "headerAuth", "responseMode": "responseNode", "options": {}},
|
||||
"id": "alert-webhook", "name": "Alertmanager webhook", "type": "n8n-nodes-base.webhook", "typeVersion": 2, "position": [240, 300], "webhookId": "mobilityops-alerts",
|
||||
"credentials": {"httpHeaderAuth": {"name": "Fleet Ops Webhook Trigger Token"}}
|
||||
},
|
||||
{
|
||||
"parameters": {"jsCode": "const body = $json.body ?? $json;\nif (!['firing', 'resolved'].includes(body.status) || !Array.isArray(body.alerts)) throw new Error('Invalid Alertmanager payload');\nconst alerts = body.alerts.slice(0, 25).map(a => ({name: String(a.labels?.alertname || 'Unknown alert').slice(0, 120), severity: String(a.labels?.severity || 'unknown').slice(0, 32), summary: String(a.annotations?.summary || '').slice(0, 500)}));\nconst esc = v => String(v).replace(/[&<>\\\"']/g, c => ({'&':'&','<':'<','>':'>','\\\"':'"',\"'\":'''}[c]));\nconst resolved = body.status === 'resolved';\nreturn [{json:{subject:`[Fleet Ops] ${resolved ? 'Hersteld' : 'Alert'} — ${alerts.length} signaal/signalen`,html:`<h2>Fleet Ops ${resolved ? 'hersteld' : 'monitoringalert'}</h2><ul>${alerts.map(a => `<li><strong>${esc(a.severity)} · ${esc(a.name)}</strong><br>${esc(a.summary)}</li>`).join('')}</ul><p>Ontvangen ${esc($now.toISO())}</p>`}}];"},
|
||||
"id": "validate-format", "name": "Validate and format", "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [500, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {"respondWith": "json", "responseBody": "={{ { accepted: true } }}", "options": {}},
|
||||
"id": "accept", "name": "Accept alert", "type": "n8n-nodes-base.respondToWebhook", "typeVersion": 1.4, "position": [740, 300]
|
||||
},
|
||||
{
|
||||
"parameters": {"toRecipients": "jens@itworx.tech", "subject": "={{ $('Validate and format').item.json.subject }}", "bodyContent": "={{ $('Validate and format').item.json.html }}", "additionalFields": {"from": "n8n@itworx.tech", "bodyContentType": "html"}},
|
||||
"id": "email", "name": "Send owner email", "type": "n8n-nodes-base.microsoftOutlook", "typeVersion": 2, "position": [980, 300],
|
||||
"credentials": {"microsoftOutlookOAuth2Api": {"id": "EDTj3sOsganaoDVL", "name": "M365 n8n Shared Mailbox"}},
|
||||
"retryOnFail": true, "maxTries": 3, "waitBetweenTries": 1000
|
||||
}
|
||||
],
|
||||
"connections": {
|
||||
"Alertmanager webhook": {"main": [[{"node": "Validate and format", "type": "main", "index": 0}]]},
|
||||
"Validate and format": {"main": [[{"node": "Accept alert", "type": "main", "index": 0}]]},
|
||||
"Accept alert": {"main": [[{"node": "Send owner email", "type": "main", "index": 0}]]}
|
||||
},
|
||||
"settings": {"executionOrder": "v1", "timezone": "Europe/Brussels", "errorWorkflow": "Xppn2rAEqUuyiCJF", "executionTimeout": 120, "saveDataSuccessExecution": "none", "saveDataErrorExecution": "all"},
|
||||
"staticData": null,
|
||||
"meta": {"templateCredsSetupCompleted": false},
|
||||
"pinData": {},
|
||||
"tags": []
|
||||
}
|
||||
Reference in New Issue
Block a user