Commit Graph

50 Commits

Author SHA1 Message Date
a6f24e9581 Fix --keyid flag scope and implement secret move command
- Restrict --keyid flag to PGP unlocker type only
- Add validation to prevent --keyid usage with non-PGP unlockers
- Implement 'secret move' command with 'mv' and 'rename' aliases
- Add comprehensive tests for move functionality
- Update documentation to reflect optional nature of --keyid for PGP

The move command allows renaming or moving secrets within a vault while
preserving all versions and metadata. It fails if the destination already
exists to prevent accidental overwrites.
2025-07-26 01:26:27 +02:00
a73a409fe4 Refactor unlockers command structure and add quiet flag to list command
- Rename 'unlockers' command to 'unlocker' for consistency
- Move all unlocker subcommands (list, add, remove) under single 'unlocker' command
- Add --quiet/-q flag to 'secret list' for scripting support
- Update documentation and tests to reflect command changes

The quiet flag outputs only secret names without headers or formatting,
making it ideal for shell script usage like: secret get $(secret list -q | head -1)
2025-07-22 16:04:44 +02:00
70d19d09d0 latest 2025-07-22 13:35:19 +02:00
8e3530a510 Fix use-after-free crash in readSecurePassphrase
The function was using defer to destroy password buffers, which caused
the buffers to be freed before the function returned. This led to a
SIGBUS error when trying to access the destroyed buffer's memory.

Changed to manual memory management to ensure buffers are only destroyed
when no longer needed, and the first buffer is returned directly to the
caller who is responsible for destroying it.
2025-07-22 12:46:16 +02:00
e5d7407c79 Fix mnemonic input to not echo to screen
Changed mnemonic input to use secure non-echoing input like passphrases:
- Use secret.ReadPassphrase() instead of readLineFromStdin()
- Add newline after hidden input for better UX
- Remove unused stdin reading functions from cli.go

This prevents sensitive mnemonic phrases from being displayed on screen
during input, matching the security behavior of passphrase input.
2025-07-22 12:39:32 +02:00
a09fa89f30 Fix cross-platform build issues and security vulnerabilities
- Add build tags to keychain implementation files (Darwin-only)
- Create stub implementations for non-Darwin platforms that panic
- Conditionally show keychain support in help text based on platform
- Platform check in UnlockersAdd prevents keychain usage on non-Darwin
- Verified GPG operations already protected against command injection
  via validateGPGKeyID() and proper exec.Command argument passing
- Keychain operations use go-keychain library, no shell commands

The application now builds and runs on Linux/non-Darwin platforms with
keychain functionality properly isolated to macOS only.
2025-07-21 22:05:23 +02:00
7af1e6efa8 Improve PGP unlocker ergonomics
- Support 'secret unlockers add pgp [keyid]' positional argument syntax
- Automatically detect and use default GPG key when no key is specified
- Change PGP unlocker ID format from <keyid>-pgp to pgp-<keyid>
- Check if PGP key is already added before creating duplicate unlocker
- Add getDefaultGPGKey() that checks gpgconf first, then falls back to
  first secret key
- Export ResolveGPGKeyFingerprint() for use in CLI
- Add checkUnlockerExists() helper to verify unlocker IDs

The new behavior:
- 'secret unlockers add pgp' uses default GPG key
- 'secret unlockers add pgp KEYID' uses specified key
- 'secret unlockers add pgp --keyid=KEYID' also works
- Errors if key is already added or no default key exists
2025-07-21 18:57:58 +02:00
09b3a1fcdc Remove internal/macse package and fix all linter issues
- Remove internal/macse package (Secure Enclave experiment)
- Fix errcheck: handle keychain.DeleteItem error return
- Fix lll: break long lines in command descriptions
- Fix mnd: add nolint comment for cobra.ExactArgs(2)
- Fix nlreturn: add blank lines before return/break statements
- Fix revive: add nolint comment for KEYCHAIN_APP_IDENTIFIER constant
- Fix nestif: simplify UnlockersRemove by using new NumSecrets method
- Add NumSecrets() method to vault.Vault for counting secrets
- Update golangci.yml to exclude ALL_CAPS warning (attempted various
  configurations but settled on nolint comment)

