-
Notifications
You must be signed in to change notification settings - Fork 4
217 lines (183 loc) · 6.76 KB
/
Copy pathrelease-sign.yml
File metadata and controls
217 lines (183 loc) · 6.76 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
215
216
217
# Sign Release Binaries
#
# This workflow signs all release artifacts with Ed25519 signatures
# using zipsign. It runs automatically when a release is created.
#
# Prerequisites:
# - ZIPSIGN_PRIVATE_KEY secret must be set in GitHub repository settings
# - The private key should be the Ed25519 private key generated via
# scripts/generate-zipsign-keypair.sh
#
# Security:
# - Private key is stored as a GitHub secret (never in code)
# - Signing happens in a clean GitHub Actions environment
# - Signed artifacts are uploaded back to the release
name: Sign Release
on:
release:
types: [created]
permissions:
contents: write # Required to upload artifacts to releases
jobs:
sign:
name: Sign Release Artifacts
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v4
- name: Install zipsign
run: |
cargo install zipsign
zipsign --version
- name: Download release artifacts
env:
GH_TOKEN: ${{ github.token }}
run: |
# Get the tag name without 'v' prefix
VERSION="${GITHUB_REF#refs/tags/v}"
echo "Version: $VERSION"
echo "VERSION=$VERSION" >> $GITHUB_ENV
# Create directory for artifacts
mkdir -p artifacts
# Download all assets from the release
gh release view "$VERSION" --json assets --jq '.assets[].name' | \
while read -r asset_name; do
# Remove quotes from asset name
asset_name=$(echo "$asset_name" | tr -d '"')
# Only download tar.gz and tar.zst archives
if [[ "$asset_name" =~ \.(tar\.gz|tar\.zst)$ ]]; then
echo "Downloading: $asset_name"
gh release download "$VERSION" --pattern "$asset_name" --dir artifacts
fi
done
# List downloaded artifacts
echo "Downloaded artifacts:"
ls -lh artifacts/
- name: Verify artifacts exist
run: |
if [ -z "$(ls -A artifacts/)" ]; then
echo "No artifacts found to sign!"
exit 1
fi
# Count archives
ARCHIVE_COUNT=$(find artifacts/ -type f \( -name "*.tar.gz" -o -name "*.tar.zst" \) | wc -l)
echo "Found $ARCHIVE_COUNT archive(s) to sign"
if [ "$ARCHIVE_COUNT" -eq 0 ]; then
echo "No tar.gz or tar.zst archives found"
exit 1
fi
- name: Sign artifacts
env:
ZIPSIGN_PRIVATE_KEY: ${{ secrets.ZIPSIGN_PRIVATE_KEY }}
run: |
if [ -z "$ZIPSIGN_PRIVATE_KEY" ]; then
echo "Error: ZIPSIGN_PRIVATE_KEY secret not set"
echo "Please set the private key as a GitHub secret"
exit 1
fi
# Save private key to temporary file
PRIVATE_KEY_FILE=$(mktemp)
echo "$ZIPSIGN_PRIVATE_KEY" > "$PRIVATE_KEY_FILE"
chmod 600 "$PRIVATE_KEY_FILE"
# Sign each archive
SIGNED_COUNT=0
for archive in artifacts/*.{tar.gz,tar.zst}; do
if [ -f "$archive" ]; then
echo "Signing: $(basename "$archive")"
# Check if already signed
if zipsign verify tar "$archive" "$PRIVATE_KEY_FILE" >/dev/null 2>&1; then
echo " Already signed, skipping"
else
# Sign the archive
if zipsign sign tar "$archive" "$PRIVATE_KEY_FILE"; then
echo " ✓ Signed successfully"
((SIGNED_COUNT++))
else
echo " ✗ Failed to sign"
exit 1
fi
fi
fi
done
echo "Signed $SIGNED_COUNT archive(s)"
# Clean up private key file
rm -f "$PRIVATE_KEY_FILE"
- name: Verify signatures
env:
ZIPSIGN_PRIVATE_KEY: ${{ secrets.ZIPSIGN_PRIVATE_KEY }}
run: |
# Save private key to temporary file
PRIVATE_KEY_FILE=$(mktemp)
echo "$ZIPSIGN_PRIVATE_KEY" > "$PRIVATE_KEY_FILE"
chmod 600 "$PRIVATE_KEY_FILE"
# Verify each signed archive
FAILED_COUNT=0
for archive in artifacts/*.{tar.gz,tar.zst}; do
if [ -f "$archive" ]; then
echo "Verifying: $(basename "$archive")"
if zipsign verify tar "$archive" "$PRIVATE_KEY_FILE"; then
echo " ✓ Signature valid"
else
echo " ✗ Signature invalid"
((FAILED_COUNT++))
fi
fi
done
# Clean up private key file
rm -f "$PRIVATE_KEY_FILE"
if [ $FAILED_COUNT -gt 0 ]; then
echo "Error: $FAILED_COUNT signature(s) failed verification"
exit 1
fi
echo "All signatures verified successfully"
- name: Upload signed artifacts to release
env:
GH_TOKEN: ${{ github.token }}
run: |
# Upload each signed artifact back to the release
# Note: gh release upload will replace existing assets with the same name
for archive in artifacts/*.{tar.gz,tar.zst}; do
if [ -f "$archive" ]; then
echo "Uploading: $(basename "$archive")"
gh release upload "$VERSION" "$archive" --clobber
fi
done
echo "All signed artifacts uploaded"
- name: Generate signature report
if: always()
run: |
echo "# Signature Verification Report" > signature-report.md
echo "" >> signature-report.md
echo "**Release**: ${{ github.ref_name }}" >> signature-report.md
echo "**Date**: $(date -u +"%Y-%m-%d %H:%M:%S UTC")" >> signature-report.md
echo "**Workflow Run**: ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}" >> signature-report.md
echo "" >> signature-report.md
echo "## Signed Artifacts" >> signature-report.md
echo "" >> signature-report.md
echo '```' >> signature-report.md
ls -lh artifacts/
echo '```' >> signature-report.md
cat signature-report.md
- name: Upload signature report
if: always()
uses: actions/upload-artifact@v4
with:
name: signature-report
path: signature-report.md
retention-days: 90
summary:
name: Generate Summary
runs-on: ubuntu-latest
needs: sign
if: always()
steps:
- name: Download signature report
uses: actions/download-artifact@v4
with:
name: signature-report
path: .
- name: Add job summary
run: |
if [ -f signature-report.md ]; then
cat signature-report.md >> $GITHUB_STEP_SUMMARY
fi