inline_forms 8.1.53 → 8.1.55

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 698cbe91c323804016404aed86eda2e03d171b2a5df33ab775d3cca68f3d4341
4
- data.tar.gz: 7ea3231464409d606c023f4b34aeeb2212d293abeaefc7a876e5ec488f6dcc8b
3
+ metadata.gz: 7fff4c0c21d69de2e6836a1a6a16e1e293b8c740fe0615a429ab6775f89fd59a
4
+ data.tar.gz: 479db5cb0c201625bc4c5561f1a3188d3e87ce128387c6a7e08c708d749600b2
5
5
  SHA512:
6
- metadata.gz: b2c7081ad209dcb79cc50ffa9cd61eaa920a9e44b609d4460a70df0aecfc65532ade283e4335836d0f824714e76107aa888931992d52f777e96868a28336ca4b
7
- data.tar.gz: 0b7dc0db8f243a6d06467fa353d423252a97c8c33b14940f24264c99aa3d851253d8580a78e2ce0265d856925ae06753da1cb1d8b793c6716014262b03e093eb
6
+ metadata.gz: 20499e3a0edf5819e20dc5a2d6893835acb72a08039df25190f184136c93d8c8904de2c5f6def7d3746dd7a1804eb01f51cc3560bd70d5d196e4a95be62911bf
7
+ data.tar.gz: 809595fc167bab2e5c9015fb034dcc10be2ff6d5dde3b958d24cdf2ae96ed027ed56577342e5e56f4d5e3f6a02311cb7662a736dfe89636456f96961442bb5bb
data/CHANGELOG.md CHANGED
@@ -4,6 +4,35 @@ All notable changes to this project are documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [8.1.55] - 2026-10-04
8
+
9
+ ### Fixed
10
+
11
+ - **Published gems were unreadable for other users.** RubyGems packages each file with its on-disk mode, and `gem install` restores it. The release checkout is group-only (`rw-rw----`), so every file in the published 8.1.53 gems was `0660`. After `gem install` only the installing user and group could read them: for anyone else `require "inline_forms"` failed silently (Bundler swallows that LoadError), so the app died at boot with `uninitialized constant InlineForms`. A Docker image that installs gems as root and runs as another user could not boot at all. Gem builds now package every file as `0644`, or `0755` when the owner may execute it, whatever the checkout's modes: `InlineFormsGemFiles` wraps `Gem::Package#add_files`, and all three gemspecs in this repo load it, so `gem build`, `rake build` and the CI full gate are all covered. validation_hints 8.1.55 has the same fix. 8.1.53 cannot be republished (RubyGems never accepts a version twice), so apps on 8.1.53 should move to 8.1.55.
12
+
13
+ ### Tests
14
+
15
+ - Gem: `test/gem_package_modes_test.rb`: group-only files on disk are packaged `0644`/`0755`, and the inline_forms, inline_forms_installer and inline_forms_schema_edit gemspecs build with every file world-readable.
16
+
17
+ ### Lockstep
18
+
19
+ - validation_hints 8.1.55, inline_forms_installer 8.1.55, inline_forms_schema_edit 8.1.55.
20
+
21
+ ## [8.1.54] - 2026-10-04
22
+
23
+ ### Fixed
24
+
25
+ - **"Forgot your password?" and the password reset page raised.** Devise 5 removed `devise_error_messages!`, and the gem's `devise/passwords/new` and `devise/passwords/edit` still called it, so both pages failed with `undefined method 'devise_error_messages!'` in every generated app. They now render Devise's own `devise/shared/error_messages` partial (`render "devise/shared/error_messages", resource: resource`).
26
+ - **`devise/shared/_header_and_errors`** (not rendered by the gem's own views; kept for host apps that render it). It looked up a translation named after the app (`t application_name`, which renders a translation_missing span), called the removed `devise_error_messages!`, and looked up `inline_forms.devise.` when `@default_message` was unset. It now shows `t('application_name', default: application_name)` like the `inline_forms` layout's title, Devise's error list when the resource has errors, and the `inline_forms.devise.<@default_message>` text only when `@default_message` is set.
27
+
28
+ ### Tests
29
+
30
+ - Example app: `example_app_devise_passwords_test.rb`: the forgot-password and reset-password pages render, an unknown email re-renders the form with Devise's error list, and `_header_and_errors` shows the app name and the resource errors. The engine's dummy app has no Devise, so these tests live in the example app only.
31
+
32
+ ### Lockstep
33
+
34
+ - validation_hints 8.1.54, inline_forms_installer 8.1.54, inline_forms_schema_edit 8.1.54.
35
+
7
36
  ## [8.1.53] - 2026-10-04
8
37
 
9
38
  ### Fixed
@@ -18,7 +18,7 @@
18
18
  }
