← back to jdx__fnox

Function bodies 391 total

All specs Real LLM only Function bodies
main function · rust · L10-L26 (17 LOC)
build.rs
fn main() {
    // Tell Cargo to rerun this build script if settings.toml changes
    println!("cargo:rerun-if-changed=settings.toml");

    // Tell Cargo to rerun this build script if any provider toml changes
    println!("cargo:rerun-if-changed=providers");
    for entry in std::fs::read_dir("providers").unwrap().flatten() {
        println!("cargo:rerun-if-changed={}", entry.path().display());
    }

    // Generate settings code
    generate_settings::generate().expect("Failed to generate settings code");

    // Generate provider code
    generate_providers::generate().expect("Failed to generate provider code");
}
prompt_and_run_auth function · rust · L17-L72 (56 LOC)
src/auth_prompt.rs
pub fn prompt_and_run_auth(
    config: &Config,
    provider_config: &ProviderConfig,
    provider_name: &str,
    error: &FnoxError,
) -> Result<bool> {
    // Check if we should prompt
    if !config.should_prompt_auth() {
        return Ok(false);
    }

    // Get the auth command for this provider
    let Some(auth_command) = provider_config.default_auth_command() else {
        return Ok(false);
    };

    // Show the error and prompt
    eprintln!(
        "Authentication failed for provider '{}': {}",
        provider_name, error
    );

    let user_confirmed = Confirm::new(format!("Run `{}` to authenticate?", auth_command))
        .affirmative("Yes")
        .negative("No")
        .run()
        .map_err(|e| FnoxError::Provider(format!("Failed to show prompt: {}", e)))?;

    if !user_confirmed {
        return Ok(false);
    }

    // Run the auth command
    eprintln!("Running: {}", auth_command);

    let status = if cfg!(target_os = "windows") {
        Command::new("
assert_command_order function · rust · L52-L60 (9 LOC)
src/clap_sort.rs
pub fn assert_command_order(cmd: &Command) {
    assert_subcommands_sorted(cmd);
    assert_arguments_sorted(cmd);

    // Recursively check subcommands
    for subcmd in cmd.get_subcommands() {
        assert_command_order(subcmd);
    }
}
format_diff function · rust · L63-L78 (16 LOC)
src/clap_sort.rs
fn format_diff<T: std::fmt::Display>(current: &[T], expected: &[T]) -> String {
    let mut output = String::new();

    output.push_str("\n\n");
    output.push_str("Current order:\n");
    for item in current {
        output.push_str(&format!("  • {}\n", item));
    }

    output.push_str("\nExpected order:\n");
    for item in expected {
        output.push_str(&format!("  • {}\n", item));
    }

    output
}
assert_subcommands_sorted function · rust · L81-L95 (15 LOC)
src/clap_sort.rs
fn assert_subcommands_sorted(cmd: &Command) {
    let subcommand_names: Vec<&str> = cmd.get_subcommands().map(|c| c.get_name()).collect();

    let mut sorted_names = subcommand_names.clone();
    sorted_names.sort_unstable();

    if subcommand_names != sorted_names {
        let diff = format_diff(&subcommand_names, &sorted_names);
        let error = OrderingError {
            command: cmd.get_name().to_string(),
            details: format!("Subcommands must be sorted alphabetically.{}", diff),
        };
        panic!("{:?}", miette::Report::new(error));
    }
}
assert_arguments_sorted function · rust · L101-L259 (159 LOC)
src/clap_sort.rs
fn assert_arguments_sorted(cmd: &Command) {
    let args: Vec<&Arg> = cmd.get_arguments().collect();

    let mut positional = Vec::new();
    let mut with_short = Vec::new();
    let mut long_only = Vec::new();

    for arg in &args {
        if arg.is_positional() {
            positional.push(*arg);
        } else if arg.get_short().is_some() {
            with_short.push(*arg);
        } else if arg.get_long().is_some() {
            long_only.push(*arg);
        }
    }

    // Check positional args are sorted
    let positional_ids: Vec<&str> = positional.iter().map(|a| a.get_id().as_str()).collect();
    let mut sorted_positional = positional_ids.clone();
    sorted_positional.sort_unstable();

    if positional_ids != sorted_positional {
        let diff = format_diff(&positional_ids, &sorted_positional);
        let error = OrderingError {
            command: cmd.get_name().to_string(),
            details: format!(
                "Positional arguments must be sorted alphabe
test_correctly_sorted_subcommands_pass function · rust · L267-L275 (9 LOC)
src/clap_sort.rs
    fn test_correctly_sorted_subcommands_pass() {
        let cli = Command::new("test")
            .subcommand(Command::new("alpha"))
            .subcommand(Command::new("beta"))
            .subcommand(Command::new("zebra"));

        // Should not panic
        assert_command_order(&cli);
    }
Powered by Repobility — scan your code at https://repobility.com
test_incorrectly_sorted_subcommands_panic function · rust · L279-L286 (8 LOC)
src/clap_sort.rs
    fn test_incorrectly_sorted_subcommands_panic() {
        let cli = Command::new("test")
            .subcommand(Command::new("zebra"))
            .subcommand(Command::new("alpha"))
            .subcommand(Command::new("beta"));

        assert_command_order(&cli);
    }
test_correctly_sorted_arguments_pass function · rust · L289-L309 (21 LOC)
src/clap_sort.rs
    fn test_correctly_sorted_arguments_pass() {
        let cli = Command::new("test")
            .arg(Arg::new("input")) // Positional
            .arg(
                Arg::new("debug")
                    .short('d')
                    .long("debug")
                    .action(ArgAction::SetTrue),
            )
            .arg(Arg::new("output").short('o').long("output"))
            .arg(
                Arg::new("verbose")
                    .short('v')
                    .long("verbose")
                    .action(ArgAction::SetTrue),
            )
            .arg(Arg::new("age-key-file").long("age-key-file"));

        // Should not panic
        assert_command_order(&cli);
    }
test_incorrectly_grouped_arguments_panic function · rust · L313-L325 (13 LOC)
src/clap_sort.rs
    fn test_incorrectly_grouped_arguments_panic() {
        // Long-only flag before short flag (wrong order)
        let cli = Command::new("test")
            .arg(Arg::new("age-key-file").long("age-key-file"))
            .arg(
                Arg::new("verbose")
                    .short('v')
                    .long("verbose")
                    .action(ArgAction::SetTrue),
            );

        assert_command_order(&cli);
    }
test_short_flags_not_sorted_panic function · rust · L329-L351 (23 LOC)
src/clap_sort.rs
    fn test_short_flags_not_sorted_panic() {
        let cli = Command::new("test")
            .arg(
                Arg::new("zebra")
                    .short('z')
                    .long("zebra")
                    .action(ArgAction::SetTrue),
            )
            .arg(
                Arg::new("alpha")
                    .short('a')
                    .long("alpha")
                    .action(ArgAction::SetTrue),
            )
            .arg(
                Arg::new("beta")
                    .short('b')
                    .long("beta")
                    .action(ArgAction::SetTrue),
            );

        assert_command_order(&cli);
    }
test_long_only_flags_not_sorted_panic function · rust · L355-L362 (8 LOC)
src/clap_sort.rs
    fn test_long_only_flags_not_sorted_panic() {
        let cli = Command::new("test")
            .arg(Arg::new("zebra").long("zebra").action(ArgAction::SetTrue))
            .arg(Arg::new("alpha").long("alpha").action(ArgAction::SetTrue))
            .arg(Arg::new("beta").long("beta").action(ArgAction::SetTrue));

        assert_command_order(&cli);
    }
test_positional_args_not_sorted_panic function · rust · L366-L372 (7 LOC)
src/clap_sort.rs
    fn test_positional_args_not_sorted_panic() {
        let cli = Command::new("test")
            .arg(Arg::new("pos2"))
            .arg(Arg::new("pos1"));

        assert_command_order(&cli);
    }
test_recursive_subcommand_validation function · rust · L375-L384 (10 LOC)
src/clap_sort.rs
    fn test_recursive_subcommand_validation() {
        let cli = Command::new("test").subcommand(
            Command::new("parent")
                .subcommand(Command::new("child-a"))
                .subcommand(Command::new("child-z")),
        );

        // Should not panic - both levels are sorted
        assert_command_order(&cli);
    }
test_recursive_subcommand_validation_fails_deep function · rust · L388-L396 (9 LOC)
src/clap_sort.rs
    fn test_recursive_subcommand_validation_fails_deep() {
        let cli = Command::new("test").subcommand(
            Command::new("parent")
                .subcommand(Command::new("child-z"))
                .subcommand(Command::new("child-a")), // Wrong order
        );

        assert_command_order(&cli);
    }
Open data scored by Repobility · https://repobility.com
test_complete_correctly_ordered_cli function · rust · L399-L421 (23 LOC)
src/clap_sort.rs
    fn test_complete_correctly_ordered_cli() {
        let cli = Command::new("test")
            .arg(Arg::new("file")) // Positional
            .arg(Arg::new("config").short('c').long("config"))
            .arg(Arg::new("profile").short('p').long("profile"))
            .arg(
                Arg::new("verbose")
                    .short('v')
                    .long("verbose")
                    .action(ArgAction::SetTrue),
            )
            .arg(Arg::new("age-key-file").long("age-key-file"))
            .arg(
                Arg::new("no-color")
                    .long("no-color")
                    .action(ArgAction::SetTrue),
            )
            .subcommand(Command::new("alpha"))
            .subcommand(Command::new("beta"));

        // Should not panic - everything is correctly ordered
        assert_command_order(&cli);
    }
test_empty_command function · rust · L424-L429 (6 LOC)
src/clap_sort.rs
    fn test_empty_command() {
        let cli = Command::new("test");

        // Should not panic - no subcommands or args to check
        assert_command_order(&cli);
    }
test_only_subcommands function · rust · L432-L440 (9 LOC)
src/clap_sort.rs
    fn test_only_subcommands() {
        let cli = Command::new("test")
            .subcommand(Command::new("a"))
            .subcommand(Command::new("b"))
            .subcommand(Command::new("c"));

        // Should not panic
        assert_command_order(&cli);
    }
test_only_args function · rust · L443-L460 (18 LOC)
src/clap_sort.rs
    fn test_only_args() {
        let cli = Command::new("test")
            .arg(
                Arg::new("alpha")
                    .short('a')
                    .long("alpha")
                    .action(ArgAction::SetTrue),
            )
            .arg(
                Arg::new("beta")
                    .short('b')
                    .long("beta")
                    .action(ArgAction::SetTrue),
            );

        // Should not panic
        assert_command_order(&cli);
    }
run function · rust · L18-L44 (27 LOC)
src/commands/activate.rs
    pub async fn run(&self) -> Result<()> {
        let shell_name = match &self.shell {
            Some(s) => s.clone(),
            None => shell::detect_shell().ok_or_else(|| {
                anyhow::anyhow!(
                    "Could not detect shell. Please specify shell explicitly: fnox activate <shell>"
                )
            })?,
        };

        let shell = shell::get_shell(Some(&shell_name))?;

        // Get the current executable path
        let exe = std::env::current_exe()
            .or_else(|_| which::which("fnox"))
            .unwrap_or_else(|_| std::path::PathBuf::from("fnox"));

        let opts = ActivateOptions {
            exe,
            no_hook_env: self.no_hook_env,
        };

        let activation_code = shell.activate(opts);
        print!("{}", activation_code);

        Ok(())
    }
run function · rust · L17-L174 (158 LOC)
src/commands/check.rs
    pub async fn run(&self, cli: &Cli, config: Config) -> Result<()> {
        config.validate()?;
        let profile = Config::get_profile(cli.profile.as_deref());

        // Load config
        println!("Checking configuration for profile: {}", profile);

        let mut issues = Vec::new();
        let mut warnings = Vec::new();

        // Check secrets
        if let Ok(secrets) = config.get_secrets(&profile) {
            if secrets.is_empty() {
                warnings.push("No secrets defined in profile".to_string());
            } else {
                println!("Found {} secret(s) in profile", secrets.len());

                for (name, secret_config) in secrets {
                    // Check if secret has a value source
                    if !secret_config.has_value() {
                        match secret_config.if_missing {
                            Some(crate::config::IfMissing::Error) => {
                                issues.push(format!(
                        
run function · rust · L12-L99 (88 LOC)
src/commands/ci_redact.rs
    pub async fn run(&self, cli: &Cli, config: Config) -> Result<()> {
        let profile = Config::get_profile(cli.profile.as_deref());
        tracing::debug!("Redacting secrets from profile '{}'", profile);

        // Check if we're in CI and get the vendor
        let ci_info = ci_info::get();
        if !ci_info.ci {
            return Err(FnoxError::Config(
                "Not running in a CI environment. The ci-redact command is only for CI/CD pipelines.".to_string()
            ));
        }

        // Determine the masking format based on CI vendor
        let mask_fn: MaskFn = match ci_info.vendor {
            Some(ci_info::types::Vendor::GitHubActions) => {
                Box::new(|key: &str, value: &str| {
                    // GitHub Actions doesn't properly handle multiline secrets
                    // Warn the user instead of attempting to mask
                    if value.contains('\n') {
                        tracing::warn!(
                            "Secr
run function · rust · L15-L41 (27 LOC)
src/commands/completion.rs
    pub async fn run(&self, _cli: &Cli) -> Result<()> {
        let output = Command::new("usage")
            .args([
                "g",
                "completion",
                &self.shell,
                "fnox",
                "--usage-cmd",
                "fnox usage",
                "--cache-key",
                env!("CARGO_PKG_VERSION"),
            ])
            .output()?;

        if !output.status.success() {
            let stderr = String::from_utf8_lossy(&output.stderr);
            return Err(crate::error::FnoxError::Config(format!(
                "Failed to generate completions: {}",
                stderr
            )));
        }

        let stdout = String::from_utf8_lossy(&output.stdout);
        print!("{}", stdout);

        Ok(())
    }
Provenance: Repobility (https://repobility.com) — every score reproducible from /scan/
run function · rust · L21-L39 (19 LOC)
src/commands/config_files.rs
    pub async fn run(&self, _cli: &Cli) -> Result<()> {
        let profile = crate::settings::Settings::get().profile.clone();
        let filenames = all_config_filenames(Some(&profile));

        let current_dir = env::current_dir().map_err(|e| {
            crate::error::FnoxError::Config(format!("Failed to get current directory: {}", e))
        })?;

        let mut printed = HashSet::new();
        self.collect_recursive(&current_dir, &filenames, &mut printed)?;

        // Global config is always checked
        let global = Config::global_config_path();
        if global.exists() && printed.insert(global.clone()) {
            println!("{}", global.display());
        }

        Ok(())
    }
collect_recursive function · rust · L40-L85 (46 LOC)
src/commands/config_files.rs
    fn collect_recursive(
        &self,
        dir: &Path,
        filenames: &[String],
        printed: &mut HashSet<PathBuf>,
    ) -> Result<()> {
        let mut found_root = false;

        for filename in filenames {
            let path = dir.join(filename);
            if path.exists() && printed.insert(path.clone()) {
                println!("{}", path.display());

                if let Ok(content) = std::fs::read_to_string(&path)
                    && let Ok(partial) = toml_edit::de::from_str::<PartialConfig>(&content)
                {
                    // Print imported config files
                    for import_path in &partial.import {
                        let import = if Path::new(import_path).is_absolute() {
                            PathBuf::from(import_path)
                        } else {
                            dir.join(import_path)
                        };
                        if import.exists() && printed.insert(import.clone()) {
         
run function · rust · L21-L41 (21 LOC)
src/commands/deactivate.rs
    pub async fn run(&self, _cli: &Cli, _config: Config) -> Result<()> {
        // Check if fnox is activated in the current shell
        if std::env::var("FNOX_SHELL").is_err() {
            anyhow::bail!(
                "fnox is not activated in this shell session.\n\
                 Run the activation command for your shell to enable fnox."
            );
        }

        let shell = shell::get_shell(None)?;

        // First, restore the original environment (unset all loaded secrets)
        let output = clear_old_env(&*shell);
        print!("{}", output);

        // Then output shell-specific deactivation commands
        let deactivate_output = shell.deactivate();
        print!("{}", deactivate_output);

        Ok(())
    }
clear_old_env function · rust · L45-L56 (12 LOC)
src/commands/deactivate.rs
fn clear_old_env(shell: &dyn shell::Shell) -> String {
    // Get the previous session state (if any)
    let prev_session = &*PREV_SESSION;

    // Unset all loaded secrets from the previous session
    let mut output = String::new();
    for key in prev_session.secret_hashes.keys() {
        output.push_str(&shell.unset_env(key));
    }

    output
}
run function · rust · L18-L89 (72 LOC)
src/commands/decrypt.rs
    pub async fn run(&self, cli: &Cli, mut config: Config) -> Result<()> {
        tracing::debug!("Decrypting configuration file");

        if config.encryption.is_none() {
            return Err(FnoxError::EncryptionNotConfigured);
        }

        let encryption_config = config.encryption.as_ref().unwrap();
        tracing::debug!("Using encryption type: {}", encryption_config.key_type);

        if encryption_config.key_type != "age" {
            return Err(FnoxError::UnsupportedEncryptionType {
                encryption_type: encryption_config.key_type.clone(),
            });
        }

        if encryption_config.encrypted_data.is_none() {
            println!("No encrypted data found. Configuration may already be decrypted.");
            return Ok(());
        }

        // Determine identity file path
        let identity_path = if let Some(ref key_path) = self.key {
            key_path.clone()
        } else if let Some(env_key) = (*env::FNOX_AGE_KEY).clone() {
      
decrypt_with_encryptor function · rust · L90-L138 (49 LOC)
src/commands/decrypt.rs
    async fn decrypt_with_encryptor(
        &self,
        cli: &Cli,
        mut config: Config,
        decryptor: AgeEncryptor,
    ) -> Result<()> {
        let encryption_config = config.encryption.as_ref().unwrap();
        let encrypted_data = encryption_config.encrypted_data.as_ref().unwrap();

        // Base64 decode
        use base64::Engine;
        let ciphertext = base64::engine::general_purpose::STANDARD
            .decode(encrypted_data)
            .map_err(|e| FnoxError::AgeDecryptionFailed {
                details: format!("Failed to decode encrypted data: {}", e),
            })?;

        // Decrypt
        let plaintext = decryptor.decrypt(&ciphertext).await.map_err(|e| {
            FnoxError::AgeDecryptionFailed {
                details: e.to_string(),
            }
        })?;

        // Deserialize secrets
        let secrets: HashMap<String, SecretValue> =
            serde_json::from_slice(&plaintext).map_err(|e| FnoxError::AgeDecryptionFailed {
    
run function · rust · L13-L130 (118 LOC)
src/commands/doctor.rs
    pub async fn run(&self, cli: &Cli, config: Config) -> Result<()> {
        let profile = Config::get_profile(cli.profile.as_deref());

        println!("🏥 Fnox Doctor Report");
        println!("====================");
        println!();

        // Config file info
        println!("📄 Configuration:");
        println!("  File: fnox.toml");
        println!("  Profile: {}", profile);

        config.validate()?;
        println!("  Status: ✓ Loaded successfully");
        println!();

        // Secrets info
        println!("🔐 Secrets:");
        match config.get_secrets(&profile) {
            Ok(secrets) => {
                println!("  Count: {}", secrets.len());
                if !secrets.is_empty() {
                    let mut with_values = 0;
                    let mut required = 0;
                    let mut with_providers = 0;

                    for secret in secrets.values() {
                        if secret.has_value() {
                            with_values 
run function · rust · L49-L182 (134 LOC)
src/commands/edit.rs
    pub async fn run(&self, cli: &Cli, config: Config) -> Result<()> {
        let profile = Config::get_profile(cli.profile.as_deref());
        tracing::debug!("Starting enhanced edit with profile: {}", profile);

        // Step 1: Load raw TOML with toml_edit to preserve formatting
        let toml_content =
            fs::read_to_string(&cli.config).map_err(|source| FnoxError::ConfigReadFailed {
                path: cli.config.clone(),
                source,
            })?;
        let doc = toml_content
            .parse::<DocumentMut>()
            .map_err(|e| FnoxError::Config(format!("Failed to parse TOML: {}", e)))?;

        // Step 2: Collect all secrets from all profiles
        let mut all_secrets = Vec::new();

        // Collect secrets from top-level [secrets] section
        if !config.secrets.is_empty() {
            self.collect_secrets(&config, "default", &config.secrets, &mut all_secrets)
                .await?;
        }

        // Collect secrets from al
Repobility · severity-and-effort ranking · https://repobility.com
collect_secrets function · rust · L185-L228 (44 LOC)
src/commands/edit.rs
    async fn collect_secrets(
        &self,
        config: &Config,
        profile: &str,
        secrets: &IndexMap<String, SecretConfig>,
        all_secrets: &mut Vec<SecretEntry>,
    ) -> Result<()> {
        for (key, secret_config) in secrets {
            // Determine provider and check if read-only
            let provider_name = if let Some(prov) = secret_config.provider() {
                Some(prov.to_string())
            } else {
                config.get_default_provider(profile)?
            };

            let (is_read_only, resolved_provider_name) = if let Some(ref prov_name) = provider_name
            {
                let providers = config.get_providers(profile);
                if let Some(provider_config) = providers.get(prov_name) {
                    let provider =
                        get_provider_resolved(config, profile, prov_name, provider_config).await?;
                    let capabilities = provider.capabilities();
                    let is_rea
create_decrypted_temp_file function · rust · L231-L303 (73 LOC)
src/commands/edit.rs
    fn create_decrypted_temp_file(
        &self,
        doc: &DocumentMut,
        all_secrets: &[SecretEntry],
    ) -> Result<NamedTempFile> {
        let mut temp_file = tempfile::Builder::new()
            .suffix(".toml")
            .tempfile()
            .map_err(|e| FnoxError::Config(format!("Failed to create temporary file: {}", e)))?;

        // Set restrictive permissions (Unix only)
        #[cfg(unix)]
        {
            use std::os::unix::fs::PermissionsExt;
            let mut perms = temp_file
                .as_file()
                .metadata()
                .map_err(|e| FnoxError::Config(format!("Failed to get file metadata: {}", e)))?
                .permissions();
            perms.set_mode(0o600);
            temp_file
                .as_file()
                .set_permissions(perms)
                .map_err(|e| FnoxError::Config(format!("Failed to set file permissions: {}", e)))?;
        }

        // Clone the document and replace encrypted values w
reencrypt_secrets function · rust · L337-L385 (49 LOC)
src/commands/edit.rs
    async fn reencrypt_secrets(
        &self,
        config: &Config,
        modified_doc: &mut DocumentMut,
        all_secrets: &[SecretEntry],
    ) -> Result<()> {
        // Create a map of secrets by (profile, key) to avoid collisions
        let secrets_map: HashMap<_, _> = all_secrets
            .iter()
            .map(|s| ((s.profile.clone(), s.key.clone()), s))
            .collect();

        // Process [secrets] section
        if let Some(secrets_table) = modified_doc
            .get_mut("secrets")
            .and_then(|item| item.as_table_mut())
        {
            self.reencrypt_secrets_table(config, secrets_table, "default", &secrets_map)
                .await?;
        }

        // Process [profiles.*] sections
        if let Some(profiles_table) = modified_doc
            .get_mut("profiles")
            .and_then(|item| item.as_table_mut())
        {
            // Collect profile names first to avoid borrow issues
            let profile_names: Vec<_> = p
set_secret_value function · rust · L528-L534 (7 LOC)
src/commands/edit.rs
    fn set_secret_value(item: &mut toml_edit::Item, value: &str) {
        if let Some(inline_table) = item.as_inline_table_mut() {
            inline_table.insert("value", Value::from(value));
        } else if let Some(table) = item.as_table_mut() {
            table.insert("value", toml_edit::value(value));
        }
    }
strip_temp_header function · rust · L537-L544 (8 LOC)
src/commands/edit.rs
    fn strip_temp_header(content: &str) -> String {
        // Only strip if the content starts with our exact header
        // This avoids accidentally removing user comments that happen to match patterns
        content
            .strip_prefix(TEMP_FILE_HEADER)
            .unwrap_or(content)
            .to_string()
    }
run function · rust · L16-L84 (69 LOC)
src/commands/encrypt.rs
    pub async fn run(&self, cli: &Cli, mut config: Config) -> Result<()> {
        tracing::debug!("Encrypting configuration file");

        if config.encryption.is_none() {
            return Err(FnoxError::EncryptionNotConfigured);
        }

        let encryption_config = config.encryption.as_ref().unwrap();
        tracing::debug!("Using encryption type: {}", encryption_config.key_type);

        if encryption_config.key_type != "age" {
            return Err(FnoxError::UnsupportedEncryptionType {
                encryption_type: encryption_config.key_type.clone(),
            });
        }

        // Check if already encrypted
        if encryption_config.encrypted_data.is_some() {
            println!("Configuration is already encrypted.");
            return Ok(());
        }

        // Get recipients
        let recipients = if encryption_config.recipients.is_empty() {
            return Err(FnoxError::AgeNotConfigured);
        } else {
            encryption_config.recipi
run function · rust · L18-L89 (72 LOC)
src/commands/exec.rs
    pub async fn run(&self, cli: &Cli, config: Config) -> Result<()> {
        if self.command.is_empty() {
            return Err(FnoxError::CommandNotSpecified);
        }

        let profile = Config::get_profile(cli.profile.as_deref());
        tracing::debug!("Running command with secrets from profile '{}'", profile);

        // Get the profile secrets
        let profile_secrets = config.get_secrets(&profile)?;

        let mut cmd = Command::new(&self.command[0]);
        if self.command.len() > 1 {
            cmd.args(&self.command[1..]);
        }

        // Resolve secrets using batch resolution for better performance
        let resolved_secrets = resolve_secrets_batch(&config, &profile, &profile_secrets).await?;

        // Keep temp files alive for the duration of the command
        let mut _temp_files: Vec<NamedTempFile> = Vec::new();

        // Add resolved secrets as environment variables
        for (key, value) in resolved_secrets {
            if let Some(value
run function · rust · L58-L146 (89 LOC)
src/commands/export.rs
    pub async fn run(&self, cli: &Cli, config: Config) -> Result<()> {
        let profile = Config::get_profile(cli.profile.as_deref());
        tracing::debug!("Exporting secrets from profile '{}'", profile);

        let profile_secrets = config.get_secrets(&profile)?;

        // Resolve secrets using batch resolution for better performance
        let resolved_secrets = resolve_secrets_batch(&config, &profile, &profile_secrets).await?;

        // Build secrets map, preserving insertion order
        // For file-based secrets, create persistent temp files
        let mut secrets = IndexMap::new();
        for (key, value_opt) in resolved_secrets {
            if let Some(value) = value_opt {
                // Check if this secret should be file-based
                if let Some(secret_config) = profile_secrets.get(&key) {
                    if secret_config.as_file {
                        // Create a persistent temp file for this secret
                        match create_per
Powered by Repobility — scan your code at https://repobility.com
export_as_env function · rust · L147-L163 (17 LOC)
src/commands/export.rs
    fn export_as_env(&self, data: &ExportData) -> Result<String> {
        let mut output = String::new();

        if let Some(metadata) = &data.metadata {
            output.push_str(&format!("# Exported from profile: {}\n", metadata.profile));
            output.push_str(&format!("# Exported at: {}\n", metadata.exported_at));
            output.push_str(&format!("# Total secrets: {}\n", metadata.total_secrets));
            output.push('\n');
        }

        for (key, value) in &data.secrets {
            output.push_str(&format!("export {}='{}'\n", key, value));
        }

        Ok(output)
    }
run function · rust · L15-L58 (44 LOC)
src/commands/get.rs
    pub async fn run(&self, cli: &Cli, config: Config) -> Result<()> {
        let profile = Config::get_profile(cli.profile.as_deref());
        tracing::debug!("Getting secret '{}' from profile '{}'", self.key, profile);

        // Validate the configuration first
        config.validate()?;

        // Get the profile secrets
        let profile_secrets = config.get_secrets(&profile)?;

        // Get the secret config
        let secret_config = profile_secrets.get(&self.key).ok_or_else(|| {
            // Find similar secret names for suggestion
            let available_keys: Vec<_> = profile_secrets.keys().map(|s| s.as_str()).collect();
            let similar = find_similar(&self.key, available_keys);
            let suggestion = format_suggestions(&similar);

            FnoxError::SecretNotFound {
                key: self.key.clone(),
                profile: profile.clone(),
                config_path: config.secret_sources.get(&self.key).cloned(),
                suggest
from_string function · rust · L20-L26 (7 LOC)
src/commands/hook_env.rs
    fn from_string(s: &str) -> Self {
        match s.to_lowercase().as_str() {
            "none" | "off" | "false" | "0" => Self::None,
            "debug" | "verbose" => Self::Debug,
            _ => Self::Normal, // default to normal
        }
    }
run function · rust · L46-L142 (97 LOC)
src/commands/hook_env.rs
    pub async fn run(&self) -> Result<()> {
        // Get settings for output mode
        let settings =
            Settings::try_get().map_err(|e| anyhow::anyhow!("Failed to get settings: {}", e))?;
        let output_mode = OutputMode::from_string(&settings.shell_integration_output);

        // Detect shell
        let shell_name = match &self.shell {
            Some(s) => s.clone(),
            None => shell::detect_shell().unwrap_or_else(|| "bash".to_string()),
        };

        let shell = shell::get_shell(Some(&shell_name))?;

        if output_mode.should_show_debug() {
            eprintln!(
                "fnox: hook-env running in {:?}",
                std::env::current_dir().ok()
            );
        }

        // Check if we can exit early (optimization)
        if hook_env::should_exit_early() {
            if output_mode.should_show_debug() {
                eprintln!("fnox: early exit - no changes detected");
            }
            // Nothing changed, no ou
calculate_changes function · rust · L146-L178 (33 LOC)
src/commands/hook_env.rs
fn calculate_changes(
    old_hashes: &indexmap::IndexMap<String, String>,
    new_secrets: &HashMap<String, String>,
) -> (Vec<(String, String)>, Vec<String>) {
    use crate::hook_env::{PREV_SESSION, hash_secret_value_with_session};

    let mut added = Vec::new();
    let mut removed = Vec::new();

    // Find additions and changes by comparing hashes
    for (key, new_value) in new_secrets {
        // Use the previous session's hash_key for comparison
        let new_hash = hash_secret_value_with_session(&PREV_SESSION, key, new_value);
        match old_hashes.get(key) {
            Some(old_hash) if old_hash == &new_hash => {
                // Hash matches, no change
            }
            _ => {
                // New or changed value (hash differs or key is new)
                added.push((key.clone(), new_value.clone()));
            }
        }
    }

    // Find removals - keys that were in old session but not in new
    for key in old_hashes.keys() {
        if !new_sec
load_secrets_from_config function · rust · L189-L285 (97 LOC)
src/commands/hook_env.rs
async fn load_secrets_from_config() -> Result<LoadedSecrets> {
    use crate::secret_resolver::resolve_secrets_batch;

    // Use load_smart to ensure provider inheritance from parent configs
    // This handles fnox.toml and fnox.local.toml with proper recursion
    let settings =
        Settings::try_get().map_err(|e| anyhow::anyhow!("Failed to get settings: {}", e))?;
    let filenames = crate::config::all_config_filenames(Some(&settings.profile));
    let mut last_error = None;
    let mut config = None;
    for filename in &filenames {
        match Config::load_smart(filename) {
            Ok(c) => {
                config = Some(c);
                break;
            }
            Err(e) => {
                // Only store parse errors (not "file not found" errors)
                // to show detailed error messages for actual config issues
                let is_not_found = matches!(&e, crate::error::FnoxError::ConfigNotFound { .. });
                if !is_not_found {
        
cleanup_old_temp_files function · rust · L288-L303 (16 LOC)
src/commands/hook_env.rs
fn cleanup_old_temp_files(
    old_files: &HashMap<String, String>,
    new_files: &HashMap<String, String>,
) {
    for (key, old_path) in old_files {
        // Only delete if this secret is no longer file-based or has a different path
        if !new_files.contains_key(key) || new_files.get(key) != Some(old_path) {
            if let Err(e) = fs::remove_file(old_path) {
                // Log but don't fail - file might already be deleted
                tracing::debug!("failed to clean up temp file for '{}': {}", key, e);
            } else {
                tracing::debug!("cleaned up temp file for secret '{}'", key);
            }
        }
    }
}
run function · rust · L66-L257 (192 LOC)
src/commands/import.rs
    pub async fn run(&self, cli: &Cli, merged_config: Config) -> Result<()> {
        let profile = Config::get_profile(cli.profile.as_deref());
        tracing::debug!(
            "Importing secrets in {} format into profile '{}'",
            self.format,
            profile
        );

        let input = self.read_input()?;
        let mut secrets = self.parse_input(&input)?;

        // When importing from stdin, --force or --dry-run is required because stdin is consumed
        // by read_input() and won't be available for the confirmation prompt
        // (dry-run doesn't need confirmation since it doesn't modify anything)
        if self.input.is_none() && !self.force && !self.dry_run {
            return Err(FnoxError::ImportStdinRequiresForce);
        }

        // Apply filter if specified
        if let Some(ref filter) = self.filter {
            let regex = Regex::new(filter).map_err(|e| FnoxError::InvalidRegexFilter {
                pattern: filter.clone(),
         
Open data scored by Repobility · https://repobility.com
read_input function · rust · L258-L276 (19 LOC)
src/commands/import.rs
    fn read_input(&self) -> Result<String> {
        if let Some(ref input_path) = self.input {
            // Read from specified file
            let input =
                std::fs::read_to_string(input_path).map_err(|e| FnoxError::ImportReadFailed {
                    path: input_path.clone(),
                    source: e,
                })?;
            Ok(input)
        } else {
            // Read from stdin
            let mut input = String::new();
            io::stdin()
                .read_to_string(&mut input)
                .map_err(|source| FnoxError::StdinReadFailed { source })?;
            Ok(input)
        }
    }
parse_input function · rust · L277-L291 (15 LOC)
src/commands/import.rs
    fn parse_input(&self, input: &str) -> Result<HashMap<String, String>> {
        let source_name = self
            .input
            .as_ref()
            .map(|p| p.display().to_string())
            .unwrap_or_else(|| "<stdin>".to_string());

        match self.format {
            ImportFormat::Env => self.parse_env(input),
            ImportFormat::Json => self.parse_json(input, &source_name),
            ImportFormat::Yaml => self.parse_yaml(input, &source_name),
            ImportFormat::Toml => self.parse_toml(input, &source_name),
        }
    }
parse_env function · rust · L292-L313 (22 LOC)
src/commands/import.rs
    fn parse_env(&self, input: &str) -> Result<HashMap<String, String>> {
        let mut secrets = HashMap::new();

        for line in input.lines() {
            let line = line.trim();

            // Skip empty lines and comments
            if line.is_empty() || line.starts_with('#') {
                continue;
            }

            // Parse export statements and simple KEY=VALUE
            if let Some(export_key_value) = line.strip_prefix("export ") {
                self.parse_key_value(export_key_value, &mut secrets)?;
            } else {
                self.parse_key_value(line, &mut secrets)?;
            }
        }

        Ok(secrets)
    }
page 1 / 8next ›