Skip to content

Commit c6d05b4

Browse files
authored
Merge pull request #9632 from ruby/bundler-9612-git-lfs-smudge
Resolve Git LFS files in git sources from the real remote
2 parents 3b5ded8 + 3515d36 commit c6d05b4

3 files changed

Lines changed: 53 additions & 0 deletions

File tree

bundler/lib/bundler/source/git/git_proxy.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,12 @@ def copy_to(destination, submodules = false)
144144
FileUtils.rm_rf(p)
145145
end
146146
git "clone", "--no-checkout", "--quiet", path.to_s, destination.to_s
147+
# The copy is cloned from the local bare cache, which holds no Git LFS
148+
# objects, so point origin back at the real remote and let git-lfs derive
149+
# its endpoint from there when checking out. Use the credential-filtered
150+
# URI to avoid persisting secrets in the copy's .git/config; auth is left
151+
# to git's credential helper.
152+
git "remote", "set-url", "origin", credential_filtered_uri, dir: destination
147153
File.chmod((File.stat(destination).mode | 0o777) & ~File.umask, destination)
148154
rescue Errno::EEXIST => e
149155
file_path = e.message[%r{.*?((?:[a-zA-Z]:)?/.*)}, 1]

spec/bundler/source/git/git_proxy_spec.rb

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,45 @@
9898
end
9999
end
100100

101+
describe "#copy_to" do
102+
let(:revision) { "abc123" }
103+
let(:destination) { tmp("git-proxy-copy") }
104+
105+
before do
106+
# The bare cache (`path`) is the clone source, so stub it away and only
107+
# exercise the post-clone wiring of the working copy at `destination`.
108+
allow(File).to receive(:stat).and_call_original
109+
allow(File).to receive(:stat).with(destination).and_return(double("File::Stat", mode: 0o755))
110+
allow(File).to receive(:chmod)
111+
allow(git_proxy).to receive(:capture).and_return(["", "", clone_result])
112+
end
113+
114+
it "points the working copy's origin back at the real remote" do
115+
expect(git_proxy).to receive(:capture).with(["remote", "set-url", "origin", uri], destination).and_return(["", "", clone_result])
116+
git_proxy.copy_to(destination)
117+
end
118+
119+
it "does not persist credentials in the working copy's origin" do
120+
Bundler.settings.temporary(uri => "u:p") do
121+
credentialed_uri = "https://u:p@github.com/ruby/rubygems.git"
122+
expect(git_proxy).not_to receive(:capture).with(["remote", "set-url", "origin", credentialed_uri], destination)
123+
expect(git_proxy).to receive(:capture).with(["remote", "set-url", "origin", uri], destination).and_return(["", "", clone_result])
124+
git_proxy.copy_to(destination)
125+
end
126+
end
127+
128+
context "when the remote URI embeds credentials" do
129+
let(:uri) { "https://user:secret@github.com/ruby/rubygems.git" }
130+
131+
it "strips the password before writing origin" do
132+
filtered_uri = "https://user@github.com/ruby/rubygems.git"
133+
expect(git_proxy).not_to receive(:capture).with(["remote", "set-url", "origin", uri], destination)
134+
expect(git_proxy).to receive(:capture).with(["remote", "set-url", "origin", filtered_uri], destination).and_return(["", "", clone_result])
135+
git_proxy.copy_to(destination)
136+
end
137+
end
138+
end
139+
101140
describe "#version" do
102141
context "with a normal version number" do
103142
before do

spec/install/gemfile/git_spec.rb

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,14 @@
3131
expect(out).to eq("WIN")
3232
end
3333

34+
it "points the installed copy's origin at the real remote, not the local cache" do
35+
install_base_gemfile
36+
37+
installed = Pathname.glob(default_bundle_path("bundler/gems/foo-1.0-*")).first
38+
origin = git("config --get remote.origin.url", installed).strip
39+
expect(origin).to eq(lib_path("foo-1.0").to_s)
40+
end
41+
3442
it "does not (yet?) enforce CHECKSUMS" do
3543
build_git "foo"
3644
revision = revision_for(lib_path("foo-1.0"))

0 commit comments

Comments
 (0)