Commit Graph

9068 Commits

Author SHA1 Message Date
Ian C. Anderson b8191db909 Reduce Striing allocations in `xml_name_escape`
When working in a large rails app, I noticed in a flamegraph of a particular request that ~68ms was spent in the `xml_name_escape` method. I also ran an allocation tracer, which showed this method at the top of the list for String allocations.

This patch updates this method to avoid 3 String allocations:
- 2 allocations saved by using gsub! instead of gsub
- 1 allocation saved by concatenating to an existing string instead of allocating a new output string

For a rough benchmark in our rails app, I wrote a test with an allocation tracer around rendering a small view component.
- 244 String allocations before this change
- 228 String allocations from switching to gsub!
- 220 String allocations with this full patch

A ~10% reduction in String allocations in a real-world example seemed like a good justification for this small change.
2022-08-16 20:27:25 +00:00
Jonathan Hefner e8f189b1cb Improve ActiveSupport::ErrorReporter API doc [ci-skip]
This moves some of the documentation from the `ErrorReporter` class
directly to the `handle` and `record` methods, and fleshes those out.
This also tweaks the documentation of the other `ErrorReporter` methods.
2022-08-10 19:08:01 -05:00
Shalvah dd80ab07a8 Update ErrorSubscriber signature
Document `severity` argument.

Change union types syntax; add docs

Trim line

Fix trailing whitespace

Co-authored-by: Hartley McGuire <skipkayhil@gmail.com>
2022-08-10 19:04:55 -05:00
Rafael Mendonça França b8868d6498
Merge pull request #44753 from ghousemohamed/extend-reserved-keywords-list-in-module-delegation
Extends ruby reserved keywords list in Module ext in Active Support
2022-08-09 16:20:45 -03:00
Jonathan Hefner 7563be4d97 Document AS::Cache::MemCacheStore#write options [ci-skip] 2022-08-05 21:36:19 -05:00
Jonathan Hefner 7e884e2996 Document AS::Cache::Store#initialize options [ci-skip] 2022-08-05 21:36:19 -05:00
Jonathan Hefner a95438caff Document AS::Cache::Store#read options [ci-skip] 2022-08-05 21:36:19 -05:00
Jonathan Hefner fc7225afc7 Rewrite AS::Cache::Store#fetch options doc as list [ci-skip] 2022-08-05 21:36:18 -05:00
Jonathan Hefner b55f079f9d Consolidate AS::Cache::Store#write documentation [ci-skip] 2022-08-05 21:36:18 -05:00
Jonathan Hefner dce8b7fe6b Improve rescue_from example [ci-skip] 2022-08-05 21:36:18 -05:00
Jonathan Hefner 32c169d014 Linkify code references [ci-skip] 2022-08-05 21:36:18 -05:00
Jonathan Hefner b13107fe5e Fix typos [ci-skip] 2022-08-05 21:36:18 -05:00
fatkodima b0061a30a0 Improve failure safety for `RedisCacheStore#delete_multi`
For redis cache store, running `Rails.cache.delete_multi(["foo", "bar"])`
will lead to an error when redis is down. Other existing cache store methods
already implement failure safety.
2022-08-04 18:53:10 +03:00
fatkodima 813b58d8f9 Fix flaky tests for RedisCacheStore 2022-08-02 15:39:06 +03:00
fatkodima 6dad6e7604 Fix `Cache::NullStore` with local caching for repeated reads 2022-08-02 03:18:35 +03:00
Jean Boussier e7bc2cb16f
Merge pull request #45717 from stevecrozz/tagged_logging_formatter_method_persistence
TaggedLogging preserves formatter methods
2022-08-01 19:27:12 +02:00
fatkodima e35eb0f779 Optimize increment and decrement for `RedisCacheStore` 2022-08-01 17:23:53 +03:00
Jean Boussier f9fce850da RedisCacheStore: get rid of the Redis::Distributed check
Instead we lazily check for pipelining support. `Redis::Distributed`
immediately raise when `pipelined` is called.

