fix(set): prompt for secret value when -k flag is used#367
Conversation
When using `fnox set -k`, the command skipped the secret value prompt because key_name was incorrectly included in the has_metadata check. This caused the secret to never be written to the provider while the config was updated as if it succeeded. Fixes #366 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Verify that `fnox set -k` correctly reads secret values from stdin and from explicit arguments, rather than silently skipping the prompt. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request addresses an issue where using the Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
There was a problem hiding this comment.
Code Review
This pull request addresses a bug where using the -k flag with fnox set would incorrectly prevent prompting for a secret value. The changes in src/commands/set.rs correctly adjust the logic to ensure a value is handled when -k is used. Additionally, new tests in test/set_key_name.bats verify the fix. My review includes a suggestion to refactor the new test file to reduce code duplication, thereby improving its maintainability.
| setup() { | ||
| load 'test_helper/common_setup' | ||
| _common_setup | ||
| } | ||
|
|
||
| teardown() { | ||
| _common_teardown | ||
| } | ||
|
|
||
| @test "fnox set -k prompts for secret value (reads from stdin)" { | ||
| # Generate age key | ||
| 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) | ||
|
|
||
| cat >test-config.toml <<EOF | ||
| [providers.age] | ||
| type = "age" | ||
| recipients = ["$public_key"] | ||
|
|
||
| [secrets] | ||
| EOF | ||
|
|
||
| # Pipe secret value via stdin with -k flag — should encrypt and store | ||
| run bash -c 'echo "my-secret-value" | "$FNOX_BIN" --config test-config.toml set -p age -k custom-key-name MY_SECRET' | ||
| assert_success | ||
|
|
||
| # The config should reference the secret | ||
| assert_file_contains test-config.toml "MY_SECRET" | ||
| # The plaintext secret value should NOT appear in the config (it should be encrypted) | ||
| assert_file_not_contains test-config.toml "my-secret-value" | ||
| } | ||
|
|
||
| @test "fnox set -k with explicit value stores the secret" { | ||
| # Generate age key | ||
| 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) | ||
|
|
||
| cat >test-config.toml <<EOF | ||
| [providers.age] | ||
| type = "age" | ||
| recipients = ["$public_key"] | ||
|
|
||
| [secrets] | ||
| EOF | ||
|
|
||
| # Provide value as argument with -k flag | ||
| run "$FNOX_BIN" --config test-config.toml set -p age -k custom-key-name MY_SECRET "my-secret-value" | ||
| assert_success | ||
|
|
||
| # The config should reference the secret | ||
| assert_file_contains test-config.toml "MY_SECRET" | ||
| # The plaintext secret value should NOT appear (it should be encrypted) | ||
| assert_file_not_contains test-config.toml "my-secret-value" | ||
| } |
There was a problem hiding this comment.
The two tests in this file share a significant amount of setup code for generating an age key and creating a test-config.toml file. To improve maintainability and reduce redundancy, this common logic can be extracted into the setup function, which runs before each test. This will make the tests cleaner and easier to read.
setup() {
load 'test_helper/common_setup'
_common_setup
# Generate age key and config for tests
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)
cat >test-config.toml <<EOF
[providers.age]
type = "age"
recipients = ["$public_key"]
[secrets]
EOF
}
teardown() {
_common_teardown
}
@test "fnox set -k prompts for secret value (reads from stdin)" {
# Pipe secret value via stdin with -k flag — should encrypt and store
run bash -c 'echo "my-secret-value" | "$FNOX_BIN" --config test-config.toml set -p age -k custom-key-name MY_SECRET'
assert_success
# The config should reference the secret
assert_file_contains test-config.toml "MY_SECRET"
# The plaintext secret value should NOT appear in the config (it should be encrypted)
assert_file_not_contains test-config.toml "my-secret-value"
}
@test "fnox set -k with explicit value stores the secret" {
# Provide value as argument with -k flag
run "$FNOX_BIN" --config test-config.toml set -p age -k custom-key-name MY_SECRET "my-secret-value"
assert_success
# The config should reference the secret
assert_file_contains test-config.toml "MY_SECRET"
# The plaintext secret value should NOT appear (it should be encrypted)
assert_file_not_contains test-config.toml "my-secret-value"
}
Greptile SummaryThis PR fixes a bug where passing Key changes:
Confidence Score: 4/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[fnox set KEY] --> B{value arg provided?}
B -- yes --> C[secret_value = arg]
B -- no --> D{has_metadata AND key_name is None?}
D -- yes --> E[secret_value = None\nmetadata-only update]
D -- no --> F{stdin piped?}
F -- yes --> G[read from stdin]
F -- no --> H[interactive prompt]
G --> I[secret_value = stdin]
H --> I
C --> J{provider set?}
I --> J
J -- encryption provider --> K[encrypt value]
J -- remote storage provider --> L[put_secret with key_name or KEY\nreturns stored key]
J -- none/other --> M[store plaintext]
K --> N[set_value encrypted blob]
L --> O[set_value remote key ref]
M --> P[set_value plaintext]
E --> Q[update description/if_missing/default only]
Reviews (3): Last reviewed commit: "fix(set): don't skip value prompt when -..." | Re-trigger Greptile |
Move age key generation into setup() to reduce duplication. Add negative assertions verifying key_name is not written to config for encryption providers. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When -k was combined with metadata flags like -d without an explicit value, has_metadata was true so the value prompt was skipped, silently discarding the -k flag. Now -k prevents the metadata-only skip path. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
### 🚀 Features - add `reencrypt` subcommand for updating encryption recipients by [@jdx](https://github.com/jdx) in [#365](#365) ### 🐛 Bug Fixes - **(set)** prompt for secret value when -k flag is used by [@jdx](https://github.com/jdx) in [#367](#367) ### 📦️ Dependency Updates - lock file maintenance by [@renovate[bot]](https://github.com/renovate[bot]) in [#360](#360) - lock file maintenance by [@renovate[bot]](https://github.com/renovate[bot]) in [#362](#362)
## Upstream release Bumps bundled fnox binary from 1.18.0 to 1.19.0. **Release**: https://github.com/jdx/fnox/releases/tag/v1.19.0 ## Release notes v1.19.0 adds a new `fnox reencrypt` command that makes it easy to re-encrypt all your secrets when encryption provider configuration changes -- for example, when adding or removing age recipients. This release also fixes a bug where `fnox set -k` would skip prompting for the secret value. ## Added **`fnox reencrypt` subcommand** ([#365](jdx/fnox#365)) -- @jdx Previously, re-encrypting secrets after changing recipients required a tedious manual loop of `fnox get` and `fnox set` for each secret. The new `fnox reencrypt` command handles this in one step: it decrypts matching secrets and re-encrypts them with the current provider configuration, writing the updated ciphertext back to the correct source config file. ```bash # Re-encrypt all age secrets fnox reencrypt -p age # Preview what would be re-encrypted fnox reencrypt -p age --dry-run # Re-encrypt specific keys fnox reencrypt MY_SECRET OTHER_SECRET # Filter by regex pattern fnox reencrypt --filter "^DB_" # Skip the confirmation prompt fnox reencrypt -p age -f ``` The command correctly handles multi-line secrets, writes back to the original source file (including distinguishing root `[secrets]` from `[profiles.X.secrets]`), clears stale sync caches, and scrubs decrypted plaintext from the process environment after re-encryption. Only secrets backed by encryption-capable providers are eligible. ## Fixed **`fnox set -k` now correctly prompts for the secret value** ([#367](jdx/fnox#367)) -- @jdx When using the `-k` / `--key-name` flag with `fnox set`, the command incorrectly treated it as a metadata-only operation and skipped prompting for the secret value. It also wrote the key name itself as the stored config value, bypassing the encryption provider entirely. Now `-k` works as expected: the secret value is read from stdin, a command-line argument, or an interactive prompt, and is properly encrypted and stored. ```bash # These now work correctly echo "my-secret" | fnox set -p age -k custom-key-name MY_SECRET fnox set -p age -k custom-key-name MY_SECRET "my-secret" ``` **Full Changelog**: jdx/fnox@v1.18.0...v1.19.0 Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Summary
key_namefrom thehas_metadatacheck inset.rs—-kspecifies the provider key name, not a metadata-only operation, so users should still be prompted for the secret valuekey_namedirectly as the config value, bypassing provider storage-kcorrectly reads secrets from stdin and explicit argumentsFixes #366
Test plan
mise run test:bats -- test/set_key_name.batspassesfnox set -g -p provider -k keyname SECRETprompts for value interactivelyecho "val" | fnox set -p provider -k keyname SECRETreads from stdin🤖 Generated with Claude Code
Note
Medium Risk
Changes
fnox setsecret-value acquisition and persistence logic when-k/--key-nameis present, which can affect whether secrets are prompted/read and what ultimately gets stored. While scoped, mistakes here could lead to missing secrets or incorrect config values.Overview
Fixes
fnox setso-k/--key-nameno longer triggers the metadata-only path: when-kis used without an explicit value, the command will still read from stdin or prompt interactively for the secret value.Removes the behavior that wrote
key_namedirectly into the secretvaluefield, ensuring provider/encryption handling determines what is persisted instead. Adds Bats coverage (test/set_key_name.bats) to verify stdin and explicit-value flows with-k(including when combined with-d) don’t store plaintext or the key name for encryption providers.Written by Cursor Bugbot for commit 1f5d4f6. This will update automatically on new commits. Configure here.