All tests pass, code is formatted and linted.
2025-07-21 17:48:47 +02:00
8ec3fc877d Fix GetValue methods to return LockedBuffer internally
- Changed Secret.GetValue and Version.GetValue to return *memguard.LockedBuffer
- Updated all internal callers to handle LockedBuffer properly
- For backward compatibility, vault.GetSecret still returns []byte but makes a copy
- This ensures secret values are protected in memory during decryption
- Updated tests to handle LockedBuffer returns
- Fixed CLI getSecretValue to use LockedBuffer throughout
2025-07-15 08:59:23 +02:00
9cbe055791 fmt 2025-07-15 08:33:16 +02:00
7596049828 uses protected memory buffers now for all secrets in ram 2025-07-15 08:32:33 +02:00
d3ca006886 Merge branch 'main' into fix-memory-security 2025-07-15 07:36:13 +02:00
7c5e78db17 fix: update JSON fields from snake_case to camelCase and make tests quiet by default
- Update all JSON field references in tests from snake_case to camelCase
- Update vault list JSON output to use currentVault instead of current_vault
- Make integration tests quiet by default unless run with -v flag
- Fix tests that were using exec.Command to use in-process execution helpers
- Tests now only show debug output when explicitly requested or on failure
2025-07-15 07:35:48 +02:00
c9774e89e0 WIP: refactor to use memguard for secure memory handling
- Add memguard dependency
- Update ReadPassphrase to return LockedBuffer
- Update EncryptWithPassphrase/DecryptWithPassphrase to accept LockedBuffer
- Remove string wrapper functions
- Update all callers to create LockedBuffers at entry points
- Update interfaces and mock implementations
2025-07-15 07:23:58 +02:00
f9938135c6 fix: resolve all remaining linter issues (staticcheck, tagliatelle, lll)
- Fix staticcheck QF1011: Remove explicit type declaration for io.Writer variables
- Fix tagliatelle: Change all JSON tags from snake_case to camelCase
  - created_at → createdAt
  - keychain_item_name → keychainItemName
  - age_public_key → agePublicKey
  - age_priv_key_passphrase → agePrivKeyPassphrase
  - encrypted_longterm_key → encryptedLongtermKey
  - derivation_index → derivationIndex
  - public_key_hash → publicKeyHash
  - mnemonic_family_hash → mnemonicFamilyHash
  - gpg_key_id → gpgKeyId
- Fix lll: Break long function signature line to stay under 120 character limit

All linter issues have been resolved. The codebase now passes all linter checks.
2025-07-15 06:33:25 +02:00
386a27c0b6 fix: resolve all revive linter issues
Added missing package comments:
- cmd/secret/main.go
- internal/cli/cli.go
- internal/secret/constants.go
- internal/vault/management.go
- pkg/bip85/bip85.go

Fixed comment format issues for exported items:
- EnvStateDir, EnvMnemonic, EnvUnlockPassphrase, EnvGPGKeyID in constants.go
- Metadata, UnlockerMetadata, SecretMetadata, Configuration in metadata.go
- AppBIP39, AppHDWIF, AppXPRV in bip85.go

Replaced unused parameters with underscore (_):
- generate.go:39 - parameter 'args'
- init.go:30 - parameter 'args'
- unlockers.go:39,77,102 - parameter 'args' or 'cmd'
- vault.go:37 - parameter 'args'
- management.go:34 - parameter 'target'
2025-07-15 06:06:48 +02:00
080a3dc253 fix: resolve all nlreturn linter errors
Add blank lines before return statements in all files to satisfy
the nlreturn linter. This improves code readability by providing
visual separation before return statements.