Also instead of using `mset` we use a pipelined. The performance
difference is extremly minimal, but it allows us to re-use `write_entry`
hence more shared code and we can speed up `write_multi` with an
expiry.
2022-08-01 14:33:29 +02:00
Jean Boussier 5aa9d16969 RedisCacheStore: avoid monkey patching redis
ConnectionPool#with is aliased as #then which is equivalent
to Object#then since Ruby 2.5. So if we use that we don't need
to monkey patch anything.
2022-08-01 12:19:14 +02:00
Jean Boussier c617b8f8fd RedisCacheStore: remove unused mget_capable? flag
Ever since its introduction it was never set to false.
2022-08-01 12:00:12 +02:00
Stephen Crosby 77209cc017
TaggedLogging preserves formatter methods
TaggedLogging preserves any methods that exist on the formatter's
singleton class.
2022-07-31 13:46:07 -07:00
Jonathan Hefner 772c462738 Save encrypted config even if YAML is invalid
In #30893, the `credentials:edit` command was changed to prevent saving
invalid YAML:

  ```yaml
  # some_invalid_yaml.yml
  secret_key_base: ...
  - new_key: new value
  ```

  ```console
  $ EDITOR='cp some_invalid_yaml.yml' bin/rails credentials:edit
  ruby-3.1.2/lib/ruby/3.1.0/psych.rb:455:in `parse': (<unknown>): did not find expected key while parsing a block mapping at line 3 column 1 (Psych::SyntaxError)

  $ bin/rails credentials:show
  secret_key_base: ...
  ```

However, throwing away user input is not ideal.  Such behavior can be
particularly troublesome when copying secrets from ephemeral sources.

This commit changes the `credentials:edit` command to always save user
input, and display a helpful warning when saving invalid YAML:

  ```console
  $ EDITOR='cp some_invalid_yaml.yml' bin/rails credentials:edit
  File encrypted and saved.
  WARNING: Invalid YAML in '/path/to/app/config/credentials.yml.enc'.

    (/path/to/app/config/credentials.yml.enc): did not find expected key while parsing a block mapping at line 3 column 1

  Your application will not be able to load 'config/credentials.yml.enc' until the error has been fixed.

  $ bin/rails credentials:show
  # some_invalid_yaml.yml
  secret_key_base: ...
  - new_key: new value
  ```

This commit also applies the same fix to the `encrypted:edit` command.
2022-07-28 16:37:18 -05:00
Jonathan Hefner 1740b1f2cb Generate master.key even when require_master_key
Prior to this commit, if `config.require_master_key` was set to true in
`config/application.rb`, the `credentials:edit` command could not
automatically generate a master key file:

  ```ruby
  # In config/application.rb
  config.require_master_key = true
  ```

  ```console
  # No previously existing credentials
  $ rm config/master.key config/credentials.yml.enc
  ```

  ```console
  $ bin/rails credentials:edit
  activesupport/lib/active_support/encrypted_file.rb:118:in `handle_missing_key': Missing encryption key to decrypt file with. Ask your team for your master key and write it to config/master.key or put it in the ENV['RAILS_MASTER_KEY']. (ActiveSupport::EncryptedFile::MissingKeyError)
  ```

This commit adds a `EncryptedFile#key?` method that can be used to check
for the existence of a key without raising `MissingKeyError`, and the
`credentials:edit` command now uses this method:

  ```console
  $ bin/rails credentials:edit
  Adding config/master.key to store the encryption key: ...

  Save this in a password manager your team can access.

  If you lose the key, no one, including you, can access anything encrypted with it.

        create  config/master.key
  ```

This commit also applies the same fix to the `encrypted:edit` command.
2022-07-27 11:22:41 -05:00
Jonathan Hefner 2af4b98870 Make EncryptedFile more memoization-friendly
Prior to this commit, `EncryptedFile` would internally memoize when a
key file was non-existent.  This meant that a key file generated after
checking `encrypted_file.key.nil?` would not be recognized, unless a new
`EncryptedFile` instance was used.  (Though setting the key in a
designated environment variable instead would entirely bypass this
memoization.)

This commit changes `EncryptedFile` to only memoize when the key file
has been read.  Consequently, this commit memoizes the `EncryptedFile`
(or, specifically, `EncryptedConfiguration`) instance used by
`CredentialsCommand`.

