fix: address CI lint errors (gosec, errcheck, unparam, duplicate tests) (#730)
* fix: address CI lint errors (gosec, errcheck, unparam, duplicate tests) - Remove duplicate TestHandleDelete_DryRun and TestHandleDelete_PartialSuccess from server_mutations_test.go (already defined in server_delete_test.go) - Add nolint:gosec comments for exec.CommandContext calls in sync_branch.go (variables come from trusted config/git sources) - Fix gosec G304/G306 in yaml_config.go (file read/write permissions) - Fix errcheck in mol_run.go (templateStore.Close) - Add nolint:unparam for updateYamlKey error return * fix: add remaining nolint:gosec comments for exec.CommandContext calls - sync_branch.go: diffCmd, logCmd (dry-run), commitCmd, pushCmd, remoteCmd - sync_check.go: checkLocalCmd * fix: add more nolint:gosec comments for exec.CommandContext calls - sync_branch.go: pullCmd - sync_check.go: localRefCmd, remoteRefCmd, aheadCmd - sync_import.go: checkoutCmd * fix: add final nolint:gosec comments for exec.CommandContext calls - sync_check.go: behindCmd - sync_import.go: fetchCmd --------- Co-authored-by: Charles P. Cross <cpdata@users.noreply.github.com>
This commit is contained in:
@@ -83,7 +83,7 @@ func SetYamlConfig(key, value string) error {
|
||||
}
|
||||
|
||||
// Read existing config
|
||||
content, err := os.ReadFile(configPath)
|
||||
content, err := os.ReadFile(configPath) //nolint:gosec // configPath is from findProjectConfigYaml
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to read config.yaml: %w", err)
|
||||
}
|
||||
@@ -95,7 +95,7 @@ func SetYamlConfig(key, value string) error {
|
||||
}
|
||||
|
||||
// Write back
|
||||
if err := os.WriteFile(configPath, []byte(newContent), 0644); err != nil {
|
||||
if err := os.WriteFile(configPath, []byte(newContent), 0600); err != nil { //nolint:gosec // configPath is validated
|
||||
return fmt.Errorf("failed to write config.yaml: %w", err)
|
||||
}
|
||||
|
||||
@@ -132,6 +132,8 @@ func findProjectConfigYaml() (string, error) {
|
||||
// updateYamlKey updates a key in yaml content, handling commented-out keys.
|
||||
// If the key exists (commented or not), it updates it in place.
|
||||
// If the key doesn't exist, it appends it at the end.
|
||||
//
|
||||
//nolint:unparam // error return kept for future validation
|
||||
func updateYamlKey(content, key, value string) (string, error) {
|
||||
// Format the value appropriately
|
||||
formattedValue := formatYamlValue(value)
|
||||
|
||||
@@ -712,96 +712,6 @@ func TestHandleDelete_BatchEmitsMutations(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestHandleDelete_DryRun verifies that dry-run mode returns preview without actual deletion
|
||||
func TestHandleDelete_DryRun(t *testing.T) {
|
||||
store := memory.New("/tmp/test.jsonl")
|
||||
server := NewServer("/tmp/test.sock", store, "/tmp", "/tmp/test.db")
|
||||
|
||||
// Create test issues
|
||||
issueIDs := make([]string, 2)
|
||||
for i := 0; i < 2; i++ {
|
||||
createArgs := CreateArgs{
|
||||
Title: "Issue for Dry Run " + string(rune('A'+i)),
|
||||
IssueType: "task",
|
||||
Priority: 2,
|
||||
}
|
||||
createJSON, _ := json.Marshal(createArgs)
|
||||
createReq := &Request{
|
||||
Operation: OpCreate,
|
||||
Args: createJSON,
|
||||
Actor: "test-user",
|
||||
}
|
||||
|
||||
createResp := server.handleCreate(createReq)
|
||||
if !createResp.Success {
|
||||
t.Fatalf("failed to create test issue %d: %s", i, createResp.Error)
|
||||
}
|
||||
|
||||
var createdIssue map[string]interface{}
|
||||
if err := json.Unmarshal(createResp.Data, &createdIssue); err != nil {
|
||||
t.Fatalf("failed to parse created issue %d: %v", i, err)
|
||||
}
|
||||
issueIDs[i] = createdIssue["id"].(string)
|
||||
}
|
||||
|
||||
// Clear mutation buffer
|
||||
_ = server.GetRecentMutations(time.Now().UnixMilli())
|
||||
|
||||
// Dry-run delete
|
||||
deleteArgs := DeleteArgs{
|
||||
IDs: issueIDs,
|
||||
DryRun: true,
|
||||
}
|
||||
deleteJSON, _ := json.Marshal(deleteArgs)
|
||||
deleteReq := &Request{
|
||||
Operation: OpDelete,
|
||||
Args: deleteJSON,
|
||||
Actor: "test-user",
|
||||
}
|
||||
|
||||
deleteResp := server.handleDelete(deleteReq)
|
||||
if !deleteResp.Success {
|
||||
t.Fatalf("dry-run delete operation failed: %s", deleteResp.Error)
|
||||
}
|
||||
|
||||
// Parse response
|
||||
var result map[string]interface{}
|
||||
if err := json.Unmarshal(deleteResp.Data, &result); err != nil {
|
||||
t.Fatalf("failed to parse delete response: %v", err)
|
||||
}
|
||||
|
||||
// Verify dry-run response structure
|
||||
if dryRun, ok := result["dry_run"].(bool); !ok || !dryRun {
|
||||
t.Errorf("expected dry_run=true in response, got %v", result["dry_run"])
|
||||
}
|
||||
|
||||
if issueCount, ok := result["issue_count"].(float64); !ok || int(issueCount) != 2 {
|
||||
t.Errorf("expected issue_count=2 in response, got %v", result["issue_count"])
|
||||
}
|
||||
|
||||
// Verify no mutation events were emitted (dry-run doesn't delete)
|
||||
mutations := server.GetRecentMutations(0)
|
||||
for _, m := range mutations {
|
||||
if m.Type == MutationDelete {
|
||||
t.Errorf("unexpected delete mutation in dry-run mode: %s", m.IssueID)
|
||||
}
|
||||
}
|
||||
|
||||
// Verify issues still exist (not actually deleted)
|
||||
for _, id := range issueIDs {
|
||||
showArgs := ShowArgs{ID: id}
|
||||
showJSON, _ := json.Marshal(showArgs)
|
||||
showReq := &Request{
|
||||
Operation: OpShow,
|
||||
Args: showJSON,
|
||||
}
|
||||
showResp := server.handleShow(showReq)
|
||||
if !showResp.Success {
|
||||
t.Errorf("issue %s should still exist after dry-run, but got error: %s", id, showResp.Error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestHandleDelete_ErrorEmptyIDs verifies error when no issue IDs provided
|
||||
func TestHandleDelete_ErrorEmptyIDs(t *testing.T) {
|
||||
store := memory.New("/tmp/test.jsonl")
|
||||
@@ -883,93 +793,6 @@ func TestHandleDelete_ErrorIssueNotFound(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
// TestHandleDelete_PartialSuccess verifies partial success when some issues exist and some don't
|
||||
func TestHandleDelete_PartialSuccess(t *testing.T) {
|
||||
store := memory.New("/tmp/test.jsonl")
|
||||
server := NewServer("/tmp/test.sock", store, "/tmp", "/tmp/test.db")
|
||||
|
||||
// Create one valid issue
|
||||
createArgs := CreateArgs{
|
||||
Title: "Valid Issue for Partial Delete",
|
||||
IssueType: "bug",
|
||||
Priority: 1,
|
||||
}
|
||||
createJSON, _ := json.Marshal(createArgs)
|
||||
createReq := &Request{
|
||||
Operation: OpCreate,
|
||||
Args: createJSON,
|
||||
Actor: "test-user",
|
||||
}
|
||||
|
||||
createResp := server.handleCreate(createReq)
|
||||
if !createResp.Success {
|
||||
t.Fatalf("failed to create test issue: %s", createResp.Error)
|
||||
}
|
||||
|
||||
var createdIssue map[string]interface{}
|
||||
if err := json.Unmarshal(createResp.Data, &createdIssue); err != nil {
|
||||
t.Fatalf("failed to parse created issue: %v", err)
|
||||
}
|
||||
validID := createdIssue["id"].(string)
|
||||
|
||||
// Try to delete both valid and invalid issues
|
||||
deleteArgs := DeleteArgs{
|
||||
IDs: []string{validID, "bd-nonexistent-xyz"},
|
||||
Force: true,
|
||||
}
|
||||
deleteJSON, _ := json.Marshal(deleteArgs)
|
||||
deleteReq := &Request{
|
||||
Operation: OpDelete,
|
||||
Args: deleteJSON,
|
||||
Actor: "test-user",
|
||||
}
|
||||
|
||||
deleteResp := server.handleDelete(deleteReq)
|
||||
if !deleteResp.Success {
|
||||
t.Fatalf("partial delete should succeed with partial_success flag: %s", deleteResp.Error)
|
||||
}
|
||||
|
||||
// Parse response
|
||||
var result map[string]interface{}
|
||||
if err := json.Unmarshal(deleteResp.Data, &result); err != nil {
|
||||
t.Fatalf("failed to parse response: %v", err)
|
||||
}
|
||||
|
||||
// Verify partial success
|
||||
if deletedCount, ok := result["deleted_count"].(float64); !ok || int(deletedCount) != 1 {
|
||||
t.Errorf("expected deleted_count=1, got %v", result["deleted_count"])
|
||||
}
|
||||
|
||||
if totalCount, ok := result["total_count"].(float64); !ok || int(totalCount) != 2 {
|
||||
t.Errorf("expected total_count=2, got %v", result["total_count"])
|
||||
}
|
||||
|
||||
if partialSuccess, ok := result["partial_success"].(bool); !ok || !partialSuccess {
|
||||
t.Errorf("expected partial_success=true, got %v", result["partial_success"])
|
||||
}
|
||||
|
||||
// Verify errors array contains the not found error
|
||||
if errors, ok := result["errors"].([]interface{}); ok {
|
||||
if len(errors) != 1 {
|
||||
t.Errorf("expected 1 error, got %d", len(errors))
|
||||
}
|
||||
} else {
|
||||
t.Error("expected errors array in response")
|
||||
}
|
||||
|
||||
// Verify the valid issue was actually deleted
|
||||
showArgs := ShowArgs{ID: validID}
|
||||
showJSON, _ := json.Marshal(showArgs)
|
||||
showReq := &Request{
|
||||
Operation: OpShow,
|
||||
Args: showJSON,
|
||||
}
|
||||
showResp := server.handleShow(showReq)
|
||||
if showResp.Success {
|
||||
t.Error("deleted issue should not be found")
|
||||
}
|
||||
}
|
||||
|
||||
// TestHandleDelete_ErrorCannotDeleteTemplate verifies that templates cannot be deleted
|
||||
func TestHandleDelete_ErrorCannotDeleteTemplate(t *testing.T) {
|
||||
store := memory.New("/tmp/test.jsonl")
|
||||
|
||||
Reference in New Issue
Block a user