diff --git a/README.md b/README.md
index bc2b2b2..e818097 100644
--- a/README.md
+++ b/README.md
@@ -138,73 +138,24 @@ Unpinning and removing "react"
## Subresource Integrity (SRI)
-For enhanced security, importmap-rails automatically includes [Subresource Integrity (SRI)](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) hashes by default when pinning packages. This ensures that JavaScript files loaded from CDNs haven't been tampered with.
-
-### Default behavior with integrity
-
-When you pin a package, integrity hashes are automatically included:
-
-```bash
-./bin/importmap pin lodash
-Pinning "lodash" to vendor/javascript/lodash.js via download from https://ga.jspm.io/npm:lodash@4.17.21/lodash.js
- Using integrity: sha384-PkIkha4kVPRlGtFantHjuv+Y9mRefUHpLFQbgOYUjzy247kvi16kLR7wWnsAmqZF
-```
-
-This generates a pin in your `config/importmap.rb` with the integrity hash:
-
-```ruby
-pin "lodash", integrity: "sha384-PkIkha4kVPRlGtFantHjuv+Y9mRefUHpLFQbgOYUjzy247kvi16kLR7wWnsAmqZF" # @4.17.21
-```
-
-### Opting out of integrity
-
-If you need to disable integrity checking (not recommended for security reasons), you can use the `--no-integrity` flag:
-
-```bash
-./bin/importmap pin lodash --no-integrity
-Pinning "lodash" to vendor/javascript/lodash.js via download from https://ga.jspm.io/npm:lodash@4.17.21/lodash.js
-```
-
-This generates a pin without integrity:
-
-```ruby
-pin "lodash" # @4.17.21
-```
-
-### Adding integrity to existing pins
-
-If you have existing pins without integrity hashes, you can add them using the `integrity` command:
-
-```bash
-# Add integrity to specific packages
-./bin/importmap integrity lodash react
-
-# Add integrity to all pinned packages
-./bin/importmap integrity
-
-# Update your importmap.rb file with integrity hashes
-./bin/importmap integrity --update
-```
+For enhanced security, importmap-rails supports [Subresource Integrity (SRI)](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity) hashes for packages loaded from external CDNs.
### Automatic integrity for local assets
-For local assets served by the Rails asset pipeline (like those created with `pin` or `pin_all_from`), you can use `integrity: true` to automatically calculate integrity hashes from the compiled assets:
+Starting with importmap-rails, **`integrity: true` is the default** for all pins. This automatically calculates integrity hashes for local assets served by the Rails asset pipeline:
```ruby
# config/importmap.rb
-# Automatically calculate integrity from asset pipeline
-pin "application", integrity: true
-pin "admin", to: "admin.js", integrity: true
-
-# Works with pin_all_from too
-pin_all_from "app/javascript/controllers", under: "controllers", integrity: true
-pin_all_from "app/javascript/lib", under: "lib", integrity: true
+# These all use integrity: true by default
+pin "application" # Auto-calculated integrity
+pin "admin", to: "admin.js" # Auto-calculated integrity
+pin_all_from "app/javascript/controllers", under: "controllers" # Auto-calculated integrity
-# Mixed usage
-pin "local_module", integrity: true # Auto-calculated
-pin "cdn_package", integrity: "sha384-abc123..." # Pre-calculated
-pin "no_integrity_package" # No integrity (default)
+# Mixed usage - explicitly controlling integrity
+pin "cdn_package", integrity: "sha384-abc123..." # Pre-calculated hash
+pin "no_integrity_package", integrity: false # Explicitly disable integrity
+pin "nil_integrity_package", integrity: nil # Explicitly disable integrity
```
This is particularly useful for:
@@ -212,11 +163,16 @@ This is particularly useful for:
* **Bulk operations** with `pin_all_from` where calculating hashes manually would be tedious
* **Development workflow** where asset contents change frequently
-The `integrity: true` option:
-* Uses the Rails asset pipeline's built-in integrity calculation
-* Works with both Sprockets and Propshaft
-* Automatically updates when assets are recompiled
-* Gracefully handles missing assets (returns `nil` for non-existent files)
+This behavior can be disabled by setting `integrity: false` or `integrity: nil`
+
+**Important for Propshaft users:** SRI support requires Propshaft 1.2+ and you must configure the integrity hash algorithm in your application:
+
+```ruby
+# config/application.rb or config/environments/*.rb
+config.assets.integrity_hash_algorithm = 'sha256' # or 'sha384', 'sha512'
+```
+
+Without this configuration, integrity will be disabled by default when using Propshaft. Sprockets includes integrity support out of the box.
**Example output with `integrity: true`:**
```json
@@ -240,10 +196,14 @@ The integrity hashes are automatically included in your import map and module pr
```json
{
"imports": {
- "lodash": "https://ga.jspm.io/npm:lodash@4.17.21/lodash.js"
+ "lodash": "https://ga.jspm.io/npm:lodash@4.17.21/lodash.js",
+ "application": "/assets/application-abc123.js",
+ "controllers/hello_controller": "/assets/controllers/hello_controller-def456.js"
},
"integrity": {
"https://ga.jspm.io/npm:lodash@4.17.21/lodash.js": "sha384-PkIkha4kVPRlGtFantHjuv+Y9mRefUHpLFQbgOYUjzy247kvi16kLR7wWnsAmqZF"
+ "/assets/application-abc123.js": "sha256-xyz789...",
+ "/assets/controllers/hello_controller-def456.js": "sha256-uvw012..."
}
}
```
@@ -251,22 +211,12 @@ The integrity hashes are automatically included in your import map and module pr
**Module preload tags:**
```html
+
+
```
Modern browsers will automatically validate these integrity hashes when loading the JavaScript modules, ensuring the files haven't been modified.
-### Redownloading packages with integrity
-
-The `pristine` command also includes integrity by default:
-
-```bash
-# Redownload all packages with integrity (default)
-./bin/importmap pristine
-
-# Redownload packages without integrity
-./bin/importmap pristine --no-integrity
-```
-
## Preloading pinned modules
To avoid the waterfall effect where the browser has to load one file after another before it can get to the deepest nested import, importmap-rails uses [modulepreload links](https://developers.google.com/web/updates/2017/12/modulepreload) by default. If you don't want to preload a dependency, because you want to load it on-demand for efficiency, append `preload: false` to the pin.
diff --git a/lib/importmap/commands.rb b/lib/importmap/commands.rb
index 3b5fd55..f56abe1 100644
--- a/lib/importmap/commands.rb
+++ b/lib/importmap/commands.rb
@@ -13,19 +13,15 @@ def self.exit_on_failure?
option :env, type: :string, aliases: :e, default: "production"
option :from, type: :string, aliases: :f, default: "jspm"
option :preload, type: :string, repeatable: true, desc: "Can be used multiple times"
- option :integrity, type: :boolean, aliases: :i, default: true, desc: "Include integrity hash from JSPM"
def pin(*packages)
- with_import_response(packages, env: options[:env], from: options[:from], integrity: options[:integrity]) do |imports, integrity_hashes|
- process_imports(imports, integrity_hashes) do |package, url, integrity_hash|
- puts %(Pinning "#{package}" to #{packager.vendor_path}/#{package}.js via download from #{url})
+ for_each_import(packages, env: options[:env], from: options[:from]) do |package, url|
+ puts %(Pinning "#{package}" to #{packager.vendor_path}/#{package}.js via download from #{url})
- packager.download(package, url)
+ packager.download(package, url)
- pin = packager.vendored_pin_for(package, url, options[:preload], integrity: integrity_hash)
+ pin = packager.vendored_pin_for(package, url, options[:preload])
- log_integrity_usage(integrity_hash)
- update_importmap_with_pin(package, pin)
- end
+ update_importmap_with_pin(package, pin)
end
end
@@ -33,12 +29,10 @@ def pin(*packages)
option :env, type: :string, aliases: :e, default: "production"
option :from, type: :string, aliases: :f, default: "jspm"
def unpin(*packages)
- with_import_response(packages, env: options[:env], from: options[:from]) do |imports, _integrity_hashes|
- imports.each do |package, url|
- if packager.packaged?(package)
- puts %(Unpinning and removing "#{package}")
- packager.remove(package)
- end
+ for_each_import(packages, env: options[:env], from: options[:from]) do |package, url|
+ if packager.packaged?(package)
+ puts %(Unpinning and removing "#{package}")
+ packager.remove(package)
end
end
end
@@ -46,18 +40,13 @@ def unpin(*packages)
desc "pristine", "Redownload all pinned packages"
option :env, type: :string, aliases: :e, default: "production"
option :from, type: :string, aliases: :f, default: "jspm"
- option :integrity, type: :boolean, aliases: :i, default: true, desc: "Include integrity hash from JSPM"
def pristine
packages = prepare_packages_with_versions
- with_import_response(packages, env: options[:env], from: options[:from], integrity: options[:integrity]) do |imports, integrity_hashes|
- process_imports(imports, integrity_hashes) do |package, url, integrity_hash|
- puts %(Downloading "#{package}" to #{packager.vendor_path}/#{package}.js from #{url})
+ for_each_import(packages, env: options[:env], from: options[:from]) do |package, url|
+ puts %(Downloading "#{package}" to #{packager.vendor_path}/#{package}.js from #{url})
- packager.download(package, url)
-
- log_integrity_usage(integrity_hash)
- end
+ packager.download(package, url)
end
end
@@ -118,33 +107,6 @@ def packages
puts npm.packages_with_versions.map { |x| x.join(' ') }
end
- desc "integrity [*PACKAGES]", "Download and add integrity hashes for packages"
- option :env, type: :string, aliases: :e, default: "production"
- option :from, type: :string, aliases: :f, default: "jspm"
- option :update, type: :boolean, aliases: :u, default: false, desc: "Update importmap.rb with integrity hashes"
- def integrity(*packages)
- packages = prepare_packages_with_versions(packages)
-
- with_import_response(packages, env: options[:env], from: options[:from], integrity: true) do |imports, integrity_hashes|
- process_imports(imports, integrity_hashes) do |package, url, integrity_hash|
- puts %(Getting integrity for "#{package}" from #{url})
-
- if integrity_hash
- puts %( #{package}: #{integrity_hash})
-
- if options[:update]
- pin_with_integrity = packager.pin_for(package, url, integrity: integrity_hash)
-
- update_importmap_with_pin(package, pin_with_integrity)
- puts %( Updated importmap.rb with integrity for "#{package}")
- end
- else
- puts %( No integrity hash available for "#{package}")
- end
- end
- end
- end
-
private
def packager
@packager ||= Importmap::Packager.new
@@ -162,10 +124,6 @@ def update_importmap_with_pin(package, pin)
end
end
- def log_integrity_usage(integrity_hash)
- puts %( Using integrity: #{integrity_hash}) if integrity_hash
- end
-
def handle_package_not_found(packages, from)
puts "Couldn't find any packages in #{packages.inspect} on #{from}"
end
@@ -205,18 +163,11 @@ def prepare_packages_with_versions(packages = [])
end
end
- def process_imports(imports, integrity_hashes, &block)
- imports.each do |package, url|
- integrity_hash = integrity_hashes[url]
- block.call(package, url, integrity_hash)
- end
- end
-
- def with_import_response(packages, **options)
+ def for_each_import(packages, **options, &block)
response = packager.import(*packages, **options)
if response
- yield response[:imports], response[:integrity]
+ response[:imports].each(&block)
else
handle_package_not_found(packages, options[:from])
end
diff --git a/lib/importmap/map.rb b/lib/importmap/map.rb
index 63fa2ef..c88063b 100644
--- a/lib/importmap/map.rb
+++ b/lib/importmap/map.rb
@@ -25,12 +25,12 @@ def draw(path = nil, &block)
self
end
- def pin(name, to: nil, preload: true, integrity: nil)
+ def pin(name, to: nil, preload: true, integrity: true)
clear_cache
@packages[name] = MappedFile.new(name: name, path: to || "#{name}.js", preload: preload, integrity: integrity)
end
- def pin_all_from(dir, under: nil, to: nil, preload: true, integrity: nil)
+ def pin_all_from(dir, under: nil, to: nil, preload: true, integrity: true)
clear_cache
@directories[dir] = MappedDir.new(dir: dir, under: under, path: to, preload: preload, integrity: integrity)
end
diff --git a/lib/importmap/packager.rb b/lib/importmap/packager.rb
index 98819d1..1873091 100644
--- a/lib/importmap/packager.rb
+++ b/lib/importmap/packager.rb
@@ -17,13 +17,12 @@ def initialize(importmap_path = "config/importmap.rb", vendor_path: "vendor/java
@vendor_path = Pathname.new(vendor_path)
end
- def import(*packages, env: "production", from: "jspm", integrity: false)
+ def import(*packages, env: "production", from: "jspm")
response = post_json({
"install" => Array(packages),
"flattenScope" => true,
"env" => [ "browser", "module", env ],
"provider" => normalize_provider(from),
- "integrity" => integrity
})
case response.code
@@ -36,20 +35,19 @@ def import(*packages, env: "production", from: "jspm", integrity: false)
end
end
- def pin_for(package, url = nil, preloads: nil, integrity: nil)
+ def pin_for(package, url = nil, preloads: nil)
to = url ? %(, to: "#{url}") : ""
preload_param = preload(preloads)
- integrity_param = integrity ? %(, integrity: "#{integrity}") : ""
- %(pin "#{package}") + to + preload_param + integrity_param
+ %(pin "#{package}") + to + preload_param
end
- def vendored_pin_for(package, url, preloads = nil, integrity: nil)
+ def vendored_pin_for(package, url, preloads = nil)
filename = package_filename(package)
version = extract_package_version_from(url)
to = "#{package}.js" != filename ? filename : nil
- pin_for(package, to, preloads: preloads, integrity: integrity) + %( # #{version})
+ pin_for(package, to, preloads: preloads) + %( # #{version})
end
def packaged?(package)
@@ -96,11 +94,9 @@ def normalize_provider(name)
def extract_parsed_response(response)
parsed = JSON.parse(response.body)
imports = parsed.dig("map", "imports")
- integrity = parsed.dig("map", "integrity") || {}
{
imports: imports,
- integrity: integrity
}
end
diff --git a/test/commands_test.rb b/test/commands_test.rb
index 410248b..bdca613 100644
--- a/test/commands_test.rb
+++ b/test/commands_test.rb
@@ -50,149 +50,6 @@ class CommandsTest < ActiveSupport::TestCase
assert_equal original, File.read("#{@tmpdir}/dummy/vendor/javascript/md5.js")
end
- test "pin command includes integrity by default" do
- out, _err = run_importmap_command("pin", "md5@2.2.0")
-
- assert_includes out, 'Pinning "md5" to vendor/javascript/md5.js via download from https://ga.jspm.io/npm:md5@2.2.0/md5.js'
- assert_includes out, 'Using integrity:'
-
- config_content = File.read("#{@tmpdir}/dummy/config/importmap.rb")
- assert_includes config_content, 'pin "md5", integrity: "sha384-'
- end
-
- test "pin command with --no-integrity option excludes integrity" do
- out, _err = run_importmap_command("pin", "md5@2.2.0", "--no-integrity")
-
- assert_includes out, 'Pinning "md5" to vendor/javascript/md5.js via download from https://ga.jspm.io/npm:md5@2.2.0/md5.js'
- assert_not_includes out, 'Using integrity:'
-
- config_content = File.read("#{@tmpdir}/dummy/config/importmap.rb")
- assert_includes config_content, 'pin "md5" # @2.2.0'
- end
-
- test "pristine command includes integrity by default" do
- FileUtils.cp("#{__dir__}/fixtures/files/outdated_import_map.rb", "#{@tmpdir}/dummy/config/importmap.rb")
-
- out, _err = run_importmap_command("pristine")
-
- assert_includes out, 'Downloading "md5" to vendor/javascript/md5.js from https://ga.jspm.io/npm:md5@2.2.0/md5.js'
- assert_includes out, 'Using integrity:'
- end
-
- test "pristine command with --no-integrity option excludes integrity" do
- FileUtils.cp("#{__dir__}/fixtures/files/outdated_import_map.rb", "#{@tmpdir}/dummy/config/importmap.rb")
-
- out, _err = run_importmap_command("pristine", "--no-integrity")
-
- assert_includes out, 'Downloading "md5" to vendor/javascript/md5.js from https://ga.jspm.io/npm:md5@2.2.0/md5.js'
- assert_not_includes out, 'Using integrity:'
- end
-
- test "pin command with explicit --integrity option includes integrity" do
- out, _err = run_importmap_command("pin", "md5@2.2.0", "--integrity")
-
- assert_includes out, 'Pinning "md5" to vendor/javascript/md5.js via download from https://ga.jspm.io/npm:md5@2.2.0/md5.js'
- assert_includes out, 'Using integrity:'
-
- config_content = File.read("#{@tmpdir}/dummy/config/importmap.rb")
- assert_includes config_content, 'integrity: "sha384-'
- end
-
- test "pin command with multiple packages includes integrity for all" do
- out, _err = run_importmap_command("pin", "md5@2.2.0", "lodash@4.17.21")
-
- assert_includes out, 'Pinning "md5"'
- assert_includes out, 'Pinning "lodash"'
- assert_includes out, 'Using integrity:'
-
- config_content = File.read("#{@tmpdir}/dummy/config/importmap.rb")
- assert_includes config_content, 'pin "md5"'
- assert_includes config_content, 'pin "lodash"'
-
- md5_lines = config_content.lines.select { |line| line.include?('pin "md5"') }
- lodash_lines = config_content.lines.select { |line| line.include?('pin "lodash"') }
- assert md5_lines.any? { |line| line.include?('integrity:') }
- assert lodash_lines.any? { |line| line.include?('integrity:') }
- end
-
- test "pin command with preload option includes integrity and preload" do
- out, _err = run_importmap_command("pin", "md5@2.2.0", "--preload", "true")
-
- assert_includes out, 'Pinning "md5" to vendor/javascript/md5.js via download from https://ga.jspm.io/npm:md5@2.2.0/md5.js'
- assert_includes out, 'Using integrity:'
-
- config_content = File.read("#{@tmpdir}/dummy/config/importmap.rb")
- assert_includes config_content, 'preload: true'
- assert_includes config_content, 'integrity: "sha384-'
- end
-
- test "integrity command shows integrity hashes for specific packages" do
- out, _err = run_importmap_command("integrity", "md5@2.2.0")
-
- assert_includes out, 'Getting integrity for "md5" from https://ga.jspm.io/npm:md5@2.2.0/md5.js'
- assert_includes out, 'md5: sha384-'
- end
-
- test "integrity command with --update option updates importmap.rb" do
- config_content = File.read("#{@tmpdir}/dummy/config/importmap.rb")
- assert_includes config_content, 'pin "md5", to: "https://cdn.skypack.dev/md5", preload: true'
-
- out, _err = run_importmap_command("integrity", "md5@2.2.0", "--update")
-
- assert_includes out, 'Getting integrity for "md5" from https://ga.jspm.io/npm:md5@2.2.0/md5.js'
- assert_includes out, 'md5: sha384-'
- assert_includes out, 'Updated importmap.rb with integrity for "md5"'
-
- config_content = File.read("#{@tmpdir}/dummy/config/importmap.rb")
- assert_includes config_content, 'pin "md5", to: "https://ga.jspm.io/npm:md5@2.2.0/md5.js", integrity: "sha384-'
- end
-
- test "integrity command with multiple packages shows integrity for all" do
- out, _err = run_importmap_command("integrity", "md5@2.2.0", "lodash@4.17.21")
-
- assert_includes out, 'Getting integrity for "md5"'
- assert_includes out, 'Getting integrity for "lodash"'
- assert_includes out, 'md5: sha384-'
- assert_includes out, 'lodash: sha384-'
- end
-
- test "integrity command without packages shows integrity for all remote packages" do
- run_importmap_command("pin", "md5@2.2.0", "--no-integrity")
-
- out, _err = run_importmap_command("integrity")
-
- assert_includes out, 'Getting integrity for "md5"'
- assert_includes out, 'md5: sha384-'
- end
-
- test "integrity command with --update updates multiple packages" do
- run_importmap_command("pin", "md5@2.2.0", "--no-integrity")
- run_importmap_command("pin", "lodash@4.17.21", "--no-integrity")
-
- out, _err = run_importmap_command("integrity", "--update")
-
- assert_includes out, 'Updated importmap.rb with integrity for "md5"'
- assert_includes out, 'Updated importmap.rb with integrity for "lodash"'
-
- config_content = File.read("#{@tmpdir}/dummy/config/importmap.rb")
- assert_includes config_content, 'pin "md5", to: "https://ga.jspm.io/npm:md5@2.2.0/md5.js", integrity: "sha384-'
- assert_includes config_content, 'pin "lodash", to: "https://ga.jspm.io/npm:lodash@4.17.21/lodash.js", integrity: "sha384-'
- end
-
- test "integrity command with env option" do
- out, _err = run_importmap_command("integrity", "md5@2.2.0", "--env", "development")
-
- assert_includes out, 'Getting integrity for "md5"'
- assert_includes out, 'md5: sha384-'
- end
-
- test "integrity command with from option" do
- out, _err = run_importmap_command("integrity", "md5@2.2.0", "--from", "jspm")
-
- assert_includes out, 'Getting integrity for "md5"'
- assert_includes out, 'md5: sha384-'
- end
-
private
def run_importmap_command(command, *args)
capture_subprocess_io { system("bin/importmap", command, *args, exception: true) }
diff --git a/test/dummy/config/importmap.rb b/test/dummy/config/importmap.rb
index 2fece22..5bbb784 100644
--- a/test/dummy/config/importmap.rb
+++ b/test/dummy/config/importmap.rb
@@ -1,5 +1,5 @@
pin_all_from "app/assets/javascripts"
-pin "md5", to: "https://cdn.skypack.dev/md5", preload: true
-pin "not_there", to: "nowhere.js", preload: false
+pin "md5", to: "https://cdn.skypack.dev/md5", preload: true, integrity: false
+pin "not_there", to: "nowhere.js", preload: false, integrity: false
pin "rich_text", preload: true, integrity: "sha384-OLBgp1GsljhM2TJ+sbHjaiH9txEUvgdDTAzHv2P24donTt6/529l+9Ua0vFImLlb"
diff --git a/test/importmap_test.rb b/test/importmap_test.rb
index 0f341d4..e422cba 100644
--- a/test/importmap_test.rb
+++ b/test/importmap_test.rb
@@ -5,13 +5,13 @@ class ImportmapTest < ActiveSupport::TestCase
def setup
@importmap = Importmap::Map.new.tap do |map|
map.draw do
- pin "application", preload: false
+ pin "application", preload: false, integrity: false
pin "editor", to: "rich_text.js", preload: false, integrity: "sha384-OLBgp1GsljhM2TJ+sbHjaiH9txEUvgdDTAzHv2P24donTt6/529l+9Ua0vFImLlb"
pin "not_there", to: "nowhere.js", preload: false, integrity: "sha384-somefakehash"
- pin "md5", to: "https://cdn.skypack.dev/md5", preload: true
- pin "leaflet", to: "https://cdn.skypack.dev/leaflet", preload: 'application'
- pin "chartkick", to: "https://cdn.skypack.dev/chartkick", preload: ['application', 'alternate']
- pin "tinyMCE", to: "https://cdn.skypack.dev/tinymce", preload: 'alternate'
+ pin "md5", to: "https://cdn.skypack.dev/md5", preload: true, integrity: false
+ pin "leaflet", to: "https://cdn.skypack.dev/leaflet", preload: 'application', integrity: false
+ pin "chartkick", to: "https://cdn.skypack.dev/chartkick", preload: ['application', 'alternate'], integrity: false
+ pin "tinyMCE", to: "https://cdn.skypack.dev/tinymce", preload: 'alternate', integrity: false
pin_all_from "app/javascript/controllers", under: "controllers", preload: true
pin_all_from "app/javascript/spina/controllers", under: "controllers/spina", preload: true
@@ -39,14 +39,44 @@ def setup
assert_not_includes generate_importmap_json["integrity"].values, "sha384-somefakehash"
end
- test "integrity is not present if there is no integrity set in the map" do
+ test "integrity is default" do
@importmap = Importmap::Map.new.tap do |map|
map.pin "application", preload: false
end
+ json = generate_importmap_json
+ assert json.key?("integrity")
+ application_path = json["imports"]["application"]
+ assert json["integrity"][application_path]
+ end
+
+ test "integrity: false explicitly disables integrity" do
+ @importmap = Importmap::Map.new.tap do |map|
+ map.pin "application", preload: false, integrity: false
+ end
+
+ assert_not generate_importmap_json.key?("integrity")
+ end
+
+ test "integrity: nil explicitly disables integrity" do
+ @importmap = Importmap::Map.new.tap do |map|
+ map.pin "application", preload: false, integrity: nil
+ end
+
assert_not generate_importmap_json.key?("integrity")
end
+ test "integrity: 'custom-hash' uses the provided string" do
+ custom_hash = "sha384-customhash123"
+ @importmap = Importmap::Map.new.tap do |map|
+ map.pin "application", preload: false, integrity: custom_hash
+ end
+
+ json = generate_importmap_json
+ application_path = json["imports"]["application"]
+ assert_equal custom_hash, json["integrity"][application_path]
+ end
+
test "local pin missing is removed from generated importmap" do
assert_nil generate_importmap_json["imports"]["not_there"]
end
diff --git a/test/packager_test.rb b/test/packager_test.rb
index ad36705..032d069 100644
--- a/test/packager_test.rb
+++ b/test/packager_test.rb
@@ -24,7 +24,6 @@ def code() "200" end
@packager.stub(:post_json, response) do
result = @packager.import("react@17.0.2")
assert_equal response.imports, result[:imports]
- assert_equal({}, result[:integrity])
end
end
@@ -51,14 +50,6 @@ def code() "200" end
test "pin_for" do
assert_equal %(pin "react", to: "https://cdn/react"), @packager.pin_for("react", "https://cdn/react")
- assert_equal(
- %(pin "react", to: "https://cdn/react", integrity: "sha384-abcdef"),
- @packager.pin_for("react", "https://cdn/react", integrity: "sha384-abcdef")
- )
- assert_equal(
- %(pin "react", to: "https://cdn/react"),
- @packager.pin_for("react", "https://cdn/react", integrity: nil)
- )
assert_equal(
%(pin "react", to: "https://cdn/react", preload: true),
@packager.pin_for("react", "https://cdn/react", preloads: ["true"])
@@ -75,27 +66,9 @@ def code() "200" end
%(pin "react", to: "https://cdn/react", preload: ["foo", "bar"]),
@packager.pin_for("react", "https://cdn/react", preloads: ["foo", "bar"])
)
- assert_equal(
- %(pin "react", to: "https://cdn/react", preload: true, integrity: "sha384-abcdef"),
- @packager.pin_for("react", "https://cdn/react", preloads: ["true"], integrity: "sha384-abcdef")
- )
- assert_equal(
- %(pin "react", to: "https://cdn/react", preload: false, integrity: "sha384-abcdef"),
- @packager.pin_for("react", "https://cdn/react", preloads: ["false"], integrity: "sha384-abcdef")
- )
- assert_equal(
- %(pin "react", to: "https://cdn/react", preload: "foo", integrity: "sha384-abcdef"),
- @packager.pin_for("react", "https://cdn/react", preloads: ["foo"], integrity: "sha384-abcdef")
- )
- assert_equal(
- %(pin "react", to: "https://cdn/react", preload: ["foo", "bar"], integrity: "sha384-abcdef"),
- @packager.pin_for("react", "https://cdn/react", preloads: ["foo", "bar"], integrity: "sha384-abcdef")
- )
assert_equal %(pin "react"), @packager.pin_for("react")
assert_equal %(pin "react", preload: true), @packager.pin_for("react", preloads: ["true"])
- assert_equal %(pin "react", integrity: "sha384-abcdef"), @packager.pin_for("react", integrity: "sha384-abcdef")
- assert_equal %(pin "react", preload: true, integrity: "sha384-abcdef"), @packager.pin_for("react", preloads: ["true"], integrity: "sha384-abcdef")
end
test "vendored_pin_for" do
@@ -105,71 +78,5 @@ def code() "200" end
assert_equal %(pin "react", preload: false # @17.0.2), @packager.vendored_pin_for("react", "https://cdn/react@17.0.2", ["false"])
assert_equal %(pin "react", preload: "foo" # @17.0.2), @packager.vendored_pin_for("react", "https://cdn/react@17.0.2", ["foo"])
assert_equal %(pin "react", preload: ["foo", "bar"] # @17.0.2), @packager.vendored_pin_for("react", "https://cdn/react@17.0.2", ["foo", "bar"])
- assert_equal(
- %(pin "react", integrity: "sha384-abcdef" # @17.0.2),
- @packager.vendored_pin_for("react", "https://cdn/react@17.0.2", nil, integrity: "sha384-abcdef")
- )
- assert_equal(
- %(pin "javascript/react", to: "javascript--react.js", integrity: "sha384-abcdef" # @17.0.2),
- @packager.vendored_pin_for("javascript/react", "https://cdn/react@17.0.2", nil, integrity: "sha384-abcdef")
- )
- assert_equal(
- %(pin "react", preload: true, integrity: "sha384-abcdef" # @17.0.2),
- @packager.vendored_pin_for("react", "https://cdn/react@17.0.2", ["true"], integrity: "sha384-abcdef")
- )
- assert_equal(
- %(pin "react", preload: false, integrity: "sha384-abcdef" # @17.0.2),
- @packager.vendored_pin_for("react", "https://cdn/react@17.0.2", ["false"], integrity: "sha384-abcdef")
- )
- assert_equal(
- %(pin "react", preload: "foo", integrity: "sha384-abcdef" # @17.0.2),
- @packager.vendored_pin_for("react", "https://cdn/react@17.0.2", ["foo"], integrity: "sha384-abcdef")
- )
- assert_equal(
- %(pin "react", preload: ["foo", "bar"], integrity: "sha384-abcdef" # @17.0.2),
- @packager.vendored_pin_for("react", "https://cdn/react@17.0.2", ["foo", "bar"], integrity: "sha384-abcdef")
- )
- assert_equal(
- %(pin "react" # @17.0.2),
- @packager.vendored_pin_for("react", "https://cdn/react@17.0.2", nil, integrity: nil)
- )
- end
-
- test "import with integrity parameter" do
- response = Class.new do
- def body
- {
- "map" => {
- "imports" => imports,
- "integrity" => integrity_map
- }
- }.to_json
- end
-
- def imports
- {
- "react" => "https://ga.jspm.io/npm:react@17.0.2/index.js",
- "object-assign" => "https://ga.jspm.io/npm:object-assign@4.1.1/index.js"
- }
- end
-
- def integrity_map
- {
- "https://ga.jspm.io/npm:react@17.0.2/index.js" => "sha384-abcdef1234567890",
- "https://ga.jspm.io/npm:object-assign@4.1.1/index.js" => "sha384-1234567890abcdef"
- }
- end
-
- def code() "200" end
- end.new
-
- @packager.stub(:post_json, response) do
- result = @packager.import("react@17.0.2", integrity: true)
- assert_equal response.imports, result[:imports]
- assert_equal({
- "https://ga.jspm.io/npm:react@17.0.2/index.js" => "sha384-abcdef1234567890",
- "https://ga.jspm.io/npm:object-assign@4.1.1/index.js" => "sha384-1234567890abcdef"
- }, result[:integrity])
- end
end
end