19
19
  ) do |f| %>
20
20
 
21
- <%= devise_error_messages! %>
21
+ <%= render "devise/shared/error_messages", resource: resource %>
22
22
  <%= f.hidden_field :reset_password_token %>
23
23
 
24
24
  <div class="row">
@@ -18,7 +18,7 @@
18
18
  }
19
19
  ) do |f| %>
20
20
 
21
- <%= devise_error_messages! %>
21
+ <%= render "devise/shared/error_messages", resource: resource %>
22
22
 
23
23
  <div class="row">
24
24
  <div class="columns">
@@ -1,4 +1,11 @@
1
- <div id="large_title"><%= t application_name -%></div>
1
+ <%# Unused by the gem's own devise views; kept for host apps that render it. %>
2
+ <%# Same title source as layouts/inline_forms; Devise 5 dropped %>
3
+ <%# devise_error_messages!, so errors use Devise's own error_messages partial. %>
4
+ <div id="large_title"><%= t('application_name', default: application_name) %></div>
2
5
  <div id="flash_message">
3
- <%= devise_error_messages!.empty? ? t("inline_forms.devise.#{@default_message}") : devise_error_messages! -%>
6
+ <% if resource.errors.any? %>
7
+ <%= render "devise/shared/error_messages", resource: resource %>
8
+ <% elsif @default_message.present? %>
9
+ <%= t("inline_forms.devise.#{@default_message}") %>
10
+ <% end %>
4
11
  </div>
@@ -1,5 +1,8 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
+ require "delegate"
4
+ require "rubygems/package"
5
+
3
6
  module InlineFormsGemFiles
