1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace RoaveTest\ComposerGpgVerify; |
6
|
|
|
|
7
|
|
|
use Composer\Composer; |
8
|
|
|
use Composer\Config; |
9
|
|
|
use Composer\Installer\InstallationManager; |
10
|
|
|
use Composer\IO\IOInterface; |
11
|
|
|
use Composer\Package\PackageInterface; |
12
|
|
|
use Composer\Repository\RepositoryInterface; |
13
|
|
|
use Composer\Repository\RepositoryManager; |
14
|
|
|
use Composer\Script\Event; |
15
|
|
|
use Composer\Script\ScriptEvents; |
16
|
|
|
use PHPUnit\Framework\TestCase; |
17
|
|
|
use Roave\ComposerGpgVerify\Exception\PackagesTrustCheckFailed; |
18
|
|
|
use Roave\ComposerGpgVerify\Exception\PreferredInstallIsNotSource; |
19
|
|
|
use Roave\ComposerGpgVerify\Verify; |
20
|
|
|
use Symfony\Component\Process\Process; |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* @covers \Roave\ComposerGpgVerify\Verify |
24
|
|
|
*/ |
25
|
|
|
final class VerifyTest extends TestCase |
26
|
|
|
{ |
27
|
|
|
/** |
28
|
|
|
* @var Event|\PHPUnit_Framework_MockObject_MockObject |
29
|
|
|
*/ |
30
|
|
|
private $event; |
31
|
|
|
|
32
|
|
|
/** |
33
|
|
|
* @var Composer|\PHPUnit_Framework_MockObject_MockObject |
34
|
|
|
*/ |
35
|
|
|
private $composer; |
36
|
|
|
|
37
|
|
|
/** |
38
|
|
|
* @var IOInterface|\PHPUnit_Framework_MockObject_MockObject |
39
|
|
|
*/ |
40
|
|
|
private $io; |
41
|
|
|
|
42
|
|
|
/** |
43
|
|
|
* @var Config|\PHPUnit_Framework_MockObject_MockObject |
44
|
|
|
*/ |
45
|
|
|
private $config; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* @var RepositoryManager|\PHPUnit_Framework_MockObject_MockObject |
49
|
|
|
*/ |
50
|
|
|
private $repositoryManager; |
51
|
|
|
|
52
|
|
|
/** |
53
|
|
|
* @var InstallationManager|\PHPUnit_Framework_MockObject_MockObject |
54
|
|
|
*/ |
55
|
|
|
private $installationManager; |
56
|
|
|
|
57
|
|
|
/** |
58
|
|
|
* @var RepositoryInterface|\PHPUnit_Framework_MockObject_MockObject |
59
|
|
|
*/ |
60
|
|
|
private $localRepository; |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* @var string |
64
|
|
|
*/ |
65
|
|
|
private $originalGpgHome; |
66
|
|
|
|
67
|
|
|
/** |
68
|
|
|
* @var string |
69
|
|
|
*/ |
70
|
|
|
private $originalLanguage; |
71
|
|
|
|
72
|
|
|
/** |
73
|
|
|
* @var PackageInterface[] indexed by installation path |
74
|
|
|
*/ |
75
|
|
|
private $installedPackages = []; |
76
|
|
|
|
77
|
|
|
protected function setUp() : void |
78
|
|
|
{ |
79
|
|
|
parent::setUp(); |
80
|
|
|
|
81
|
|
|
$this->installedPackages = []; |
82
|
|
|
$this->originalGpgHome = (string) getenv('GNUPGHOME'); |
83
|
|
|
$this->originalLanguage = (string) getenv('LANGUAGE'); |
84
|
|
|
|
85
|
|
|
$this->event = $this->createMock(Event::class); |
86
|
|
|
$this->composer = $this->createMock(Composer::class); |
87
|
|
|
$this->io = $this->createMock(IOInterface::class); |
88
|
|
|
$this->config = $this->createMock(Config::class); |
89
|
|
|
$this->repositoryManager = $this->createMock(RepositoryManager::class); |
90
|
|
|
$this->installationManager = $this->createMock(InstallationManager::class); |
91
|
|
|
$this->localRepository = $this->createMock(RepositoryInterface::class); |
92
|
|
|
|
93
|
|
|
$this->event->expects(self::any())->method('getComposer')->willReturn($this->composer); |
94
|
|
|
$this->event->expects(self::any())->method('getIO')->willReturn($this->io); |
95
|
|
|
$this->composer->expects(self::any())->method('getConfig')->willReturn($this->config); |
96
|
|
|
$this |
97
|
|
|
->composer |
98
|
|
|
->expects(self::any()) |
99
|
|
|
->method('getRepositoryManager') |
100
|
|
|
->willReturn($this->repositoryManager); |
101
|
|
|
$this |
102
|
|
|
->composer |
103
|
|
|
->expects(self::any()) |
104
|
|
|
->method('getInstallationManager') |
105
|
|
|
->willReturn($this->installationManager); |
106
|
|
|
$this |
107
|
|
|
->repositoryManager |
108
|
|
|
->expects(self::any()) |
109
|
|
|
->method('getLocalRepository') |
110
|
|
|
->willReturn($this->localRepository); |
111
|
|
|
$this |
112
|
|
|
->installationManager |
113
|
|
|
->expects(self::any()) |
114
|
|
|
->method('getInstallPath') |
115
|
|
|
->willReturnCallback(function (PackageInterface $package) : string { |
116
|
|
|
return array_search($package, $this->installedPackages, true); |
117
|
|
|
}); |
118
|
|
|
$this |
119
|
|
|
->localRepository |
120
|
|
|
->expects(self::any()) |
121
|
|
|
->method('getPackages') |
122
|
|
|
->willReturnCallback(function () { |
123
|
|
|
return array_values($this->installedPackages); |
124
|
|
|
}); |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
protected function tearDown() : void |
128
|
|
|
{ |
129
|
|
|
putenv(sprintf('GNUPGHOME=%s', $this->originalGpgHome)); |
130
|
|
|
putenv(sprintf('LANGUAGE=%s', $this->originalLanguage)); |
131
|
|
|
|
132
|
|
|
parent::tearDown(); |
133
|
|
|
} |
134
|
|
|
|
135
|
|
|
public function testWillDisallowInstallationOnNonSourceInstall() : void |
136
|
|
|
{ |
137
|
|
|
$this |
138
|
|
|
->config |
139
|
|
|
->expects(self::any()) |
140
|
|
|
->method('get') |
141
|
|
|
->with('preferred-install') |
142
|
|
|
->willReturn('foo'); |
143
|
|
|
|
144
|
|
|
$this->expectException(PreferredInstallIsNotSource::class); |
145
|
|
|
|
146
|
|
|
Verify::verify($this->event); |
147
|
|
|
} |
148
|
|
|
|
149
|
|
|
public function testWillRetrieveSubscribedEvents() : void |
150
|
|
|
{ |
151
|
|
|
$events = Verify::getSubscribedEvents(); |
152
|
|
|
|
153
|
|
|
self::assertNotEmpty($events); |
154
|
|
|
|
155
|
|
|
$availableEvents = (new \ReflectionClass(ScriptEvents::class))->getConstants(); |
156
|
|
|
|
157
|
|
|
foreach ($events as $eventName => $callback) { |
158
|
|
|
self::assertContains($eventName, $availableEvents); |
159
|
|
|
self::assertInternalType('string', $callback); |
160
|
|
|
self::assertInternalType('callable', [Verify::class, $callback]); |
161
|
|
|
} |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
public function testWillAcceptSignedAndTrustedPackages() : void |
165
|
|
|
{ |
166
|
|
|
$gpgHomeDirectory = $this->makeGpgHomeDirectory(); |
167
|
|
|
|
168
|
|
|
$vendorName = 'Mr. Magoo'; |
169
|
|
|
$vendorEmail = '[email protected]'; |
170
|
|
|
$vendorKey = $this->makeKey($gpgHomeDirectory, $vendorEmail, $vendorName); |
171
|
|
|
$vendorDir = $this->makeVendorDirectory(); |
172
|
|
|
$vendor1 = $this->makeDependencyGitRepository($vendorDir, 'vendor1/package1', $vendorEmail, $vendorName); |
173
|
|
|
|
174
|
|
|
$this->signDependency($vendor1, $gpgHomeDirectory, $vendorKey); |
175
|
|
|
|
176
|
|
|
$this->configureCorrectComposerSetup(); |
177
|
|
|
|
178
|
|
|
putenv('GNUPGHOME=' . $gpgHomeDirectory); |
179
|
|
|
|
180
|
|
|
$this->assertWillSucceedPackageVerification(); |
181
|
|
|
} |
182
|
|
|
|
183
|
|
View Code Duplication |
public function testWillRejectPackageSignedWithImportedButUnTrustedKey() : void |
|
|
|
|
184
|
|
|
{ |
185
|
|
|
$personalGpgDirectory = $this->makeGpgHomeDirectory(); |
186
|
|
|
$foreignGpgDirectory = $this->makeGpgHomeDirectory(); |
187
|
|
|
|
188
|
|
|
$this->makeKey($personalGpgDirectory, '[email protected]', 'Just Me'); |
189
|
|
|
|
190
|
|
|
$vendorName = 'Mr. Magoo'; |
191
|
|
|
$vendorEmail = '[email protected]'; |
192
|
|
|
$vendorKey = $this->makeKey($foreignGpgDirectory, $vendorEmail, $vendorName); |
193
|
|
|
$vendorDir = $this->makeVendorDirectory(); |
194
|
|
|
$vendor1 = $this->makeDependencyGitRepository($vendorDir, 'vendor1/package1', $vendorEmail, $vendorName); |
195
|
|
|
|
196
|
|
|
$this->signDependency($vendor1, $foreignGpgDirectory, $vendorKey); |
197
|
|
|
|
198
|
|
|
$this->importForeignKeys($personalGpgDirectory, $foreignGpgDirectory, $vendorKey, false); |
199
|
|
|
|
200
|
|
|
$this->configureCorrectComposerSetup(); |
201
|
|
|
|
202
|
|
|
putenv('GNUPGHOME=' . $personalGpgDirectory); |
203
|
|
|
|
204
|
|
|
$this->assertWillFailPackageVerification(); |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
public function testWillRejectPackageSignedWithImportedButUnTrustedKeyWithDifferentLocaleSettings() : void |
208
|
|
|
{ |
209
|
|
|
$personalGpgDirectory = $this->makeGpgHomeDirectory(); |
210
|
|
|
$foreignGpgDirectory = $this->makeGpgHomeDirectory(); |
211
|
|
|
|
212
|
|
|
$this->makeKey($personalGpgDirectory, '[email protected]', 'Just Me'); |
213
|
|
|
|
214
|
|
|
$vendorName = 'Mr. Magoo'; |
215
|
|
|
$vendorEmail = '[email protected]'; |
216
|
|
|
|
217
|
|
|
$vendorKey = $this->makeKey($foreignGpgDirectory, $vendorEmail, $vendorName); |
218
|
|
|
$vendorDir = $this->makeVendorDirectory(); |
219
|
|
|
$vendor1 = $this->makeDependencyGitRepository($vendorDir, 'vendor1/package1', $vendorEmail, $vendorName); |
220
|
|
|
|
221
|
|
|
$this->signDependency($vendor1, $foreignGpgDirectory, $vendorKey); |
222
|
|
|
|
223
|
|
|
$this->importForeignKeys($personalGpgDirectory, $foreignGpgDirectory, $vendorKey, false); |
224
|
|
|
|
225
|
|
|
$this->configureCorrectComposerSetup(); |
226
|
|
|
|
227
|
|
|
putenv('GNUPGHOME=' . $personalGpgDirectory); |
228
|
|
|
putenv('LANGUAGE=de_DE'); |
229
|
|
|
|
230
|
|
|
try { |
231
|
|
|
Verify::verify($this->event); |
232
|
|
|
} catch (PackagesTrustCheckFailed $failure) { |
233
|
|
|
self::assertSame('de_DE', getenv('LANGUAGE')); |
234
|
|
|
|
235
|
|
|
return; |
236
|
|
|
} |
237
|
|
|
|
238
|
|
|
self::fail('Exception was not thrown'); |
239
|
|
|
} |
240
|
|
|
|
241
|
|
View Code Duplication |
public function testWillAcceptPackageSignedWithImportedAndTrustedKey() : void |
|
|
|
|
242
|
|
|
{ |
243
|
|
|
$personalGpgDirectory = $this->makeGpgHomeDirectory(); |
244
|
|
|
$foreignGpgDirectory = $this->makeGpgHomeDirectory(); |
245
|
|
|
|
246
|
|
|
$this->makeKey($personalGpgDirectory, '[email protected]', 'Just Me'); |
247
|
|
|
|
248
|
|
|
$vendorName = 'Mr. Magoo'; |
249
|
|
|
$vendorEmail = '[email protected]'; |
250
|
|
|
$vendorKey = $this->makeKey($foreignGpgDirectory, $vendorEmail, $vendorName); |
251
|
|
|
$vendorDir = $this->makeVendorDirectory(); |
252
|
|
|
$vendor1 = $this->makeDependencyGitRepository($vendorDir, 'vendor1/package1', $vendorEmail, $vendorName); |
253
|
|
|
|
254
|
|
|
$this->signDependency($vendor1, $foreignGpgDirectory, $vendorKey); |
255
|
|
|
|
256
|
|
|
$this->importForeignKeys($personalGpgDirectory, $foreignGpgDirectory, $vendorKey, true); |
257
|
|
|
|
258
|
|
|
$this->configureCorrectComposerSetup(); |
259
|
|
|
|
260
|
|
|
putenv('GNUPGHOME=' . $personalGpgDirectory); |
261
|
|
|
|
262
|
|
|
$this->assertWillSucceedPackageVerification(); |
263
|
|
|
} |
264
|
|
|
|
265
|
|
View Code Duplication |
public function testWillRejectPackageTaggedAndSignedWithImportedButUnTrustedKey() : void |
|
|
|
|
266
|
|
|
{ |
267
|
|
|
$personalGpgDirectory = $this->makeGpgHomeDirectory(); |
268
|
|
|
$foreignGpgDirectory = $this->makeGpgHomeDirectory(); |
269
|
|
|
|
270
|
|
|
$this->makeKey($personalGpgDirectory, '[email protected]', 'Just Me'); |
271
|
|
|
|
272
|
|
|
$vendorName = 'Mr. Magoo'; |
273
|
|
|
$vendorEmail = '[email protected]'; |
274
|
|
|
$vendorKey = $this->makeKey($foreignGpgDirectory, $vendorEmail, $vendorName); |
275
|
|
|
$vendorDir = $this->makeVendorDirectory(); |
276
|
|
|
$vendor1 = $this->makeDependencyGitRepository($vendorDir, 'vendor1/package1', $vendorEmail, $vendorName); |
277
|
|
|
|
278
|
|
|
$this->createDependencySignedTag($vendor1, $foreignGpgDirectory, $vendorKey); |
279
|
|
|
|
280
|
|
|
$this->importForeignKeys($personalGpgDirectory, $foreignGpgDirectory, $vendorKey, false); |
281
|
|
|
|
282
|
|
|
$this->configureCorrectComposerSetup(); |
283
|
|
|
|
284
|
|
|
putenv('GNUPGHOME=' . $personalGpgDirectory); |
285
|
|
|
|
286
|
|
|
$this->assertWillFailPackageVerification(); |
287
|
|
|
} |
288
|
|
|
|
289
|
|
View Code Duplication |
public function testWillAcceptPackageTaggedAndSignedWithImportedAndTrustedKey() : void |
|
|
|
|
290
|
|
|
{ |
291
|
|
|
$personalGpgDirectory = $this->makeGpgHomeDirectory(); |
292
|
|
|
$foreignGpgDirectory = $this->makeGpgHomeDirectory(); |
293
|
|
|
|
294
|
|
|
$this->makeKey($personalGpgDirectory, '[email protected]', 'Just Me'); |
295
|
|
|
|
296
|
|
|
$vendorName = 'Mr. Magoo'; |
297
|
|
|
$vendorEmail = '[email protected]'; |
298
|
|
|
$vendorKey = $this->makeKey($foreignGpgDirectory, $vendorEmail, $vendorName); |
299
|
|
|
$vendorDir = $this->makeVendorDirectory(); |
300
|
|
|
$vendor1 = $this->makeDependencyGitRepository($vendorDir, 'vendor1/package1', $vendorEmail, $vendorName); |
301
|
|
|
|
302
|
|
|
$this->createDependencySignedTag($vendor1, $foreignGpgDirectory, $vendorKey); |
303
|
|
|
|
304
|
|
|
$this->importForeignKeys($personalGpgDirectory, $foreignGpgDirectory, $vendorKey, true); |
305
|
|
|
|
306
|
|
|
$this->configureCorrectComposerSetup(); |
307
|
|
|
|
308
|
|
|
putenv('GNUPGHOME=' . $personalGpgDirectory); |
309
|
|
|
|
310
|
|
|
$this->assertWillSucceedPackageVerification(); |
311
|
|
|
} |
312
|
|
|
|
313
|
|
|
public function testWillAcceptSignedAndTrustedTaggedPackages() : void |
314
|
|
|
{ |
315
|
|
|
$gpgHomeDirectory = $this->makeGpgHomeDirectory(); |
316
|
|
|
|
317
|
|
|
$vendorName = 'Mr. Magoo'; |
318
|
|
|
$vendorEmail = '[email protected]'; |
319
|
|
|
$vendorKey = $this->makeKey($gpgHomeDirectory, $vendorEmail, $vendorName); |
320
|
|
|
$vendorDir = $this->makeVendorDirectory(); |
321
|
|
|
$vendor1 = $this->makeDependencyGitRepository($vendorDir, 'vendor1/package1', $vendorEmail, $vendorName); |
322
|
|
|
|
323
|
|
|
$this->createDependencySignedTag($vendor1, $gpgHomeDirectory, $vendorKey); |
324
|
|
|
|
325
|
|
|
$this->configureCorrectComposerSetup(); |
326
|
|
|
|
327
|
|
|
putenv('GNUPGHOME=' . $gpgHomeDirectory); |
328
|
|
|
|
329
|
|
|
$this->assertWillSucceedPackageVerification(); |
330
|
|
|
} |
331
|
|
|
|
332
|
|
|
public function testWillRejectUnSignedCommits() : void |
333
|
|
|
{ |
334
|
|
|
$vendorName = 'Mr. Magoo'; |
335
|
|
|
$vendorEmail = '[email protected]'; |
336
|
|
|
$vendorDir = $this->makeVendorDirectory(); |
337
|
|
|
$vendor1 = $this->makeDependencyGitRepository($vendorDir, 'vendor1/package1', $vendorEmail, $vendorName); |
338
|
|
|
|
339
|
|
|
(new Process('git commit --allow-empty -m "unsigned commit"', $vendor1)) |
340
|
|
|
->setTimeout(30) |
341
|
|
|
->mustRun(); |
342
|
|
|
|
343
|
|
|
$this->configureCorrectComposerSetup(); |
344
|
|
|
|
345
|
|
|
putenv('GNUPGHOME=' . $this->makeGpgHomeDirectory()); |
346
|
|
|
|
347
|
|
|
$this->assertWillFailPackageVerification(); |
348
|
|
|
} |
349
|
|
|
|
350
|
|
|
public function testWillRejectUnSignedTags() : void |
351
|
|
|
{ |
352
|
|
|
$vendorName = 'Mr. Magoo'; |
353
|
|
|
$vendorEmail = '[email protected]'; |
354
|
|
|
$vendorDir = $this->makeVendorDirectory(); |
355
|
|
|
$vendor1 = $this->makeDependencyGitRepository($vendorDir, 'vendor1/package1', $vendorEmail, $vendorName); |
356
|
|
|
|
357
|
|
|
(new Process('git commit --allow-empty -m "unsigned commit"', $vendor1)) |
358
|
|
|
->setTimeout(30) |
359
|
|
|
->mustRun(); |
360
|
|
|
|
361
|
|
|
(new Process('git tag unsigned-tag -m "unsigned tag"', $vendor1)) |
362
|
|
|
->setTimeout(30) |
363
|
|
|
->mustRun(); |
364
|
|
|
|
365
|
|
|
$this->configureCorrectComposerSetup(); |
366
|
|
|
|
367
|
|
|
putenv('GNUPGHOME=' . $this->makeGpgHomeDirectory()); |
368
|
|
|
|
369
|
|
|
$this->assertWillFailPackageVerification(); |
370
|
|
|
} |
371
|
|
|
|
372
|
|
View Code Duplication |
public function testWillRejectSignedTagsFromUnknownKey() : void |
|
|
|
|
373
|
|
|
{ |
374
|
|
|
$personalGpgDirectory = $this->makeGpgHomeDirectory(); |
375
|
|
|
$foreignGpgDirectory = $this->makeGpgHomeDirectory(); |
376
|
|
|
$vendorName = 'Mr. Magoo'; |
377
|
|
|
$vendorEmail = '[email protected]'; |
378
|
|
|
$vendorKey = $this->makeKey($foreignGpgDirectory, $vendorEmail, $vendorName); |
379
|
|
|
$vendorDir = $this->makeVendorDirectory(); |
380
|
|
|
$vendor1 = $this->makeDependencyGitRepository($vendorDir, 'vendor1/package1', $vendorEmail, $vendorName); |
381
|
|
|
|
382
|
|
|
$this->createDependencySignedTag($vendor1, $foreignGpgDirectory, $vendorKey); |
383
|
|
|
|
384
|
|
|
$this->configureCorrectComposerSetup(); |
385
|
|
|
|
386
|
|
|
putenv('GNUPGHOME=' . $personalGpgDirectory); |
387
|
|
|
|
388
|
|
|
$this->assertWillFailPackageVerification(); |
389
|
|
|
} |
390
|
|
|
|
391
|
|
View Code Duplication |
public function testWillRejectSignedTagsFromNonHeadCommit() : void |
|
|
|
|
392
|
|
|
{ |
393
|
|
|
$gpgHome = $this->makeGpgHomeDirectory(); |
394
|
|
|
$vendorName = 'Mr. Magoo'; |
395
|
|
|
$vendorEmail = '[email protected]'; |
396
|
|
|
$vendorKey = $this->makeKey($gpgHome, $vendorEmail, $vendorName); |
397
|
|
|
$vendorDir = $this->makeVendorDirectory(); |
398
|
|
|
$vendor1 = $this->makeDependencyGitRepository($vendorDir, 'vendor1/package1', $vendorEmail, $vendorName); |
399
|
|
|
|
400
|
|
|
$this->createDependencySignedTag($vendor1, $gpgHome, $vendorKey); |
401
|
|
|
|
402
|
|
|
(new Process('git commit --allow-empty -m "unsigned commit"', $vendor1)) |
403
|
|
|
->setTimeout(30) |
404
|
|
|
->mustRun(); |
405
|
|
|
|
406
|
|
|
$this->configureCorrectComposerSetup(); |
407
|
|
|
|
408
|
|
|
putenv('GNUPGHOME=' . $gpgHome); |
409
|
|
|
|
410
|
|
|
$this->assertWillFailPackageVerification(); |
411
|
|
|
} |
412
|
|
|
|
413
|
|
View Code Duplication |
public function testWillOnlyConsiderTheHeadCommitForValidation() : void |
|
|
|
|
414
|
|
|
{ |
415
|
|
|
$gpgHome = $this->makeGpgHomeDirectory(); |
416
|
|
|
$vendorName = 'Mr. Magoo'; |
417
|
|
|
$vendorEmail = '[email protected]'; |
418
|
|
|
$vendorKey = $this->makeKey($gpgHome, $vendorEmail, $vendorName); |
419
|
|
|
$vendorDir = $this->makeVendorDirectory(); |
420
|
|
|
$vendor1 = $this->makeDependencyGitRepository($vendorDir, 'vendor1/package1', $vendorEmail, $vendorName); |
421
|
|
|
|
422
|
|
|
$this->signDependency($vendor1, $gpgHome, $vendorKey); |
423
|
|
|
|
424
|
|
|
(new Process('git commit --allow-empty -m "unsigned commit"', $vendor1)) |
425
|
|
|
->setTimeout(30) |
426
|
|
|
->mustRun(); |
427
|
|
|
|
428
|
|
|
$this->configureCorrectComposerSetup(); |
429
|
|
|
|
430
|
|
|
putenv('GNUPGHOME=' . $gpgHome); |
431
|
|
|
|
432
|
|
|
$this->assertWillFailPackageVerification(); |
433
|
|
|
} |
434
|
|
|
|
435
|
|
View Code Duplication |
public function testWillRejectSignedCommitsFromUnknownKeys() : void |
|
|
|
|
436
|
|
|
{ |
437
|
|
|
$personalGpgDirectory = $this->makeGpgHomeDirectory(); |
438
|
|
|
$foreignGpgDirectory = $this->makeGpgHomeDirectory(); |
439
|
|
|
|
440
|
|
|
$vendorName = 'Mr. Magoo'; |
441
|
|
|
$vendorEmail = '[email protected]'; |
442
|
|
|
$vendorKey = $this->makeKey($foreignGpgDirectory, $vendorEmail, $vendorName); |
443
|
|
|
$vendorDir = $this->makeVendorDirectory(); |
444
|
|
|
$vendor1 = $this->makeDependencyGitRepository($vendorDir, 'vendor1/package1', $vendorEmail, $vendorName); |
445
|
|
|
|
446
|
|
|
$this->signDependency($vendor1, $foreignGpgDirectory, $vendorKey); |
447
|
|
|
|
448
|
|
|
$this->configureCorrectComposerSetup(); |
449
|
|
|
|
450
|
|
|
putenv('GNUPGHOME=' . $personalGpgDirectory); |
451
|
|
|
|
452
|
|
|
$this->assertWillFailPackageVerification(); |
453
|
|
|
} |
454
|
|
|
|
455
|
|
View Code Duplication |
private function makeVendorDirectory() : string |
|
|
|
|
456
|
|
|
{ |
457
|
|
|
$vendorDirectory = sys_get_temp_dir() . '/' . uniqid('vendor', true); |
458
|
|
|
|
459
|
|
|
self::assertTrue(mkdir($vendorDirectory)); |
460
|
|
|
|
461
|
|
|
return $vendorDirectory; |
462
|
|
|
} |
463
|
|
|
|
464
|
|
|
private function signDependency( |
465
|
|
|
string $dependencyDirectory, |
466
|
|
|
string $gpgHomeDirectory, |
467
|
|
|
string $signingKey |
468
|
|
|
) : void { |
469
|
|
|
(new Process(sprintf('git config --local --add user.signingkey %s', escapeshellarg($signingKey)), $dependencyDirectory)) |
470
|
|
|
->setTimeout(30) |
471
|
|
|
->mustRun(); |
472
|
|
|
|
473
|
|
|
(new Process( |
474
|
|
|
'git commit --allow-empty -m "signed commit" -S', |
475
|
|
|
$dependencyDirectory, |
476
|
|
|
['GNUPGHOME' => $gpgHomeDirectory, 'GIT_TRACE' => '2'] |
477
|
|
|
)) |
478
|
|
|
->setTimeout(30) |
479
|
|
|
->mustRun(); |
480
|
|
|
} |
481
|
|
|
|
482
|
|
|
private function createDependencySignedTag( |
483
|
|
|
string $dependencyDirectory, |
484
|
|
|
string $gpgHomeDirectory, |
485
|
|
|
string $signingKey |
486
|
|
|
) : void { |
487
|
|
|
(new Process(sprintf('git config --local --add user.signingkey %s', escapeshellarg($signingKey)), $dependencyDirectory)) |
488
|
|
|
->setTimeout(30) |
489
|
|
|
->mustRun(); |
490
|
|
|
|
491
|
|
|
(new Process('git commit --allow-empty -m "unsigned commit"', $dependencyDirectory)) |
492
|
|
|
->setTimeout(30) |
493
|
|
|
->mustRun(); |
494
|
|
|
|
495
|
|
|
(new Process( |
496
|
|
|
'git tag -s "tag-name" -m "signed tag"', |
497
|
|
|
$dependencyDirectory, |
498
|
|
|
['GNUPGHOME' => $gpgHomeDirectory, 'GIT_TRACE' => '2'] |
499
|
|
|
)) |
500
|
|
|
->setTimeout(30) |
501
|
|
|
->mustRun(); |
502
|
|
|
} |
503
|
|
|
|
504
|
|
|
private function makeDependencyGitRepository( |
505
|
|
|
string $vendorDirectory, |
506
|
|
|
string $packageName, |
507
|
|
|
string $email, |
508
|
|
|
string $name |
509
|
|
|
) : string { |
510
|
|
|
$dependencyRepository = $vendorDirectory . '/' . $packageName; |
511
|
|
|
|
512
|
|
|
self::assertTrue(mkdir($dependencyRepository, 0777, true)); |
513
|
|
|
|
514
|
|
|
(new Process('git init', $dependencyRepository)) |
515
|
|
|
->setTimeout(30) |
516
|
|
|
->mustRun(); |
517
|
|
|
|
518
|
|
|
(new Process(sprintf('git config --local --add user.email %s', escapeshellarg($email)), $dependencyRepository)) |
519
|
|
|
->setTimeout(30) |
520
|
|
|
->mustRun(); |
521
|
|
|
|
522
|
|
|
(new Process(sprintf('git config --local --add user.name %s', escapeshellarg($name)), $dependencyRepository)) |
523
|
|
|
->setTimeout(30) |
524
|
|
|
->mustRun(); |
525
|
|
|
|
526
|
|
|
/* @var $package PackageInterface|\PHPUnit_Framework_MockObject_MockObject */ |
527
|
|
|
$package = $this->createMock(PackageInterface::class); |
528
|
|
|
|
529
|
|
|
$package->expects(self::any())->method('getName')->willReturn($packageName); |
530
|
|
|
|
531
|
|
|
$this->installedPackages[$dependencyRepository] = $package; |
532
|
|
|
|
533
|
|
|
return $dependencyRepository; |
534
|
|
|
} |
535
|
|
|
|
536
|
|
View Code Duplication |
private function makeGpgHomeDirectory() : string |
|
|
|
|
537
|
|
|
{ |
538
|
|
|
$homeDirectory = sys_get_temp_dir() . '/' . uniqid('gpg-verification-test', true); |
539
|
|
|
|
540
|
|
|
self::assertTrue(mkdir($homeDirectory, 0700)); |
541
|
|
|
|
542
|
|
|
return $homeDirectory; |
543
|
|
|
} |
544
|
|
|
|
545
|
|
|
private function makeKey(string $gpgHomeDirectory, string $emailAddress, string $name) : string |
546
|
|
|
{ |
547
|
|
|
$input = <<<'KEY' |
548
|
|
|
%echo Generating a standard key |
549
|
|
|
Key-Type: RSA |
550
|
|
|
Key-Length: 128 |
551
|
|
|
Name-Real: <<<NAME>>> |
552
|
|
|
Name-Email: <<<EMAIL>>> |
553
|
|
|
Expire-Date: 0 |
554
|
|
|
%no-protection |
555
|
|
|
%no-ask-passphrase |
556
|
|
|
%commit |
557
|
|
|
%echo done |
558
|
|
|
|
559
|
|
|
KEY; |
560
|
|
|
self::assertGreaterThan( |
561
|
|
|
0, |
562
|
|
|
file_put_contents( |
563
|
|
|
$gpgHomeDirectory . '/key-info.txt', |
564
|
|
|
str_replace(['<<<NAME>>>', '<<<EMAIL>>>'], [$name, $emailAddress], $input) |
565
|
|
|
) |
566
|
|
|
); |
567
|
|
|
|
568
|
|
|
$keyOutput = (new Process( |
569
|
|
|
'gpg --batch --gen-key -a key-info.txt', |
570
|
|
|
$gpgHomeDirectory, |
571
|
|
|
['GNUPGHOME' => $gpgHomeDirectory] |
572
|
|
|
)) |
573
|
|
|
->setTimeout(30) |
574
|
|
|
->mustRun() |
575
|
|
|
->getErrorOutput(); |
576
|
|
|
|
577
|
|
|
self::assertRegExp('/key [0-9A-F]+ marked as ultimately trusted/i', $keyOutput); |
578
|
|
|
|
579
|
|
|
preg_match('/key ([0-9A-F]+) marked as ultimately trusted/i', $keyOutput, $matches); |
580
|
|
|
|
581
|
|
|
return $matches[1]; |
582
|
|
|
} |
583
|
|
|
|
584
|
|
|
private function configureCorrectComposerSetup() : void |
585
|
|
|
{ |
586
|
|
|
$this |
587
|
|
|
->config |
588
|
|
|
->expects(self::any()) |
589
|
|
|
->method('get') |
590
|
|
|
->with('preferred-install') |
591
|
|
|
->willReturn('source'); |
592
|
|
|
} |
593
|
|
|
|
594
|
|
View Code Duplication |
private function assertWillSucceedPackageVerification() : void |
|
|
|
|
595
|
|
|
{ |
596
|
|
|
$this |
597
|
|
|
->io |
598
|
|
|
->expects(self::exactly(2)) |
599
|
|
|
->method('write') |
600
|
|
|
->with(self::logicalOr( |
601
|
|
|
'<info>roave/composer-gpg-verify:</info> Analysing downloaded packages...', |
602
|
|
|
'<info>roave/composer-gpg-verify:</info> All installed packages passed GPG validation!' |
603
|
|
|
)); |
604
|
|
|
|
605
|
|
|
Verify::verify($this->event); |
606
|
|
|
} |
607
|
|
|
|
608
|
|
View Code Duplication |
private function assertWillFailPackageVerification() : void |
|
|
|
|
609
|
|
|
{ |
610
|
|
|
$this |
611
|
|
|
->io |
612
|
|
|
->expects(self::once()) |
613
|
|
|
->method('write') |
614
|
|
|
->with(self::logicalOr('<info>roave/composer-gpg-verify:</info> Analysing downloaded packages...')); |
615
|
|
|
|
616
|
|
|
$this->expectException(PackagesTrustCheckFailed::class); |
617
|
|
|
|
618
|
|
|
Verify::verify($this->event); |
619
|
|
|
} |
620
|
|
|
|
621
|
|
|
private function importForeignKeys( |
622
|
|
|
string $localGpgHome, |
623
|
|
|
string $foreignGpgHome, |
624
|
|
|
string $foreignKey, |
625
|
|
|
bool $sign |
626
|
|
|
) : void { |
627
|
|
|
$exportPath = sys_get_temp_dir() . '/' . uniqid('exportedKey', true); |
628
|
|
|
|
629
|
|
|
(new Process( |
630
|
|
|
sprintf('gpg --export --armor > %s', escapeshellarg($exportPath)), |
631
|
|
|
null, |
632
|
|
|
['GNUPGHOME' => $foreignGpgHome] |
633
|
|
|
)) |
634
|
|
|
->setTimeout(30) |
635
|
|
|
->mustRun(); |
636
|
|
|
|
637
|
|
|
self::assertFileExists($exportPath); |
638
|
|
|
|
639
|
|
|
(new Process( |
640
|
|
|
sprintf('gpg --import < %s', escapeshellarg($exportPath)), |
641
|
|
|
null, |
642
|
|
|
['GNUPGHOME' => $localGpgHome] |
643
|
|
|
)) |
644
|
|
|
->setTimeout(30) |
645
|
|
|
->mustRun(); |
646
|
|
|
|
647
|
|
|
if (! $sign) { |
648
|
|
|
return; |
649
|
|
|
} |
650
|
|
|
|
651
|
|
|
(new Process( |
652
|
|
|
sprintf('gpg --batch --yes --sign-key %s', escapeshellarg($foreignKey)), |
653
|
|
|
null, |
654
|
|
|
['GNUPGHOME' => $localGpgHome] |
655
|
|
|
)) |
656
|
|
|
->setTimeout(30) |
657
|
|
|
->mustRun(); |
658
|
|
|
} |
659
|
|
|
} |
660
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.