Changes made across 24 files:
- internal/cli/*.go
- internal/secret/*.go
- internal/vault/*.go
- pkg/agehd/agehd.go
- pkg/bip85/bip85.go

All 143 nlreturn issues have been resolved.
2025-07-15 06:00:32 +02:00
54fce0f187 fix: resolve mnd and nestif linter errors
- Define base85 constants (base85ChunkSize, base85DigitCount, base85Base)
- Replace magic numbers in base85 encoding logic with named constants
- Add nolint:nestif comments for legitimate nested conditionals:
  - crypto.go: Clear separation between secret generation vs retrieval
  - secrets.go: Separate JSON and table output formatting logic
  - vault.go: Separate JSON and text output formatting logic
2025-07-09 12:54:59 -07:00
95ba80f618 fix: resolve gochecknoglobals, gosec, lll, and mnd linter errors
- Add nolint comments for BIP85 standard constants (MainNetPrivateKey, TestNetPrivateKey)
- Handle error return from shake.Write() in NewBIP85DRNG
- Fix line length issue by moving nolint comment to separate line
- Add nolint comment for cobra.ExactArgs(2) magic number
- Replace magic number 32 with named constant x25519KeySize in agehd package
2025-07-09 12:49:59 -07:00
38b450cbcf fix: resolve mnd and nestif linter errors
- Added constants to replace magic numbers:
  - agePrivKeyPassphraseLength = 64
  - versionNameParts = 2
  - maxVersionsPerDay = 999
- Refactored crypto.go to reduce nesting complexity:
  - Inverted if condition to handle non-existent secret first
  - Extracted getSecretValue helper method
2025-07-09 07:05:07 -07:00
6fe49344e2 fix: resolve errcheck, gosec, and mnd linter errors
- Fixed unhandled errors in init.go (os.Setenv/Unsetenv)
- Fixed unhandled errors in test_helpers.go (os.Setenv/Unsetenv)
- Replaced magic numbers with named constants:
  - defaultSecretLength = 16
  - mnemonicEntropyBits = 128
  - tabWriterPadding = 2
2025-07-09 06:59:01 -07:00
11e43542cf fix: handle error returns from os.Unsetenv and file.Close (errcheck)
Fixed the first five errcheck linter errors:
- Added error handling for os.Unsetenv in cli_test.go
- Added error handling for file.Close() in crypto.go (4 instances)
2025-07-09 06:16:13 -07:00
bdcddadf90 fix: resolve exported type stuttering issues (revive)
- Rename VaultMetadata to Metadata in internal/vault package to avoid stuttering
- Rename BIP85DRNG to DRNG in pkg/bip85 package to avoid stuttering
- Update all references in code and tests
2025-06-20 12:47:06 -07:00
9e35bf21a3 fix: more nlreturn and testifylint issues
- Add blank lines before return statements
- Use require.Error instead of assert.Error for error assertions
- Keep exact float64 comparisons as-is (they are integers from JSON)
2025-06-20 09:40:17 -07:00
2a1e0337fd fix: add blank lines before return statements (nlreturn)
Fix nlreturn linting issues by adding blank lines before return
statements in cli and secret packages.
2025-06-20 09:37:56 -07:00
dd2e95f8af fix: replace magic file permissions and add crypto constant comments
Replace hardcoded 0o600 with secret.FilePerms constant for consistency.
Add explanatory comments for cryptographic constants (32-byte keys,
bech32 encoding parameters) rather than extracting them as they are
well-known cryptographic standard values.
2025-06-20 09:23:50 -07:00
c450e1c13d fix: replace remaining os.Setenv with t.Setenv in tests
Replace all os.Setenv calls with t.Setenv in test functions to ensure
proper test environment cleanup and better test isolation. This leaves
only legitimate application code and helper functions using os.Setenv.
2025-06-20 09:22:01 -07:00
5d973f76ec fix: break long lines to 77 characters in non-test files
Break long lines in function signatures and strings to comply with
77 character preference by using multi-line formatting and extracting
variables where appropriate.
2025-06-20 09:17:45 -07:00
fd125c5fe1 fix: disable line length checks for test files with test vectors
Add nolint:lll directives to test files containing long test vectors
and function signatures to avoid unnecessary line breaking.
2025-06-20 09:16:40 -07:00
f569bc55ea fix: convert for loops to Go 1.22+ integer range syntax (intrange)
Convert traditional for loops to use the new Go 1.22+ integer range syntax:
- for i := 0; i < n; i++ → for i := range n (when index is used)
- for i := 0; i < n; i++ → for range n (when index is not used)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-20 09:05:49 -07:00
9231409c5c fix: remove unnecessary string conversions (unconvert)
Remove redundant string() conversions on output variables that are
already strings in test assertions and logging.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-20 09:02:56 -07:00
0d140b4636 fix: correct file permissions in integration test (gosec G306)
Change WriteFile permissions from 0o644 to 0o600 to address security
linting issue about file permissions being too permissive.

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-06-20 09:02:01 -07:00
dcab84249f Fix unused parameter errors in CLI integration tests
Remove unused tempDir parameter from test11ListSecrets and test15VaultIsolation
Remove unused runSecretWithStdin parameter from test17ImportFromFile
Update call sites to match new signatures
2025-06-20 08:50:34 -07:00
e5b18202f3 Fix revive package stuttering errors
- Rename SecretMetadata to Metadata in secret package
- Rename SecretVersion to Version in secret package
- Update NewSecretVersion to NewVersion function
- Update all references across the codebase including:
  - vault package aliases
  - CLI usage
  - test files
  - method receivers and signatures
2025-06-20 08:48:17 -07:00
c52430554a Fix usetesting errors in CLI integration test
Replace os.Setenv() with t.Setenv() for GODEBUG and SB_SECRET_STATE_DIR
environment variables in TestSecretManagerIntegration and test23ErrorHandling
2025-06-20 08:24:54 -07:00
434b73d834 Fix intrange and G101 linting issues
- Convert for loops to use Go 1.22+ integer ranges in generate.go and helpers.go
- Disable G101 false positives for test vectors and environment variable names
- Add file-level gosec disable for bip85_test.go containing BIP85 test vectors
- Add targeted nolint comments for legitimate test data and constants
2025-06-20 08:08:01 -07:00
004dce5472 passes tests now! 2025-06-20 07:24:48 -07:00
0b31fba663 latest from ai, it broke the tests 2025-06-20 05:40:20 -07:00
03e0ee2f95 refactor: remove confusing dual ID method pattern from Unlocker interface - Removed redundant ID() method from Unlocker interface - Removed ID field from UnlockerMetadata struct - Modified GetID() to generate IDs dynamically based on unlocker type and data - Updated vault package to create unlocker instances when searching by ID - Fixed all tests and CLI code to remove ID field references - IDs are now consistently generated from unlocker data, preventing redundancy 2025-06-11 15:21:20 -07:00
9adf0c0803 refactor: fix redundant metadata fields across the codebase - Removed VaultMetadata.Name (redundant with directory structure) - Removed SecretMetadata.Name (redundant with Secret.Name field) - Removed AgePublicKey and AgeRecipient from PGPUnlockerMetadata - Removed AgePublicKey from KeychainUnlockerMetadata - Changed PGP and Keychain unlockers to store recipient in pub.txt instead of pub.age - Fixed all tests to reflect these changes - Follows DRY principle and prevents data inconsistency 2025-06-09 17:44:10 -07:00
2e3fc475cf fix: Use vault metadata derivation index for environment mnemonic - Fixed bug where GetValue() used hardcoded index 0 instead of vault metadata - Added test31 to verify environment mnemonic respects vault derivation index - Rewrote test19DisasterRecovery to actually test manual recovery process - Removed all test skip statements as requested 2025-06-09 17:21:02 -07:00
1f89fce21b latest 2025-06-09 05:59:26 -07:00
02be4b2a55 Fix integration tests: correct vault derivation index and debug test failures 2025-06-09 04:54:45 -07:00
fbda2d91af add secret versioning support 2025-06-08 22:07:19 -07:00
f59ee4d2d6 'unlock keys' renamed to 'unlockers' 2025-05-30 07:29:02 -07:00
34d6870e6a feat: add derivation index to vault metadata for unique keys - Add VaultMetadata fields: DerivationIndex, LongTermKeyHash, MnemonicHash - Implement GetNextDerivationIndex() to track and increment indices for same mnemonics - Update init and import commands to use proper derivation indices - Add ComputeDoubleSHA256() for hash calculations - Save vault metadata on creation with all derivation information - Add comprehensive tests for metadata functionality. This ensures multiple vaults using the same mnemonic will derive different long-term keys by using incremented derivation indices. The mnemonic is double SHA256 hashed and stored to track which vaults share mnemonics. Fixes TODO item #5 2025-05-29 16:23:29 -07:00
a4d7225036 Standardize file permissions using constants and fix parameter ordering inconsistencies 2025-05-29 13:13:44 -07:00
8dc2e9d748 Remove duplicated wrapper crypto functions and use exported implementations directly 2025-05-29 13:08:00 -07:00
ddb395901b Refactor vault functionality to dedicated package, fix import cycles with interface pattern, fix tests 2025-05-29 12:48:36 -07:00
e95609ce69 latest 2025-05-29 11:02:22 -07:00