diff options
author | Paul Cristian Sarbu <paul.cristian.sarbu@huawei.com> | 2023-02-13 15:31:01 +0100 |
---|---|---|
committer | Paul Cristian Sarbu <paul.cristian.sarbu@huawei.com> | 2023-03-03 16:21:14 +0100 |
commit | 91f33def73223721ad91f99040158f3ff54dffab (patch) | |
tree | 1781e6e22ff169fafc81697d6502bc9dc9f396cb /src/other_tools/git_operations/git_repo_remote.cpp | |
parent | cab6734ee8d6ffc5a001144aead0ce6c79c90048 (diff) | |
download | justbuild-91f33def73223721ad91f99040158f3ff54dffab.tar.gz |
GitRepoRemote: Correctly honor SSL certification settings in fetch and commit update
Uses the SSL certification utility method to correctly set the
certification check options for the remote URL libgit2 calls.
Due to the fact that remote operations are done via a temporary
repository to allow concurrent work, the correct repository
configuration needs to be interrogated. Thankfully, libgit2
provides a thread safe config snapshot object to be used in
such scenarios.
Also updates the existing GitRepoRemote tests accordingly.
Diffstat (limited to 'src/other_tools/git_operations/git_repo_remote.cpp')
-rw-r--r-- | src/other_tools/git_operations/git_repo_remote.cpp | 139 |
1 files changed, 87 insertions, 52 deletions
diff --git a/src/other_tools/git_operations/git_repo_remote.cpp b/src/other_tools/git_operations/git_repo_remote.cpp index 7d2ee7f4..f599c108 100644 --- a/src/other_tools/git_operations/git_repo_remote.cpp +++ b/src/other_tools/git_operations/git_repo_remote.cpp @@ -17,6 +17,7 @@ #include "fmt/core.h" #include "src/buildtool/file_system/git_utils.hpp" #include "src/buildtool/logging/logger.hpp" +#include "src/other_tools/git_operations/git_config_settings.hpp" extern "C" { #include <git2.h> @@ -67,48 +68,6 @@ void fetch_backend_free(git_odb_backend* /*_backend*/) {} // A backend that can be used to fetch from the remote of another repository. auto const kFetchIntoODBParent = CreateFetchIntoODBParent(); -// callback to enable SSL certificate check for remote fetch -const auto certificate_check_cb = [](git_cert* /*cert*/, - int /*valid*/, - const char* /*host*/, - void* /*payload*/) -> int { return 1; }; - -// callback to remote fetch without an SSL certificate check -const auto certificate_passthrough_cb = [](git_cert* /*cert*/, - int /*valid*/, - const char* /*host*/, - void* /*payload*/) -> int { - return 0; -}; - -/// \brief Set a custom SSL certificate check callback to honor the existing Git -/// configuration of a repository trying to connect to a remote. -[[nodiscard]] auto SetCustomSSLCertificateCheckCallback(git_repository* repo) - -> git_transport_certificate_check_cb { - // check SSL verification settings, from most to least specific - std::optional<int> check_cert{std::nullopt}; - // check gitconfig; ignore errors - git_config* cfg{nullptr}; - int tmp{}; - if (git_repository_config(&cfg, repo) == 0 and - git_config_get_bool(&tmp, cfg, "http.sslVerify") == 0) { - check_cert = tmp; - } - if (not check_cert) { - // check for GIT_SSL_NO_VERIFY environment variable - const char* ssl_no_verify_var{std::getenv("GIT_SSL_NO_VERIFY")}; - if (ssl_no_verify_var != nullptr and - git_config_parse_bool(&tmp, ssl_no_verify_var) == 0) { - check_cert = tmp; - } - } - // cleanup memory - git_config_free(cfg); - // set callback - return (check_cert and check_cert.value() == 0) ? certificate_passthrough_cb - : certificate_check_cb; -} - } // namespace auto GitRepoRemote::Open(GitCASPtr git_cas) noexcept @@ -157,7 +116,8 @@ auto GitRepoRemote::InitAndOpen(std::filesystem::path const& repo_path, return std::nullopt; } -auto GitRepoRemote::GetCommitFromRemote(std::string const& repo_url, +auto GitRepoRemote::GetCommitFromRemote(std::shared_ptr<git_config> cfg, + std::string const& repo_url, std::string const& branch, anon_logger_ptr const& logger) noexcept -> std::optional<std::string> { @@ -183,14 +143,34 @@ auto GitRepoRemote::GetCommitFromRemote(std::string const& repo_url, } auto remote = std::unique_ptr<git_remote, decltype(&remote_closer)>( remote_ptr, remote_closer); + // get the canonical url + auto canonical_url = std::string(git_remote_url(remote.get())); + + // get a well-defined config file + if (not cfg) { + // get config snapshot of current repo (shared with caller) + cfg = GetConfigSnapshot(); + if (cfg == nullptr) { + (*logger)(fmt::format("retrieving config object in get commit " + "from remote failed with:\n{}", + GitLastError()), + true /*fatal*/); + return std::nullopt; + } + } // connect to remote git_remote_callbacks callbacks{}; git_remote_init_callbacks(&callbacks, GIT_REMOTE_CALLBACKS_VERSION); - // set custom SSL verification callback - callbacks.certificate_check = - SetCustomSSLCertificateCheckCallback(GetRepoRef().get()); + // set custom SSL verification callback; use canonicalized url + auto cert_check = + GitConfigSettings::GetSSLCallback(cfg, canonical_url, logger); + if (not cert_check) { + // error occurred while handling the url + return std::nullopt; + } + callbacks.certificate_check = *cert_check; git_proxy_options proxy_opts{}; git_proxy_options_init(&proxy_opts, GIT_PROXY_OPTIONS_VERSION); @@ -251,7 +231,8 @@ auto GitRepoRemote::GetCommitFromRemote(std::string const& repo_url, } } -auto GitRepoRemote::FetchFromRemote(std::string const& repo_url, +auto GitRepoRemote::FetchFromRemote(std::shared_ptr<git_config> cfg, + std::string const& repo_url, std::optional<std::string> const& branch, anon_logger_ptr const& logger) noexcept -> bool { @@ -279,6 +260,24 @@ auto GitRepoRemote::FetchFromRemote(std::string const& repo_url, // wrap remote object auto remote = std::unique_ptr<git_remote, decltype(&remote_closer)>( remote_ptr, remote_closer); + // get the canonical url + auto canonical_url = std::string(git_remote_url(remote.get())); + + // get a well-defined config file + if (not cfg) { + // get config snapshot of current repo + git_config* cfg_ptr{nullptr}; + if (git_repository_config_snapshot(&cfg_ptr, GetRepoRef().get()) != + 0) { + (*logger)(fmt::format("retrieving config object in fetch from " + "remote failed with:\n{}", + GitLastError()), + true /*fatal*/); + return false; + } + // share pointer with caller + cfg.reset(cfg_ptr, config_closer); + } // define default fetch options git_fetch_options fetch_opts{}; @@ -287,9 +286,25 @@ auto GitRepoRemote::FetchFromRemote(std::string const& repo_url, // set the option to auto-detect proxy settings fetch_opts.proxy_opts.type = GIT_PROXY_AUTO; - // set custom SSL verification callback - fetch_opts.callbacks.certificate_check = - SetCustomSSLCertificateCheckCallback(GetRepoRef().get()); + // set custom SSL verification callback; use canonicalized url + if (not cfg) { + // get config snapshot of current repo (shared with caller) + cfg = GetConfigSnapshot(); + if (cfg == nullptr) { + (*logger)(fmt::format("retrieving config object in fetch from " + "remote failed with:\n{}", + GitLastError()), + true /*fatal*/); + return false; + } + } + auto cert_check = + GitConfigSettings::GetSSLCallback(cfg, canonical_url, logger); + if (not cert_check) { + // error occurred while handling the url + return false; + } + fetch_opts.callbacks.certificate_check = *cert_check; // disable update of the FETCH_HEAD pointer fetch_opts.update_fetchhead = 0; @@ -352,7 +367,17 @@ auto GitRepoRemote::UpdateCommitViaTmpRepo( msg), fatal); }); - return tmp_repo->GetCommitFromRemote(repo_url, branch, wrapped_logger); + // get the config of the correct target repo + auto cfg = GetConfigSnapshot(); + if (cfg == nullptr) { + (*logger)(fmt::format("retrieving config object in update commit " + "via tmp repo failed with:\n{}", + GitLastError()), + true /*fatal*/); + return std::nullopt; + } + return tmp_repo->GetCommitFromRemote( + cfg, repo_url, branch, wrapped_logger); } catch (std::exception const& ex) { Logger::Log(LogLevel::Error, "update commit via tmp repo failed with:\n{}", @@ -395,7 +420,17 @@ auto GitRepoRemote::FetchViaTmpRepo(std::filesystem::path const& tmp_repo_path, "While doing branch fetch via tmp repo:\n{}", msg), fatal); }); - return tmp_repo->FetchFromRemote(repo_url, branch, wrapped_logger); + // get the config of the correct target repo + auto cfg = GetConfigSnapshot(); + if (cfg == nullptr) { + (*logger)(fmt::format("retrieving config object in fetch via " + "tmp repo failed with:\n{}", + GitLastError()), + true /*fatal*/); + return false; + } + return tmp_repo->FetchFromRemote( + cfg, repo_url, branch, wrapped_logger); } return false; } catch (std::exception const& ex) { |