Skip to content

Commit aabd2a0

Browse files
imheresamirGitHub Enterprise
authored andcommitted
Merge pull request #24 from Conjur-Enterprise/ss-bugfixes-1
CNJR-9026: Improve Error Logging
2 parents 9f28cc7 + a6e7b46 commit aabd2a0

19 files changed

+283
-362
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,15 @@ All notable changes to this project will be documented in this file.
44
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
55
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
66

7+
## [0.3.1] - 2025-04-23
8+
9+
### Fixed
10+
- Provide error messages from the API back to the user
11+
- Make `retention` and `purge` fields for safes `computed` so the API can provide default values if they are not user-provided
12+
- Safe resource update should look at safe members in the plan, not the existing state
13+
- Handle removing or adding the optional `address` property when updating an account
14+
- Fix crash when debug logging is enabled
15+
716
## [0.3.0] - 2025-04-11
817

918
### Added

internal/cyberark/client.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,18 @@ func (c *Client) DoRequest(ctx context.Context, method string, path string, body
5454

5555
if c.logResponse {
5656
responseBody, err := io.ReadAll(response.Body)
57+
58+
var url url.URL
59+
if req.URL != nil {
60+
url = *req.URL
61+
}
62+
5763
if err == nil && len(responseBody) > 0 {
5864
tflog.Debug(
5965
ctx,
6066
"Response from CyberArk API",
6167
map[string]interface{}{
62-
"request_url": req.URL,
68+
"request_url": url.String(),
6369
"method": method,
6470
"response_status": response.Status,
6571
"response_body": string(responseBody),

internal/cyberark/error.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package cyberark
2+
3+
import (
4+
"encoding/json"
5+
"errors"
6+
"fmt"
7+
"io"
8+
)
9+
10+
func APIErrorFromResponse(code int, body io.ReadCloser) error {
11+
errorStr := fmt.Sprintf("HTTP status code %d", code)
12+
13+
var jsonError interface{}
14+
err := json.NewDecoder(body).Decode(&jsonError)
15+
if err != nil {
16+
return errors.New(errorStr)
17+
}
18+
19+
if jsonError != nil {
20+
if jsonErrorStr, ok := jsonError.(string); ok {
21+
// If the error is a string, just append it to the error message
22+
errorStr = fmt.Sprintf("%s\n\n%s", errorStr, jsonErrorStr)
23+
} else {
24+
prettyJSON, err := json.MarshalIndent(jsonError, "", " ")
25+
if err == nil {
26+
errorStr = fmt.Sprintf("%s\n%s", errorStr, string(prettyJSON))
27+
}
28+
}
29+
}
30+
31+
return errors.New(errorStr)
32+
}

internal/cyberark/pam.go

Lines changed: 30 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -70,11 +70,8 @@ func (a *pamAPI) AddAccount(ctx context.Context, credential Credential) (*Creden
7070
return nil, err
7171
}
7272

73-
if response.StatusCode == 409 {
74-
tflog.Info(ctx, fmt.Sprintf("Account [%s] already exists.", *credential.Name))
75-
return nil, nil
76-
} else if response.StatusCode != 201 {
77-
return nil, fmt.Errorf("failed to add account, expected status code 201, got %d", response.StatusCode)
73+
if response.StatusCode != 201 {
74+
return nil, APIErrorFromResponse(response.StatusCode, response.Body)
7875
}
7976

8077
createdAccount := CredentialResponse{}
@@ -83,9 +80,6 @@ func (a *pamAPI) AddAccount(ctx context.Context, credential Credential) (*Creden
8380
return nil, err
8481
}
8582

86-
tflog.Info(ctx, fmt.Sprintf("Successfully added new account [%s]: Name [%s] - ID [%v]",
87-
*createdAccount.UserName, *createdAccount.Name, *createdAccount.CredID))
88-
8983
return &createdAccount, nil
9084
}
9185

@@ -104,7 +98,7 @@ func (a *pamAPI) GetAccount(ctx context.Context, accountID string) (*CredentialR
10498
}
10599

106100
if response.StatusCode != 200 {
107-
return nil, fmt.Errorf("failed to get account. Expected status code 200, got %d", response.StatusCode)
101+
return nil, APIErrorFromResponse(response.StatusCode, response.Body)
108102
}
109103

110104
account := CredentialResponse{}
@@ -133,7 +127,7 @@ func (a *pamAPI) FilterAccounts(ctx context.Context, search string, filter []str
133127
}
134128

135129
if response.StatusCode != 200 {
136-
return nil, fmt.Errorf("failed to filter accounts. Expected status code 200, got %d", response.StatusCode)
130+
return nil, APIErrorFromResponse(response.StatusCode, response.Body)
137131
}
138132

139133
searchAccounts := CredentialSearchResponse{}
@@ -198,8 +192,7 @@ func (a *pamAPI) UpdateAccount(ctx context.Context, accountID string, credential
198192
}
199193

200194
if response.StatusCode != 200 {
201-
tflog.Error(ctx, fmt.Sprintf("failed to update account, got response: %s", response.Body))
202-
return nil, fmt.Errorf("failed to update account. Expected status code 200, got %d", response.StatusCode)
195+
return nil, APIErrorFromResponse(response.StatusCode, response.Body)
203196
}
204197

205198
updatedAccount := CredentialResponse{}
@@ -208,9 +201,6 @@ func (a *pamAPI) UpdateAccount(ctx context.Context, accountID string, credential
208201
return nil, err
209202
}
210203

211-
tflog.Info(ctx, fmt.Sprintf("Successfully updated account [%s]: Name [%s] - ID [%v]",
212-
*updatedAccount.UserName, *updatedAccount.Name, *updatedAccount.CredID))
213-
214204
return &updatedAccount, nil
215205
}
216206

@@ -237,6 +227,19 @@ func generateAccountPatch(existing *CredentialResponse, desired *Credential) ([]
237227
"path": "/address",
238228
"value": *desired.Address,
239229
})
230+
} else if desired.Address != nil && existing.Address == nil {
231+
// If existing has no address but desired does, add it
232+
patch = append(patch, map[string]interface{}{
233+
"op": "add",
234+
"path": "/address",
235+
"value": *desired.Address,
236+
})
237+
} else if desired.Address == nil && existing.Address != nil {
238+
// If existing has an address but desired does not, remove it
239+
patch = append(patch, map[string]interface{}{
240+
"op": "remove",
241+
"path": "/address",
242+
})
240243
}
241244

242245
if desired.UserName != nil && existing.UserName != nil && *existing.UserName != *desired.UserName {
@@ -332,11 +335,9 @@ func (a *pamAPI) DeleteAccount(ctx context.Context, accountID string) error {
332335
}
333336

334337
if response.StatusCode != 204 {
335-
tflog.Error(ctx, fmt.Sprintf("failed to delete account, got response: %s", response.Body))
336-
return fmt.Errorf("failed to delete account. Expected status code 204, got %d", response.StatusCode)
338+
return APIErrorFromResponse(response.StatusCode, response.Body)
337339
}
338340

339-
tflog.Info(ctx, fmt.Sprintf("Successfully deleted account with ID [%s]", accountID))
340341
return nil
341342
}
342343

@@ -359,11 +360,8 @@ func (a *pamAPI) AddSafe(ctx context.Context, safe SafeData) (*SafeData, error)
359360
return nil, err
360361
}
361362

362-
if response.StatusCode == 409 {
363-
tflog.Info(ctx, fmt.Sprintf("Safe [%s] already exists.", *safe.Name))
364-
return nil, nil
365-
} else if response.StatusCode != 201 {
366-
return nil, fmt.Errorf("failed to add safe, expected status code 201, got %d", response.StatusCode)
363+
if response.StatusCode != 201 {
364+
return nil, APIErrorFromResponse(response.StatusCode, response.Body)
367365
}
368366

369367
savedSafe := SafeData{}
@@ -372,9 +370,6 @@ func (a *pamAPI) AddSafe(ctx context.Context, safe SafeData) (*SafeData, error)
372370
return nil, err
373371
}
374372

375-
tflog.Info(ctx, fmt.Sprintf("Successfully added new safe [%s]: Name [%s] - ID [%v]",
376-
*savedSafe.Name, *savedSafe.URLID, *savedSafe.NUMBER))
377-
378373
return &savedSafe, nil
379374
}
380375

