Skip to content

Migrate HTTP transport from rest-client to Faraday#113

Merged
deitch merged 1 commit intodeitch:masterfrom
arharovets:replace_restclient_faraday
Mar 19, 2026
Merged

Migrate HTTP transport from rest-client to Faraday#113
deitch merged 1 commit intodeitch:masterfrom
arharovets:replace_restclient_faraday

Conversation

@arharovets
Copy link
Contributor

@arharovets arharovets commented Mar 17, 2026

Hello @deitch ,
It recently came to my attention that rest-client is not stripping private headers like Cookie or Authorization on following http redirects to another host. This allows for a trivial session takeover when the redirecting target host is compromised or has a vulnerability to reply with the request headers somewhere. In addition to that, looks like rest-client is no longer maintained, with the latest commit dated 7 years ago.

This moves the gem onto a maintained HTTP client while keeping the public API stable by replacing rest-client with Faraday.

Changes:

  • add Faraday request/response transport in lib/registry/registry.rb to centralize HTTP handling, normalize responses, and preserve existing registry operations like tags, manifest, blob, and rmtag;
  • reimplement auth challenge handling for anonymous, basic, and bearer flows to keep the old behavior where the client probes anonymously, then retries correctly when the registry responds with WWW-Authenticate;
  • add explicit HTTP error handling via RegistryHTTPException. Faraday does not raise for many non-2xx responses by default, so this restores fail-fast behavior instead of letting callers parse error bodies as success;
  • enable redirect following with standards-compliant semantics - registries commonly redirect blob and manifest requests, and mutating requests must retain their original method across redirects;
  • ensure cross-host redirects do not forward Authorization. This prevents credential leakage to redirected hosts;
  • fix streamed blob downloads so 401 challenge bodies are not written into output files to avoid corrupting downloaded blobs when auth is required;
  • preserve caller-supplied http_options broadly, including string-keyed values - existing integrations may pass config from YAML/JSON or rely on non-symbol keys;
  • restore compatibility for legacy TLS-related http_options as users may still rely on restclient options like verify_ssl, ssl_ca_file, ssl_ca_path, ssl_cert_store, ssl_client_cert, and ssl_client_key;
  • convert legacy mTLS cert/key file paths into openssl objects. Faraday/Net::HTTP expects parsed certificate and key objects, not raw file path strings;
  • add Ruby 3.4 toolchain support dependencies (base64 and benchmark) for development/test - newer Ruby versions no longer expose those stdlib pieces the same way during bundling and test execution;
  • change Gemfile.lock BUNDLED WITH to 2.6.9 to keep bundling compatible with the repo’s supported Ruby 3.0/3.1 CI matrix;
  • update README wording for http_options - the transport layer is now Faraday-based so the documentation should reflect that;
  • add RSpec coverage for redirects, auth retries, streaming, HTTP failures, and http_options compatibility to lock down the migration behavior and prevent regressions in the edge cases found during review.

How to test locally:

bundle install
bundle exec rspec
make test BUILD=local

@deitch
Copy link
Owner

deitch commented Mar 18, 2026

Hi @arharovets ; thanks for this. I don't spend all that much time on this library (as you can tell), but it stays around. I think some parts of Dependabot depend on it (or at least used to), as do some others.

Moving from rest-client to faraday is a good idea. The implementation looks good, but CI is failing.

@arharovets
Copy link
Contributor Author

Hi @arharovets ; thanks for this. I don't spend all that much time on this library (as you can tell), but it stays around. I think some parts of Dependabot depend on it (or at least used to), as do some others.

My team is using it too 🙂

Moving from rest-client to faraday is a good idea. The implementation looks good, but CI is failing.

Yeah, I see that 3.0 build and test are failing. Would it be convenient to you if I update the build matrix by dropping EOL 3.0 and 3.1 and adding 4.0 to the list of Ruby versions?

@deitch
Copy link
Owner

deitch commented Mar 18, 2026

Yeah, I see that 3.0 build and test are failing. Would it be convenient to you if I update the build matrix by dropping EOL 3.0 and 3.1 and adding 4.0 to the list of Ruby versions?

Makes sense to me.

Hey, you are a SuSE guy? Or at least your profile says so? I had lots of dealings with them over the years through various clients. But best not discussed here to mess up the issue. I am at https://linkedIn.com/in/deitcher

@deitch
Copy link
Owner

deitch commented Mar 18, 2026

Some of the other workflow files have the matrix as well, need to be updated.

We probably should make something reusable out of it, but let's get this working first.

@arharovets
Copy link
Contributor Author

Hey, you are a SuSE guy? Or at least your profile says so? I had lots of dealings with them over the years through various clients. But best not discussed here to mess up the issue. I am at https://linkedIn.com/in/deitcher

