Skip to content

Commit 7a26f2a

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 7a26f2a

File tree

1 file changed

+212
-0
lines changed

1 file changed

+212
-0
lines changed

.github/workflows/bitsign.yml

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

0 commit comments

Comments
 (0)