Add API key support for git authentication

- Add nixos_config_api_key_file option to NixOS configuration
- Support reading API token from file for private repositories
- Automatically inject token into HTTPS URLs (https://token@host/repo.git)
- Graceful fallback to original URL if key file missing/empty
- Default key file location: /var/lib/cm-dashboard/git-api-key

Usage: echo 'your-api-token' | sudo tee /var/lib/cm-dashboard/git-api-key
This commit is contained in:
Christoffer Martinsson 2025-10-24 19:30:26 +02:00
parent 8978356c49
commit 114ad52ae8
5 changed files with 39 additions and 7 deletions

View File

@ -232,9 +232,9 @@ impl Agent {
error!("Failed to execute service control: {}", e);
}
}
AgentCommand::SystemRebuild { git_url, git_branch, working_dir } => {
AgentCommand::SystemRebuild { git_url, git_branch, working_dir, api_key_file } => {
info!("Processing SystemRebuild command: {} @ {} -> {}", git_url, git_branch, working_dir);
if let Err(e) = self.handle_system_rebuild(&git_url, &git_branch, &working_dir).await {
if let Err(e) = self.handle_system_rebuild(&git_url, &git_branch, &working_dir, api_key_file.as_deref()).await {
error!("Failed to execute system rebuild: {}", e);
}
}
@ -282,7 +282,7 @@ impl Agent {
}
/// Handle NixOS system rebuild commands with git clone approach
async fn handle_system_rebuild(&self, git_url: &str, git_branch: &str, working_dir: &str) -> Result<()> {
async fn handle_system_rebuild(&self, git_url: &str, git_branch: &str, working_dir: &str, api_key_file: Option<&str>) -> Result<()> {
info!("Starting NixOS system rebuild: {} @ {} -> {}", git_url, git_branch, working_dir);
// Enable maintenance mode before rebuild
@ -294,7 +294,7 @@ impl Agent {
}
// Clone or update repository
let git_result = self.ensure_git_repository(git_url, git_branch, working_dir).await;
let git_result = self.ensure_git_repository(git_url, git_branch, working_dir, api_key_file).await;
// Execute nixos-rebuild if git operation succeeded
let rebuild_result = if git_result.is_ok() {
@ -345,9 +345,37 @@ impl Agent {
}
/// Ensure git repository is cloned and up to date
async fn ensure_git_repository(&self, git_url: &str, git_branch: &str, working_dir: &str) -> Result<()> {
async fn ensure_git_repository(&self, git_url: &str, git_branch: &str, working_dir: &str, api_key_file: Option<&str>) -> Result<()> {
use std::path::Path;
// Read API key if provided
let auth_url = if let Some(key_file) = api_key_file {
match tokio::fs::read_to_string(key_file).await {
Ok(api_key) => {
let api_key = api_key.trim();
if !api_key.is_empty() {
// Convert https://gitea.cmtec.se/cm/nixosbox.git to https://token@gitea.cmtec.se/cm/nixosbox.git
if git_url.starts_with("https://") {
let url_without_protocol = &git_url[8..]; // Remove "https://"
format!("https://{}@{}", api_key, url_without_protocol)
} else {
info!("API key provided but URL is not HTTPS, using original URL");
git_url.to_string()
}
} else {
info!("API key file is empty, using original URL");
git_url.to_string()
}
}
Err(e) => {
info!("Could not read API key file {}: {}, using original URL", key_file, e);
git_url.to_string()
}
}
} else {
git_url.to_string()
};
let git_dir = Path::new(working_dir).join(".git");
if git_dir.exists() {
@ -372,12 +400,12 @@ impl Agent {
} else {
info!("Cloning git repository from {} (branch: {})", git_url, git_branch);
// Clone repository
// Clone repository with authentication if available
let output = tokio::process::Command::new("git")
.arg("clone")
.arg("--branch")
.arg(git_branch)
.arg(git_url)
.arg(&auth_url) // Use authenticated URL
.arg(working_dir)
.output()
.await?;

View File

@ -109,6 +109,7 @@ pub enum AgentCommand {
git_url: String,
git_branch: String,
working_dir: String,
api_key_file: Option<String>,
},
}

View File

@ -303,6 +303,7 @@ impl Dashboard {
git_url: self.config.system.nixos_config_git_url.clone(),
git_branch: self.config.system.nixos_config_branch.clone(),
working_dir: self.config.system.nixos_config_working_dir.clone(),
api_key_file: self.config.system.nixos_config_api_key_file.clone(),
};
self.zmq_command_sender.send_command(&hostname, agent_command).await?;
}

View File

@ -26,6 +26,7 @@ pub enum AgentCommand {
git_url: String,
git_branch: String,
working_dir: String,
api_key_file: Option<String>,
},
}

View File

@ -28,6 +28,7 @@ pub struct SystemConfig {
pub nixos_config_git_url: String,
pub nixos_config_branch: String,
pub nixos_config_working_dir: String,
pub nixos_config_api_key_file: Option<String>,
}
impl DashboardConfig {