@@ -393,7 +388,7 @@ func (a *pamAPI) GetSafe(ctx context.Context, safeID string) (*SafeData, error)
393388
}
394389

395390
if response.StatusCode != 200 {
396-
return nil, fmt.Errorf("failed to get safe. Expected status code 200, got %d", response.StatusCode)
391+
return nil, APIErrorFromResponse(response.StatusCode, response.Body)
397392
}
398393

399394
safe := SafeData{}
@@ -425,8 +420,7 @@ func (a *pamAPI) UpdateSafe(ctx context.Context, safeID string, safe SafeData) (
425420
}
426421

427422
if response.StatusCode != 200 {
428-
tflog.Error(ctx, fmt.Sprintf("failed to update safe, got response: %s", response.Body))
429-
return nil, fmt.Errorf("failed to update safe. Expected status code 200, got %d", response.StatusCode)
423+
return nil, APIErrorFromResponse(response.StatusCode, response.Body)
430424
}
431425

432426
updatedSafe := SafeData{}
@@ -435,9 +429,6 @@ func (a *pamAPI) UpdateSafe(ctx context.Context, safeID string, safe SafeData) (
435429
return nil, err
436430
}
437431

438-
tflog.Info(ctx, fmt.Sprintf("Successfully updated safe [%s]: Name [%s] - ID [%v]",
439-
*updatedSafe.Name, *updatedSafe.URLID, *updatedSafe.NUMBER))
440-
441432
return &updatedSafe, nil
442433
}
443434

