i18n_proofreading 0.12.1 → 1.0.1

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: 22fd6bf49d89c237346f9d8a2a5bc10314e0eab0fd8401dcca45dd96278ca62b
4
- data.tar.gz: ba87b38138192aa1d850203839268109f1fc916c3e12160aa439f703f943336a
3
+ metadata.gz: 1018fa5f4f5be802e224bfc1a8bf5e93b1cff5c9122e854327792a9ffc89c0eb
4
+ data.tar.gz: 48b4c23cef0d8aac0ba47f996be007b259d3354fffa6065a1fea5f820b4802eb
5
5
  SHA512:
6
- metadata.gz: 9d22947ee3ec8bb759537acbdee15e0d1520427f948499cd1cdc9af43eb4b0cf82ca30f35c562d02c4e0bada7813f8215a6ca071ecdb393563b7fca22581177e
7
- data.tar.gz: d71f01a6a53c301f5f15453bdcdc8015ffefedcbd442c08ae0638301591496545776f2c98b424d68ad1b7777f5ea7f682b01c5de83bcba5e60e7a7fab0112d74
6
+ metadata.gz: cb442c1774c324987f44e8a347f74f061cd7ee64388df006f77b4a7d94ff6b6e57844303190f9fce36d7f556d7391160a1ef611e2424fe9a2a090d78638f16df
7
+ data.tar.gz: 3094f3c4160701c912116a499be621486b1f718168450b8030956bb43d3b1864576e7a278a95e948552444969c45835b150f7a05cd50106408bd9b3dfa381587
data/AGENTS.md CHANGED
@@ -5,7 +5,7 @@ Instructions for coding agents. Two audiences:
5
5
  - **[Installing i18n_proofreading into a Rails app](#installing-into-a-rails-app)** — you are working in a host app and were asked to add in-context translation review or a way for someone to suggest better wording.
6
6
  - **[Working on the gem itself](#working-on-the-gem-itself)** — you are working in this repository.
7
7
 
8
- Requirements: Ruby >= 3.2, Rails >= 7.1. The widget needs the CSRF token from `csrf_meta_tags`, which a standard Rails layout already has.
8
+ Requirements: Ruby >= 3.2, Rails >= 7.1 and < 9. The widget needs the CSRF token from `csrf_meta_tags`, which a standard Rails layout already has.
9
9
 
10
10
  **Read this first: the gem never writes to your locale files, and it is not a production tool.** Both are deliberate, and both are covered below.
11
11
 
@@ -137,6 +137,11 @@ The tool's own UI ships in 26 languages, RTL mirrored, and follows system light/
137
137
 
138
138
  ## Working on the gem itself
139
139
 
140
+ The development toolchain is pinned to Ruby 4.0.5 in `mise.toml`. Do not use
141
+ macOS's `/usr/bin/ruby`. In shells, hooks, or automation where mise activation
142
+ is uncertain, explicitly prepend the configured Ruby, for example
143
+ `PATH="$(mise where ruby)/bin:$PATH" bundle exec rake test`.
144
+
140
145
  ```bash
141
146
  bundle exec rake test # minitest, dummy app under test/dummy
142
147
  bundle exec rubocop # must be clean
data/CHANGELOG.md CHANGED
@@ -1,5 +1,40 @@
1
1
  # Changelog
2
2
 
3
+ ## [Unreleased]
4
+
5
+ ## [1.0.1] - 2026-08-11
6
+
7
+ - **A failing `on_submit` hook no longer turns a saved suggestion into a 500.**
8
+ The failure is logged after persistence, so host notifications cannot make
9
+ the review submission appear lost.
10
+ - **Stored page context is now privacy-filtered.** Only bounded HTTP(S) URLs
11
+ without credentials, query strings, or fragments are retained.
12
+
13
+ ## [1.0.0] - 2026-08-11
14
+
15
+ - **The documented integration surface is now the stable 1.x contract.**
16
+ `I18nProofreading.configure`, every generated configuration option,
17
+ `mount_i18n_proofreading`, `i18n_proofreading_tag`, the toggle parameter,
18
+ `I18nProofreading::Suggestion`'s documented fields/status helpers/scopes, and
19
+ the `on_submit` callback will follow semantic versioning. Engine controllers,
20
+ partials, CSS classes and widget internals remain private implementation.
21
+ - **Hosts that load Action View from an initializer boot normally.** `TagHelper`
22
+ is required from `lib` before the engine registers its Action View load hook,
23
+ rather than relying on an `app/helpers` autoload that Rails may not have set
24
+ up yet. A dummy-host initializer now reproduces that early load on every test
25
+ boot. The helper constant and `i18n_proofreading_tag` API are unchanged.
26
+ - Supported combinations are Ruby 3.2 through 4.0 and Rails 7.1 through 8.1.
27
+ Rails now has a `< 9` upper bound: future Rails majors must pass the suite
28
+ before Bundler treats them as supported.
29
+ - Added a security policy and documented the data a suggestion stores, the
30
+ production-off default, private vulnerability reporting, and host-owned
31
+ retention/deletion. Upgrading from 0.12.1 requires no migration or config
32
+ change.
33
+ - Release validation now runs the normal and browser suites, RuboCop, the
34
+ widget syntax check and gem build on Ruby 4.0; it verifies the published
35
+ version and creates the GitHub Release. Generator tests now write only under
36
+ ignored root `tmp/`, so running the suite no longer rewrites tracked fixtures.
37
+
3
38
  ## 0.12.1
4
39
 
5
40
  - **The demo suggestions now teach the review contract.** Pending explains the
@@ -72,8 +107,6 @@
72
107
  does, so a uuid-keyed host gets a uuid table.
73
108
  - A `BackboneTest` now fails the build on any of the above regressing.
74
109
 
75
- ## [Unreleased]
76
-
77
110
  ## [0.10.6]
78
111
 
79
112
  - Added `AGENTS.md`: install and integration instructions written for coding
data/README.md CHANGED
@@ -46,8 +46,8 @@ No layout change needed — the widget injects itself into HTML responses.
46
46
  > `%w[development staging]`, and the review dashboard defaults to development
47
47
  > only. This is not a production tool.
48
48
 
49
- Ruby >= 3.2 · Rails >= 7.1 · CSRF token comes from `csrf_meta_tags`, already in
50
- a standard Rails layout.
49
+ Ruby 3.2–4.0 · Rails 7.1–8.1 · CSRF token comes from `csrf_meta_tags`, already
50
+ in a standard Rails layout.
51
51
 
52
52
  Installing with a coding agent? Point it at [AGENTS.md](AGENTS.md) — the same
53
53
  steps in the order an agent needs them, the gates it tends to get wrong, and the
@@ -273,6 +273,36 @@ to use the localized `i18n_proofreading.pill` key.
273
273
 
274
274
  </details>
275
275
 
276
+ ## Compatibility and public API
277
+
278
+ Starting with 1.0, these documented integration points follow semantic
279
+ versioning: incompatible changes wait for a new major version, while a
280
+ deprecation normally ships in a preceding minor release.
281
+
282
+ - `I18nProofreading.configure` and the configuration options listed above.
283
+ - `mount_i18n_proofreading at:` and the mounted dashboard root.
284
+ - `i18n_proofreading_tag` for hosts that disable automatic injection.
285
+ - The configured toggle parameter and its `true` / `false` behavior.
286
+ - `I18nProofreading::Suggestion` fields documented under Reviewing
287
+ suggestions, `STATUSES`, prefixed status helpers/scopes, and `newest_first`.
288
+ - `on_submit`, called with the saved suggestion.
289
+
290
+ Engine controllers, view partials, CSS classes, generated HTML structure, and
291
+ the JavaScript object behind the widget are implementation details. Integrate
292
+ through the APIs above rather than reopening or linking to those internals.
293
+
294
+ Supported versions are Ruby 3.2 through 4.0 and Rails 7.1 through 8.1. The gem
295
+ depends on Rails `< 9`; support for a future Rails major is released after that
296
+ major passes the compatibility and browser suites.
297
+
298
+ ### Upgrading from 0.12.1
299
+
300
+ Change the version requirement and run `bundle update i18n_proofreading`. No
301
+ database migration, generator, initializer change, or data rewrite is needed.
302
+ The `I18nProofreading::TagHelper` constant and `i18n_proofreading_tag` behavior
303
+ are unchanged; only the helper's internal load location moved so hosts that
304
+ configure Action View during initialization can boot reliably.
305
+
276
306
  ## Security
277
307
 
278
308
  - **Gated on the server** for every marker, endpoint, and injection. Setting
@@ -286,6 +316,12 @@ to use the localized `i18n_proofreading.pill` key.
286
316
  survives Turbo visits.
287
317
  - **Rate-limited per IP** on the submission endpoint (30/min by default,
288
318
  Rails 7.2+).
319
+ - **Host-owned review data.** A row may contain translated text, proposed text,
320
+ a comment, page URL, and optional author fields. The host controls access,
321
+ backups, retention, and deletion.
322
+
323
+ Report vulnerabilities privately through the process in
324
+ [SECURITY.md](SECURITY.md), not through a public issue.
289
325
 
290
326
  ## Development
291
327
 
@@ -296,7 +332,8 @@ bundle exec rake test:system # browser tests (headless Chrome)
296
332
  bundle exec rubocop
297
333
  ```
298
334
 
299
- Tests run against a dummy Rails app in `test/dummy`.
335
+ Tests run against a dummy Rails app in `test/dummy`. CI covers Ruby 3.2–4.0
336
+ against Rails 7.1–8.1, plus the real browser flow on Ruby 4.0.
300
337
 
301
338
  ## One family
302
339
 
data/SECURITY.md ADDED
@@ -0,0 +1,38 @@
1
+ # Security policy
2
+
3
+ ## Supported versions
4
+
5
+ Security fixes are released for the latest 1.x version. If a report also
6
+ affects the newest 0.x release, a backport may be published when the fix is
7
+ small and the affected application cannot upgrade immediately.
8
+
9
+ ## Reporting a vulnerability
10
+
11
+ Please do not open a public issue for a vulnerability. Use
12
+ [GitHub private vulnerability reporting](https://github.com/yshmarov/i18n_proofreading/security/advisories/new)
13
+ and include the affected version, a minimal reproduction, impact, and any known
14
+ workaround. Credentials, session cookies, private application URLs, customer
15
+ text, and production database contents should not be included.
16
+
17
+ Public disclosure should wait until a fixed version is available and affected
18
+ users have had a reasonable opportunity to upgrade.
19
+
20
+ ## Data and deployment boundary
21
+
22
+ The proofreading widget is enabled only in development and staging by default.
23
+ Adding production to `enabled_environments` is unsupported: key marking changes
24
+ rendered application text and the suggestion endpoint is intended for trusted
25
+ review environments.
26
+
27
+ A suggestion can store its translation key, locale, current and proposed text,
28
+ comment, page URL, status, timestamps, and optional host-provided author id and
29
+ label. Host applications own that data, its backups, retention period, access
30
+ controls, and deletion. Delete a suggestion with ordinary Active Record when a
31
+ reviewer or application policy requires erasure:
32
+
33
+ ```ruby
34
+ I18nProofreading::Suggestion.find(id).destroy!
35
+ ```
36
+
37
+ The mounted dashboard is independently protected by `authorize_admin`. Outside
38
+ development it fails closed until the host explicitly grants access.
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'uri'
4
+
3
5
  module I18nProofreading
4
6
  # Who is asking, and the gates that answer it.
5
7
  #
@@ -37,5 +39,23 @@ module I18nProofreading
37
39
 
38
40
  @current_author = I18nProofreading.config.current_user.call(request)
39
41
  end
42
+
43
+ # Browser URLs can carry password-reset tokens, signed ids, and campaign
44
+ # details in their query or fragment. Store only a bounded HTTP(S) location
45
+ # without credentials before it reaches the suggestion table.
46
+ def clean_page_url(value)
47
+ raw = value.to_s
48
+ return if raw.blank? || raw.length > 2_048
49
+
50
+ uri = URI.parse(raw)
51
+ return unless %w[http https].include?(uri.scheme&.downcase)
52
+ return if uri.host.blank? || uri.userinfo.present?
53
+
54
+ uri.query = nil
55
+ uri.fragment = nil
56
+ uri.to_s.first(255)
57
+ rescue URI::InvalidURIError
58
+ nil
59
+ end
40
60
  end
41
61
  end
@@ -37,10 +37,11 @@ module I18nProofreading
37
37
 
38
38
  def create
39
39
  suggestion = Suggestion.new(suggestion_params)
40
+ suggestion.page_url = clean_page_url(suggestion.page_url)
40
41
  attribute_author(suggestion)
41
42
 
42
43
  if suggestion.save
43
- I18nProofreading.config.on_submit.call(suggestion)
44
+ notify_host(suggestion)
44
45
  head :created
45
46
  else
46
47
  render json: { errors: suggestion.errors.full_messages }, status: :unprocessable_entity
@@ -49,6 +50,15 @@ module I18nProofreading
49
50
 
50
51
  private
51
52
 
53
+ # The host's hook must never turn a saved suggestion into a 500 — the
54
+ # suggestion is in the database; notification failures are the host's
55
+ # logs' problem.
56
+ def notify_host(suggestion)
57
+ I18nProofreading.config.on_submit.call(suggestion)
58
+ rescue StandardError => e
59
+ Rails.logger.error("i18n_proofreading: on_submit hook raised #{e.class}: #{e.message}")
60
+ end
61
+
52
62
  def attribute_author(suggestion)
53
63
  author = current_author
54
64
  return unless author
@@ -1,9 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module I18nProofreading
4
- # Lets a host place the widget explicitly (`<%= i18n_proofreading_tag %>` at the end
5
- # of a layout) instead of relying on auto-injection. Renders nothing unless the
6
- # tool is available for the current request.
4
+ # Lets a host place the widget explicitly (`<%= i18n_proofreading_tag %>` at
5
+ # the end of a layout) instead of relying on auto-injection. This lives under
6
+ # lib and is required before the engine registers its Action View load hook:
7
+ # a host initializer may load Action View before Rails sets up application
8
+ # autoloaders, when an app/helpers constant cannot be resolved yet.
7
9
  module TagHelper
8
10
  def i18n_proofreading_tag
9
11
  return ''.html_safe unless I18nProofreading.available?(request)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module I18nProofreading
4
- VERSION = '0.12.1'
4
+ VERSION = '1.0.1'
5
5
  end
@@ -4,6 +4,7 @@ require 'i18n_proofreading/version'
4
4
  require 'i18n_proofreading/configuration'
5
5
  require 'i18n_proofreading/marking'
6
6
  require 'i18n_proofreading/widget'
7
+ require 'i18n_proofreading/tag_helper'
7
8
  require 'i18n_proofreading/middleware'
8
9
  require 'i18n_proofreading/seeds'
9
10
  require 'i18n_proofreading/engine'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: i18n_proofreading
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.12.1
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yaroslav Shmarov
@@ -16,6 +16,9 @@ dependencies:
16
16
  - - ">="
17
17
  - !ruby/object:Gem::Version
18
18
  version: '7.1'
19
+ - - "<"
20
+ - !ruby/object:Gem::Version
21
+ version: '9'
19
22
  type: :runtime
20
23
  prerelease: false
21
24
  version_requirements: !ruby/object:Gem::Requirement
@@ -23,6 +26,9 @@ dependencies:
23
26
  - - ">="
24
27
  - !ruby/object:Gem::Version
25
28
  version: '7.1'
29
+ - - "<"
30
+ - !ruby/object:Gem::Version
31
+ version: '9'
26
32
  description: |
27
33
  A mountable Rails engine that renders each translation alongside its i18n key
28
34
  in development and staging, lets reviewers click any string in the running app
@@ -39,13 +45,13 @@ files:
39
45
  - MIT-LICENSE
40
46
  - README.md
41
47
  - Rakefile
48
+ - SECURITY.md
42
49
  - app/controllers/concerns/i18n_proofreading/request_context.rb
43
50
  - app/controllers/i18n_proofreading/application_controller.rb
44
51
  - app/controllers/i18n_proofreading/dashboard_controller.rb
45
52
  - app/controllers/i18n_proofreading/submissions_controller.rb
46
53
  - app/controllers/i18n_proofreading/suggestions_controller.rb
47
54
  - app/controllers/i18n_proofreading/widgets_controller.rb
48
- - app/helpers/i18n_proofreading/tag_helper.rb
49
55
  - app/models/i18n_proofreading/application_record.rb
50
56
  - app/models/i18n_proofreading/suggestion.rb
51
57
  - app/views/i18n_proofreading/shared/_dashboard.html.erb
@@ -91,6 +97,7 @@ files:
91
97
  - lib/i18n_proofreading/marking.rb
92
98
  - lib/i18n_proofreading/middleware.rb
93
99
  - lib/i18n_proofreading/seeds.rb
100
+ - lib/i18n_proofreading/tag_helper.rb
94
101
  - lib/i18n_proofreading/version.rb
95
102
  - lib/i18n_proofreading/widget.js
96
103
  - lib/i18n_proofreading/widget.rb
@@ -101,6 +108,7 @@ licenses:
101
108
  metadata:
102
109
  source_code_uri: https://github.com/yshmarov/i18n_proofreading
103
110
  changelog_uri: https://github.com/yshmarov/i18n_proofreading/blob/main/CHANGELOG.md
111
+ bug_tracker_uri: https://github.com/yshmarov/i18n_proofreading/issues
104
112
  rubygems_mfa_required: 'true'
105
113
  rdoc_options: []
106
114
  require_paths:
@@ -116,7 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
116
124
  - !ruby/object:Gem::Version
117
125
  version: '0'
118
126
  requirements: []
119
- rubygems_version: 4.0.10
127
+ rubygems_version: 4.0.16
120
128
  specification_version: 4
121
129
  summary: 'In-context i18n proofreading for Rails: click any translated string and
122
130
  suggest a fix.'