Skip to content

Commit

Permalink
[import_from_git] Add Git basic authorization support (fastlane#22135)
Browse files Browse the repository at this point in the history
* Add git_basic_authorization to clone command

* Add param description

* Update description

* Update README

* Fix doc syntax

* fix PR comments

* Fix incorrect method parameter name

Also updates the parameter documentation.

* Make documentation a bit more clearer

* Refactor: Add missing type to the dependencies option

* Allow specifying multiple HTTP headers for git

* Refactor: Move local variable close to its usage

* Refactor: Made command construction more consistent

* Refactor: Made command construction more consistent

* Fix too many arguments crash on Windows

* Refactor: Make condition clearer

* Fix vulnerable git clone command execution

---------

Co-authored-by: Jens Kuhr Hansen <[email protected]>
Co-authored-by: Iulian Onofrei <[email protected]>
  • Loading branch information
3 people authored Oct 25, 2024
1 parent c5f10c2 commit ec78d7d
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 10 deletions.
15 changes: 11 additions & 4 deletions fastlane/lib/fastlane/actions/import_from_git.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ def self.available_options
default_value: 'HEAD',
optional: true),
FastlaneCore::ConfigItem.new(key: :dependencies,
description: "The array of additional Fastfiles in the repository",
default_value: [],
optional: true),
description: "The array of additional Fastfiles in the repository",
default_value: [],
type: Array,
optional: true),
FastlaneCore::ConfigItem.new(key: :path,
description: "The path of the Fastfile in the repository",
default_value: 'fastlane/Fastfile',
Expand All @@ -43,6 +44,11 @@ def self.available_options
optional: true),
FastlaneCore::ConfigItem.new(key: :cache_path,
description: "The path to a directory where the repository should be cloned into. Defaults to `nil`, which causes the repository to be cloned on every call, to a temporary directory",
optional: true),
FastlaneCore::ConfigItem.new(key: :git_extra_headers,
description: "An optional list of custom HTTP headers to access the git repo (`Authorization: Basic <YOUR BASE64 KEY>`, `Cache-Control: no-cache`, etc.)",
default_value: [],
type: Array,
optional: true)
]
end
Expand All @@ -68,7 +74,8 @@ def self.example_code
branch: "HEAD", # The branch to checkout on the repository.
path: "fastlane/Fastfile", # The path of the Fastfile in the repository.
version: [">= 1.1.0", "< 2.0.0"], # The version to checkout on the repository. Multiple conditions can be used to select the latest version within constraints.
cache_path: "~/.cache/fastlane/imported" # A directory in which the repository will be added, which means that it will not be cloned again on subsequent calls.
cache_path: "~/.cache/fastlane/imported", # A directory in which the repository will be added, which means that it will not be cloned again on subsequent calls.
git_extra_headers: ["Authorization: Basic <YOUR BASE64 KEY>", "Cache-Control: no-cache"]
)'
]
end
Expand Down
15 changes: 9 additions & 6 deletions fastlane/lib/fastlane/fast_file.rb
Original file line number Diff line number Diff line change
Expand Up @@ -278,7 +278,8 @@ def find_tag(folder: nil, version: nil, remote: false)
# @param version [String, Array] Version requirement for repo tags
# @param dependencies [Array] An optional array of additional Fastfiles in the repository
# @param cache_path [String] An optional path to a directory where the repository should be cloned into
def import_from_git(url: nil, branch: 'HEAD', path: 'fastlane/Fastfile', version: nil, dependencies: [], cache_path: nil) # rubocop:disable Metrics/PerceivedComplexity
# @param git_extra_headers [Array] An optional array of custom HTTP headers to access the git repo (`Authorization: Basic <YOUR BASE64 KEY>`, `Cache-Control: no-cache`, etc.)
def import_from_git(url: nil, branch: 'HEAD', path: 'fastlane/Fastfile', version: nil, dependencies: [], cache_path: nil, git_extra_headers: []) # rubocop:disable Metrics/PerceivedComplexity
UI.user_error!("Please pass a path to the `import_from_git` action") if url.to_s.length == 0

Actions.execute_action('import_from_git') do
Expand All @@ -297,8 +298,6 @@ def import_from_git(url: nil, branch: 'HEAD', path: 'fastlane/Fastfile', version
import_block = proc do |target_path|
clone_folder = File.join(target_path, repo_name)

branch_option = "--branch #{branch}" if branch != 'HEAD'

checkout_dependencies = dependencies.map(&:shellescape).join(" ")

# If the current call is eligible for caching, we check out all the
Expand All @@ -309,12 +308,16 @@ def import_from_git(url: nil, branch: 'HEAD', path: 'fastlane/Fastfile', version
if Dir[clone_folder].empty?
UI.message("Cloning remote git repo...")
Helper.with_env_values('GIT_TERMINAL_PROMPT' => '0') do
command = ['git', 'clone', url, clone_folder, '--no-checkout']
# When using cached clones, we need the entire repository history
# so we can switch between tags or branches instantly, or else,
# it would defeat the caching's purpose.
depth = is_eligible_for_caching ? "" : "--depth 1"

Actions.sh("git clone #{url.shellescape} #{clone_folder.shellescape} #{depth} --no-checkout #{branch_option}")
command += ['--depth', '1'] unless is_eligible_for_caching
command += ['--branch', branch] unless branch == 'HEAD'
git_extra_headers.each do |header|
command += ['--config', "http.extraHeader=#{header}"]
end
Actions.sh(*command)
end
end

Expand Down
23 changes: 23 additions & 0 deletions fastlane/spec/actions_specs/import_from_git_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -305,6 +305,29 @@ def self.is_supported?(platform)
end
end

it "works with one HTTP header" do
header = 'Authorization: Basic my_base_64_key'

allow(Fastlane::Actions).to receive(:sh).and_call_original
expect(Fastlane::Actions).to receive(:sh).with(any_args, '--config', "http.extraHeader=#{header}")

Fastlane::FastFile.new.parse("lane :test do
import_from_git(url: '#{source_directory_path}', git_extra_headers: ['#{header}'])
end").runner.execute(:test)
end

it "works with two HTTP headers" do
first_header = 'Authorization: Basic my_base_64_key'
second_header = 'Cache-Control: no-cache'

allow(Fastlane::Actions).to receive(:sh).and_call_original
expect(Fastlane::Actions).to receive(:sh).with(any_args, '--config', "http.extraHeader=#{first_header}", '--config', "http.extraHeader=#{second_header}")

Fastlane::FastFile.new.parse("lane :test do
import_from_git(url: '#{source_directory_path}', git_extra_headers: ['#{first_header}', '#{second_header}'])
end").runner.execute(:test)
end

after :all do
ENV.delete("FORCE_SH_DURING_TESTS")

Expand Down

0 comments on commit ec78d7d

Please sign in to comment.