@@ -456,11 +447,9 @@ func (a *pamAPI) DeleteSafe(ctx context.Context, safeID string) error {
456447
}
457448

458449
if response.StatusCode != 204 {
459-
tflog.Error(ctx, fmt.Sprintf("failed to delete safe, got response: %s", response.Body))
460-
return fmt.Errorf("failed to delete safe. Expected status code 204, got %d", response.StatusCode)
450+
return APIErrorFromResponse(response.StatusCode, response.Body)
461451
}
462452

463-
tflog.Info(ctx, fmt.Sprintf("Successfully deleted safe with ID [%s]", safeID))
464453
return nil
465454
}
466455

@@ -489,11 +478,8 @@ func (a *pamAPI) AddSafeMember(ctx context.Context, safe SafeData) (*Member, err
489478
return nil, err
490479
}
491480

492-
if response.StatusCode == 409 {
493-
tflog.Info(ctx, fmt.Sprintf("Safe [%s] already has member [%s].", *safe.Name, *safe.Owner))
494-
return nil, nil
495-
} else if response.StatusCode != 201 {
496-
return nil, fmt.Errorf("failed to add safe member, expected status code 201, got %d", response.StatusCode)
481+
if response.StatusCode != 201 {
482+
return nil, APIErrorFromResponse(response.StatusCode, response.Body)
497483
}
498484

499485
safeMember := Member{}
@@ -520,7 +506,7 @@ func (a *pamAPI) GetSafeMember(ctx context.Context, safe SafeData) (*Member, err
520506
}
521507

522508
if response.StatusCode != 200 {
523-
return nil, fmt.Errorf("failed to get safe member. Expected status code 200, got %d", response.StatusCode)
509+
return nil, APIErrorFromResponse(response.StatusCode, response.Body)
524510
}
525511

526512
safeMember := Member{}
@@ -565,18 +551,14 @@ func (a *pamAPI) UpdateSafeMember(ctx context.Context, safe SafeData) (*Member,
565551
}
566552

567553
if response.StatusCode != 200 {
568-
tflog.Error(ctx, fmt.Sprintf("failed to update safe member, got response: %s", response.Body))
569-
return nil, fmt.Errorf("failed to update safe member, expected status code 200, got %d", response.StatusCode)
554+
return nil, APIErrorFromResponse(response.StatusCode, response.Body)
570555
}
571556

572-
tflog.Info(ctx, fmt.Sprintf("Successfully updated member [%s] permissions in safe [%s]", *safe.Owner, *safe.Name))
573557
return &updatedSafeMember, nil
574558
}
575559

576560
// DeleteSafeMember deletes a safe member from the SecretsHub.
577561
func (a *pamAPI) DeleteSafeMember(ctx context.Context, safeName string, memberName string) error {
578-
tflog.Debug(ctx, fmt.Sprintf("Attempting to delete member [%s] from safe [%s]", memberName, safeName))
579-
580562
response, err := a.client.DoRequest(
581563
ctx,
582564
"DELETE",
@@ -589,14 +571,10 @@ func (a *pamAPI) DeleteSafeMember(ctx context.Context, safeName string, memberNa
589571
return err
590572
}
591573

592-
if response.StatusCode == 404 {
593-
tflog.Info(ctx, fmt.Sprintf("Member [%s] not found in safe [%s]", memberName, safeName))
594-
return nil
595-
} else if response.StatusCode != 204 {
596-
return fmt.Errorf("failed to delete safe member, expected status code 204, got %d", response.StatusCode)
574+
if response.StatusCode != 204 {
575+
return APIErrorFromResponse(response.StatusCode, response.Body)
597576
}
598577

599-
tflog.Info(ctx, fmt.Sprintf("Successfully removed member [%s] from safe [%s]", memberName, safeName))
600578
return nil
601579
}
602580

0 commit comments

Comments
 (0)