Skip to content

Commit d821fc5

Browse files
committed
Merge branch 'adjustments-for-cargo'
2 parents 3678a6a + 38ae61a commit d821fc5

File tree

11 files changed

+424
-33
lines changed

11 files changed

+424
-33
lines changed

Diff for: git-repository/src/config/cache/init.rs

+2
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,8 @@ fn apply_environment_overrides(
273273
("GIT_HTTP_PROXY_AUTHMETHOD", "proxyAuthMethod"),
274274
("all_proxy", "all-proxy-lower"),
275275
("ALL_PROXY", "all-proxy"),
276+
("GIT_SSL_CAINFO", "sslCAInfo"),
277+
("GIT_SSL_VERSION", "sslVersion"),
276278
] {
277279
if let Some(value) = var_as_bstring(var, http_transport) {
278280
section.push_with_comment(

Diff for: git-repository/src/config/mod.rs

+10-1
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,11 @@ pub mod transport {
139139
source: git_config::value::Error,
140140
key: &'static str,
141141
},
142+
#[error("Could not interpolate path at key {key:?}")]
143+
InterpolatePath {
144+
source: git_config::path::interpolate::Error,
145+
key: &'static str,
146+
},
142147
#[error("Could not decode value at key {key:?} as UTF-8 string")]
143148
IllformedUtf8 {
144149
key: Cow<'static, BStr>,
@@ -154,7 +159,7 @@ pub mod transport {
154159
pub mod http {
155160
use std::borrow::Cow;
156161

157-
use crate::bstr::BStr;
162+
use crate::bstr::{BStr, BString};
158163

159164
/// The error produced when configuring a HTTP transport.
160165
#[derive(Debug, thiserror::Error)]
@@ -164,6 +169,10 @@ pub mod transport {
164169
InvalidProxyAuthMethod { value: String, key: Cow<'static, BStr> },
165170
#[error("Could not configure the credential helpers for the authenticated proxy url")]
166171
ConfigureProxyAuthenticate(#[from] crate::config::snapshot::credential_helpers::Error),
172+
#[error("The SSL version at key `{key} named {name:?} is unknown")]
173+
InvalidSslVersion { key: &'static str, name: BString },
174+
#[error("The HTTP version at key `{key} named {name:?} is unknown")]
175+
InvalidHttpVersion { key: &'static str, name: BString },
167176
}
168177
}
169178
}

Diff for: git-repository/src/repository/config/transport.rs

+129-12
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ impl crate::Repository {
4747
sync::{Arc, Mutex},
4848
};
4949

50+
use git_transport::client::http::options::{HttpVersion, SslVersion, SslVersionRangeInclusive};
5051
use git_transport::client::{http, http::options::ProxyAuthMethod};
5152

5253
use crate::{bstr::ByteVec, config::cache::util::ApplyLeniency};
@@ -142,6 +143,39 @@ impl crate::Repository {
142143
Ok(value)
143144
}
144145

146+
fn ssl_version(
147+
config: &git_config::File<'static>,
148+
key: &'static str,
149+
mut filter: fn(&git_config::file::Metadata) -> bool,
150+
lenient: bool,
151+
) -> Result<Option<SslVersion>, crate::config::transport::Error> {
152+
config
153+
.string_filter_by_key(key, &mut filter)
154+
.filter(|v| !v.is_empty())
155+
.map(|v| {
156+
use git_protocol::transport::client::http::options::SslVersion::*;
157+
Ok(match v.as_ref().as_ref() {
158+
b"default" => Default,
159+
b"tlsv1" => TlsV1,
160+
b"sslv2" => SslV2,
161+
b"sslv3" => SslV3,
162+
b"tlsv1.0" => TlsV1_0,
163+
b"tlsv1.1" => TlsV1_1,
164+
b"tlsv1.2" => TlsV1_2,
165+
b"tlsv1.3" => TlsV1_3,
166+
_ => {
167+
return Err(crate::config::transport::http::Error::InvalidSslVersion {
168+
key,
169+
name: v.into_owned(),
170+
})
171+
}
172+
})
173+
})
174+
.transpose()
175+
.with_leniency(lenient)
176+
.map_err(Into::into)
177+
}
178+
145179
fn proxy(
146180
value: Option<(Cow<'_, BStr>, Cow<'static, BStr>)>,
147181
lenient: bool,
@@ -286,18 +320,101 @@ impl crate::Repository {
286320
opts.connect_timeout =
287321
integer_opt(config, lenient, "gitoxide.http.connectTimeout", "u64", trusted_only)?
288322
.map(std::time::Duration::from_millis);
289-
opts.user_agent = config
290-
.string_filter_by_key("http.userAgent", &mut trusted_only)
291-
.and_then(|v| try_cow_to_string(v, lenient, Cow::Borrowed("http.userAgent".into())).transpose())
292-
.transpose()?
293-
.or_else(|| Some(crate::env::agent().into()));
294-
let key = "gitoxide.http.verbose";
295-
opts.verbose = config
296-
.boolean_filter_by_key(key, &mut trusted_only)
297-
.transpose()
298-
.with_leniency(lenient)
299-
.map_err(|err| crate::config::transport::Error::ConfigValue { source: err, key })?
300-
.unwrap_or_default();
323+
{
324+
let key = "http.userAgent";
325+
opts.user_agent = config
326+
.string_filter_by_key(key, &mut trusted_only)
327+
.and_then(|v| try_cow_to_string(v, lenient, Cow::Borrowed(key.into())).transpose())
328+
.transpose()?
329+
.or_else(|| Some(crate::env::agent().into()));
330+
}
331+
332+
{
333+
let key = "http.version";
334+
opts.http_version = config
335+
.string_filter_by_key(key, &mut trusted_only)
336+
.map(|v| {
337+
Ok(match v.as_ref().as_ref() {
338+
b"HTTP/1.1" => HttpVersion::V1_1,
339+
b"HTTP/2" => HttpVersion::V2,
340+
_ => {
341+
return Err(crate::config::transport::http::Error::InvalidHttpVersion {
342+
name: v.into_owned(),
343+
key,
344+
})
345+
}
346+
})
347+
})
348+
.transpose()?;
349+
}
350+
351+
{
352+
let key = "gitoxide.http.verbose";
353+
opts.verbose = config
354+
.boolean_filter_by_key(key, &mut trusted_only)
355+
.transpose()
356+
.with_leniency(lenient)
357+
.map_err(|err| crate::config::transport::Error::ConfigValue { source: err, key })?
358+
.unwrap_or_default();
359+
}
360+
361+
let may_use_cainfo = {
362+
let key = "http.schannelUseSSLCAInfo";
363+
config
364+
.boolean_filter_by_key(key, &mut trusted_only)
365+
.transpose()
366+
.with_leniency(lenient)
367+
.map_err(|err| crate::config::transport::Error::ConfigValue { source: err, key })?
368+
.unwrap_or(true)
369+
};
370+
371+
if may_use_cainfo {
372+
let key = "http.sslCAInfo";
373+
opts.ssl_ca_info = config
374+
.path_filter_by_key(key, &mut trusted_only)
375+
.map(|p| {
376+
use crate::config::cache::interpolate_context;
377+
p.interpolate(interpolate_context(
378+
self.install_dir().ok().as_deref(),
379+
self.config.home_dir().as_deref(),
380+
))
381+
.map(|cow| cow.into_owned())
382+
})
383+
.transpose()
384+
.with_leniency(lenient)
385+
.map_err(|err| crate::config::transport::Error::InterpolatePath { source: err, key })?;
386+
}
387+
388+
{
389+
opts.ssl_version = ssl_version(config, "http.sslVersion", trusted_only, lenient)?
390+
.map(|v| SslVersionRangeInclusive { min: v, max: v });
391+
let min_max = ssl_version(config, "gitoxide.http.sslVersionMin", trusted_only, lenient)
392+
.and_then(|min| {
393+
ssl_version(config, "gitoxide.http.sslVersionMax", trusted_only, lenient)
394+
.map(|max| min.and_then(|min| max.map(|max| (min, max))))
395+
})?;
396+
if let Some((min, max)) = min_max {
397+
let v = opts.ssl_version.get_or_insert_with(|| SslVersionRangeInclusive {
398+
min: SslVersion::TlsV1_3,
399+
max: SslVersion::TlsV1_3,
400+
});
401+
v.min = min;
402+
v.max = max;
403+
}
404+
}
405+
406+
#[cfg(feature = "blocking-http-transport-curl")]
407+
{
408+
let key = "http.schannelCheckRevoke";
409+
let schannel_check_revoke = config
410+
.boolean_filter_by_key(key, &mut trusted_only)
411+
.transpose()
412+
.with_leniency(lenient)
413+
.map_err(|err| crate::config::transport::Error::ConfigValue { source: err, key })?;
414+
let backend = git_protocol::transport::client::http::curl::Options { schannel_check_revoke };
415+
opts.backend =
416+
Some(Arc::new(Mutex::new(backend)) as Arc<Mutex<dyn Any + Send + Sync + 'static>>);
417+
}
301418

302419
Ok(Some(Box::new(opts)))
303420
}
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
version https://git-lfs.github.com/spec/v1
2-
oid sha256:f90e312e56b67e6da1596b444bb4a266238b28b7ca6744b59f650ab86ec195fa
3-
size 14404
2+
oid sha256:efd00ab741a24adfab823d76b5ae486b4448cbc8ae82ba0d5fd8cf9862782337
3+
size 15232

Diff for: git-repository/tests/fixtures/make_config_repos.sh

+21
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ git init http-config
1414
git config http.proxyAuthMethod basic
1515
git config http.userAgent agentJustForHttp
1616
git config gitoxide.http.connectTimeout 60k
17+
git config http.schannelCheckRevoke true
18+
git config http.sslCAInfo ./CA.pem
19+
git config http.sslVersion sslv2
20+
git config http.version HTTP/1.1
1721
)
1822

1923
git clone --shared http-config http-remote-override
@@ -33,6 +37,23 @@ git init http-no-proxy
3337
git config gitoxide.http.noProxy "no validation done here"
3438
)
3539

40+
git init http-ssl-version-min-max
41+
(cd http-ssl-version-min-max
42+
git config http.sslVersion sslv3
43+
git config gitoxide.http.sslVersionMin tlsv1.1
44+
git config gitoxide.http.sslVersionMax tlsv1.2
45+
)
46+
47+
git init http-ssl-version-default
48+
(cd http-ssl-version-default
49+
git config http.sslVersion default
50+
)
51+
52+
git init http-disabled-cainfo
53+
(cd http-disabled-cainfo
54+
git config http.sslCAInfo ./CA.pem
55+
git config http.schannelUseSSLCAInfo false
56+
)
3657

3758
git init http-proxy-empty
3859
(cd http-proxy-empty

Diff for: git-repository/tests/repository/config/transport_options.rs

+87-5
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,20 @@
44
))]
55
mod http {
66
use git_repository as git;
7-
use git_transport::client::http::options::{FollowRedirects, ProxyAuthMethod};
7+
use git_transport::client::http::options::{
8+
FollowRedirects, HttpVersion, ProxyAuthMethod, SslVersion, SslVersionRangeInclusive,
9+
};
810

911
pub(crate) fn repo(name: &str) -> git::Repository {
12+
repo_opts(name, |opts| opts.strict_config(true))
13+
}
14+
15+
pub(crate) fn repo_opts(
16+
name: &str,
17+
modify: impl FnOnce(git::open::Options) -> git::open::Options,
18+
) -> git::Repository {
1019
let dir = git_testtools::scripted_fixture_read_only("make_config_repos.sh").unwrap();
11-
git::open_opts(dir.join(name), git::open::Options::isolated()).unwrap()
20+
git::open_opts(dir.join(name), modify(git::open::Options::isolated())).unwrap()
1221
}
1322

1423
fn http_options(
@@ -55,6 +64,9 @@ mod http {
5564
user_agent,
5665
connect_timeout,
5766
verbose,
67+
ssl_ca_info,
68+
ssl_version,
69+
http_version,
5870
backend,
5971
} = http_options(&repo, None, "https://example.com/does/not/matter");
6072
assert_eq!(
@@ -75,10 +87,80 @@ mod http {
7587
assert_eq!(connect_timeout, Some(std::time::Duration::from_millis(60 * 1024)));
7688
assert_eq!(no_proxy, None);
7789
assert!(!verbose, "verbose is disabled by default");
90+
assert_eq!(ssl_ca_info.as_deref(), Some(std::path::Path::new("./CA.pem")));
91+
#[cfg(feature = "blocking-http-transport-reqwest")]
92+
{
93+
assert!(
94+
backend.is_none(),
95+
"backed is never set as it's backend specific, rather custom options typically"
96+
)
97+
}
98+
#[cfg(feature = "blocking-http-transport-curl")]
99+
{
100+
let backend = backend
101+
.as_ref()
102+
.map(|b| b.lock().expect("not poisoned"))
103+
.expect("backend is set for curl due to specific options");
104+
match backend.downcast_ref::<git_protocol::transport::client::http::curl::Options>() {
105+
Some(opts) => {
106+
assert_eq!(opts.schannel_check_revoke, Some(true));
107+
}
108+
None => panic!("Correct backend option type is used"),
109+
}
110+
}
111+
112+
let version = SslVersion::SslV2;
113+
assert_eq!(
114+
ssl_version,
115+
Some(SslVersionRangeInclusive {
116+
min: version,
117+
max: version
118+
})
119+
);
120+
assert_eq!(http_version, Some(HttpVersion::V1_1));
121+
}
122+
123+
#[test]
124+
fn http_ssl_cainfo_suppressed_by_() {
125+
let repo = repo("http-disabled-cainfo");
126+
let opts = http_options(&repo, None, "https://example.com/does/not/matter");
78127
assert!(
79-
backend.is_none(),
80-
"backed is never set as it's backend specific, rather custom options typically"
81-
)
128+
opts.ssl_ca_info.is_none(),
129+
"http.schannelUseSSLCAInfo is explicitly set and prevents the ssl_ca_info to be set"
130+
);
131+
}
132+
133+
#[test]
134+
fn http_ssl_version_min_max_overrides_ssl_version() {
135+
let repo = repo("http-ssl-version-min-max");
136+
let opts = http_options(&repo, None, "https://example.com/does/not/matter");
137+
assert_eq!(
138+
opts.ssl_version,
139+
Some(SslVersionRangeInclusive {
140+
min: SslVersion::TlsV1_1,
141+
max: SslVersion::TlsV1_2
142+
})
143+
);
144+
}
145+
146+
#[test]
147+
fn http_ssl_version_default() {
148+
let repo = repo("http-ssl-version-default");
149+
let opts = http_options(&repo, None, "https://example.com/does/not/matter");
150+
assert_eq!(
151+
opts.ssl_version,
152+
Some(SslVersionRangeInclusive {
153+
min: SslVersion::Default,
154+
max: SslVersion::Default
155+
})
156+
);
157+
}
158+
159+
#[test]
160+
fn http_ssl_version_empty_resets_prior_values() {
161+
let repo = repo_opts("http-config", |opts| opts.config_overrides(["http.sslVersion="]));
162+
let opts = http_options(&repo, None, "https://example.com/does/not/matter");
163+
assert!(opts.ssl_version.is_none(), "empty strings reset what was there");
82164
}
83165

84166
#[test]

0 commit comments

Comments
 (0)