4
7
  INSTALLER_FILE_PREFIXES = %w[
5
8
  bin/inline_forms
@@ -68,4 +71,33 @@ module InlineFormsGemFiles
68
71
  include_installer ? !installer_file : installer_file
69
72
  end
70
73
  end
74
+
75
+ # Mode a file gets inside the .gem: 0755 if the owner may execute it,
76
+ # else 0644. RubyGems packages each file's on-disk mode (File.lstat) and
77
+ # `gem install` restores it, and this checkout is group-only (rw-rw----),
78
+ # so 8.1.53 shipped every file as 0660: only the installing user and group
79
+ # could read the installed gem, `require "inline_forms"` failed silently
80
+ # for anyone else (Bundler swallows the LoadError), and a Docker image that
81
+ # installs as root and runs as another user could not boot.
82
+ def packaged_mode(mode)
83
+ (mode & 0o100).zero? ? 0o644 : 0o755
84
+ end
85
+
86
+ # Wraps the tar writer Gem::Package#add_files writes to, so every file
87
+ # goes in with packaged_mode instead of its on-disk mode.
88
+ class ReadableTar < SimpleDelegator
89
+ def add_file_simple(name, mode, size, &block)
90
+ __getobj__.add_file_simple(name, InlineFormsGemFiles.packaged_mode(mode), size, &block)
91
+ end
92
+ end
93
+
94
+ module ReadablePackage
95
+ def add_files(tar)
96
+ super(ReadableTar.new(tar))
97
+ end
98
+ end
71
99
  end
100
+
101
+ # Loaded by every gemspec in this repo, so `gem build`, `rake build` and the
102
+ # CI full gate all package world-readable files whatever the checkout's modes.
103
+ Gem::Package.prepend(InlineFormsGemFiles::ReadablePackage) unless Gem::Package <= InlineFormsGemFiles::ReadablePackage
@@ -1,5 +1,5 @@
1
1
  # -*- encoding : utf-8 -*-
2
2
 
3
3
  module InlineForms
4
- VERSION = "8.1.53"
4
+ VERSION = "8.1.55"
5
5
  end
@@ -0,0 +1,86 @@
1
+ # frozen_string_literal: true
2
+
3
+ $LOAD_PATH.unshift File.expand_path("../lib", __dir__)
4
+
5
+ require "minitest/autorun"
6
+ require "tmpdir"
7
+ require "zlib"
8
+ require "inline_forms/gem_files"
9
+
10
+ # 8.1.53 shipped every file as 0660 (the checkout's group-only modes), so an
11
+ # installed gem was unreadable for anyone outside the installing user and
12
+ # group. Gem builds now package 0644 / 0755 whatever the on-disk modes.
13
+ class GemPackageModesTest < Minitest::Test
14
+ REPO_ROOT = File.expand_path("..", __dir__)
15
+
16
+ def packaged_modes(gem_path)
17
+ modes = {}
18
+ File.open(gem_path, "rb") do |io|
19
+ Gem::Package::TarReader.new(io).each do |entry|
20
+ next unless entry.full_name == "data.tar.gz"
21
+
22
+ Gem::Package::TarReader.new(Zlib::GzipReader.new(entry)).each do |file|
23
+ modes[file.full_name] = file.header.mode & 0o777
24
+ end
25
+ end
26
+ end
27
+ modes
28
+ end
29
+
30
+ def build(spec, dir, gem_dir)
31
+ gem_path = File.join(gem_dir, "#{spec.full_name}.gem")
32
+ Dir.chdir(dir) do
33
+ package = Gem::Package.new(gem_path)
34
+ package.spec = spec
35
+ Gem::DefaultUserInteraction.use_ui(Gem::SilentUI.new) { package.build(true) }
36
+ end
37
+ gem_path
38
+ end
39
+
40
+ def test_packaged_mode_keeps_only_the_owner_execute_bit
41
+ assert_equal 0o644, InlineFormsGemFiles.packaged_mode(0o100660)
42
+ assert_equal 0o644, InlineFormsGemFiles.packaged_mode(0o100600)
43
+ assert_equal 0o755, InlineFormsGemFiles.packaged_mode(0o100770)
44
+ assert_equal 0o755, InlineFormsGemFiles.packaged_mode(0o100700)
45
+ end
46
+
47
+ def test_group_only_files_are_packaged_world_readable
48
+ Dir.mktmpdir do |src|
49
+ Dir.mktmpdir do |out|
50
+ File.write(File.join(src, "plain.rb"), "# plain\n")
51
+ File.write(File.join(src, "tool"), "#!/bin/sh\n")
52
+ File.chmod(0o660, File.join(src, "plain.rb"))
53
+ File.chmod(0o700, File.join(src, "tool"))
54
+
55
+ spec = Gem::Specification.new do |s|
56
+ s.name = "modes_probe"
57
+ s.version = "0.0.1"
58
+ s.summary = "probe"
59
+ s.authors = ["probe"]
60
+ s.files = %w[plain.rb tool]
61
+ end
62
+
63
+ modes = packaged_modes(build(spec, src, out))
64
+
65
+ assert_equal({ "plain.rb" => 0o644, "tool" => 0o755 }, modes)
66
+ end
67
+ end
68
+ end
69
+
70
+ def test_every_gemspec_in_the_repo_packages_world_readable_files
71
+ %w[inline_forms.gemspec inline_forms_installer.gemspec
72
+ inline_forms_schema_edit/inline_forms_schema_edit.gemspec].each do |gemspec|
73
+ path = File.join(REPO_ROOT, gemspec)
74
+ spec = Gem::Specification.load(path)
75
+ refute_nil spec, gemspec
76
+
77
+ Dir.mktmpdir do |out|
78
+ modes = packaged_modes(build(spec, File.dirname(path), out))
79
+
80
+ refute_empty modes, gemspec
81
+ unreadable = modes.reject { |_, mode| (mode & 0o444) == 0o444 }
82
+ assert_empty unreadable, "#{gemspec}: not world-readable in the .gem"
83
+ end
84
+ end
85
+ end
86
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inline_forms
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.1.53
4
+ version: 8.1.55
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ace Suares
@@ -308,6 +308,7 @@ files:
308
308
  - test/dummy/config/initializers/paper_trail_yaml_safe_load.rb
309
309
  - test/dummy/config/routes.rb
310
310
  - test/form_element_from_callee_test.rb
311
+ - test/gem_package_modes_test.rb
311
312
  - test/inline_edit_polymorphic_path_test.rb
312
313
  - test/inline_forms_addto_generator_test.rb
313
314
  - test/inline_forms_generator_test.rb
@@ -388,6 +389,7 @@ test_files:
388
389
  - test/dummy/config/initializers/paper_trail_yaml_safe_load.rb
389
390
  - test/dummy/config/routes.rb
390
391
  - test/form_element_from_callee_test.rb
392
+ - test/gem_package_modes_test.rb
391
393
  - test/inline_edit_polymorphic_path_test.rb
392
394
  - test/inline_forms_addto_generator_test.rb
393
395
  - test/inline_forms_generator_test.rb