fnox 1.25.1

A flexible secret management tool supporting multiple providers and encryption methods
Documentation
#!/usr/bin/env bats

load 'test_helper/common_setup'

# Test that fnox import and fnox remove preserve TOML comments

setup() {
	_common_setup
}

teardown() {
	_common_teardown
}

# Helper function to setup age provider with comments in config
setup_age_with_comments() {
	if ! command -v age-keygen >/dev/null 2>&1; then
		skip "age-keygen not installed"
	fi

	# Generate age key
	local keygen_output
	keygen_output=$(age-keygen -o key.txt 2>&1)
	local public_key
	public_key=$(echo "$keygen_output" | grep "^Public key:" | cut -d' ' -f3)

	# Create config with comments throughout
	cat >fnox.toml <<EOF
# Main configuration file for the project
root = true

# Age encryption provider
[providers.age]
type = "age"
recipients = ["$public_key"]

# Application secrets
[secrets]
# Database connection string
DB_URL= { provider = "age", value = "plaintext-db-url" }
# API key for external service
API_KEY= { provider = "age", value = "plaintext-api-key" }
# End of secrets section
EOF
}

@test "fnox remove preserves comments in fnox.toml" {
	setup_age_with_comments

	# Remove one secret
	assert_fnox_success remove API_KEY

	# Verify all comments are preserved
	run cat fnox.toml
	assert_output --partial "# Main configuration file for the project"
	assert_output --partial "# Age encryption provider"
	assert_output --partial "# Application secrets"
	assert_output --partial "# Database connection string"
	assert_output --partial "# End of secrets section"

	# Verify the removed secret is gone
	refute_output --partial "API_KEY"

	# Verify the remaining secret is still there
	assert_output --partial "DB_URL"
}

@test "fnox remove preserves comments when removing last secret" {
	setup_age_with_comments

	# Remove both secrets
	assert_fnox_success remove DB_URL
	assert_fnox_success remove API_KEY

	# Verify comments are still preserved
	run cat fnox.toml
	assert_output --partial "# Main configuration file for the project"
	assert_output --partial "# Age encryption provider"
	assert_output --partial "# Application secrets"
}

@test "fnox import preserves existing comments in fnox.toml" {
	setup_age_with_comments

	# Create a .env file with new secrets to import
	cat >.env <<EOF
NEW_SECRET=new-secret-value
ANOTHER_SECRET=another-value
EOF

	# Import new secrets
	assert_fnox_success import -i .env --provider age --force

	# Verify all original comments are preserved
	run cat fnox.toml
	assert_output --partial "# Main configuration file for the project"
	assert_output --partial "# Age encryption provider"
	assert_output --partial "# Application secrets"
	assert_output --partial "# Database connection string"
	assert_output --partial "# API key for external service"
	assert_output --partial "# End of secrets section"

	# Verify new secrets were added
	assert_output --partial "NEW_SECRET"
	assert_output --partial "ANOTHER_SECRET"

	# Verify existing secrets are still there
	assert_output --partial "DB_URL"
	assert_output --partial "API_KEY"
}

@test "fnox import preserves comments when config file has no existing secrets" {
	if ! command -v age-keygen >/dev/null 2>&1; then
		skip "age-keygen not installed"
	fi

	local keygen_output
	keygen_output=$(age-keygen -o key.txt 2>&1)
	local public_key
	public_key=$(echo "$keygen_output" | grep "^Public key:" | cut -d' ' -f3)

	# Create config with comments but no secrets section
	cat >fnox.toml <<EOF
# Project config
root = true

# Encryption provider
[providers.age]
type = "age"
recipients = ["$public_key"]
EOF

	cat >.env <<EOF
MY_SECRET=my-value
EOF

	assert_fnox_success import -i .env --provider age --force

	# Verify comments preserved
	run cat fnox.toml
	assert_output --partial "# Project config"
	assert_output --partial "# Encryption provider"
	assert_output --partial "MY_SECRET"
}

@test "fnox import followed by remove preserves comments" {
	setup_age_with_comments

	# Import a new secret
	cat >.env <<EOF
TEMP_SECRET=temp-value
EOF
	assert_fnox_success import -i .env --provider age --force

	# Then remove it
	assert_fnox_success remove TEMP_SECRET

	# All original comments should still be there
	run cat fnox.toml
	assert_output --partial "# Main configuration file for the project"
	assert_output --partial "# Age encryption provider"
	assert_output --partial "# Application secrets"
	assert_output --partial "# Database connection string"
	assert_output --partial "# API key for external service"
	assert_output --partial "# End of secrets section"

	# Original secrets should still be there
	assert_output --partial "DB_URL"
	assert_output --partial "API_KEY"

	# Temp secret should be gone
	refute_output --partial "TEMP_SECRET"
}