fix ssh toml option, fix so it runs error fn

This commit is contained in:
Bryson Steck 2025-03-16 15:49:24 -06:00
parent 6d3ff502a9
commit 54d2d69421
Signed by: bryson
SSH key fingerprint: SHA256:XpKABw/nP4z8UVaH+weLaBnEOD86+cVwif+QjuYLGT4
4 changed files with 84 additions and 60 deletions

View file

@ -5,7 +5,9 @@ pub enum ExitCode {
FilesystemError = 3, FilesystemError = 3,
RepositoryError = 4, RepositoryError = 4,
RemoteError = 5, RemoteError = 5,
PushError = 6 PushError = 6,
FetchError = 7,
ConfigError = 8
} }
pub struct ReturnData { pub struct ReturnData {

View file

@ -49,6 +49,11 @@ impl fmt::Display for ConfigFile {
Some(path) => format!("{}", path) Some(path) => format!("{}", path)
}; };
let ssh_key = match &self.config.git.ssh_identity_file {
Some(k) => k,
None => &format!("Not defined")
};
let schedule_interval = match self.config.schedule.interval { let schedule_interval = match self.config.schedule.interval {
None => { None => {
if !self.config.schedule.enabled { if !self.config.schedule.enabled {
@ -72,7 +77,7 @@ impl fmt::Display for ConfigFile {
Schedule enabled: {}\ Schedule enabled: {}\
{}" {}"
, self.path, self.file.is_file(), self.file.permissions().readonly(), self.config.from , self.path, self.file.is_file(), self.file.permissions().readonly(), self.config.from
, to_list, branches_list, work_dir_path, self.config.git.ssh_identity_file, self.config.schedule.enabled , to_list, branches_list, work_dir_path, ssh_key, self.config.schedule.enabled
, schedule_interval) , schedule_interval)
} }
} }
@ -91,7 +96,7 @@ pub struct Config {
#[derive(PartialEq)] #[derive(PartialEq)]
#[derive(Deserialize)] #[derive(Deserialize)]
pub struct Git { pub struct Git {
pub ssh_identity_file: String, pub ssh_identity_file: Option<String>,
} }
#[derive(PartialEq)] #[derive(PartialEq)]
@ -184,6 +189,10 @@ fn verify_config(config: &Config) -> Result<(), String> {
&& !&config.from.starts_with("https://") && !&config.from.starts_with("https://")
&& !&config.from.starts_with("http://") { && !&config.from.starts_with("http://") {
return Err(format!("'from' value does not use a supported protocol")) return Err(format!("'from' value does not use a supported protocol"))
} else if !&config.from.starts_with("ssh://") {
if let None = &config.git.ssh_identity_file {
return Err(format!("'from' value using ssh, but no ssh identity file was defined"))
}
} }
Ok(()) Ok(())

View file

@ -90,10 +90,12 @@ fn main() -> Result<(), String> {
return Ok(()) return Ok(())
} }
let cfgs = match config::read_config(args.config, &refractr) { let mut cfgs = vec![];
Ok(cfgs) => cfgs, match config::read_config(args.config, &refractr) {
Err(e) => return Err(e) Ok(c) => cfgs = c,
Err(e) => common::error(format!("{}", e), common::ExitCode::ConfigError)
}; };
if refractr.verbose >= 2 { if refractr.verbose >= 2 {
// no need to loop over configs if verbose is not at the correct level // no need to loop over configs if verbose is not at the correct level
for i in &cfgs { for i in &cfgs {
@ -108,5 +110,4 @@ fn main() -> Result<(), String> {
}; };
Ok(()) Ok(())
} }

View file

@ -25,6 +25,7 @@ pub struct Refractr {
struct OpenedRepository { struct OpenedRepository {
repo: Repository, repo: Repository,
path: String, path: String,
ssh: bool,
remotes: Vec<String>, remotes: Vec<String>,
cfg: Config, cfg: Config,
} }
@ -60,35 +61,33 @@ impl Refractr {
Ok(()) Ok(())
} }
fn fetch(&self, repo: &Repository, branches: &Vec<String>, ssh: Option<&String>) -> Result<(), Error> { fn fetch(&self, repo: &Repository, branches: &Vec<String>, ssh: bool, ssh_key: &Option<String>) -> Result<(), Error> {
match ssh { let mut cb = RemoteCallbacks::new();
Some(key) => { let mut fo = FetchOptions::new();
let mut cb = RemoteCallbacks::new(); if ssh {
let mut fo = FetchOptions::new(); let key_string: String = ssh_key.clone().unwrap();
cb.credentials(move |_,_,_| Cred::ssh_key( cb.credentials(move |_,_,_| Cred::ssh_key(
"git", "git",
None, None,
Path::new(&key), Path::new(&key_string),
None)); None));
cb.certificate_check(|cert, url| { cb.certificate_check(|cert, url| {
let mut sha256 = String::new(); let mut sha256 = String::new();
for i in cert.as_hostkey().unwrap().hash_sha256().unwrap().to_vec() { for i in cert.as_hostkey().unwrap().hash_sha256().unwrap().to_vec() {
sha256.push_str(&hex::encode(i.to_string())); sha256.push_str(&hex::encode(i.to_string()));
} }
common::warning( common::warning(
format!("implicitly trusting unknown host {} with sha256 host key {}", format!("implicitly trusting unknown host {} with sha256 host key {}",
url, url,
hex::encode(cert.as_hostkey().unwrap().hash_sha256().unwrap().to_vec()))); hex::encode(cert.as_hostkey().unwrap().hash_sha256().unwrap().to_vec())));
common::warning( common::warning(
format!("to ignore this error in the future, add this host to your known_hosts file")); format!("to ignore this error in the future, add this host to your known_hosts file"));
Ok(CertificateCheckStatus::CertificateOk) Ok(CertificateCheckStatus::CertificateOk)
}); });
fo.download_tags(git2::AutotagOption::All); }
fo.remote_callbacks(cb); fo.download_tags(git2::AutotagOption::All);
repo.find_remote("origin")?.fetch(&branches, Some(&mut fo), None)?; fo.remote_callbacks(cb);
}, repo.find_remote("origin")?.fetch(&branches, Some(&mut fo), None)?;
None => repo.find_remote("origin")?.fetch(&branches, None, None)?
};
Ok(()) Ok(())
} }
@ -129,7 +128,7 @@ impl Refractr {
Ok(remote_list) Ok(remote_list)
} }
fn push_remotes(&self, cfg: &Config, repo: &Repository, remote_list: &Vec<String>) -> Result<(), String> { fn push_remotes(&self, cfg: &Config, ssh: bool, repo: &Repository, remote_list: &Vec<String>) -> Result<(), String> {
for id in remote_list { for id in remote_list {
let mut remote = repo.find_remote(&id).unwrap(); let mut remote = repo.find_remote(&id).unwrap();
common::verbose( common::verbose(
@ -137,24 +136,27 @@ impl Refractr {
1, 1,
format!("Pushing to remote: {}", remote.url().unwrap())); format!("Pushing to remote: {}", remote.url().unwrap()));
let mut callbacks = RemoteCallbacks::new(); let mut callbacks = RemoteCallbacks::new();
callbacks.credentials(|_,_,_| Cred::ssh_key( if ssh {
"git", let key_string: String = cfg.git.ssh_identity_file.clone().unwrap();
None, callbacks.credentials(move |_,_,_| Cred::ssh_key(
&Path::new(&cfg.git.ssh_identity_file), "git",
None)); None,
callbacks.certificate_check(|cert, url| { &Path::new(&key_string),
let mut sha256 = String::new(); None));
for i in cert.as_hostkey().unwrap().hash_sha256().unwrap().to_vec() { callbacks.certificate_check(|cert, url| {
sha256.push_str(&hex::encode(i.to_string())); let mut sha256 = String::new();
} for i in cert.as_hostkey().unwrap().hash_sha256().unwrap().to_vec() {
common::warning( sha256.push_str(&hex::encode(i.to_string()));
format!("implicitly trusting unknown host {} with sha256 host key {}", }
url, common::warning(
hex::encode(cert.as_hostkey().unwrap().hash_sha256().unwrap().to_vec()))); format!("implicitly trusting unknown host {} with sha256 host key {}",
common::warning( url,
format!("to ignore this error in the future, add this host to your known_hosts file")); hex::encode(cert.as_hostkey().unwrap().hash_sha256().unwrap().to_vec())));
Ok(CertificateCheckStatus::CertificateOk) common::warning(
}); format!("to ignore this error in the future, add this host to your known_hosts file"));
Ok(CertificateCheckStatus::CertificateOk)
});
}
let mut push_options = PushOptions::new(); let mut push_options = PushOptions::new();
push_options.remote_callbacks(callbacks); push_options.remote_callbacks(callbacks);
@ -221,6 +223,7 @@ impl Refractr {
let _ = self.fast_forward(&repos[i].path, &repos[i].cfg.branches); let _ = self.fast_forward(&repos[i].path, &repos[i].cfg.branches);
if let Err(e) = self.push_remotes( if let Err(e) = self.push_remotes(
&repos[i].cfg, &repos[i].cfg,
repos[i].ssh,
&repos[i].repo, &repos[i].repo,
&repos[i].remotes) { &repos[i].remotes) {
common::error(e, ExitCode::PushError) common::error(e, ExitCode::PushError)
@ -273,13 +276,14 @@ impl Refractr {
}) })
}; };
let ssh = cfg.config.from.starts_with("ssh://");
let mut builder = RepoBuilder::new(); let mut builder = RepoBuilder::new();
let mut cb = RemoteCallbacks::new(); let mut cb = RemoteCallbacks::new();
let mut fo = FetchOptions::new(); let mut fo = FetchOptions::new();
// make initial clone // make initial clone
if cfg.config.from.starts_with("ssh://") { if ssh {
let key_string = cfg.config.git.ssh_identity_file.clone(); let key_string = cfg.config.git.ssh_identity_file.clone().unwrap();
cb.credentials(move |_,_,_| Cred::ssh_key( cb.credentials(move |_,_,_| Cred::ssh_key(
"git", "git",
None, None,
@ -311,7 +315,9 @@ impl Refractr {
let repo = match builder.clone(&cfg.config.from, Path::new(&repo_dir)) { let repo = match builder.clone(&cfg.config.from, Path::new(&repo_dir)) {
Ok(repo) => repo, Ok(repo) => repo,
Err(e) => { Err(e) => {
println!("{}", e); if e.code() != ErrorCode::Exists {
common::error(format!("failed to clone repo to {}: {}", repo_dir, e), ExitCode::FilesystemError);
}
common::warning(format!("found existing repo at {}, attempting to use", repo_dir)); common::warning(format!("found existing repo at {}, attempting to use", repo_dir));
match self.fast_forward(&repo_dir, &cfg.config.branches) { match self.fast_forward(&repo_dir, &cfg.config.branches) {
Ok(_) => if let Ok(repo) = Repository::open(Path::new(&repo_dir)) { Ok(_) => if let Ok(repo) = Repository::open(Path::new(&repo_dir)) {
@ -331,7 +337,12 @@ impl Refractr {
}; };
self.set_up_refs(&repo, &cfg.config.branches).unwrap(); self.set_up_refs(&repo, &cfg.config.branches).unwrap();
self.fetch(&repo, &cfg.config.branches, Some(&cfg.config.git.ssh_identity_file)).unwrap(); if let Err(e) = self.fetch(&repo,
&cfg.config.branches,
ssh,
&cfg.config.git.ssh_identity_file) {
common::error(format!("failed to fetch repo {}: {}", cfg.config.from, e), ExitCode::FetchError);
}
let remotes = match self.make_remotes(&repo, &cfg) { let remotes = match self.make_remotes(&repo, &cfg) {
Ok(v) => v, Ok(v) => v,
@ -340,7 +351,7 @@ impl Refractr {
msg: e msg: e
}) })
}; };
if let Err(e) = self.push_remotes(&cfg.config, &repo, &remotes) { if let Err(e) = self.push_remotes(&cfg.config, ssh, &repo, &remotes) {
common::error(e, ExitCode::PushError); common::error(e, ExitCode::PushError);
} }
@ -348,6 +359,7 @@ impl Refractr {
loop_repos.push(OpenedRepository { loop_repos.push(OpenedRepository {
repo, repo,
path: repo_dir, path: repo_dir,
ssh: cfg.config.from.starts_with("ssh://"),
remotes, remotes,
cfg: cfg.config cfg: cfg.config
}); });