3
3
@file sign.py
4
4
@author Nat Goodspeed
5
5
@date 2023-09-14
6
- @brief Sign the designated executable using Windows signtool .
6
+ @brief Sign the designated executable using Microsoft AzureSignTool .
7
7
8
8
$LicenseInfo:firstyear=2023&license=viewerlgpl$
9
9
Copyright (c) 2023, Linden Research, Inc.
20
20
from datetime import datetime , timedelta
21
21
from pathlib import Path
22
22
23
- from autobuild .autobuild_tool_source_environment import SourceEnvError , _available_vsvers , load_vsvars
24
23
from pyng .commands import Commands
25
24
26
25
@@ -38,94 +37,42 @@ class Error(Exception):
38
37
39
38
# Interactively, don't print our int return value
40
39
@command .format (lambda ret : None )
41
- def sign (executable , * , service : Iterable , certificate ,
42
- delay = 5 , retries = 6 , backoff = 1.5 , certwarning = 14 ,
43
- description = 'Second Life Setup' ):
40
+ def sign (executable , * , vault_uri , cert_name , client_id , client_secret , tenant_id ,
41
+ certwarning = 14 ):
44
42
"""
45
- Sign the designated executable using Windows signtool .
43
+ Sign the designated executable using Microsoft AzureSignTool .
46
44
47
45
Pass:
48
46
49
- executable: path to executable to sign
50
- certificate: path to certificate file with authentication
51
- service: iterable of URLs to timestamp services
52
- delay: initial delay before signing attempt
53
- retries: number of times to attempt the signing operation
54
- backoff: scale factor by which to multiply delay for each retry
55
- certwarning: warn if certificate will expire in fewer than this many days
56
- description: pass to signtool
47
+ executable: path to executable to sign
48
+ vault_uri: Azure key vault URI
49
+ cert_name: Name of certificate on Azure
50
+ client_id: Azure signer app clientId
51
+ client_secret: Azure signer app clientSecret
52
+ tenant_id: Azure signer app tenantId
53
+ certwarning: warn if certificate will expire in fewer than this many days
57
54
"""
58
- # First, locate signtool.
59
- # Don't even pretend to support 32-bit any more.
60
- os .environ ['AUTOBUILD_ADDRSIZE' ] = '64'
61
- try :
62
- vsver = _available_vsvers ()[- 1 ]
63
- except SourceEnvError as err :
64
- raise Error (str (err )) from err
65
- except IndexError :
66
- raise Error ("Can't determine latest Visual Studio version, is it installed?" )
67
-
68
- try :
69
- vsvars = load_vsvars (vsver )
70
- except SourceEnvError as err :
71
- raise Error (str (err )) from err
72
-
73
- try :
74
- # load_vsvars() returns an ordinary Python dict, that is,
75
- # case-sensitive. Empirically the keys are all uppercase. We could go
76
- # through the exercise of loading this data into a case-insensitive
77
- # dict, but it's simpler to use an uppercase key.
78
- VerBinPath = vsvars ['WINDOWSSDKVERBINPATH' ]
79
- except KeyError :
80
- from pprint import pprint
81
- pprint ({key : value for key , value in vsvars .items () if 'Kits' in value })
82
- raise Error (f"WindowsSdkVerBinPath not set by VS version { vsver } " )
83
-
84
- signtool = Path (VerBinPath ) / 'X64' / 'signtool.exe'
85
- assert signtool .is_file ()
86
-
87
55
name = Path (executable ).name
88
56
89
- # If we bang on the timestamp server too hard by signing executables
90
- # back-to-back, we may get throttled.
91
- # "Error: SignerSign() failed. (-1073700864/0xc000a000)"
92
- # may be throttle-related, and it somehow fails the build despite the
93
- # backoff loop meant to deal with it. (???)
94
- # At any rate, a small fixed delay may keep us out of throttle trouble.
95
- done = None
96
- for retry in range (retries ):
97
- if retry :
98
- print (f'{ name } signing { retry } failed, ' , end = '' )
99
- print (f'waiting { delay :.1f} seconds' )
100
- time .sleep (delay )
101
- delay *= backoff
102
- # round-robin between listed services
103
- svc = service [retry % len (service )]
104
- command = [str (signtool ), 'sign' ,
105
- '/f' , certificate ,
106
- '/t' , svc ,
107
- '/d' , description ,
108
- '/fd' , 'sha256' ,
109
- '/v' ,
110
- executable ]
111
- try :
112
- print (f'{ name } attempt { retry + 1 } :' , shlex .join (command ))
113
- except TypeError :
114
- print (repr (command ))
115
- raise
116
- done = subprocess .run (command ,
117
- stdout = subprocess .PIPE ,
118
- stderr = subprocess .STDOUT ,
119
- text = True )
120
- print (done .stdout , end = '' )
121
- if done .returncode == 0 :
122
- break
123
- else :
124
- raise Error (f'{ name } signing failed after { retries } attempts, giving up' )
125
-
126
- # Here the last of the retries succeeded, setting 'done'
57
+ command = ['AzureSignTool' , 'sign' ,
58
+ '-kvu' , vault_uri ,
59
+ '-kvi' , client_id ,
60
+ '-kvt' , tenant_id ,
61
+ '-kvs' , client_secret ,
62
+ '-kvc' , cert_name ,
63
+ '-tr' , 'http://timestamp.digicert.com' ,
64
+ '-v' , executable ]
65
+ print (name , 'signing:' , shlex .join (command ))
66
+ done = subprocess .run (command ,
67
+ stdout = subprocess .PIPE ,
68
+ stderr = subprocess .STDOUT ,
69
+ text = True )
70
+ print (done .stdout , end = '' )
127
71
rc = done .returncode
128
- print ('Signing succeeded' )
72
+ if rc != 0 :
73
+ raise Error (name + ' signing failed' )
74
+
75
+ print (name , 'signing succeeded' )
129
76
# Check the certificate expiration date in the output to warn of imminent expiration
130
77
for line in done .stdout .splitlines ():
131
78
found = ExpiresLine .search (line )
@@ -136,13 +83,14 @@ def sign(executable, *, service: Iterable, certificate,
136
83
except ValueError :
137
84
raise Error ('failed to parse expiration from: ' + line )
138
85
else :
86
+ expires = expiration - datetime .now ()
87
+ print (f'Certificate expires in { expires .days } days' )
88
+ if expires < timedelta (certwarning ):
89
+ print (f'::warning::Certificate expires in { expires .days } days: { expiration } ' )
139
90
break
140
91
else :
141
- raise Error ('Failed to find certificate expiration date' )
142
- expires = expiration - datetime .now ()
143
- print (f'Certificate expires in { expires .days } days' )
144
- if expires < timedelta (certwarning ):
145
- print (f'::warning::Certificate expires in { expires .days } days: { expiration } ' )
92
+ ## raise Error('Failed to find certificate expiration date')
93
+ print ('::warning::Failed to find certificate expiration date' )
146
94
return rc
147
95
148
96
0 commit comments