I am, yes. Let's connect on LinkedIn 🙂

Some of the other workflow files have the matrix as well, need to be updated.

We probably should make something reusable out of it, but let's get this working first.

Yeah, I missed that on the first run. Also, I can see that bundler likely needs to be updated, I'll try that.

@deitch
Copy link
Owner

deitch commented Mar 18, 2026

The only thing it is complaining about is that 3.1 did not run, but you removed it anyways, right? So we can merge?

@arharovets
Copy link
Contributor Author

The only thing it is complaining about is that 3.1 did not run, but you removed it anyways, right? So we can merge?

Thanks a lot for reviewing this!

Yeah, I removed it. I haven't yet updated the version and changelog, should I do that before we merge?

@deitch
Copy link
Owner

deitch commented Mar 18, 2026

I haven't yet updated the version and changelog, should I do that before we merge?

Yup, good call. Tell me when ready, I will hit merge.

- Replace rest-client with Faraday in the runtime dependencies.
  Reason: move the gem onto a maintained HTTP client while keeping the public API stable.
- Add Faraday request/response transport in lib/registry/registry.rb.
  Reason: centralize HTTP handling, normalize responses, and preserve existing registry operations like tags, manifest, blob, and rmtag.
- Reimplement auth challenge handling for anonymous, basic, and bearer flows.
  Reason: keep the old behavior where the client probes anonymously, then retries correctly when the registry responds with WWW-Authenticate.
- Add explicit HTTP error handling via RegistryHTTPException.
  Reason: Faraday does not raise for many non-2xx responses by default, so this restores fail-fast behavior instead of letting callers parse error bodies as success.
- Enable redirect following with standards-compliant semantics.
  Reason: registries commonly redirect blob and manifest requests, and mutating requests must retain their original method across redirects.
- Ensure cross-host redirects do not forward Authorization.
  Reason: prevent credential leakage to redirected hosts.
- Fix streamed blob downloads so 401 challenge bodies are not written into output files.
  Reason: avoid corrupting downloaded blobs when auth is required.
- Preserve caller-supplied http_options broadly, including string-keyed values.
  Reason: existing integrations may pass config from YAML/JSON or rely on non-symbol keys.
- Restore compatibility for legacy TLS-related http_options.
  Reason: users may still rely on RestClient-era options like verify_ssl, ssl_ca_file, ssl_ca_path, ssl_cert_store, ssl_client_cert, and ssl_client_key.
- Convert legacy mTLS cert/key file paths into OpenSSL objects.
  Reason: Faraday/Net::HTTP expects parsed certificate and key objects, not raw file path strings.
- Add Ruby 3.4 toolchain support dependencies (base64, benchmark) for development/test.
  Reason: newer Ruby versions no longer expose those stdlib pieces the same way during bundling and test execution.
- Change Gemfile.lock BUNDLED WITH to 2.6.9.
  Reason: keep bundling compatible with the repo’s supported Ruby 3.0/3.1 CI matrix.
- Update README wording for http_options.
  Why: the transport layer is now Faraday-based, so the documentation should reflect that.
- Add/expand RSpec coverage for redirects, auth retries, streaming, HTTP failures, and http_options compatibility.
  Why: lock down the migration behavior and prevent regressions in the edge cases found during review.
- Drop unsupported Ruby 3.0 and 3.1 from the build matrix, add Ruby 4.0.
- Update bundler.
- Update Dockerfile and test.sh to run Ruby 3.4.9 image.
- Retry v1 manifest requests with legacy Accept header parsefter registry 500.
- Run legacy schema-v1 tests on a registry 2.8.3 image.
- Bump version and add a changelog entry.
@arharovets arharovets force-pushed the replace_restclient_faraday branch from 7e5272e to b1e371b Compare March 19, 2026 09:05
@arharovets
Copy link
Contributor Author

arharovets commented Mar 19, 2026

I haven't yet updated the version and changelog, should I do that before we merge?

Yup, good call. Tell me when ready, I will hit merge.

@deitch
Rebased, bumped the version to 1.19.0 and added a changelog entry. I think it's ready now 👍

@deitch deitch merged commit 63888fc into deitch:master Mar 19, 2026
22 checks passed
@arharovets
Copy link
Contributor Author

@deitch do we need anything else to push 1.19.0 to Rubygems?

@deitch
Copy link
Owner

deitch commented Mar 19, 2026

Darn. I had created a release.yaml workflow file, but I don't think it was fully implemented. I will push it out.

@arharovets
Copy link
Contributor Author

Darn. I had created a release.yaml workflow file, but I don't think it was fully implemented. I will push it out.

Thanks a lot!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants