forked from mirrors/kingfisher
- Updating to support Bitbucket App Passwords
- Improved boundaries for several rules - Added more rules
This commit is contained in:
parent
42797b747d
commit
17e0ca3594
11 changed files with 245 additions and 37 deletions
|
|
@ -4,6 +4,7 @@ use std::{
|
|||
};
|
||||
|
||||
use tracing::{debug, debug_span};
|
||||
use url::Url;
|
||||
|
||||
use crate::{bitbucket::is_bitbucket_access_token, git_url::GitUrl};
|
||||
|
||||
|
|
@ -101,6 +102,8 @@ pub struct Git {
|
|||
credentials: Vec<String>,
|
||||
ignore_certs: bool,
|
||||
bitbucket_access_token: Option<String>,
|
||||
bitbucket_env: Vec<(String, String)>,
|
||||
bitbucket_basic_auth: Option<(String, String)>,
|
||||
}
|
||||
|
||||
impl Git {
|
||||
|
|
@ -110,23 +113,60 @@ impl Git {
|
|||
pub fn new(ignore_certs: bool) -> Self {
|
||||
let mut credentials = Vec::new();
|
||||
|
||||
fn normalized_env_var(name: &str) -> Option<String> {
|
||||
std::env::var(name)
|
||||
.ok()
|
||||
.map(|value| value.trim().to_owned())
|
||||
.filter(|value| !value.is_empty())
|
||||
}
|
||||
|
||||
let bitbucket_username = normalized_env_var("KF_BITBUCKET_USERNAME");
|
||||
let bitbucket_app_password = normalized_env_var("KF_BITBUCKET_APP_PASSWORD");
|
||||
let bitbucket_token = normalized_env_var("KF_BITBUCKET_TOKEN");
|
||||
let bitbucket_password = normalized_env_var("KF_BITBUCKET_PASSWORD");
|
||||
let bitbucket_oauth_token = normalized_env_var("KF_BITBUCKET_OAUTH_TOKEN");
|
||||
|
||||
let mut bitbucket_env = Vec::new();
|
||||
for (key, value) in [
|
||||
("KF_BITBUCKET_USERNAME", bitbucket_username.as_ref()),
|
||||
("KF_BITBUCKET_APP_PASSWORD", bitbucket_app_password.as_ref()),
|
||||
("KF_BITBUCKET_TOKEN", bitbucket_token.as_ref()),
|
||||
("KF_BITBUCKET_PASSWORD", bitbucket_password.as_ref()),
|
||||
("KF_BITBUCKET_OAUTH_TOKEN", bitbucket_oauth_token.as_ref()),
|
||||
] {
|
||||
if let Some(value) = value {
|
||||
bitbucket_env.push((key.to_string(), value.to_string()));
|
||||
}
|
||||
}
|
||||
|
||||
let has_github_token =
|
||||
matches!(std::env::var("KF_GITHUB_TOKEN"), Ok(token) if !token.is_empty());
|
||||
let has_gitlab_token =
|
||||
matches!(std::env::var("KF_GITLAB_TOKEN"), Ok(token) if !token.is_empty());
|
||||
let has_gitea_token =
|
||||
matches!(std::env::var("KF_GITEA_TOKEN"), Ok(token) if !token.is_empty());
|
||||
let has_bitbucket_username =
|
||||
matches!(std::env::var("KF_BITBUCKET_USERNAME"), Ok(value) if !value.is_empty());
|
||||
let bitbucket_access_token = std::env::var("KF_BITBUCKET_TOKEN")
|
||||
.ok()
|
||||
.filter(|value| !value.is_empty() && is_bitbucket_access_token(value));
|
||||
let has_bitbucket_password =
|
||||
["KF_BITBUCKET_APP_PASSWORD", "KF_BITBUCKET_TOKEN", "KF_BITBUCKET_PASSWORD"]
|
||||
.iter()
|
||||
.any(|key| matches!(std::env::var(key), Ok(value) if !value.is_empty()));
|
||||
let has_bitbucket_oauth_token =
|
||||
matches!(std::env::var("KF_BITBUCKET_OAUTH_TOKEN"), Ok(value) if !value.is_empty());
|
||||
let bitbucket_access_token =
|
||||
bitbucket_token.as_ref().filter(|token| is_bitbucket_access_token(token)).cloned();
|
||||
let bitbucket_basic_password = bitbucket_app_password
|
||||
.clone()
|
||||
.or(bitbucket_token.clone())
|
||||
.or(bitbucket_password.clone());
|
||||
let bitbucket_basic_auth = if let Some(token) = bitbucket_oauth_token.clone() {
|
||||
Some(("x-token-auth".to_string(), token))
|
||||
} else if let Some(token) = bitbucket_access_token.clone() {
|
||||
Some(("x-token-auth".to_string(), token))
|
||||
} else if let (Some(username), Some(password)) =
|
||||
(bitbucket_username.clone(), bitbucket_basic_password)
|
||||
{
|
||||
Some((username, password))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let has_bitbucket_username = bitbucket_username.is_some();
|
||||
let has_bitbucket_password = bitbucket_app_password.is_some()
|
||||
|| bitbucket_token.is_some()
|
||||
|| bitbucket_password.is_some();
|
||||
let has_bitbucket_oauth_token = bitbucket_oauth_token.is_some();
|
||||
let has_bitbucket_credentials = has_bitbucket_oauth_token
|
||||
|| bitbucket_access_token.is_some()
|
||||
|| (has_bitbucket_username && has_bitbucket_password);
|
||||
|
|
@ -186,7 +226,13 @@ impl Git {
|
|||
credentials.push(HUGGINGFACE_CREDENTIAL_HELPER.into());
|
||||
}
|
||||
|
||||
Self { credentials, ignore_certs, bitbucket_access_token }
|
||||
Self {
|
||||
credentials,
|
||||
ignore_certs,
|
||||
bitbucket_access_token,
|
||||
bitbucket_env,
|
||||
bitbucket_basic_auth,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a basic `git` `Command` with environment variables set to
|
||||
|
|
@ -201,6 +247,9 @@ impl Git {
|
|||
if self.ignore_certs {
|
||||
cmd.env("GIT_SSL_NO_VERIFY", "1");
|
||||
}
|
||||
for (key, value) in &self.bitbucket_env {
|
||||
cmd.env(key, value);
|
||||
}
|
||||
if let Some(token) = &self.bitbucket_access_token {
|
||||
cmd.env("KF_BITBUCKET_ACCESS_TOKEN", token);
|
||||
}
|
||||
|
|
@ -268,11 +317,31 @@ impl Git {
|
|||
cmd.arg("--quiet");
|
||||
cmd.arg("-c");
|
||||
cmd.arg("remote.origin.fetch=+refs/*:refs/remotes/origin/*");
|
||||
cmd.arg(repo_url.as_str());
|
||||
cmd.arg(self.repo_arg_for_clone(repo_url));
|
||||
cmd.arg(output_dir);
|
||||
debug!("{cmd:#?}");
|
||||
self.run_cmd(cmd)
|
||||
}
|
||||
|
||||
fn repo_arg_for_clone(&self, repo_url: &GitUrl) -> String {
|
||||
if let Some((username, password)) = &self.bitbucket_basic_auth {
|
||||
if let Ok(mut url) = Url::parse(repo_url.as_str()) {
|
||||
if url
|
||||
.host_str()
|
||||
.map(|host| host.eq_ignore_ascii_case("bitbucket.org"))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
if url.set_username(username).is_ok()
|
||||
&& url.set_password(Some(password)).is_ok()
|
||||
{
|
||||
return url.into();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
repo_url.as_str().to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Git {
|
||||
|
|
@ -349,6 +418,61 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_repo_arg_for_clone_includes_bitbucket_app_password() {
|
||||
let url =
|
||||
GitUrl::try_from(url::Url::parse("https://bitbucket.org/workspace/demo.git").unwrap())
|
||||
.unwrap();
|
||||
|
||||
temp_env::with_vars(
|
||||
&[
|
||||
("KF_BITBUCKET_USERNAME", Some("user")),
|
||||
("KF_BITBUCKET_APP_PASSWORD", Some("secret")),
|
||||
],
|
||||
|| {
|
||||
let git = Git::new(false);
|
||||
assert_eq!(
|
||||
git.repo_arg_for_clone(&url),
|
||||
"https://user:secret@bitbucket.org/workspace/demo.git"
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_repo_arg_for_clone_uses_token_auth_when_available() {
|
||||
let url =
|
||||
GitUrl::try_from(url::Url::parse("https://bitbucket.org/workspace/demo.git").unwrap())
|
||||
.unwrap();
|
||||
|
||||
temp_env::with_vars(&[("KF_BITBUCKET_OAUTH_TOKEN", Some("token123"))], || {
|
||||
let git = Git::new(false);
|
||||
assert_eq!(
|
||||
git.repo_arg_for_clone(&url),
|
||||
"https://x-token-auth:token123@bitbucket.org/workspace/demo.git"
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_repo_arg_for_clone_leaves_non_bitbucket_urls_untouched() {
|
||||
let url = GitUrl::try_from(
|
||||
url::Url::parse("https://github.com/octocat/Hello-World.git").unwrap(),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
temp_env::with_vars(
|
||||
&[
|
||||
("KF_BITBUCKET_USERNAME", Some("user")),
|
||||
("KF_BITBUCKET_APP_PASSWORD", Some("secret")),
|
||||
],
|
||||
|| {
|
||||
let git = Git::new(false);
|
||||
assert_eq!(git.repo_arg_for_clone(&url), url.as_str());
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_git_new_bitbucket_access_token() {
|
||||
let token = "AT1234567890_ACCESS_TOKEN_EXAMPLE_WITH_UNDERSCORE";
|
||||
|
|
@ -360,6 +484,30 @@ mod tests {
|
|||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_git_new_bitbucket_trims_whitespace() {
|
||||
let trimmed_token = "AT1234567890_ACCESS_TOKEN_EXAMPLE_WITH_UNDERSCORE";
|
||||
let token = format!(" {trimmed_token} \n");
|
||||
|
||||
temp_env::with_vars(
|
||||
&[("KF_BITBUCKET_USERNAME", Some(" user\n")), ("KF_BITBUCKET_TOKEN", Some(&token))],
|
||||
|| {
|
||||
let git = Git::new(false);
|
||||
|
||||
assert_eq!(
|
||||
git.bitbucket_env,
|
||||
vec![
|
||||
("KF_BITBUCKET_USERNAME".to_string(), "user".to_string()),
|
||||
("KF_BITBUCKET_TOKEN".to_string(), trimmed_token.to_string(),),
|
||||
],
|
||||
);
|
||||
assert_eq!(git.credentials.len(), 4);
|
||||
assert!(git.credentials.iter().any(|value| value == BITBUCKET_CREDENTIAL_HELPER));
|
||||
assert_eq!(git.bitbucket_access_token.as_deref(), Some(trimmed_token));
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_clone_mode_arg() {
|
||||
assert_eq!(CloneMode::Bare.arg(), Some("--bare"));
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue