fluidattacks_core_git/clone/
codecommit.rs1use anyhow::Result;
2use std::path::Path;
3use tokio::process::Command;
4
5use super::{build_clone_args, reason, redirect_config, CloneOpts};
6use crate::aws;
7use crate::types::CredentialKind;
8
9pub async fn clone_codecommit(opts: &CloneOpts, dest: &Path) -> Result<()> {
10 let (arn, external_id, via) = match &opts.credentials.as_ref().map(|c| &c.kind) {
11 Some(CredentialKind::AwsRole {
12 arn,
13 external_id,
14 via,
15 }) => (arn.as_str(), external_id.as_str(), via.as_deref()),
16 _ => anyhow::bail!("expected AwsRole credentials for CodeCommit clone"),
17 };
18
19 let creds = aws::assume_role(arn, external_id, &opts.repo_url, via).await?;
20
21 reason::run(
22 Command::new("git")
23 .args(clone_args(opts, dest))
24 .env("AWS_ACCESS_KEY_ID", &creds.access_key)
25 .env("AWS_SECRET_ACCESS_KEY", &creds.secret_key)
26 .env("AWS_SESSION_TOKEN", &creds.session_token)
27 .env("AWS_DEFAULT_REGION", &creds.region),
28 &[],
29 )
30 .await?;
31
32 Ok(())
33}
34
35fn clone_args(opts: &CloneOpts, dest: &Path) -> Vec<std::ffi::OsString> {
36 build_clone_args(
37 opts,
38 &opts.repo_url,
39 dest,
40 &redirect_config(opts.follow_redirects),
41 )
42}
43
44#[cfg(test)]
45mod tests {
46 use std::path::Path;
47
48 use super::clone_args;
49 use crate::clone::tests::opts;
50 use crate::clone::{CloneOpts, CloneShape};
51
52 #[test]
53 fn a_redirect_is_followed_only_when_the_root_asks_for_one() {
54 for follow_redirects in [false, true] {
55 let opts = CloneOpts {
56 follow_redirects,
57 ..opts(CloneShape::SingleBranch)
58 };
59
60 let args = clone_args(&opts, Path::new("/tmp/a_root"));
61
62 let config = format!("http.followRedirects={follow_redirects}");
63 assert!(args.windows(2).any(|pair| pair == ["-c", config.as_str()]));
64 }
65 }
66}