Files
Vault Sovereign 37a867c485 Initial commit: Cloudflare infrastructure with WAF Intelligence
- Complete Cloudflare Terraform configuration (DNS, WAF, tunnels, access)
- WAF Intelligence MCP server with threat analysis and ML classification
- GitOps automation with PR workflows and drift detection
- Observatory monitoring stack with Prometheus/Grafana
- IDE operator rules for governed development
- Security playbooks and compliance frameworks
- Autonomous remediation and state reconciliation
2025-12-16 18:31:53 +00:00

327 lines
9.8 KiB
Cheetah

{{/* Email notification templates for Cloudflare Mesh Observatory */}}
{{/* HTML email template */}}
{{ define "email.cloudflare.html" }}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
line-height: 1.6;
color: #333;
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.header {
background: linear-gradient(135deg, #F6821F 0%, #F38020 100%);
color: white;
padding: 20px;
border-radius: 8px 8px 0 0;
text-align: center;
}
.header h1 {
margin: 0;
font-size: 24px;
}
.status-badge {
display: inline-block;
padding: 4px 12px;
border-radius: 20px;
font-size: 12px;
font-weight: bold;
text-transform: uppercase;
margin-top: 10px;
}
.status-firing { background: #dc3545; color: white; }
.status-resolved { background: #28a745; color: white; }
.content {
background: #fff;
border: 1px solid #e0e0e0;
border-top: none;
padding: 20px;
border-radius: 0 0 8px 8px;
}
.alert-card {
background: #f8f9fa;
border-left: 4px solid #F6821F;
padding: 15px;
margin: 15px 0;
border-radius: 0 4px 4px 0;
}
.alert-card.critical { border-left-color: #dc3545; }
.alert-card.warning { border-left-color: #ffc107; }
.alert-card.info { border-left-color: #17a2b8; }
.alert-card.resolved { border-left-color: #28a745; }
.alert-title {
font-size: 16px;
font-weight: bold;
color: #333;
margin-bottom: 10px;
}
.alert-meta {
font-size: 12px;
color: #666;
margin-bottom: 10px;
}
.alert-meta span {
display: inline-block;
margin-right: 15px;
}
.label {
display: inline-block;
background: #e9ecef;
padding: 2px 8px;
border-radius: 4px;
font-size: 11px;
margin: 2px;
}
.description {
margin: 10px 0;
padding: 10px;
background: white;
border-radius: 4px;
}
.runbook-link {
display: inline-block;
background: #F6821F;
color: white;
padding: 8px 16px;
border-radius: 4px;
text-decoration: none;
font-size: 14px;
margin-top: 10px;
}
.runbook-link:hover {
background: #e67316;
}
.summary-table {
width: 100%;
border-collapse: collapse;
margin: 20px 0;
}
.summary-table th, .summary-table td {
padding: 10px;
text-align: left;
border-bottom: 1px solid #e0e0e0;
}
.summary-table th {
background: #f8f9fa;
font-weight: 600;
}
.footer {
text-align: center;
font-size: 12px;
color: #888;
margin-top: 20px;
padding-top: 20px;
border-top: 1px solid #e0e0e0;
}
.footer a {
color: #F6821F;
text-decoration: none;
}
</style>
</head>
<body>
<div class="header">
<h1>Cloudflare Mesh Observatory</h1>
<span class="status-badge status-{{ .Status }}">{{ .Status }}</span>
</div>
<div class="content">
<h2>Alert Summary</h2>
<table class="summary-table">
<tr>
<th>Status</th>
<td>{{ .Status | toUpper }}</td>
</tr>
<tr>
<th>Alert Name</th>
<td>{{ .CommonLabels.alertname }}</td>
</tr>
<tr>
<th>Severity</th>
<td>{{ .CommonLabels.severity | toUpper }}</td>
</tr>
<tr>
<th>Component</th>
<td>{{ .CommonLabels.component }}</td>
</tr>
<tr>
<th>Firing Alerts</th>
<td>{{ .Alerts.Firing | len }}</td>
</tr>
<tr>
<th>Resolved Alerts</th>
<td>{{ .Alerts.Resolved | len }}</td>
</tr>
</table>
<h2>Alert Details</h2>
{{ range .Alerts }}
<div class="alert-card {{ .Labels.severity }}{{ if eq .Status "resolved" }} resolved{{ end }}">
<div class="alert-title">
{{ .Labels.alertname }}
<span class="status-badge status-{{ .Status }}" style="font-size: 10px; padding: 2px 8px;">{{ .Status }}</span>
</div>
<div class="alert-meta">
<span><strong>Severity:</strong> {{ .Labels.severity }}</span>
<span><strong>Component:</strong> {{ .Labels.component }}</span>
<span><strong>Started:</strong> {{ .StartsAt.Format "2006-01-02 15:04:05 UTC" }}</span>
{{ if eq .Status "resolved" }}
<span><strong>Resolved:</strong> {{ .EndsAt.Format "2006-01-02 15:04:05 UTC" }}</span>
{{ end }}
</div>
<div class="description">
<strong>Summary:</strong> {{ .Annotations.summary }}<br>
<strong>Description:</strong> {{ .Annotations.description }}
</div>
<div style="margin-top: 10px;">
<strong>Labels:</strong><br>
{{ range .Labels.SortedPairs }}
<span class="label">{{ .Name }}: {{ .Value }}</span>
{{ end }}
</div>
{{ if .Annotations.runbook_url }}
<a href="{{ .Annotations.runbook_url }}" class="runbook-link">View Runbook</a>
{{ end }}
</div>
{{ end }}
<h2>Quick Links</h2>
<ul>
<li><a href="http://localhost:3000">Grafana Dashboard</a></li>
<li><a href="http://localhost:9090">Prometheus</a></li>
<li><a href="https://dash.cloudflare.com">Cloudflare Dashboard</a></li>
</ul>
</div>
<div class="footer">
<p>
This alert was generated by <strong>Cloudflare Mesh Observatory</strong><br>
<a href="http://localhost:9093">Alertmanager</a> |
<a href="http://localhost:3000">Grafana</a> |
<a href="http://localhost:9090">Prometheus</a>
</p>
<p>
Generated at {{ .ExternalURL }}
</p>
</div>
</body>
</html>
{{ end }}
{{/* Plain text email template */}}
{{ define "email.cloudflare.text" }}
================================================================================
CLOUDFLARE MESH OBSERVATORY - ALERT {{ .Status | toUpper }}
================================================================================
Status: {{ .Status | toUpper }}
Alert: {{ .CommonLabels.alertname }}
Severity: {{ .CommonLabels.severity | toUpper }}
Component: {{ .CommonLabels.component }}
Firing: {{ .Alerts.Firing | len }} alerts
Resolved: {{ .Alerts.Resolved | len }} alerts
================================================================================
ALERT DETAILS
================================================================================
{{ range .Alerts }}
--------------------------------------------------------------------------------
{{ .Labels.alertname }} [{{ .Status | toUpper }}]
--------------------------------------------------------------------------------
Severity: {{ .Labels.severity }}
Component: {{ .Labels.component }}
Started: {{ .StartsAt.Format "2006-01-02 15:04:05 UTC" }}
{{ if eq .Status "resolved" }}Resolved: {{ .EndsAt.Format "2006-01-02 15:04:05 UTC" }}{{ end }}
Summary: {{ .Annotations.summary }}
Description: {{ .Annotations.description }}
Labels:
{{ range .Labels.SortedPairs }} - {{ .Name }}: {{ .Value }}
{{ end }}
{{ if .Annotations.runbook_url }}Runbook: {{ .Annotations.runbook_url }}{{ end }}
{{ end }}
================================================================================
QUICK LINKS
================================================================================
Grafana: http://localhost:3000
Prometheus: http://localhost:9090
Alertmanager: http://localhost:9093
Cloudflare: https://dash.cloudflare.com
================================================================================
Generated by Cloudflare Mesh Observatory
{{ end }}
{{/* Daily digest email template */}}
{{ define "email.cloudflare.digest" }}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<style>
/* Same styles as above */
</style>
</head>
<body>
<div class="header">
<h1>Daily Alert Digest</h1>
<p>{{ now.Format "Monday, January 2, 2006" }}</p>
</div>
<div class="content">
<h2>24-Hour Summary</h2>
<table class="summary-table">
<tr>
<th>Metric</th>
<th>Count</th>
</tr>
<tr>
<td>Total Alerts</td>
<td>{{ len .Alerts }}</td>
</tr>
<tr>
<td>Currently Firing</td>
<td>{{ .Alerts.Firing | len }}</td>
</tr>
<tr>
<td>Resolved</td>
<td>{{ .Alerts.Resolved | len }}</td>
</tr>
</table>
<h2>Alerts by Severity</h2>
<!-- Alert breakdown would go here -->
<h2>Alerts by Component</h2>
<!-- Component breakdown would go here -->
</div>
<div class="footer">
<p>This is an automated daily digest from Cloudflare Mesh Observatory</p>
</div>
</body>
</html>
{{ end }}