Skip to content

Commit ea519c4

Browse files
committed
.github: add bitSign workflow for signing releases
This is currently a standalone workflow that needs manual trigger via workflow_dispatch, but the end goal here is to chain it to the release job. Signed-off-by: Richard Alpe <[email protected]>
1 parent 2f13fc7 commit ea519c4

File tree

1 file changed

+202
-0
lines changed

1 file changed

+202
-0
lines changed

.github/workflows/bitsign.yml

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
name: bitSign Infix Release
2+
3+
on:
4+
workflow_dispatch:
5+
inputs:
6+
release_version:
7+
description: 'Release version (e.g., v25.08.0)'
8+
required: true
9+
type: string
10+
push:
11+
branches: [ sign-with-bitsign ]
12+
13+
jobs:
14+
sign-infix-release:
15+
runs-on: ubuntu-latest
16+
17+
steps:
18+
- name: Checkout repository
19+
uses: actions/checkout@v4
20+
21+
- name: Validate release version format
22+
id: validate
23+
run: |
24+
VERSION="${{ inputs.release_version }}"
25+
echo "Validating release version: $VERSION"
26+
27+
# Check if version starts with 'v' and has proper format
28+
if ! echo "$VERSION" | grep -qE '^v[0-9]+\.[0-9]+(\.[0-9]+)?(-alpha[0-9]*|-beta[0-9]*|-rc[0-9]*)?$'; then
29+
echo "❌ Invalid version format. Expected format: vYY.MM(.PP)(-alphaN|-betaN|-rcN)"
30+
echo "Examples: v25.08.0, v25.08.0-alpha1, v25.08.0-rc1"
31+
exit 1
32+
fi
33+
34+
# Extract version without 'v' prefix for filename
35+
FILE_VERSION="${VERSION#v}"
36+
FILENAME="infix-x86_64-${FILE_VERSION}.tar.gz"
37+
RELEASE_URL="https://github.com/kernelkit/infix/releases/download/${VERSION}/${FILENAME}"
38+
39+
echo "✅ Version format valid"
40+
echo "file_version=${FILE_VERSION}" >> $GITHUB_OUTPUT
41+
echo "filename=${FILENAME}" >> $GITHUB_OUTPUT
42+
echo "release_url=${RELEASE_URL}" >> $GITHUB_OUTPUT
43+
44+
- name: Download Infix release
45+
run: |
46+
RELEASE_URL="${{ steps.validate.outputs.release_url }}"
47+
FILENAME="${{ steps.validate.outputs.filename }}"
48+
49+
echo "Downloading Infix release: $FILENAME"
50+
echo "From: $RELEASE_URL"
51+
52+
if ! curl -L "$RELEASE_URL" -o "$FILENAME" --fail --show-error --progress-bar; then
53+
echo "❌ Failed to download release file from: $RELEASE_URL"
54+
echo "Please verify that the release version exists and contains the x86_64 build."
55+
echo "You can check available releases at: https://github.com/kernelkit/infix/releases"
56+
exit 1
57+
fi
58+
59+
# Verify download
60+
if [ -f "$FILENAME" ] && [ -s "$FILENAME" ]; then
61+
FILE_SIZE=$(ls -lh "$FILENAME" | awk '{print $5}')
62+
echo "✅ Successfully downloaded: $FILENAME ($FILE_SIZE)"
63+
else
64+
echo "❌ Failed to download release file"
65+
exit 1
66+
fi
67+
68+
- name: Create signing request
69+
id: create_request
70+
run: |
71+
FILENAME="${{ steps.validate.outputs.filename }}"
72+
echo "Creating signing request for $FILENAME..."
73+
74+
# Create signing request using BitSign API
75+
RESPONSE=$(curl -s -X POST "https://portal.bitsign.se/api/v1/requests" \
76+
-H "Authorization: Bearer ${{ secrets.BITSIGN_API_KEY }}" \
77+
-F "file=@$FILENAME" \
78+
-F "key=bit42-Demo1" \
79+
-F "job=Infix-x86" \
80+
-F "parameters={\"timestamp\": true}")
81+
82+
echo "API Response: $RESPONSE"
83+
84+
# Check if request was successful
85+
if echo "$RESPONSE" | jq -e '.success == true' > /dev/null; then
86+
REQUEST_ID=$(echo "$RESPONSE" | jq -r '.requestId')
87+
echo "✅ Request created successfully with ID: $REQUEST_ID"
88+
echo "request_id=$REQUEST_ID" >> $GITHUB_OUTPUT
89+
else
90+
echo "❌ Failed to create signing request"
91+
echo "$RESPONSE" | jq -r '.error // .message // "Unknown error"'
92+
exit 1
93+
fi
94+
95+
- name: Wait for signing completion
96+
id: wait_completion
97+
run: |
98+
REQUEST_ID="${{ steps.create_request.outputs.request_id }}"
99+
echo "Waiting for signing completion for request: $REQUEST_ID"
100+
101+
# Poll status for up to 10 minutes (600 seconds) - longer timeout for larger files
102+
MAX_WAIT=600
103+
WAITED=0
104+
105+
while [ $WAITED -lt $MAX_WAIT ]; do
106+
RESPONSE=$(curl -s -X GET "https://portal.bitsign.se/api/v1/requests/$REQUEST_ID/status" \
107+
-H "Authorization: Bearer ${{ secrets.BITSIGN_API_KEY }}")
108+
109+
STATUS=$(echo "$RESPONSE" | jq -r '.status')
110+
echo "Current status: $STATUS (waited ${WAITED}s)"
111+
112+
if [ "$STATUS" = "completed" ]; then
113+
echo "✅ Signing completed successfully!"
114+
break
115+
elif [ "$STATUS" = "failed" ]; then
116+
echo "❌ Signing failed"
117+
echo "$RESPONSE" | jq -r '.error // .message // "Unknown error"'
118+
exit 1
119+
fi
120+
121+
sleep 10
122+
WAITED=$((WAITED + 10))
123+
done
124+
125+
if [ $WAITED -ge $MAX_WAIT ]; then
126+
echo "❌ Timeout: Signing did not complete within ${MAX_WAIT} seconds"
127+
exit 1
128+
fi
129+
130+
- name: Download signed file
131+
id: download_signed
132+
run: |
133+
REQUEST_ID="${{ steps.create_request.outputs.request_id }}"
134+
FILENAME="${{ steps.validate.outputs.filename }}"
135+
FILE_VERSION="${{ steps.validate.outputs.file_version }}"
136+
SIGNED_FILENAME="infix-x86_64-${FILE_VERSION}-signed.tar.gz"
137+
138+
echo "Downloading signed file for request: $REQUEST_ID"
139+
echo "Expected signed filename: $SIGNED_FILENAME"
140+
141+
# Download the signed file
142+
curl -X GET "https://portal.bitsign.se/api/v1/requests/$REQUEST_ID/download" \
143+
-H "Authorization: Bearer ${{ secrets.BITSIGN_API_KEY }}" \
144+
-o "$SIGNED_FILENAME" \
145+
--fail --show-error
146+
147+
if [ -f "$SIGNED_FILENAME" ] && [ -s "$SIGNED_FILENAME" ]; then
148+
FILE_SIZE=$(ls -lh "$SIGNED_FILENAME" | awk '{print $5}')
149+
echo "Successfully downloaded signed file: $SIGNED_FILENAME ($FILE_SIZE)"
150+
echo "signed_filename=$SIGNED_FILENAME" >> $GITHUB_OUTPUT
151+
else
152+
echo "Failed to download signed file"
153+
exit 1
154+
fi
155+
156+
- name: Upload signed artifacts
157+
uses: actions/upload-artifact@v4
158+
with:
159+
name: signed-infix-${{ steps.validate.outputs.file_version }}
160+
path: |
161+
${{ steps.validate.outputs.filename }}
162+
${{ steps.download_signed.outputs.signed_filename }}
163+
retention-days: 90
164+
165+
- name: Summary
166+
run: |
167+
cat >> $GITHUB_STEP_SUMMARY << 'EOF'
168+
# bitSign Infix Release Signing Complete
169+
170+
The Infix release has been successfully signed using the bitSign API.
171+
172+
## Process Overview
173+
174+
1. **Release Download** - Downloaded specified Infix release from GitHub
175+
2. **Signing Request** - Created signing request via bitSign API
176+
3. **Approval Process** - Trusted signers received notification and approved with 2FA
177+
4. **bitSign Processing** - Backend securely signed the release file
178+
5. **Download & Store** - Retrieved signed result and stored as artifacts
179+
180+
## Signing Details
181+
182+
| Property | Value |
183+
|----------|-------|
184+
| 📦 **Original File** | `${{ steps.validate.outputs.filename }}` |
185+
| ✍️ **Signed File** | `${{ steps.download_signed.outputs.signed_filename }}` |
186+
| 🔑 **Signing Key** | `bit42-Demo1` |
187+
| ⚙️ **Job Type** | `Infix-x86` |
188+
| 🆔 **Request ID** | `${{ steps.create_request.outputs.request_id }}` |
189+
| 📋 **Release Version** | `${{ inputs.release_version }}` |
190+
| 🌐 **API Endpoint** | `portal.bitsign.se` |
191+
192+
## Download Files
193+
194+
> **Both the original release file and signed version are available as a workflow artifact:**
195+
> **`signed-infix-${{ steps.validate.outputs.file_version }}`**
196+
>
197+
> The artifact contains both `${{ steps.validate.outputs.filename }}` and `${{ steps.download_signed.outputs.signed_filename }}` files.
198+
199+
---
200+
201+
**Next Steps:** The signed release can now be distributed with cryptographic verification of authenticity.
202+
EOF

0 commit comments

Comments
 (0)