Skip to content

Commit 2d37f12

Browse files
committed
ACP2E-3854: Bundled/Merged JS not part of SRI Hashes
1 parent f0e6870 commit 2d37f12

File tree

2 files changed

+224
-0
lines changed

2 files changed

+224
-0
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Csp\Test\Unit\Plugin;
9+
10+
use Magento\Csp\Model\SubresourceIntegrity;
11+
use Magento\Csp\Model\SubresourceIntegrity\HashGenerator;
12+
use Magento\Csp\Model\SubresourceIntegrityCollector;
13+
use Magento\Csp\Model\SubresourceIntegrityFactory;
14+
use Magento\Csp\Plugin\GenerateBundleAssetIntegrity;
15+
use Magento\Deploy\Service\Bundle;
16+
use Magento\Framework\Exception\FileSystemException;
17+
use Magento\Framework\Filesystem;
18+
use Magento\Framework\Filesystem\Directory\ReadInterface;
19+
use Magento\Framework\Filesystem\Io\File;
20+
use PHPUnit\Framework\MockObject\Exception;
21+
use PHPUnit\Framework\MockObject\MockObject;
22+
use PHPUnit\Framework\TestCase;
23+
24+
class GenerateBundleAssetIntegrityTest extends TestCase
25+
{
26+
/**
27+
* @var HashGenerator|MockObject
28+
*/
29+
private HashGenerator $hashGenerator;
30+
31+
/**
32+
* @var SubresourceIntegrityFactory|MockObject
33+
*/
34+
private SubresourceIntegrityFactory $integrityFactory;
35+
36+
/**
37+
* @var SubresourceIntegrityCollector|MockObject
38+
*/
39+
private SubresourceIntegrityCollector $integrityCollector;
40+
41+
/**
42+
* @var Filesystem|MockObject
43+
*/
44+
private Filesystem $filesystem;
45+
46+
/**
47+
* @var File|MockObject
48+
*/
49+
private File $fileIo;
50+
51+
/**
52+
* Initialize Dependencies
53+
*
54+
* @return void
55+
* @throws Exception
56+
*/
57+
protected function setUp(): void
58+
{
59+
$this->hashGenerator = $this->createMock(HashGenerator::class);
60+
$this->integrityFactory = $this->createMock(SubresourceIntegrityFactory::class);
61+
$this->integrityCollector = $this->createMock(SubresourceIntegrityCollector::class);
62+
$this->filesystem = $this->createMock(Filesystem::class);
63+
$this->fileIo = $this->createMock(File::class);
64+
}
65+
66+
/**
67+
* @return void
68+
* @throws Exception
69+
* @throws FileSystemException
70+
*/
71+
public function testAfterDeploy(): void
72+
{
73+
$subject = $this->createMock(Bundle::class);
74+
$result = null;
75+
$area = 'frontend';
76+
$theme = 'Magento/blank';
77+
$locale = 'en_US';
78+
$file = '/path/to/file.js';
79+
$hash = 'asdfghjkl';
80+
$fileContent = 'content';
81+
82+
$pubStaticDir = $this->createMock(ReadInterface::class);
83+
$pubStaticDir->expects($this->once())->method('search')->with(
84+
$area ."/" . $theme . "/" . $locale . "/" . Bundle::BUNDLE_JS_DIR . "/*.js"
85+
)->willReturn([$file]);
86+
$pubStaticDir->expects($this->once())->method('readFile')->willReturn($fileContent);
87+
$this->filesystem->expects($this->once())->method('getDirectoryRead')->willReturn($pubStaticDir);
88+
$integrity = $this->createMock(SubresourceIntegrity::class);
89+
$this->hashGenerator->expects($this->once())
90+
->method('generate')
91+
->with($fileContent)
92+
->willReturn($hash);
93+
$this->fileIo->expects($this->once())
94+
->method('getPathInfo')
95+
->with($file)
96+
->willReturn(['basename' => 'file.js']);
97+
$this->integrityFactory->expects($this->once())
98+
->method('create')
99+
->with([
100+
'data' => [
101+
'hash' => $hash,
102+
'path' => $area . '/' . $theme . '/' . $locale . '/' . Bundle::BUNDLE_JS_DIR . '/file.js'
103+
]
104+
])
105+
->willReturn($integrity);
106+
$this->integrityCollector->expects($this->once())->method('collect')->with($integrity);
107+
108+
$plugin = new GenerateBundleAssetIntegrity(
109+
$this->hashGenerator,
110+
$this->integrityFactory,
111+
$this->integrityCollector,
112+
$this->filesystem,
113+
$this->fileIo
114+
);
115+
$plugin->afterDeploy($subject, $result, $area, $theme, $locale);
116+
}
117+
}
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
<?php
2+
/**
3+
* Copyright 2025 Adobe
4+
* All Rights Reserved.
5+
*/
6+
declare(strict_types=1);
7+
8+
namespace Magento\Csp\Test\Unit\Plugin;
9+
10+
use Magento\Csp\Model\SubresourceIntegrity;
11+
use Magento\Csp\Model\SubresourceIntegrity\HashGenerator;
12+
use Magento\Csp\Model\SubresourceIntegrityFactory;
13+
use Magento\Csp\Model\SubresourceIntegrityRepository;
14+
use Magento\Csp\Model\SubresourceIntegrityRepositoryPool;
15+
use Magento\Framework\App\Area;
16+
use Magento\Framework\App\Filesystem\DirectoryList;
17+
use Magento\Framework\Filesystem;
18+
use Magento\Framework\Filesystem\Directory\WriteInterface;
19+
use Magento\Framework\View\Asset\File;
20+
use Magento\Framework\View\Asset\MergeStrategy\FileExists;
21+
use Magento\Csp\Plugin\GenerateMergedAssetIntegrity;
22+
use PHPUnit\Framework\MockObject\Exception;
23+
use PHPUnit\Framework\MockObject\MockObject;
24+
use PHPUnit\Framework\TestCase;
25+
26+
class GenerateMergedAssetIntegrityTest extends TestCase
27+
{
28+
/**
29+
* @var SubresourceIntegrityRepositoryPool|MockObject
30+
*/
31+
private SubresourceIntegrityRepositoryPool $sourceIntegrityRepository;
32+
33+
/**
34+
* @var HashGenerator|MockObject
35+
*/
36+
private HashGenerator $hashGenerator;
37+
38+
/**
39+
* @var SubresourceIntegrityFactory|MockObject
40+
*/
41+
private SubresourceIntegrityFactory $integrityFactory;
42+
43+
/**
44+
* @var Filesystem|MockObject
45+
*/
46+
private Filesystem $filesystem;
47+
48+
/**
49+
* @return void
50+
* @throws Exception
51+
*/
52+
protected function setUp(): void
53+
{
54+
$this->sourceIntegrityRepository = $this->createMock(SubresourceIntegrityRepositoryPool::class);
55+
$this->hashGenerator = $this->createMock(HashGenerator::class);
56+
$this->integrityFactory = $this->createMock(SubresourceIntegrityFactory::class);
57+
$this->filesystem = $this->createMock(Filesystem::class);
58+
}
59+
60+
/**
61+
* @return void
62+
* @throws Exception
63+
*/
64+
public function testAfterMerge(): void
65+
{
66+
$subject = $this->createMock(FileExists::class);
67+
$result = null;
68+
$assetsToMerge = [];
69+
$fileExtension = 'js';
70+
$filePath = 'path/to/file.js';
71+
$hash = '1234567890abcdef';
72+
$fileContent = 'some content';
73+
$resultAsset = $this->createMock(File::class);
74+
$resultAsset->expects($this->once())->method('getContentType')->willReturn($fileExtension);
75+
$resultAsset->expects($this->exactly(2))
76+
->method('getRelativeSourceFilePath')
77+
->willReturn($filePath);
78+
$pubStaticDir = $this->createMock(WriteInterface::class);
79+
$pubStaticDir->expects($this->once())->method('readFile')->with($filePath)->willReturn($fileContent);
80+
$this->filesystem->expects($this->once())
81+
->method('getDirectoryWrite')
82+
->with(DirectoryList::STATIC_VIEW)
83+
->willReturn($pubStaticDir);
84+
$this->hashGenerator->expects($this->once())->method('generate')->with($fileContent)->willReturn($hash);
85+
$integrity = $this->createMock(SubresourceIntegrity::class);
86+
$this->integrityFactory->expects($this->once())
87+
->method('create')->with([
88+
'data' => [
89+
'hash' => $hash,
90+
'path' => $filePath
91+
]
92+
])->willReturn($integrity);
93+
$repository = $this->createMock(SubresourceIntegrityRepository::class);
94+
$this->sourceIntegrityRepository->expects($this->once())->method('get')
95+
->with(Area::AREA_FRONTEND)
96+
->willReturn($repository);
97+
$repository->expects($this->once())->method('save')->with($integrity);
98+
99+
$plugin = new GenerateMergedAssetIntegrity(
100+
$this->sourceIntegrityRepository,
101+
$this->hashGenerator,
102+
$this->integrityFactory,
103+
$this->filesystem
104+
);
105+
$plugin->afterMerge($subject, $result, $assetsToMerge, $resultAsset);
106+
}
107+
}

0 commit comments

Comments
 (0)