package openbao import ( "errors" "os/exec" "path/filepath" "strings" "testing" ) func TestEnsureRecoveryIdentity(t *testing.T) { if _, err := exec.LookPath("age-keygen"); err != nil { t.Skip("age-keygen is required for OpenBao recovery setup") } recipient, err := EnsureRecoveryIdentity(filepath.Join(t.TempDir(), "recovery-key.txt")) if err != nil { t.Fatal(err) } if !strings.HasPrefix(recipient, "age1") { t.Fatalf("invalid recovery recipient") } } func TestReadRecoveryMaterialDecryptsAndValidatesBundle(t *testing.T) { original := decryptRecovery t.Cleanup(func() { decryptRecovery = original }) called := false decryptRecovery = func(identityPath, bundlePath string) ([]byte, error) { called = identityPath == "recovery-identity" && bundlePath == "recovery-bundle" return []byte(`{"unseal_keys_b64":["test-share-1","test-share-2"],"unseal_threshold":2,"root_token":"test-root"}`), nil } material, err := ReadRecoveryMaterial("recovery-identity", "recovery-bundle") if err != nil || !called || material.UnsealThreshold != 2 || len(material.UnsealKeysB64) != 2 || material.RootToken == "" { t.Fatal("valid OpenBao recovery material was not read") } } func TestReadRecoveryMaterialRejectsMalformedOrInsufficientBundle(t *testing.T) { original := decryptRecovery t.Cleanup(func() { decryptRecovery = original }) for _, plaintext := range [][]byte{ []byte(`{"unseal_keys_b64":`), []byte(`{"unseal_keys_b64":["test-share"],"unseal_threshold":2,"root_token":"test-root"}`), } { decryptRecovery = func(string, string) ([]byte, error) { return plaintext, nil } if _, err := ReadRecoveryMaterial("recovery-identity", "recovery-bundle"); err == nil { t.Fatal("invalid OpenBao recovery material was accepted") } } decryptRecovery = func(string, string) ([]byte, error) { return nil, errors.New("unavailable") } if _, err := ReadRecoveryMaterial("recovery-identity", "recovery-bundle"); err == nil { t.Fatal("recovery decryption failure was accepted") } }