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
This commit is contained in:
parent
e9d03987f9
commit
9adf0c0803
@ -9,7 +9,6 @@ import (
|
||||
|
||||
// CLIEntry is the entry point for the secret CLI application
|
||||
func CLIEntry() {
|
||||
secret.Debug("CLIEntry starting - debug output is working")
|
||||
cmd := newRootCmd()
|
||||
if err := cmd.Execute(); err != nil {
|
||||
os.Exit(1)
|
||||
|
@ -236,7 +236,6 @@ func (cli *CLIInstance) VaultImport(vaultName string) error {
|
||||
if err != nil {
|
||||
// If metadata doesn't exist, create new
|
||||
existingMetadata = &vault.VaultMetadata{
|
||||
Name: vaultName,
|
||||
CreatedAt: time.Now(),
|
||||
}
|
||||
}
|
||||
|
@ -18,8 +18,6 @@ import (
|
||||
// KeychainUnlockerMetadata extends UnlockerMetadata with keychain-specific data
|
||||
type KeychainUnlockerMetadata struct {
|
||||
UnlockerMetadata
|
||||
// Age keypair information
|
||||
AgePublicKey string `json:"age_public_key"`
|
||||
// Keychain item name
|
||||
KeychainItemName string `json:"keychain_item_name"`
|
||||
}
|
||||
@ -256,11 +254,11 @@ func CreateKeychainUnlocker(fs afero.Fs, stateDir string) (*KeychainUnlocker, er
|
||||
return nil, fmt.Errorf("failed to generate age private key passphrase: %w", err)
|
||||
}
|
||||
|
||||
// Step 3: Store age public key as plaintext
|
||||
agePublicKeyString := ageIdentity.Recipient().String()
|
||||
agePubKeyPath := filepath.Join(unlockerDir, "pub.age")
|
||||
if err := afero.WriteFile(fs, agePubKeyPath, []byte(agePublicKeyString), FilePerms); err != nil {
|
||||
return nil, fmt.Errorf("failed to write age public key: %w", err)
|
||||
// Step 3: Store age recipient as plaintext
|
||||
ageRecipient := ageIdentity.Recipient().String()
|
||||
recipientPath := filepath.Join(unlockerDir, "pub.txt")
|
||||
if err := afero.WriteFile(fs, recipientPath, []byte(ageRecipient), FilePerms); err != nil {
|
||||
return nil, fmt.Errorf("failed to write age recipient: %w", err)
|
||||
}
|
||||
|
||||
// Step 4: Encrypt age private key with the generated passphrase and store on disk
|
||||
@ -348,7 +346,7 @@ func CreateKeychainUnlocker(fs afero.Fs, stateDir string) (*KeychainUnlocker, er
|
||||
|
||||
// Step 7: Prepare keychain data
|
||||
keychainData := KeychainData{
|
||||
AgePublicKey: agePublicKeyString,
|
||||
AgePublicKey: ageRecipient,
|
||||
AgePrivKeyPassphrase: agePrivKeyPassphrase,
|
||||
EncryptedLongtermKey: hex.EncodeToString(encryptedLtPrivKeyToAge),
|
||||
}
|
||||
@ -374,7 +372,6 @@ func CreateKeychainUnlocker(fs afero.Fs, stateDir string) (*KeychainUnlocker, er
|
||||
CreatedAt: time.Now(),
|
||||
Flags: []string{"keychain", "macos"},
|
||||
},
|
||||
AgePublicKey: agePublicKeyString,
|
||||
KeychainItemName: keychainItemName,
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,6 @@ import (
|
||||
|
||||
// VaultMetadata contains information about a vault
|
||||
type VaultMetadata struct {
|
||||
Name string `json:"name"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
Description string `json:"description,omitempty"`
|
||||
DerivationIndex uint32 `json:"derivation_index"`
|
||||
@ -23,7 +22,6 @@ type UnlockerMetadata struct {
|
||||
|
||||
// SecretMetadata contains information about a secret
|
||||
type SecretMetadata struct {
|
||||
Name string `json:"name"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
}
|
||||
|
@ -342,13 +342,13 @@ Passphrase: ` + testPassphrase + `
|
||||
}
|
||||
|
||||
// Check if required files exist
|
||||
pubKeyPath := filepath.Join(unlockerDir, "pub.age")
|
||||
pubKeyExists, err := afero.Exists(fs, pubKeyPath)
|
||||
recipientPath := filepath.Join(unlockerDir, "pub.txt")
|
||||
recipientExists, err := afero.Exists(fs, recipientPath)
|
||||
if err != nil {
|
||||
t.Fatalf("Failed to check if public key file exists: %v", err)
|
||||
t.Fatalf("Failed to check if recipient file exists: %v", err)
|
||||
}
|
||||
if !pubKeyExists {
|
||||
t.Errorf("PGP unlock key public key file does not exist: %s", pubKeyPath)
|
||||
if !recipientExists {
|
||||
t.Errorf("PGP unlock key recipient file does not exist: %s", recipientPath)
|
||||
}
|
||||
|
||||
privKeyPath := filepath.Join(unlockerDir, "priv.age.gpg")
|
||||
@ -465,10 +465,10 @@ Passphrase: ` + testPassphrase + `
|
||||
t.Fatalf("Failed to generate age identity: %v", err)
|
||||
}
|
||||
|
||||
// Write the public key
|
||||
pubKeyPath := filepath.Join(unlockerDir, "pub.age")
|
||||
if err := afero.WriteFile(fs, pubKeyPath, []byte(ageIdentity.Recipient().String()), secret.FilePerms); err != nil {
|
||||
t.Fatalf("Failed to write public key: %v", err)
|
||||
// Write the recipient
|
||||
recipientPath := filepath.Join(unlockerDir, "pub.txt")
|
||||
if err := afero.WriteFile(fs, recipientPath, []byte(ageIdentity.Recipient().String()), secret.FilePerms); err != nil {
|
||||
t.Fatalf("Failed to write recipient: %v", err)
|
||||
}
|
||||
|
||||
// GPG encrypt the private key using our custom encrypt function
|
||||
|
@ -31,9 +31,6 @@ type PGPUnlockerMetadata struct {
|
||||
UnlockerMetadata
|
||||
// GPG key ID used for encryption
|
||||
GPGKeyID string `json:"gpg_key_id"`
|
||||
// Age keypair information
|
||||
AgePublicKey string `json:"age_public_key"`
|
||||
AgeRecipient string `json:"age_recipient"`
|
||||
}
|
||||
|
||||
// PGPUnlocker represents a PGP-protected unlocker
|
||||
@ -209,11 +206,11 @@ func CreatePGPUnlocker(fs afero.Fs, stateDir string, gpgKeyID string) (*PGPUnloc
|
||||
return nil, fmt.Errorf("failed to generate age keypair: %w", err)
|
||||
}
|
||||
|
||||
// Step 2: Store age public key as plaintext
|
||||
agePublicKeyString := ageIdentity.Recipient().String()
|
||||
agePubKeyPath := filepath.Join(unlockerDir, "pub.age")
|
||||
if err := afero.WriteFile(fs, agePubKeyPath, []byte(agePublicKeyString), FilePerms); err != nil {
|
||||
return nil, fmt.Errorf("failed to write age public key: %w", err)
|
||||
// Step 2: Store age recipient as plaintext
|
||||
ageRecipient := ageIdentity.Recipient().String()
|
||||
recipientPath := filepath.Join(unlockerDir, "pub.txt")
|
||||
if err := afero.WriteFile(fs, recipientPath, []byte(ageRecipient), FilePerms); err != nil {
|
||||
return nil, fmt.Errorf("failed to write age recipient: %w", err)
|
||||
}
|
||||
|
||||
// Step 3: Get or derive the long-term private key
|
||||
@ -303,9 +300,7 @@ func CreatePGPUnlocker(fs afero.Fs, stateDir string, gpgKeyID string) (*PGPUnloc
|
||||
CreatedAt: time.Now(),
|
||||
Flags: []string{"gpg", "encrypted"},
|
||||
},
|
||||
GPGKeyID: gpgKeyID,
|
||||
AgePublicKey: agePublicKeyString,
|
||||
AgeRecipient: ageIdentity.Recipient().String(),
|
||||
GPGKeyID: gpgKeyID,
|
||||
}
|
||||
|
||||
metadataBytes, err := json.MarshalIndent(pgpMetadata, "", " ")
|
||||
|
@ -55,7 +55,6 @@ func NewSecret(vault VaultInterface, name string) *Secret {
|
||||
Directory: secretDir,
|
||||
vault: vault,
|
||||
Metadata: SecretMetadata{
|
||||
Name: name,
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
},
|
||||
@ -218,7 +217,6 @@ func (s *Secret) LoadMetadata() error {
|
||||
// For backward compatibility, we'll populate with basic info
|
||||
now := time.Now()
|
||||
s.Metadata = SecretMetadata{
|
||||
Name: s.Name,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
}
|
||||
|
@ -247,7 +247,6 @@ func CreateVault(fs afero.Fs, stateDir string, name string) (*Vault, error) {
|
||||
|
||||
// Save vault metadata
|
||||
metadata := &VaultMetadata{
|
||||
Name: name,
|
||||
CreatedAt: time.Now(),
|
||||
DerivationIndex: derivationIndex,
|
||||
PublicKeyHash: publicKeyHash,
|
||||
|
@ -71,7 +71,6 @@ func TestVaultMetadata(t *testing.T) {
|
||||
}
|
||||
|
||||
metadata1 := &VaultMetadata{
|
||||
Name: "vault1",
|
||||
DerivationIndex: 0,
|
||||
PublicKeyHash: pubKeyHash0,
|
||||
}
|
||||
@ -117,7 +116,6 @@ func TestVaultMetadata(t *testing.T) {
|
||||
}
|
||||
|
||||
metadata2 := &VaultMetadata{
|
||||
Name: "vault2",
|
||||
DerivationIndex: 5,
|
||||
PublicKeyHash: pubKeyHash0, // Same hash since it's from the same mnemonic
|
||||
}
|
||||
@ -143,7 +141,6 @@ func TestVaultMetadata(t *testing.T) {
|
||||
|
||||
// Create and save metadata
|
||||
metadata := &VaultMetadata{
|
||||
Name: "test-vault",
|
||||
DerivationIndex: 3,
|
||||
PublicKeyHash: "test-public-key-hash",
|
||||
}
|
||||
@ -158,9 +155,6 @@ func TestVaultMetadata(t *testing.T) {
|
||||
t.Fatalf("Failed to load metadata: %v", err)
|
||||
}
|
||||
|
||||
if loaded.Name != metadata.Name {
|
||||
t.Errorf("Name mismatch: expected %s, got %s", metadata.Name, loaded.Name)
|
||||
}
|
||||
if loaded.DerivationIndex != metadata.DerivationIndex {
|
||||
t.Errorf("DerivationIndex mismatch: expected %d, got %d", metadata.DerivationIndex, loaded.DerivationIndex)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user