This commit also adds more test coverage around key file generation for
`CredentialsCommand`.
2022-07-25 11:57:04 -05:00
Jonathan Hefner 3d0686a9f6 Document ActiveSupport::EncryptedFile#key [ci-skip] 2022-07-24 18:43:19 -05:00
Jonathan Hefner 789a3648f3
Merge pull request #45619 from pbstriker38/add_skip_nil_to_fetch_multi
Add `skip_nil:` support to `ActiveSupport::Cache::Store#fetch_multi`
2022-07-21 10:33:34 -05:00
Jonathan Hefner aced3bb07b
Merge pull request #45569 from whyinzoo/whyinzoo-update-docs-ActiveSupport--Notification-monotonic-subscribe-for-pr
Add docs for ActiveSupport::Notifications.monotonic_subscribe [ci-skip]
2022-07-21 10:24:06 -05:00
Ryan Zhou e3de7872b1 better docs for ActiveSupport::Notifications.monotonic_subscribe 2022-07-21 03:20:33 +00:00
Daniel Alfaro 1344031d7e Add `skip_nil:` support to `ActiveSupport::Cache::Store#fetch_multi` 2022-07-20 17:02:25 -05:00
John Hawthorn b5a758db1b
Avoid checking defined?(@html_safe) (#45620)
We should not need to check defined? here because we are only interested
in whether @html_safe is truthy or falsy.

We can  use an aliased attr_reader to make this even faster by skipping
both method dispatch.

Co-authored-by: Jean Boussier <jean.boussier@gmail.com>
2022-07-19 15:16:21 -07:00
Jonathan Hefner 4e9fee9629
Merge pull request #45570 from whyinzoo/whyinzoo-update-docs-ActiveSupport--EncryptedFile-read-for-pr
Add docs for ActiveSupport::EncryptedFile#read [ci-skip]
2022-07-18 11:16:44 -05:00
Ryan Zhou d64367e765 better docs for ActiveSupport::EncryptedFile#read 2022-07-16 04:04:42 +00:00
Hartley McGuire 81c5c9971a
Fix extra changelog entry added in 959d46e (#45604)
The :urlsafe option was renamed to :url_safe in 7094d0f and the correct
entry is still below
2022-07-14 17:03:07 -07:00
matt swanson 959d46ef87
Add `quarter` method to date/time (#45009)
Co-authored-by: David Heinemeier Hansson <david@hey.com>
2022-07-14 16:43:52 -07:00
Hartley McGuire 5458571254
Add missing CHANGELOG authors
Ref 44a2971
Ref 9f0b8eb
2022-07-11 01:43:32 -04:00
Jonathan Hefner 7094d0fc43 Rename :urlsafe option to :url_safe
Although Ruby provides `Base64.urlsafe_encode64` and
`Base64.urlsafe_decode64` methods, the technical term is "URL-safe",
with "URL" and "safe" as separate words.

For better readability, this commit renames the `:urlsafe` option for
`MessageEncryptor` and `MessageVerifier` to `:url_safe`.
2022-07-08 15:36:24 -05:00
fatkodima faacccdb75 Clear cache in MemCacheStore tests 2022-07-07 00:25:15 +03:00
Ryo Nakamura 6f9bb2cc0f Fix NoMethodError on custom ActiveSupport::Deprecation behavior
with some additional changes made later:

1. Flip the condition for backward compatibility
   Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>

2. Improve custom behavior test
   Co-authored-by: Jonathan Hefner <jonathan@hefner.pro>

3. Fix indentation
2022-07-06 06:41:41 +09:00
Jonathan Hefner 50402fc2ce
Merge pull request #45473 from jonathanhefner/message_encryptor-urlsafe-option
Support `:urlsafe` option for `MessageEncryptor`
2022-06-29 16:21:12 -05:00
Jonathan Hefner d9823326e8 Support :urlsafe option for MessageEncryptor
This adds a `:urlsafe` option to the `MessageEncryptor` constructor.
When enabled, this option ensures that messages use a URL-safe encoding.
This matches the `MessageVerifier` `:urlsafe` option added in #45419.
2022-06-29 16:00:16 -05:00
Jonathan Hefner 815f5baf14 Refactor message parts logic in MessageEncryptor
Follow-up to #43924.

This commit refactors the logic around assembling and extracting the
parts of a message (namely: the encrypted data, the IV, and the auth
tag).  It also provides a small but reproducible performance increase
for a roundtrip.

Benchmark:

```ruby
require "benchmark/ips"
require "active_support/message_encryptor"

DATA = "x" * 100
ENCRYPTOR = ActiveSupport::MessageEncryptor.new(SecureRandom.random_bytes(32))

Benchmark.ips do |x|
  x.report("roundtrip") do
    ENCRYPTOR.decrypt_and_verify(ENCRYPTOR.encrypt_and_sign(DATA))
  end
end
```

Before:

```
Warming up --------------------------------------
           roundtrip     1.342k i/100ms
Calculating -------------------------------------
           roundtrip     13.525k (± 1.5%) i/s -     68.442k in   5.061532s
```

After:

```
Warming up --------------------------------------
           roundtrip     1.409k i/100ms
Calculating -------------------------------------
           roundtrip     14.125k (± 1.4%) i/s -     71.859k in   5.088419s
```
2022-06-28 14:28:47 -05:00
Jonathan Hefner 73ef37902e Replace MessageVerifier :urlsafe option tests
The `test_urlsafe` test could not fail when `urlsafe: false` because the
serialized input data did not contain a bit sequence that would encode
to a non-URL-safe character.  The `test_no_padding` *could* fail when
`urlsafe: false`, except when the default serializer uses JSON, because
the serialized input data would be a multiple of 3 bytes, thus not
requiring any padding.

This commit replaces those tests with a falsifiable test using a
carefully chosen input string.
2022-06-28 14:19:28 -05:00
Hartley McGuire 31d2468a25
Document that load hooks run if already triggered
After first learning of this in c2a3ff0 and later discussion about cross
component dependencies, it makes sense to document it explicitly.
2022-06-23 17:34:41 -04:00
eileencodes 9766eb4a83
Fix tests for minitest 5.16
In minitest/minitest@6e06ac9 minitest changed such that it now accepts
`kwargs` instead of requiring kwargs to be shoved into the args array.
This is a good change but required some updates to our test code to get
the new version of minitest passing.

Changes are as follows:

1) Lock minitest to 5.15 for Ruby 2.7. We don't love this change but
it's pretty difficult to get 2.7 and 3.0 to play nicely together with
the new kwargs changes. Dropping 2.7 support isn't an option right
now for Rails. This is safe because all of the code changes here are
internal methods to Rails like assert_called_with. Applications
shouldn't be consuming them as they are no-doc'd.
2) Update the `assert_called_with` method to take any kwargs but also
the returns kwarg.
3) Update callers of `assert_called_with` to move the kwargs outside the
args array.
4) Update the message from marshaled exceptions. In 5.16 the exception
message is "result not reported" instead of "Wrapped undumpable
exception".

