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