Some checks failed
Docs CI / lint-and-preview (push) Has been cancelled
Signals CI & Image / signals-ci (push) Has been cancelled
Signals Reachability Scoring & Events / reachability-smoke (push) Has been cancelled
Signals Reachability Scoring & Events / sign-and-upload (push) Has been cancelled
AOC Guard CI / aoc-guard (push) Has been cancelled
AOC Guard CI / aoc-verify (push) Has been cancelled
Reachability Corpus Validation / validate-corpus (push) Has been cancelled
Reachability Corpus Validation / validate-ground-truths (push) Has been cancelled
Scanner Analyzers / Discover Analyzers (push) Has been cancelled
Scanner Analyzers / Validate Test Fixtures (push) Has been cancelled
Reachability Corpus Validation / determinism-check (push) Has been cancelled
Scanner Analyzers / Build Analyzers (push) Has been cancelled
Scanner Analyzers / Test Language Analyzers (push) Has been cancelled
Scanner Analyzers / Verify Deterministic Output (push) Has been cancelled
Notify Smoke Test / Notify Unit Tests (push) Has been cancelled
Notify Smoke Test / Notifier Service Tests (push) Has been cancelled
Notify Smoke Test / Notification Smoke Test (push) Has been cancelled
Policy Lint & Smoke / policy-lint (push) Has been cancelled
211 lines
7.7 KiB
Plaintext
211 lines
7.7 KiB
Plaintext
# GAP-VEX-006: Sample VEX decision notification templates
|
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
|
#
|
|
# Usage:
|
|
# 1. Copy to etc/notify-templates/vex-decision.yaml
|
|
# 2. Customize templates per channel type
|
|
# 3. Import via: stella notify template import vex-decision.yaml
|
|
|
|
templates:
|
|
# Email template for VEX decision notifications
|
|
- key: vex.decision.changed
|
|
channel_type: email
|
|
locale: en-US
|
|
render_mode: markdown
|
|
description: "Notification when VEX decision status changes"
|
|
body: |
|
|
## VEX Decision Changed: {{ vulnerability_id }}
|
|
|
|
**Product:** {{ product.name }} ({{ product.version }})
|
|
**PURL:** `{{ product.purl }}`
|
|
|
|
**Status Changed:** {{ previous_status }} → **{{ new_status }}**
|
|
|
|
### Reachability Evidence
|
|
{% if reachability_evidence %}
|
|
- **State:** {{ reachability_evidence.state }}
|
|
- **Confidence:** {{ reachability_evidence.confidence | percent }}
|
|
- **Graph Hash:** `{{ reachability_evidence.graph_hash }}`
|
|
{% if reachability_evidence.call_paths | length > 0 %}
|
|
|
|
#### Call Paths ({{ reachability_evidence.call_paths | length }})
|
|
{% for path in reachability_evidence.call_paths | slice(0, 3) %}
|
|
- **{{ path.entry_point }}** → ... → **{{ path.vulnerable_function }}** (depth {{ path.depth }})
|
|
{% endfor %}
|
|
{% if reachability_evidence.call_paths | length > 3 %}
|
|
_(and {{ reachability_evidence.call_paths | length - 3 }} more paths)_
|
|
{% endif %}
|
|
{% endif %}
|
|
{% if reachability_evidence.runtime_hits | length > 0 %}
|
|
|
|
#### Runtime Hits ({{ reachability_evidence.runtime_hits | length }})
|
|
| Function | Hits | Last Observed |
|
|
|----------|------|---------------|
|
|
{% for hit in reachability_evidence.runtime_hits | slice(0, 5) %}
|
|
| {{ hit.function_name }} | {{ hit.hit_count }} | {{ hit.last_observed | date }} |
|
|
{% endfor %}
|
|
{% endif %}
|
|
{% else %}
|
|
_(No reachability evidence available)_
|
|
{% endif %}
|
|
|
|
### Signature
|
|
{% if signature.signed %}
|
|
- **Signed:** Yes
|
|
- **Algorithm:** {{ signature.algorithm }}
|
|
- **Key ID:** `{{ signature.key_id }}`
|
|
- **DSSE Envelope:** `{{ signature.dsse_envelope_id }}`
|
|
{% if signature.rekor_entry_id %}
|
|
- **Rekor Entry:** [{{ signature.rekor_entry_id }}]({{ signature.rekor_url }})
|
|
{% endif %}
|
|
{% else %}
|
|
- **Signed:** No (unsigned decision)
|
|
{% endif %}
|
|
|
|
---
|
|
[View in StellaOps]({{ dashboard_url }}/vuln/{{ vulnerability_id }})
|
|
|
|
# Slack template for VEX decision notifications
|
|
- key: vex.decision.changed
|
|
channel_type: slack
|
|
locale: en-US
|
|
render_mode: slack_blocks
|
|
description: "Slack notification for VEX decision changes"
|
|
body: |
|
|
{
|
|
"blocks": [
|
|
{
|
|
"type": "header",
|
|
"text": {
|
|
"type": "plain_text",
|
|
"text": "VEX Decision Changed: {{ vulnerability_id }}"
|
|
}
|
|
},
|
|
{
|
|
"type": "section",
|
|
"fields": [
|
|
{
|
|
"type": "mrkdwn",
|
|
"text": "*Product:*\n{{ product.name }}"
|
|
},
|
|
{
|
|
"type": "mrkdwn",
|
|
"text": "*Status:*\n{{ previous_status }} → *{{ new_status }}*"
|
|
}
|
|
]
|
|
},
|
|
{% if reachability_evidence %}
|
|
{
|
|
"type": "section",
|
|
"text": {
|
|
"type": "mrkdwn",
|
|
"text": "*Reachability:* {{ reachability_evidence.state }} ({{ reachability_evidence.confidence | percent }} confidence)\n*Graph Hash:* `{{ reachability_evidence.graph_hash | truncate(16) }}...`"
|
|
}
|
|
},
|
|
{% if reachability_evidence.call_paths | length > 0 %}
|
|
{
|
|
"type": "section",
|
|
"text": {
|
|
"type": "mrkdwn",
|
|
"text": "*Call Paths:* {{ reachability_evidence.call_paths | length }} found\n{% for path in reachability_evidence.call_paths | slice(0, 2) %}• {{ path.entry_point }} → {{ path.vulnerable_function }}\n{% endfor %}"
|
|
}
|
|
},
|
|
{% endif %}
|
|
{% endif %}
|
|
{
|
|
"type": "actions",
|
|
"elements": [
|
|
{
|
|
"type": "button",
|
|
"text": {
|
|
"type": "plain_text",
|
|
"text": "View Details"
|
|
},
|
|
"url": "{{ dashboard_url }}/vuln/{{ vulnerability_id }}"
|
|
}
|
|
]
|
|
}
|
|
]
|
|
}
|
|
|
|
# Teams template for VEX decision notifications
|
|
- key: vex.decision.changed
|
|
channel_type: teams
|
|
locale: en-US
|
|
render_mode: adaptive_card
|
|
description: "Teams notification for VEX decision changes"
|
|
body: |
|
|
{
|
|
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
|
|
"type": "AdaptiveCard",
|
|
"version": "1.4",
|
|
"body": [
|
|
{
|
|
"type": "TextBlock",
|
|
"text": "VEX Decision Changed: {{ vulnerability_id }}",
|
|
"weight": "Bolder",
|
|
"size": "Large"
|
|
},
|
|
{
|
|
"type": "FactSet",
|
|
"facts": [
|
|
{ "title": "Product", "value": "{{ product.name }} {{ product.version }}" },
|
|
{ "title": "PURL", "value": "{{ product.purl }}" },
|
|
{ "title": "Status", "value": "{{ previous_status }} → {{ new_status }}" }
|
|
{% if reachability_evidence %}
|
|
,{ "title": "Reachability", "value": "{{ reachability_evidence.state }} ({{ reachability_evidence.confidence | percent }})" }
|
|
,{ "title": "Call Paths", "value": "{{ reachability_evidence.call_paths | length }}" }
|
|
,{ "title": "Runtime Hits", "value": "{{ reachability_evidence.runtime_hits | length }}" }
|
|
{% endif %}
|
|
]
|
|
}
|
|
],
|
|
"actions": [
|
|
{
|
|
"type": "Action.OpenUrl",
|
|
"title": "View in StellaOps",
|
|
"url": "{{ dashboard_url }}/vuln/{{ vulnerability_id }}"
|
|
}
|
|
]
|
|
}
|
|
|
|
# Webhook template for VEX decision notifications (JSON payload)
|
|
- key: vex.decision.changed
|
|
channel_type: webhook
|
|
locale: en-US
|
|
render_mode: json
|
|
description: "Webhook payload for VEX decision changes"
|
|
body: |
|
|
{
|
|
"event_type": "vex.decision.changed",
|
|
"timestamp": "{{ timestamp | iso8601 }}",
|
|
"vulnerability_id": "{{ vulnerability_id }}",
|
|
"product": {
|
|
"key": "{{ product.key }}",
|
|
"name": "{{ product.name }}",
|
|
"version": "{{ product.version }}",
|
|
"purl": "{{ product.purl }}"
|
|
},
|
|
"previous_status": "{{ previous_status }}",
|
|
"new_status": "{{ new_status }}",
|
|
"reachability_evidence": {% if reachability_evidence %}{
|
|
"state": "{{ reachability_evidence.state }}",
|
|
"confidence": {{ reachability_evidence.confidence }},
|
|
"graph_hash": "{{ reachability_evidence.graph_hash }}",
|
|
"graph_cas_uri": "{{ reachability_evidence.graph_cas_uri }}",
|
|
"call_path_count": {{ reachability_evidence.call_paths | length }},
|
|
"runtime_hit_count": {{ reachability_evidence.runtime_hits | length }},
|
|
"dsse_envelope_id": "{{ reachability_evidence.dsse_envelope_id }}",
|
|
"rekor_entry_id": "{{ reachability_evidence.rekor_entry_id }}"
|
|
}{% else %}null{% endif %},
|
|
"signature": {
|
|
"signed": {{ signature.signed | json }},
|
|
"algorithm": "{{ signature.algorithm }}",
|
|
"key_id": "{{ signature.key_id }}",
|
|
"dsse_envelope_id": "{{ signature.dsse_envelope_id }}",
|
|
"rekor_entry_id": "{{ signature.rekor_entry_id }}"
|
|
},
|
|
"tenant_id": "{{ tenant_id }}",
|
|
"dashboard_url": "{{ dashboard_url }}/vuln/{{ vulnerability_id }}"
|
|
}
|