-
Notifications
You must be signed in to change notification settings - Fork 137
214 lines (183 loc) · 9.44 KB
/
Copy pathrelease-notes-diff.yaml
File metadata and controls
214 lines (183 loc) · 9.44 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
name: Release Notes Diff
on:
release:
types:
- published
workflow_dispatch:
inputs:
tag:
description: "Release tag to (re)generate notes for"
required: true
type: string
permissions:
contents: write
actions: read
security-events: read
jobs:
generate-diff:
if: ${{ !github.event.release.prerelease && !github.event.release.draft }}
runs-on: ubuntu-latest
env:
GH_TOKEN: ${{ github.token }}
CURRENT_TAG: ${{ github.event.release.tag_name || inputs.tag }}
steps:
- name: Checkout repository
uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0
- name: Check for CVEs in standard k3s/k0s images
id: cve-check
run: |
tag="${CURRENT_TAG}"
# Find workflow runs for this tag from both release workflows
workflow_runs=$(gh api "repos/${{ github.repository }}/actions/runs?event=push&per_page=100" \
--jq "[.workflow_runs[] | select(.head_branch == \"$tag\" and (.name | test(\"Release (AMD64|ARM)\")))]")
if [ -z "$workflow_runs" ] || [ "$workflow_runs" = "[]" ]; then
echo "No matching workflow runs found for tag $tag"
echo "has_cve=false" >> "$GITHUB_OUTPUT"
exit 0
fi
cve_warning=""
has_k3s_cve=false
has_k0s_cve=false
# Check each workflow run for failed or successful jobs with CVE indicators
for run_id in $(echo "$workflow_runs" | jq -r '.[].id'); do
jobs=$(gh api "repos/${{ github.repository }}/actions/runs/${run_id}/jobs?per_page=100" --jq '.jobs')
# Check for standard k3s jobs with security issues (jobs that have grype/trivy and are standard)
k3s_jobs=$(echo "$jobs" | jq -r '[.[] | select(.name | test("standard.*k3s"; "i"))]')
k0s_jobs=$(echo "$jobs" | jq -r '[.[] | select(.name | test("standard.*k0s"; "i"))]')
# For report-only mode, we need to check the job logs or annotations for CVE findings
# Since we changed to report-only, jobs will succeed but may have CVE warnings in annotations
for job_id in $(echo "$k3s_jobs" | jq -r '.[].id // empty'); do
annotations=$(gh api "repos/${{ github.repository }}/check-runs/${job_id}/annotations" 2>/dev/null || echo "[]")
if echo "$annotations" | jq -e '.[] | select(.annotation_level == "warning" and (.message | test("CVE|vulnerability|critical|high"; "i")))' > /dev/null 2>&1; then
has_k3s_cve=true
fi
done
for job_id in $(echo "$k0s_jobs" | jq -r '.[].id // empty'); do
annotations=$(gh api "repos/${{ github.repository }}/check-runs/${job_id}/annotations" 2>/dev/null || echo "[]")
if echo "$annotations" | jq -e '.[] | select(.annotation_level == "warning" and (.message | test("CVE|vulnerability|critical|high"; "i")))' > /dev/null 2>&1; then
has_k0s_cve=true
fi
done
done
# Also check code scanning alerts for this ref
alerts=$(gh api "repos/${{ github.repository }}/code-scanning/alerts?ref=refs/tags/${tag}&per_page=100" 2>/dev/null || echo "[]")
if [ "$alerts" != "[]" ] && [ -n "$alerts" ]; then
# Check for k3s related CVEs
if echo "$alerts" | jq -e '.[] | select(.rule.description | test("k3s"; "i"))' > /dev/null 2>&1; then
has_k3s_cve=true
fi
# Check for k0s related CVEs
if echo "$alerts" | jq -e '.[] | select(.rule.description | test("k0s"; "i"))' > /dev/null 2>&1; then
has_k0s_cve=true
fi
fi
# Build warning message
if [ "$has_k3s_cve" = "true" ] || [ "$has_k0s_cve" = "true" ]; then
cve_warning="> [!WARNING]\n> **Security Notice:** The standard images in this release contain known CVEs from upstream components"
if [ "$has_k3s_cve" = "true" ] && [ "$has_k0s_cve" = "true" ]; then
cve_warning="${cve_warning} (k3s and k0s)."
elif [ "$has_k3s_cve" = "true" ]; then
cve_warning="${cve_warning} (k3s)."
else
cve_warning="${cve_warning} (k0s)."
fi
cve_warning="${cve_warning} These vulnerabilities originate from the Kubernetes distribution binaries and are outside our control. Please review the security scan results before deploying to production.\n"
echo "has_cve=true" >> "$GITHUB_OUTPUT"
# Use a delimiter to handle multiline output
{
echo "warning<<EOF"
echo -e "$cve_warning"
echo "EOF"
} >> "$GITHUB_OUTPUT"
else
echo "has_cve=false" >> "$GITHUB_OUTPUT"
fi
- name: Prepend CVE warning to release notes
if: ${{ steps.cve-check.outputs.has_cve == 'true' }}
run: |
warning_header="> [!WARNING]"
gh release view "$CURRENT_TAG" --repo "${{ github.repository }}" --json body --jq '.body // ""' > current_body.md
# Check if warning already exists
if grep -Fq "$warning_header" current_body.md; then
echo "CVE warning already present in release body. Skipping prepend."
exit 0
fi
{
echo '${{ steps.cve-check.outputs.warning }}'
cat current_body.md
} > updated_body.md
gh release edit "$CURRENT_TAG" --repo "${{ github.repository }}" --notes-file updated_body.md
echo "CVE warning prepended to release notes."
- name: Resolve previous final release tag
id: prev
run: |
# NOTE: per_page=100 reliably times out (HTTP 504) on this repo's releases
# endpoint and returns an HTML error page instead of JSON. Releases are
# returned newest-first, so a smaller page is enough to find the relevant
# releases. We also guard against a non-JSON response so a transient API
# hiccup skips diff generation instead of failing the release.
releases_json=$(gh api "repos/${{ github.repository }}/releases?per_page=50") || {
echo "Could not fetch releases (API error). Skipping diff generation."
echo "skip=true" >> "$GITHUB_OUTPUT"
exit 0
}
if ! echo "$releases_json" | jq -e 'type == "array"' > /dev/null 2>&1; then
echo "Unexpected releases response (not a JSON array). Skipping diff generation."
echo "skip=true" >> "$GITHUB_OUTPUT"
exit 0
fi
# Resolve the final release that immediately precedes CURRENT_TAG in the
# newest-first list. This works for both the release:published trigger
# (where CURRENT_TAG is the newest release) and manual workflow_dispatch
# runs that target an older tag. If CURRENT_TAG is not among the recent
# final releases (e.g. too old for this page), we skip rather than diff
# against the wrong base.
previous_tag=$(echo "$releases_json" | jq -r --arg current "$CURRENT_TAG" '[.[] | select(.draft == false and .prerelease == false) | .tag_name] as $finals | ($finals | index($current)) as $i | (if $i == null then empty else $finals[$i + 1] end) // empty')
if [ -z "$previous_tag" ] || [ "$previous_tag" = "null" ]; then
echo "No previous final release found for $CURRENT_TAG. Skipping diff generation."
echo "skip=true" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "Previous final release: $previous_tag"
echo "skip=false" >> "$GITHUB_OUTPUT"
echo "tag=$previous_tag" >> "$GITHUB_OUTPUT"
- name: Generate release diff markdown
if: ${{ steps.prev.outputs.skip == 'false' }}
run: |
output_file="RELEASE_DIFF_${CURRENT_TAG}.md"
./scripts/kairos-diff.sh "${{ steps.prev.outputs.tag }}" "$CURRENT_TAG" --output "$output_file"
echo "output_file=$output_file" >> "$GITHUB_ENV"
- name: Append diff to release description
if: ${{ steps.prev.outputs.skip == 'false' }}
id: append
run: |
header="# Changes since previous version (${{ steps.prev.outputs.tag }})"
gh release view "$CURRENT_TAG" --repo "${{ github.repository }}" --json body --jq '.body // ""' > current_body.md
if grep -Fq "$header" current_body.md; then
echo "Header already present in release body. Skipping append."
echo "appended=false" >> "$GITHUB_OUTPUT"
exit 0
fi
{
cat current_body.md
echo
echo "$header"
echo
cat "${output_file}"
} > combined_body.md
gh release edit "$CURRENT_TAG" --repo "${{ github.repository }}" --notes-file combined_body.md
echo "appended=true" >> "$GITHUB_OUTPUT"
- name: Write workflow summary
if: ${{ steps.prev.outputs.skip == 'false' }}
run: |
{
echo "## Release diff generated"
echo
echo "- Current release: \`${CURRENT_TAG}\`"
echo "- Previous final release: \`${{ steps.prev.outputs.tag }}\`"
if [ "${{ steps.append.outputs.appended }}" = "true" ]; then
echo "- Release description updated: \`yes\`"
else
echo "- Release description updated: \`no (already contained section header)\`"
fi
} >> "$GITHUB_STEP_SUMMARY"