diff --git a/app/code/Magento/Csp/Block/Sri/Hashes.php b/app/code/Magento/Csp/Block/Sri/Hashes.php
new file mode 100644
index 0000000000000..7b67ec4ca534f
--- /dev/null
+++ b/app/code/Magento/Csp/Block/Sri/Hashes.php
@@ -0,0 +1,94 @@
+integrityRepositoryPool = $integrityRepositoryPool ?: ObjectManager::getInstance()
+ ->get(SubresourceIntegrityRepositoryPool::class);
+
+ $this->serializer = $serializer ?: ObjectManager::getInstance()
+ ->get(SerializerInterface::class);
+ }
+
+ /**
+ * Retrieves integrity hashes in serialized format.
+ *
+ * @throws LocalizedException
+ *
+ * @return string
+ */
+ public function getSerialized(): string
+ {
+ $result = [];
+
+ $baseUrl = $this->_urlBuilder->getBaseUrl(
+ ["_type" => UrlInterface::URL_TYPE_STATIC]
+ );
+
+ $integrityRepository = $this->integrityRepositoryPool->get(
+ Package::BASE_AREA
+ );
+
+ foreach ($integrityRepository->getAll() as $integrity) {
+ $url = $baseUrl . $integrity->getPath();
+
+ $result[$url] = $integrity->getHash();
+ }
+
+ $integrityRepository = $this->integrityRepositoryPool->get(
+ $this->_appState->getAreaCode()
+ );
+
+ foreach ($integrityRepository->getAll() as $integrity) {
+ $url = $baseUrl . $integrity->getPath();
+
+ $result[$url] = $integrity->getHash();
+ }
+
+ return $this->serializer->serialize($result);
+ }
+}
diff --git a/app/code/Magento/Csp/Model/Deploy/Package/Processor/PostProcessor/Integrity.php b/app/code/Magento/Csp/Model/Deploy/Package/Processor/PostProcessor/Integrity.php
new file mode 100644
index 0000000000000..41e81752632fb
--- /dev/null
+++ b/app/code/Magento/Csp/Model/Deploy/Package/Processor/PostProcessor/Integrity.php
@@ -0,0 +1,89 @@
+filesystem = $filesystem;
+ $this->hashGenerator = $hashGenerator;
+ $this->integrityFactory = $integrityFactory;
+ $this->integrityCollector = $integrityCollector;
+ }
+
+ /**
+ * @inheritdoc
+ */
+ public function process(Package $package, array $options): bool
+ {
+ $staticDir = $this->filesystem->getDirectoryRead(
+ DirectoryList::ROOT
+ );
+
+ foreach ($package->getFiles() as $file) {
+ if ($file->getExtension() == "js") {
+ $integrity = $this->integrityFactory->create(
+ [
+ "data" => [
+ 'hash' => $this->hashGenerator->generate(
+ $staticDir->readFile($file->getSourcePath())
+ ),
+ 'path' => $file->getDeployedFilePath()
+ ]
+ ]
+ );
+
+ $this->integrityCollector->collect($integrity);
+ }
+ }
+
+ return true;
+ }
+}
diff --git a/app/code/Magento/Csp/Model/Deploy/Package/Processor/PostProcessor/Map.php b/app/code/Magento/Csp/Model/Deploy/Package/Processor/PostProcessor/Map.php
new file mode 100644
index 0000000000000..4e97517a165c5
--- /dev/null
+++ b/app/code/Magento/Csp/Model/Deploy/Package/Processor/PostProcessor/Map.php
@@ -0,0 +1,139 @@
+minification = $minification;
+ $this->integrityFactory = $integrityFactory;
+ $this->hashGenerator = $hashGenerator;
+ $this->driver = $driver;
+ $this->integrityCollector = $integrityCollector;
+ $this->filesystem = $filesystem;
+ parent::__construct($deployStaticFile, $formatter, $packageFileFactory, $minification);
+ }
+
+ /**
+ * @inheritdoc
+ *
+ * @throws FileSystemException
+ */
+ public function process(Package $package, array $options): bool
+ {
+ parent::process($package, $options);
+ $fileName = $this->minification->addMinifiedSign(RepositoryMap::REQUIRE_JS_MAP_NAME);
+ $path = $package->getPath();
+ $relativePath = $path . DIRECTORY_SEPARATOR . $fileName;
+
+ if ($this->fileExists($relativePath)) {
+ $dir = $this->filesystem->getDirectoryWrite(DirectoryList::STATIC_VIEW);
+ $absolutePath = $dir->getAbsolutePath($relativePath);
+ $fileContent = $this->driver->fileGetContents($absolutePath);
+
+ if ($fileContent) {
+ $integrity = $this->integrityFactory->create(
+ [
+ "data" => [
+ 'hash' => $this->hashGenerator->generate($fileContent),
+ 'path' => $relativePath
+ ]
+ ]
+ );
+ $this->integrityCollector->collect($integrity);
+ }
+ }
+ return true;
+ }
+
+ /**
+ * Check if file exist
+ *
+ * @param string $path
+ * @return bool
+ * @throws FileSystemException
+ */
+ private function fileExists(string $path): bool
+ {
+ $dir = $this->filesystem->getDirectoryWrite(DirectoryList::STATIC_VIEW);
+ return $dir->isExist($path);
+ }
+}
diff --git a/app/code/Magento/Csp/Model/SubresourceIntegrity.php b/app/code/Magento/Csp/Model/SubresourceIntegrity.php
new file mode 100644
index 0000000000000..0a2824c93027e
--- /dev/null
+++ b/app/code/Magento/Csp/Model/SubresourceIntegrity.php
@@ -0,0 +1,34 @@
+getData("path");
+ }
+
+ /**
+ * Gets an integrity hash.
+ *
+ * @return string|null
+ */
+ public function getHash(): ?string
+ {
+ return $this->getData("hash");
+ }
+}
diff --git a/app/code/Magento/Csp/Model/SubresourceIntegrity/HashGenerator.php b/app/code/Magento/Csp/Model/SubresourceIntegrity/HashGenerator.php
new file mode 100644
index 0000000000000..be78a1a0c66b8
--- /dev/null
+++ b/app/code/Magento/Csp/Model/SubresourceIntegrity/HashGenerator.php
@@ -0,0 +1,37 @@
+data = $data;
+ }
+
+ /**
+ * Collects given Integrity object.
+ *
+ * @param SubresourceIntegrity $integrity
+ *
+ * @return void
+ */
+ public function collect(SubresourceIntegrity $integrity): void
+ {
+ $this->data[] = $integrity;
+ }
+
+ /**
+ * Provides all collected Integrity objects.
+ *
+ * @return SubresourceIntegrity[]
+ */
+ public function release(): array
+ {
+ return $this->data;
+ }
+}
diff --git a/app/code/Magento/Csp/Model/SubresourceIntegrityRepository.php b/app/code/Magento/Csp/Model/SubresourceIntegrityRepository.php
new file mode 100644
index 0000000000000..f2ef550a8bda3
--- /dev/null
+++ b/app/code/Magento/Csp/Model/SubresourceIntegrityRepository.php
@@ -0,0 +1,207 @@
+cache = $cache;
+ $this->serializer = $serializer;
+ $this->integrityFactory = $integrityFactory;
+ $this->context = $context;
+ }
+
+ /**
+ * Gets an Integrity object by path.
+ *
+ * @param string $path
+ *
+ * @return SubresourceIntegrity|null
+ */
+ public function getByPath(string $path): ?SubresourceIntegrity
+ {
+ $data = $this->getData();
+
+ if (isset($data[$path])) {
+ return $this->integrityFactory->create(
+ [
+ "data" => [
+ "path" => $path,
+ "hash" => $data[$path]
+ ]
+ ]
+ );
+ }
+
+ return null;
+ }
+
+ /**
+ * Gets all available Integrity objects.
+ *
+ * @return SubresourceIntegrity[]
+ */
+ public function getAll(): array
+ {
+ $result = [];
+
+ foreach ($this->getData() as $path => $hash) {
+ $result[] = $this->integrityFactory->create(
+ [
+ "data" => [
+ "path" => $path,
+ "hash" => $hash
+ ]
+ ]
+ );
+ }
+
+ return $result;
+ }
+
+ /**
+ * Saves Integrity object.
+ *
+ * @param SubresourceIntegrity $integrity
+ *
+ * @return bool
+ */
+ public function save(SubresourceIntegrity $integrity): bool
+ {
+ $data = $this->getData();
+
+ $data[$integrity->getPath()] = $integrity->getHash();
+
+ $this->data = $data;
+
+ return $this->cache->save(
+ $this->serializer->serialize($this->data),
+ $this->getCacheKey(),
+ [self::CACHE_PREFIX]
+ );
+ }
+
+ /**
+ * Saves a bunch of Integrity objects.
+ *
+ * @param SubresourceIntegrity[] $bunch
+ *
+ * @return bool
+ */
+ public function saveBunch(array $bunch): bool
+ {
+ $data = $this->getData();
+
+ foreach ($bunch as $integrity) {
+ $data[$integrity->getPath()] = $integrity->getHash();
+ }
+
+ $this->data = $data;
+
+ return $this->cache->save(
+ $this->serializer->serialize($this->data),
+ $this->getCacheKey(),
+ [self::CACHE_PREFIX]
+ );
+ }
+
+ /**
+ * Deletes all Integrity objects.
+ *
+ * @return bool
+ */
+ public function deleteAll(): bool
+ {
+ $this->data = null;
+
+ return $this->cache->remove(
+ $this->getCacheKey()
+ );
+ }
+
+ /**
+ * Loads integrity data from a storage.
+ *
+ * @return array
+ */
+ private function getData(): array
+ {
+ if ($this->data === null) {
+ $cache = $this->cache->load($this->getCacheKey());
+
+ $this->data = $cache ? $this->serializer->unserialize($cache) : [];
+ }
+
+ return $this->data;
+ }
+
+ /**
+ * Gets a cache key based on current context.
+ *
+ * @return string
+ */
+ private function getCacheKey(): string
+ {
+ $cacheKey = self::CACHE_PREFIX;
+
+ if ($this->context) {
+ $cacheKey .= "_" . $this->context;
+ }
+
+ return $cacheKey;
+ }
+}
diff --git a/app/code/Magento/Csp/Model/SubresourceIntegrityRepositoryPool.php b/app/code/Magento/Csp/Model/SubresourceIntegrityRepositoryPool.php
new file mode 100644
index 0000000000000..5ad9c6c676de8
--- /dev/null
+++ b/app/code/Magento/Csp/Model/SubresourceIntegrityRepositoryPool.php
@@ -0,0 +1,53 @@
+integrityRepositoryFactory = $integrityRepositoryFactory;
+ }
+
+ /**
+ * Gets subresource integrity repository by given context.
+ *
+ * @param string $context
+ *
+ * @return SubresourceIntegrityRepository
+ */
+ public function get(string $context): SubresourceIntegrityRepository
+ {
+ if (!isset($this->repositories[$context])) {
+ $this->repositories[$context] = $this->integrityRepositoryFactory->create(
+ [
+ "context" => $context
+ ]
+ );
+ }
+
+ return $this->repositories[$context];
+ }
+}
diff --git a/app/code/Magento/Csp/Plugin/AddDefaultPropertiesToGroupPlugin.php b/app/code/Magento/Csp/Plugin/AddDefaultPropertiesToGroupPlugin.php
new file mode 100644
index 0000000000000..159e2180427a5
--- /dev/null
+++ b/app/code/Magento/Csp/Plugin/AddDefaultPropertiesToGroupPlugin.php
@@ -0,0 +1,81 @@
+state = $state;
+ $this->integrityRepositoryPool = $integrityRepositoryPool;
+ }
+
+ /**
+ * Before Plugin to add Properties to JS assets
+ *
+ * @param GroupedCollection $subject
+ * @param AssetInterface $asset
+ * @param array $properties
+ * @return array
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function beforeGetFilteredProperties(
+ GroupedCollection $subject,
+ AssetInterface $asset,
+ array $properties = []
+ ): array {
+ if ($asset instanceof LocalInterface) {
+ $integrityRepository = $this->integrityRepositoryPool->get(
+ Package::BASE_AREA
+ );
+
+ $integrity = $integrityRepository->getByPath($asset->getPath());
+
+ if (!$integrity) {
+ $integrityRepository = $this->integrityRepositoryPool->get(
+ $this->state->getAreaCode()
+ );
+
+ $integrity = $integrityRepository->getByPath($asset->getPath());
+ }
+
+ if ($integrity && $integrity->getHash()) {
+ $properties['attributes']['integrity'] = $integrity->getHash();
+ $properties['attributes']['crossorigin'] = 'anonymous';
+ }
+ }
+
+ return [$asset, $properties];
+ }
+}
diff --git a/app/code/Magento/Csp/Plugin/GenerateAssetIntegrity.php b/app/code/Magento/Csp/Plugin/GenerateAssetIntegrity.php
new file mode 100644
index 0000000000000..2b461588fa5ad
--- /dev/null
+++ b/app/code/Magento/Csp/Plugin/GenerateAssetIntegrity.php
@@ -0,0 +1,91 @@
+hashGenerator = $hashGenerator;
+ $this->integrityFactory = $integrityFactory;
+ $this->integrityCollector = $integrityCollector;
+ }
+
+ /**
+ * Generates integrity for RequireJs config.
+ *
+ * @param FileManager $subject
+ * @param File $result
+ *
+ * @return File
+ *
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function afterCreateRequireJsConfigAsset(
+ FileManager $subject,
+ File $result
+ ): File {
+ if (PHP_SAPI == 'cli') {
+ if (in_array($result->getContentType(), self::CONTENT_TYPES)) {
+ $integrity = $this->integrityFactory->create(
+ [
+ "data" => [
+ 'hash' => $this->hashGenerator->generate(
+ $result->getContent()
+ ),
+ 'path' => $result->getPath()
+ ]
+ ]
+ );
+
+ $this->integrityCollector->collect($integrity);
+ }
+ }
+
+ return $result;
+ }
+}
diff --git a/app/code/Magento/Csp/Plugin/RemoveAllAssetIntegrityHashes.php b/app/code/Magento/Csp/Plugin/RemoveAllAssetIntegrityHashes.php
new file mode 100644
index 0000000000000..85b97e9091c54
--- /dev/null
+++ b/app/code/Magento/Csp/Plugin/RemoveAllAssetIntegrityHashes.php
@@ -0,0 +1,69 @@
+integrityRepositoryPool = $integrityRepositoryPool;
+ }
+
+ /**
+ * Removes existing integrity hashes before static content deploy
+ *
+ * @param DeployStaticContent $subject
+ * @param array $options
+ *
+ * @return void
+ *
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function beforeDeploy(
+ DeployStaticContent $subject,
+ array $options
+ ): void {
+ if (PHP_SAPI == 'cli' && !$this->isRefreshContentVersionOnly($options)) {
+ foreach ([Package::BASE_AREA, Area::AREA_FRONTEND, Area::AREA_ADMINHTML] as $area) {
+ $this->integrityRepositoryPool->get($area)
+ ->deleteAll();
+ }
+ }
+ }
+
+ /**
+ * Checks if only version refresh is requested.
+ *
+ * @param array $options
+ *
+ * @return bool
+ */
+ private function isRefreshContentVersionOnly(array $options): bool
+ {
+ return isset($options[DeployStaticOptions::REFRESH_CONTENT_VERSION_ONLY])
+ && $options[DeployStaticOptions::REFRESH_CONTENT_VERSION_ONLY];
+ }
+}
diff --git a/app/code/Magento/Csp/Plugin/StoreAssetIntegrityHashes.php b/app/code/Magento/Csp/Plugin/StoreAssetIntegrityHashes.php
new file mode 100644
index 0000000000000..21bfd581449cb
--- /dev/null
+++ b/app/code/Magento/Csp/Plugin/StoreAssetIntegrityHashes.php
@@ -0,0 +1,70 @@
+integrityCollector = $integrityCollector;
+ $this->integrityRepositoryPool = $integrityRepositoryPool;
+ }
+
+ /**
+ * Stores generated integrity hashes after static content deploy
+ *
+ * @param DeployStaticContent $subject
+ * @param mixed $result
+ * @param array $options
+ *
+ * @return void
+ *
+ * @SuppressWarnings(PHPMD.UnusedFormalParameter)
+ */
+ public function afterDeploy(
+ DeployStaticContent $subject,
+ mixed $result,
+ array $options
+ ): void {
+ $bunches = [];
+
+ foreach ($this->integrityCollector->release() as $integrity) {
+ $area = explode("/", $integrity->getPath())[0];
+
+ $bunches[$area][] = $integrity;
+ }
+
+ foreach ($bunches as $area => $bunch) {
+ $this->integrityRepositoryPool->get($area)
+ ->saveBunch($bunch);
+ }
+ }
+}
diff --git a/app/code/Magento/Csp/Test/Unit/Model/SubresourceIntegrityRepositoryTest.php b/app/code/Magento/Csp/Test/Unit/Model/SubresourceIntegrityRepositoryTest.php
new file mode 100644
index 0000000000000..0b7a55d896f04
--- /dev/null
+++ b/app/code/Magento/Csp/Test/Unit/Model/SubresourceIntegrityRepositoryTest.php
@@ -0,0 +1,129 @@
+cacheMock = $this->getMockBuilder(CacheInterface::class)
+ ->disableOriginalConstructor()
+ ->onlyMethods(['save', 'load'])
+ ->getMockForAbstractClass();
+ $this->serializerMock = $this->getMockBuilder(SerializerInterface::class)
+ ->disableOriginalConstructor()
+ ->onlyMethods(['serialize', 'unserialize'])
+ ->getMockForAbstractClass();
+ $this->integrityFactoryMock = $this->getMockBuilder(SubresourceIntegrityFactory::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+
+ $this->subresourceIntegrityRepository = new SubresourceIntegrityRepository(
+ $this->cacheMock,
+ $this->serializerMock,
+ $this->integrityFactoryMock
+ );
+ }
+
+ /** Test save repository
+ *
+ *
+ * @return void
+ */
+ public function testSave(): void
+ {
+ $data = new SubresourceIntegrity(
+ [
+ 'hash' => 'testhash',
+ 'path' => 'js/jquery.js'
+ ]
+ );
+
+ $expected[$data->getPath()] = $data->getHash();
+ $serialized = json_encode($expected);
+ $this->cacheMock->expects($this->once())->method('load')->willReturn(false);
+ $this->serializerMock->expects($this->once())->method('serialize')->with($expected)->willReturn($serialized);
+ $this->cacheMock->expects($this->once())->method('save')->willReturn(true);
+ $this->assertTrue($this->subresourceIntegrityRepository->save($data));
+ }
+
+ /** Test that cache saves in bunch
+ *
+ *
+ * @return void
+ */
+ public function testSaveBunch(): void
+ {
+ $bunch1 = new SubresourceIntegrity(
+ [
+ 'hash' => 'testhash',
+ 'path' => 'js/jquery.js'
+ ]
+ );
+
+ $bunch2 = new SubresourceIntegrity(
+ [
+ 'hash' => 'testhash2',
+ 'path' => 'js/test.js'
+ ]
+ );
+
+ $bunches = [$bunch1, $bunch2];
+
+ $expected = [];
+
+ foreach ($bunches as $bunch) {
+ $expected[$bunch->getPath()] = $bunch->getHash();
+ }
+ $serializedBunch = json_encode($expected);
+ $this->cacheMock->expects($this->once())->method('load')->willReturn(false);
+ $this->serializerMock->expects($this->once())->method('serialize')
+ ->with($expected)->willReturn($serializedBunch);
+ $this->cacheMock->expects($this->once())->method('save')->willReturn(true);
+ $this->assertTrue($this->subresourceIntegrityRepository->saveBunch($bunches));
+ }
+}
diff --git a/app/code/Magento/Csp/Test/Unit/Plugin/AddDefaultPropertiesToGroupPluginTest.php b/app/code/Magento/Csp/Test/Unit/Plugin/AddDefaultPropertiesToGroupPluginTest.php
new file mode 100644
index 0000000000000..3e6b08f17bb7b
--- /dev/null
+++ b/app/code/Magento/Csp/Test/Unit/Plugin/AddDefaultPropertiesToGroupPluginTest.php
@@ -0,0 +1,113 @@
+integrityRepositoryPoolMock = $this->getMockBuilder(SubresourceIntegrityRepositoryPool::class)
+ ->disableOriginalConstructor()
+ ->onlyMethods(['get'])
+ ->getMock();
+ $this->assetInterfaceMock = $this->getMockBuilder(File::class)
+ ->disableOriginalConstructor()
+ ->onlyMethods(['getPath'])
+ ->getMockForAbstractClass();
+ $this->stateMock = $this->getMockBuilder(State::class)
+ ->disableOriginalConstructor()
+ ->onlyMethods(['getAreaCode'])
+ ->getMock();
+ $this->plugin = new AddDefaultPropertiesToGroupPlugin(
+ $this->stateMock,
+ $this->integrityRepositoryPoolMock
+ );
+ }
+
+ /**
+ * Test for plugin with Js assets
+ *
+ * @return void
+ */
+ public function testBeforeGetFilteredProperties(): void
+ {
+ $integrityRepositoryMock = $this->getMockBuilder(SubresourceIntegrityRepository::class)
+ ->disableOriginalConstructor()
+ ->onlyMethods(['getByPath'])
+ ->getMock();
+ $groupedCollectionMock = $this->getMockBuilder(GroupedCollection::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $path = 'jquery.js';
+ $area = 'base';
+
+ $data = new SubresourceIntegrity(
+ [
+ 'hash' => 'testhash',
+ 'path' => $path
+ ]
+ );
+ $properties['attributes']['integrity'] = $data->getHash();
+ $properties['attributes']['crossorigin'] = 'anonymous';
+ $expected = [$this->assetInterfaceMock, $properties];
+ $this->integrityRepositoryPoolMock->expects($this->once())->method('get')->with($area)
+ ->willReturn(
+ $integrityRepositoryMock
+ );
+ $this->assetInterfaceMock->expects($this->once())->method('getPath')->willReturn($path);
+ $integrityRepositoryMock->expects($this->once())->method('getByPath')->with($path)->willReturn($data);
+ $this->assertEquals(
+ $expected,
+ $this->plugin->beforeGetFilteredProperties(
+ $groupedCollectionMock,
+ $this->assetInterfaceMock
+ )
+ );
+ }
+}
diff --git a/app/code/Magento/Csp/Test/Unit/Plugin/StoreAssetIntegrityHashesTest.php b/app/code/Magento/Csp/Test/Unit/Plugin/StoreAssetIntegrityHashesTest.php
new file mode 100644
index 0000000000000..7ac1d462015c7
--- /dev/null
+++ b/app/code/Magento/Csp/Test/Unit/Plugin/StoreAssetIntegrityHashesTest.php
@@ -0,0 +1,96 @@
+integrityRepositoryPoolMock = $this->getMockBuilder(SubresourceIntegrityRepositoryPool::class)
+ ->disableOriginalConstructor()
+ ->onlyMethods(['get'])
+ ->getMock();
+ $this->integrityCollectorMock = $this->getMockBuilder(SubresourceIntegrityCollector::class)
+ ->disableOriginalConstructor()
+ ->onlyMethods(['release'])
+ ->getMock();
+ $this->plugin = new StoreAssetIntegrityHashes(
+ $this->integrityCollectorMock,
+ $this->integrityRepositoryPoolMock,
+ );
+ }
+
+ /**
+ * Test After Deploy method of plugin
+ *
+ * @return void
+ * @doesNotPerformAssertions
+ */
+ public function testAfterDeploy(): void
+ {
+ $bunch1 = new SubresourceIntegrity(
+ [
+ 'hash' => 'testhash',
+ 'path' => 'adminhtml/js/jquery.js'
+ ]
+ );
+
+ $bunch2 = new SubresourceIntegrity(
+ [
+ 'hash' => 'testhash2',
+ 'path' => 'frontend/js/test.js'
+ ]
+ );
+
+ $bunches = [$bunch1, $bunch2];
+ $deployStaticContentMock = $this->getMockBuilder(DeployStaticContent::class)
+ ->disableOriginalConstructor()
+ ->getMock();
+ $subResourceIntegrityMock = $this->getMockBuilder(SubresourceIntegrityRepository::class)
+ ->disableOriginalConstructor()
+ ->onlyMethods(['saveBunch'])
+ ->getMock();
+ $this->integrityCollectorMock->expects($this->once())->method('release')->willReturn($bunches);
+ $this->integrityRepositoryPoolMock->expects($this->any())->method('get')->willReturn($subResourceIntegrityMock);
+ $subResourceIntegrityMock->expects($this->any())->method('saveBunch')->willReturn(true);
+ $this->plugin->afterDeploy($deployStaticContentMock, null, []);
+ }
+}
diff --git a/app/code/Magento/Csp/composer.json b/app/code/Magento/Csp/composer.json
index c085b06d6900d..c85b28e04a6b0 100644
--- a/app/code/Magento/Csp/composer.json
+++ b/app/code/Magento/Csp/composer.json
@@ -7,7 +7,9 @@
"require": {
"php": "~8.1.0||~8.2.0||~8.3.0",
"magento/framework": "*",
- "magento/module-store": "*"
+ "magento/module-store": "*",
+ "magento/module-require-js": "*",
+ "magento/module-deploy": "*"
},
"type": "magento2-module",
"license": [
diff --git a/app/code/Magento/Csp/etc/di.xml b/app/code/Magento/Csp/etc/di.xml
index b6a887ab9d943..13c1f225a00f2 100644
--- a/app/code/Magento/Csp/etc/di.xml
+++ b/app/code/Magento/Csp/etc/di.xml
@@ -111,4 +111,27 @@
Magento\Csp\Model\BlockCache
+
+
+
+ - Magento\Csp\Model\Deploy\Package\Processor\PostProcessor\Integrity
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Magento\Framework\Filesystem\Driver\File
+
+
diff --git a/app/code/Magento/Csp/view/adminhtml/layout/sales_order_create_index.xml b/app/code/Magento/Csp/view/adminhtml/layout/sales_order_create_index.xml
new file mode 100644
index 0000000000000..73fe99913466c
--- /dev/null
+++ b/app/code/Magento/Csp/view/adminhtml/layout/sales_order_create_index.xml
@@ -0,0 +1,17 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/code/Magento/Csp/view/base/templates/sri/hashes.phtml b/app/code/Magento/Csp/view/base/templates/sri/hashes.phtml
new file mode 100644
index 0000000000000..e9d666a50550d
--- /dev/null
+++ b/app/code/Magento/Csp/view/base/templates/sri/hashes.phtml
@@ -0,0 +1,18 @@
+
+
+getSerialized();
+$scriptString = <<