-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Fix resource-collection.js fingerprint for non-fingerprinted assets #64857
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from 3 commits
9b9ec1b
7827aaf
00e5cf2
9c8b9c1
0a8a76e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,161 @@ | ||
| // Licensed to the .NET Foundation under one or more agreements. | ||
| // The .NET Foundation licenses this file to you under the MIT license. | ||
|
|
||
| namespace Microsoft.AspNetCore.Components.Endpoints; | ||
|
|
||
| public class ResourceCollectionUrlEndpointTest | ||
| { | ||
| [Fact] | ||
| public void ComputeFingerprintSuffix_IncludesIntegrityForNonFingerprintedAssets() | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Look at the microsoftdocs and use modern C# (collection initializers, target type, etc.) where possible.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated to use collection expressions and target-typed |
||
| { | ||
| // Arrange - Create a collection with non-fingerprinted assets that have integrity hashes | ||
| var resources = new List<ResourceAsset> | ||
| { | ||
| // Non-fingerprinted asset with integrity (simulates WasmFingerprintAssets=false scenario) | ||
| new ResourceAsset("/_framework/MyApp.dll", new[] | ||
| { | ||
| new ResourceAssetProperty("integrity", "sha256-ABC123") | ||
| }), | ||
| new ResourceAsset("/_framework/System.dll", new[] | ||
| { | ||
| new ResourceAssetProperty("integrity", "sha256-XYZ789") | ||
| }) | ||
| }; | ||
| var collection = new ResourceAssetCollection(resources); | ||
|
|
||
| // Act | ||
| var fingerprint1 = ResourceCollectionUrlEndpoint.ComputeFingerprintSuffix(collection); | ||
|
|
||
| // Arrange - Change the integrity of one asset (simulates content change between builds) | ||
| resources = new List<ResourceAsset> | ||
| { | ||
| new ResourceAsset("/_framework/MyApp.dll", new[] | ||
| { | ||
| new ResourceAssetProperty("integrity", "sha256-CHANGED") | ||
| }), | ||
| new ResourceAsset("/_framework/System.dll", new[] | ||
| { | ||
| new ResourceAssetProperty("integrity", "sha256-XYZ789") | ||
| }) | ||
| }; | ||
| collection = new ResourceAssetCollection(resources); | ||
|
|
||
| // Act | ||
| var fingerprint2 = ResourceCollectionUrlEndpoint.ComputeFingerprintSuffix(collection); | ||
|
|
||
| // Assert - Fingerprints should be different because integrity changed | ||
| Assert.NotEqual(fingerprint1, fingerprint2); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void ComputeFingerprintSuffix_DoesNotIncludeIntegrityForFingerprintedAssets() | ||
| { | ||
| // Arrange - Create a collection with fingerprinted assets (have label property) | ||
| var resources = new List<ResourceAsset> | ||
| { | ||
| // Fingerprinted asset with label (simulates WasmFingerprintAssets=true scenario) | ||
| new ResourceAsset("/_framework/MyApp.ABC123.dll", new[] | ||
| { | ||
| new ResourceAssetProperty("label", "MyApp.dll"), | ||
| new ResourceAssetProperty("integrity", "sha256-ABC123") | ||
| }), | ||
| new ResourceAsset("/_framework/System.XYZ789.dll", new[] | ||
| { | ||
| new ResourceAssetProperty("label", "System.dll"), | ||
| new ResourceAssetProperty("integrity", "sha256-XYZ789") | ||
| }) | ||
| }; | ||
| var collection = new ResourceAssetCollection(resources); | ||
|
|
||
| // Act | ||
| var fingerprint1 = ResourceCollectionUrlEndpoint.ComputeFingerprintSuffix(collection); | ||
|
|
||
| // Arrange - Change the integrity (but not the URL) of one asset | ||
| // For fingerprinted assets, the URL already contains the hash, so we don't need to include integrity | ||
| resources = new List<ResourceAsset> | ||
| { | ||
| new ResourceAsset("/_framework/MyApp.ABC123.dll", new[] | ||
| { | ||
| new ResourceAssetProperty("label", "MyApp.dll"), | ||
| new ResourceAssetProperty("integrity", "sha256-CHANGED") | ||
| }), | ||
| new ResourceAsset("/_framework/System.XYZ789.dll", new[] | ||
| { | ||
| new ResourceAssetProperty("label", "System.dll"), | ||
| new ResourceAssetProperty("integrity", "sha256-XYZ789") | ||
| }) | ||
| }; | ||
| collection = new ResourceAssetCollection(resources); | ||
|
|
||
| // Act | ||
| var fingerprint2 = ResourceCollectionUrlEndpoint.ComputeFingerprintSuffix(collection); | ||
|
|
||
| // Assert - Fingerprints should be the same because for fingerprinted assets, | ||
| // the URL (not integrity) is what matters, and the URL didn't change | ||
| Assert.Equal(fingerprint1, fingerprint2); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void ComputeFingerprintSuffix_HandlesMixedAssets() | ||
| { | ||
| // Arrange - Mix of fingerprinted and non-fingerprinted assets | ||
| var resources = new List<ResourceAsset> | ||
| { | ||
| // Fingerprinted asset | ||
| new ResourceAsset("/_framework/MyApp.ABC123.dll", new[] | ||
| { | ||
| new ResourceAssetProperty("label", "MyApp.dll"), | ||
| new ResourceAssetProperty("integrity", "sha256-ABC123") | ||
| }), | ||
| // Non-fingerprinted asset | ||
| new ResourceAsset("/_framework/custom.js", new[] | ||
| { | ||
| new ResourceAssetProperty("integrity", "sha256-CUSTOM") | ||
| }) | ||
| }; | ||
| var collection = new ResourceAssetCollection(resources); | ||
|
|
||
| // Act | ||
| var fingerprint1 = ResourceCollectionUrlEndpoint.ComputeFingerprintSuffix(collection); | ||
|
|
||
| // Arrange - Change only the non-fingerprinted asset's integrity | ||
| resources = new List<ResourceAsset> | ||
| { | ||
| // Fingerprinted asset (same as before) | ||
| new ResourceAsset("/_framework/MyApp.ABC123.dll", new[] | ||
| { | ||
| new ResourceAssetProperty("label", "MyApp.dll"), | ||
| new ResourceAssetProperty("integrity", "sha256-ABC123") | ||
| }), | ||
| // Non-fingerprinted asset with changed integrity | ||
| new ResourceAsset("/_framework/custom.js", new[] | ||
| { | ||
| new ResourceAssetProperty("integrity", "sha256-MODIFIED") | ||
| }) | ||
| }; | ||
| collection = new ResourceAssetCollection(resources); | ||
|
|
||
| // Act | ||
| var fingerprint2 = ResourceCollectionUrlEndpoint.ComputeFingerprintSuffix(collection); | ||
|
|
||
| // Assert - Fingerprints should be different because non-fingerprinted asset's integrity changed | ||
| Assert.NotEqual(fingerprint1, fingerprint2); | ||
| } | ||
|
|
||
| [Fact] | ||
| public void ComputeFingerprintSuffix_HandlesAssetsWithNoProperties() | ||
| { | ||
| // Arrange | ||
| var resources = new List<ResourceAsset> | ||
| { | ||
| new ResourceAsset("/_framework/file1.dll", null), | ||
| new ResourceAsset("/_framework/file2.dll", new ResourceAssetProperty[] { }) | ||
| }; | ||
| var collection = new ResourceAssetCollection(resources); | ||
|
|
||
| // Act & Assert - Should not throw | ||
| var fingerprint = ResourceCollectionUrlEndpoint.ComputeFingerprintSuffix(collection); | ||
| Assert.NotNull(fingerprint); | ||
| Assert.StartsWith(".", fingerprint); | ||
| } | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @copilot Add a unit test that simulates the original scenario, which is the integrity of a non-fingerprinted asset changes. First we compute the fingerprint suffix, then we change the integrity on a non-fingerprinted asset and verify the suffix is different.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is the only test we need for this. All other behavior will be well covered by existing tests
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added |
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Move this into a helper method that returns a string and then have the check be against the returned string. If there is more data we need to hash we will return a non-null string. Otherwise, we return null and skip.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Extracted
GetAdditionalDataForFingerprinthelper method that returnsstring?- returns the integrity value for non-fingerprinted assets or null otherwise. Commit: 9c8b9c1