Co-authored-by: Matthew Draper <matthew@trebex.net>
2022-06-23 08:32:11 -04:00
Jean Boussier 2f5dcb7255
Merge pull request #45424 from shouichi/remove-padding-from-urlsafe-message-verifier
Fix urlsafe MessageVerifier not to include padding
2022-06-22 23:55:23 +02:00
Jonathan Hefner 1003e974ed Tweak MessageVerifier :urlsafe option doc [ci-skip]
Follow-up to #45425.

This fixes a few typos, and slightly adjusts the wording.
2022-06-22 11:21:10 -05:00
Shouichi Kamiya 3234863a83 Document urlsafe option of MessageVerifier
Also clarify that MessageVerifier generates non-urlsafe strings by
default.

[skip ci]
2022-06-22 15:47:21 +09:00
Shouichi Kamiya 08afa160a5 Fix urlsafe MessageVerifier not to include padding
urlsafe option was introduced to MessageVerifier in
09c3f36a96 but it can generate strings
containing padding character ("=") which is not urlsafe.

Fix not to pad when base64 encode.
2022-06-22 15:15:02 +09:00
Shouichi Kamiya 09c3f36a96 Add urlsafe option to MessageVerifier initializer
MessageVerifier uses Base64.strict_encode64 and generated strings are
not urlsafe. Though the goal is to make MessageVerifier generated
strings urlsafe, We can not simply switch to Base64.urlsafe_encode64
because it will be a breaking change. Thus, as a first step, urlsafe
option is added to the MessageVerifier initializer.
2022-06-21 21:40:35 +09:00
John Crepezzi df0de681dc Remove the multi-call form of assert_called_with
The `assert_called_with` helper allows passing a multi-dimensional array to
mock multiple calls to the same method for a given block. This works
fine now, but when adding support for real kwargs arguments to line up with
recent upgrades in Minitest, this approach is no longer workable because
we can't pass multiple sets of differing kwargs.

Rather than complicated this method further, this commit removes the
multi-call form of `assert_called_with` and modifies the tests that
currently make use of that functionality to just use the underlying
`Minitest::Mock` calls.

Co-authored-by: Eileen M. Uchitelle <eileencodes@gmail.com>
2022-06-16 11:13:57 -04:00