-
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathaction.yml
405 lines (359 loc) · 17.3 KB
/
action.yml
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
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
name: "Code Sign Action"
description: "A GitHub Action for code signing files. Particularly those generated with vercel/pkg."
branding:
color: purple
icon: lock
inputs:
# Required
file:
description: "The file to sign"
required: true
certificate-data:
description: "A `base64` encoded string of your `p12` or `pfx` cert contents. Note: if you use KeyLocker, this will be the base64 encoded client certificate (`SM_CLIENT_CERT_FILE`)"
required: true
certificate-password:
description: "The password to unlock the certificate-data"
required: true
# Optional
apple-notary-password:
description: "The Apple Developer account password to use in notarization"
required: false
apple-notary-user:
description: "The Apple Developer account email to use in notarization"
required: false
apple-notary-tool:
description: "The xcrun tool to use to notarize."
required: false
default: notarytool
apple-product-id:
description: "The unique product ID to use for notarization"
required: false
apple-team-id:
description: "The Apple Developer account Team ID"
required: false
certificate-id:
description: "A string to identify the correct signing cert"
required: true
keylocker-api-key:
description: "The API key to use for KeyLocker"
required: false
keylocker-cert-sha1-hash:
description: "The SHA1 hash of the certificate to use for KeyLocker"
required: false
keylocker-host:
description: "The host to use for KeyLocker"
required: false
keylocker-keypair-alias:
description: "The alias of the keypair to use for KeyLocker"
required: false
options:
description: "Extra options to pass to the codesigning tool"
required: false
signtool:
description: "The signtool to use"
required: false
default: auto
outputs:
file:
description: "The path to the signed binary."
value: ${{ steps.code-sign-action.outputs.file }}
runs:
using: composite
steps:
- name: Validate user inputs
shell: bash
run: |
echo "::group::Ensure file is set"
if [ "${{ inputs.file }}" == "" ]; then
echo "::error title=File is not set!::You must specify a file to sign!"
exit 1
fi
echo "::endgroup::"
echo "::group::Ensure cert data is set"
if [ "${{ inputs.certificate-data }}" == "" ]; then
echo "::error title=Cert data is not set!::You must specify the cert you want to sign with!"
exit 2
fi
echo "::endgroup::"
echo "::group::Ensure certificate password is set"
if [ "${{ inputs.certificate-password }}" == "" ]; then
echo "::error title=Cert password is not set!::You must specify the password to unlock the cert with!"
exit 2
fi
echo "::endgroup::"
- name: Set generic internal inputs
id: code-sign-action-generic-internal
shell: bash
run: |
# standardize os stuff
if [ "${{ runner.os }}" == "Linux" ]; then
echo "os=linux" >> $GITHUB_OUTPUT
elif [ "${{ runner.os }}" == "macOS" ]; then
echo "os=macos" >> $GITHUB_OUTPUT
elif [ "${{ runner.os }}" == "Windows" ]; then
echo "os=win" >> $GITHUB_OUTPUT
fi
# cert id
if [ "${{ runner.os }}" == "macOS" ] && [[ -n "${{ inputs.apple-team-id }}" ]]; then
echo "signid=${{ inputs.apple-team-id }}" >> $GITHUB_OUTPUT
else
echo "signid=${{ inputs.certificate-id }}" >> $GITHUB_OUTPUT
fi
# signtool discovery if needed
if [ "${{ inputs.signtool }}" == "auto" ]; then
# keylocker
if [ "${{ runner.os }}" != "macOS" ] \
&& [[ -n "${{ inputs.keylocker-api-key }}" ]] \
&& [[ -n "${{ inputs.keylocker-cert-sha1-hash }}" ]] \
&& [[ -n "${{ inputs.keylocker-host }}" ]] \
&& [[ -n "${{ inputs.keylocker-keypair-alias }}" ]]; then
echo "signtool=keylocker" >> $GITHUB_OUTPUT
# signtool
elif [ "${{ runner.os }}" == "Windows" ]; then
echo "signtool=signtool" >> $GITHUB_OUTPUT
# codesign
elif [ "${{ runner.os }}" == "macOS" ]; then
echo "signtool=codesign" >> $GITHUB_OUTPUT
fi
fi
# notarize logix
if [ "${{ runner.os }}" == "macOS" ] \
&& [[ -n "${{ inputs.apple-notary-password }}" ]] \
&& [[ -n "${{ inputs.apple-notary-user }}" ]] \
&& [[ -n "${{ inputs.apple-product-id }}" ]]; then
echo "notarize=true" >> $GITHUB_OUTPUT
fi
- name: Set osy internal inputs
if: runner.os == 'Windows'
id: code-sign-action-win-internal
shell: powershell
run: |
# sign cert
$certpath = "$env:RUNNER_TEMP\signcert.p12"
Write-Output "signcert=$certpath" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
# input file
if ((Split-Path -Path "${{ inputs.file }}" -IsAbsolute) -eq $true) {
$file="${{ inputs.file }}"
} else {
$file="$(Get-Location)/${{ inputs.file }}"
}
Write-Output "file=$file" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
# relative file path from GITHUB_WORKSPACE for keylocker things
function Get-RelativePath {
param (
[string]$FromPath,
[string]$ToPath
)
# ensure paths are fully resolved
$resolvedFromPath = (Resolve-Path -LiteralPath $FromPath).Path
$resolvedToPath = (Resolve-Path -LiteralPath $ToPath).Path
# ensure $FromPath is treated as a directory (append a trailing slash if it's a directory and doesn't already have one)
if ((Test-Path -LiteralPath $resolvedFromPath -PathType Container) -and ($resolvedFromPath -notlike '*\')) {
$resolvedFromPath += '\'
}
# create URI objects
$fromUri = New-Object System.Uri -ArgumentList $resolvedFromPath
$toUri = New-Object System.Uri -ArgumentList $resolvedToPath
# compute the relative path
$relativeUri = $fromUri.MakeRelativeUri($toUri)
$relativePath = [System.Uri]::UnescapeDataString($relativeUri.ToString())
# convert URI-style paths to file system style paths (Windows-specific)
if ($relativePath -notlike "*:*") {
$relativePath = $relativePath -replace '/', '\'
}
return $relativePath
}
$relativePath = Get-RelativePath -FromPath "$env:GITHUB_WORKSPACE" -ToPath "$file"
Write-Output "ghwrfile=$relativePath" | Out-File -FilePath $env:GITHUB_OUTPUT -Append -Encoding utf8
- name: Set osy internal inputs
if: runner.os != 'Windows'
id: code-sign-action-posix-internal
shell: bash
run: |
# sign cert
certpath="$RUNNER_TEMP/signcert.p12"
echo "signcert=$certpath" >> $GITHUB_OUTPUT
# input file
if [[ "${{ inputs.file }}" == /* ]]; then
echo "file=${{ inputs.file }}" >> $GITHUB_OUTPUT
else
echo "file=$(pwd)/${{ inputs.file }}" >> $GITHUB_OUTPUT
fi
- name: Set internal inputs
id: code-sign-action-internal
shell: bash
run: |
# generics
echo "notarize=${{ steps.code-sign-action-generic-internal.outputs.notarize }}" >> $GITHUB_OUTPUT
echo "os=${{ steps.code-sign-action-generic-internal.outputs.os }}" >> $GITHUB_OUTPUT
echo "signid=${{ steps.code-sign-action-generic-internal.outputs.signid }}" >> $GITHUB_OUTPUT
echo "signtool=${{ steps.code-sign-action-generic-internal.outputs.signtool }}" >> $GITHUB_OUTPUT
# osy
if [ "${{ runner.os }}" == "Windows" ]; then
echo "file=${{ steps.code-sign-action-win-internal.outputs.file }}" >> $GITHUB_OUTPUT
echo "ghwrfile=${{ steps.code-sign-action-win-internal.outputs.ghwrfile }}" >> $GITHUB_OUTPUT
echo "signcert=${{ steps.code-sign-action-win-internal.outputs.signcert }}" >> $GITHUB_OUTPUT
else
echo "file=${{ steps.code-sign-action-posix-internal.outputs.file }}" >> $GITHUB_OUTPUT
echo "signcert=${{ steps.code-sign-action-posix-internal.outputs.signcert }}" >> $GITHUB_OUTPUT
fi
- name: Verify Outputs
shell: bash
run: |
echo "::group::Internal output information"
echo "file=${{ steps.code-sign-action-internal.outputs.file }}"
echo "ghwrfile=${{ steps.code-sign-action-internal.outputs.ghwrfile }}"
echo "notarize=${{ steps.code-sign-action-internal.outputs.notarize }}"
echo "os=${{ steps.code-sign-action-internal.outputs.os }}"
echo "signcert=${{ steps.code-sign-action-internal.outputs.signcert }}"
echo "signid=${{ steps.code-sign-action-internal.outputs.signid }}"
echo "signtool=${{ steps.code-sign-action-internal.outputs.signtool }}"
echo "::endgroup::"
- name: Validate linux specific inputs
if: steps.code-sign-action-internal.outputs.os == 'linux'
shell: bash
run: |
echo "::error::Codesigning is not available on Linux! FWIW its not usually necessary to sign binaries on Linux."
exit 1
- name: Validate macos specific inputs
if: steps.code-sign-action-internal.outputs.os == 'macos'
shell: bash
run: |
# supported codesigner
if [ "${{ steps.code-sign-action-internal.outputs.signtool }}" != "codesign" ]; then
echo "::error::You must specify osslsigncode, keylocker or smctl as your signtool! You specified ${{ steps.code-sign-action-internal.outputs.signtool }}."
exit 1
fi
# team id
if [ "${{ steps.code-sign-action-internal.outputs.signid }}" == "" ]; then
echo "::error::You must specify a certificate-id or apple-team-id to sign!"
exit 1
fi
- name: Validate windows specific inputs
if: steps.code-sign-action-internal.outputs.os == 'win'
shell: bash
run: |
# supported codesigner
if [ "${{ steps.code-sign-action-internal.outputs.signtool }}" != "signtool" ] \
&& [ "${{ steps.code-sign-action-internal.outputs.signtool }}" != "keylocker" ] \
&& [ "${{ steps.code-sign-action-internal.outputs.signtool }}" != "smctl" ]; then
echo "::error::You must specify osslsigncode, keylocker or smctl as your signtool! You specified ${{ steps.code-sign-action-internal.outputs.signtool }}."
exit 1
fi
- name: Dump certs
if: steps.code-sign-action-internal.outputs.os == 'macos'
shell: bash
run: |
echo "::group::Dumping inputs.certificate-data"
echo "Dumping cert to ${{ steps.code-sign-action-internal.outputs.signcert }}..."
echo "${{ inputs.certificate-data }}" | base64 --decode > "${{ steps.code-sign-action-internal.outputs.signcert }}"
echo "::endgroup::"
- name: Dump certs
if: steps.code-sign-action-internal.outputs.os == 'win'
shell: powershell
run: |
echo "::group::Dumping inputs.certificate-data"
Write-Output "Dumping cert to ${{ steps.code-sign-action-internal.outputs.signcert }}..."
$bytes = [Convert]::FromBase64String("${{ inputs.certificate-data }}")
[IO.File]::WriteAllBytes("${{ steps.code-sign-action-internal.outputs.signcert }}", $bytes)
echo "::endgroup::"
# signing with codesign on macos
- name: Signing with ${{ steps.code-sign-action-internal.outputs.signtool }} (${{ steps.code-sign-action-internal.outputs.os }})
if: steps.code-sign-action-internal.outputs.signtool == 'codesign'
shell: bash
run: |
echo "::group::Signsetup"
# Throw error if file does not exist
if [ ! -f "${{ steps.code-sign-action-internal.outputs.file }}" ]; then
echo "${{ steps.code-sign-action-internal.outputs.file }} does not exist!"
exit 5
fi
function import_cert() {
security import "$1" -k ~/Library/Keychains/macos-build.keychain -P "$2" -T /usr/bin/codesign -T /usr/bin/productsign
}
# Create keychain
security create-keychain -p actions macos-build.keychain
security default-keychain -s macos-build.keychain
security unlock-keychain -p actions macos-build.keychain
security set-keychain-settings -t 3600 -u macos-build.keychain
# attempt to import p12 directly but fallback if it fails
if ! import_cert "${{ steps.code-sign-action-internal.outputs.signcert }}" "${{ inputs.certificate-password }}"; then
openssl pkcs12 -in "${{ steps.code-sign-action-internal.outputs.signcert }}" -nocerts -out "$RUNNER_TEMP/codesign.key" -nodes -password pass:"${{ inputs.certificate-password }}"
openssl pkcs12 -in "${{ steps.code-sign-action-internal.outputs.signcert }}" -clcerts -nokeys -out "$RUNNER_TEMP/codesign.crt" -password pass:"${{ inputs.certificate-password }}"
import_cert "$RUNNER_TEMP/codesign.key" ""
import_cert "$RUNNER_TEMP/codesign.crt" ""
fi
# Key signing
security set-key-partition-list -S apple-tool:,apple: -s -k actions macos-build.keychain
echo "::endgroup::"
# Scope out the keychain
security find-identity -v macos-build.keychain
# Force the codesignature
codesign --force ${{ inputs.options }} -s "${{ steps.code-sign-action-internal.outputs.signid }}" "${{ steps.code-sign-action-internal.outputs.file }}"
# Verify the code signature
codesign -v "${{ steps.code-sign-action-internal.outputs.file }}" --verbose
# signing with signtool on windows
- name: Signing with ${{ steps.code-sign-action-internal.outputs.signtool }} (${{ steps.code-sign-action-internal.outputs.os }})
if: steps.code-sign-action-internal.outputs.signtool == 'signtool'
shell: powershell
run: |
$ErrorActionPreference = "Stop"
echo "::group::Signsetup"
# get some things for cert opts
$file = "${{ steps.code-sign-action-internal.outputs.file }}"
$cert_secure_password = $null
$signtool = "${env:ProgramFiles(x86)}\Windows Kits\10\bin\x64\signtool.exe"
$signtool2022 = "${env:ProgramFiles(x86)}\Windows Kits\10\bin\10.0.17763.0\x86\signtool.exe"
# throw error if file does not exist
if (!(Test-Path "${{ steps.code-sign-action-internal.outputs.file }}"))
{
throw "${{ steps.code-sign-action-internal.outputs.file }} does not exist"
}
# use more recent signtool if we can
If (Test-Path $signtool2022) {
$signtool = "$signtool2022"
}
echo "::endgroup::"
# verify the cert and password are good
Write-Output "Verifying cert is good to go..."
$cert_secure_password = ConvertTo-SecureString "${{ inputs.certificate-password }}" -AsPlainText -Force
Import-PfxCertificate -FilePath "${{ steps.code-sign-action-internal.outputs.signcert }}" -Password $cert_secure_password -CertStoreLocation "Cert:\LocalMachine\My"
# sign and verify
Write-Output "Trying to sign ${{ steps.code-sign-action-internal.outputs.file }} with $signtool..."
& $signtool sign -f "${{ steps.code-sign-action-internal.outputs.signcert }}" -p "${{ inputs.certificate-password }}" -fd sha256 -tr "http://timestamp.comodoca.com/?td=sha256" -td sha256 ${{ inputs.options }} -as -v "${{ steps.code-sign-action-internal.outputs.file }}"
Write-Output "Verifying $file has been signed with the signtool..."
& $signtool verify -pa -v "${{ steps.code-sign-action-internal.outputs.file }}"
- name: Signing with ${{ steps.code-sign-action-internal.outputs.signtool }} (${{ steps.code-sign-action-internal.outputs.os }})
if: steps.code-sign-action-internal.outputs.signtool == 'keylocker' || steps.code-sign-action-internal.outputs.signtool == 'smctl'
uses: cognitedata/code-sign-action/@v3
with:
path-to-binary: ${{ steps.code-sign-action-internal.outputs.ghwrfile }}
env:
CERTIFICATE_HOST: ${{ inputs.keylocker-host }}
CERTIFICATE_HOST_API_KEY: ${{ inputs.keylocker-api-key }}
CERTIFICATE_SHA1_HASH: ${{ inputs.keylocker-cert-sha1-hash }}
CLIENT_CERTIFICATE: ${{ inputs.certificate-data }}
CLIENT_CERTIFICATE_PASSWORD: ${{ inputs.certificate-password }}
KEYPAIR_ALIAS: ${{ inputs.keylocker-keypair-alias }}
- name: Notarizing
if: steps.code-sign-action-internal.outputs.notarize == 'true'
uses: lando/notarize-action@v2
with:
appstore-connect-username: ${{ inputs.apple-notary-user }}
appstore-connect-password: ${{ inputs.apple-notary-password }}
appstore-connect-team-id: ${{ steps.code-sign-action-internal.outputs.signid }}
primary-bundle-id: ${{ inputs.apple-product-id }}
product-path: ${{ steps.code-sign-action-internal.outputs.file }}
tool: ${{ inputs.apple-notary-tool }}
verbose: true
- name: Verifying Notarization
if: steps.code-sign-action-internal.outputs.notarize == 'true'
shell: bash
run: codesign -vvvv -R="notarized" --check-notarization "${{ steps.code-sign-action-internal.outputs.file }}"
- name: Set outputs
id: code-sign-action
shell: bash
run: |
echo "::group::Setting outputs"
echo "file=${{ steps.code-sign-action-internal.outputs.file }}" >> $GITHUB_OUTPUT
echo "::endgroup::"