40 lines
9.9 KiB
JSON
40 lines
9.9 KiB
JSON
[
|
|
{"file": "internal/service/material.go", "line": 50, "severity": "medium", "category": "error-handling", "description": "Error from s.logSvc.LogCreate is only logged as warning, not propagated. If logging fails silently, caller has no indication."},
|
|
{"file": "internal/service/material.go", "line": 73, "severity": "low", "category": "null-pointer", "description": "Error from s.GetByID for old material is ignored. oldMaterial can be nil when passed to LogUpdate, causing potential nil pointer dereference in LogUpdate at line 33 where json.Marshal(oldMaterial) is called."},
|
|
{"file": "internal/service/material.go", "line": 83, "severity": "low", "category": "null-pointer", "description": "Error from s.GetByID for new material is ignored. If this fails, newMaterial is nil and will cause nil pointer dereference in LogUpdate."},
|
|
{"file": "internal/service/material.go", "line": 98, "severity": "high", "category": "null-pointer", "description": "Error from s.GetByID is completely ignored with _. If GetByID fails, material is nil and LogDelete at line 107 will receive nil, causing panic in LogDelete when accessing material.Name."},
|
|
{"file": "internal/service/material_log.go", "line": 22, "severity": "low", "category": "error-handling", "description": "json.Marshal error is silently ignored with _. If marshaling fails, empty newValue is stored without any error indication."},
|
|
{"file": "internal/service/material_log.go", "line": 34, "severity": "low", "category": "error-handling", "description": "json.Marshal errors for oldMaterial and material are silently ignored. If marshaling fails, empty values are stored."},
|
|
{"file": "internal/service/material_log.go", "line": 48, "severity": "low", "category": "error-handling", "description": "json.Marshal error is silently ignored with _. If marshaling fails, empty oldValue is stored."},
|
|
{"file": "internal/repository/material.go", "line": 172, "severity": "medium", "category": "error-handling", "description": "QueryRow().Scan(&count) error is completely ignored. If the query fails, count remains 0 and deletion proceeds incorrectly."},
|
|
{"file": "internal/repository/material.go", "line": 178, "severity": "medium", "category": "error-handling", "description": "QueryRow().Scan(&count) error is completely ignored for outbound_items check."},
|
|
{"file": "internal/repository/material.go", "line": 184, "severity": "medium", "category": "error-handling", "description": "QueryRow().Scan(&count) error is completely ignored for stock_logs check."},
|
|
{"file": "internal/repository/application.go", "line": 39, "severity": "low", "category": "error-handling", "description": "LastInsertId error is silently ignored with _. If LastInsertId fails, item.ID remains 0."},
|
|
{"file": "internal/service/application.go", "line": 109, "severity": "medium", "category": "error-handling", "description": "GetApproverName error is silently ignored with _. If it fails, approverName is empty string, and the outbound handler field will be blank."},
|
|
{"file": "internal/handler/api.go", "line": 988, "severity": "low", "category": "error-handling", "description": "ShouldBindJSON error is ignored with c.ShouldBindJSON(&req). If binding fails, req.AutoOutbound defaults to false without the user knowing their request was malformed."},
|
|
{"file": "internal/middleware/auth.go", "line": 21, "severity": "medium", "category": "resource-leak", "description": "service.NewAuthService() is called on every request in the middleware. Each call creates a new UserRepository and potentially new database connections. Should be a shared service instance."},
|
|
{"file": "internal/middleware/auth.go", "line": 101, "severity": "medium", "category": "resource-leak", "description": "service.NewAuthService() is called in OptionalAuth middleware on every request, creating new service instances repeatedly."},
|
|
{"file": "internal/repository/user.go", "line": 189, "severity": "high", "category": "business-logic", "description": "CreateDefaultUsers inserts two users in separate transactions. If admin is created but user creation fails, only admin exists. Subsequent runs will skip due to admin existing check, but the function is not idempotent for user creation."},
|
|
{"file": "internal/service/inbound.go", "line": 159, "severity": "high", "category": "business-logic", "description": "In Update method, reversing stock for old items uses -item.Quantity but old items are not validated against current stock. If previous update reduced stock below current values, this could cause incorrect stock restoration."},
|
|
{"file": "internal/service/application.go", "line": 86, "severity": "high", "category": "business-logic", "description": "Approve method checks stock for all items but does not reserve the stock atomically. Between the check and actual deduction in autoOutbound path, another request could consume the stock (race condition)."},
|
|
{"file": "internal/service/auth.go", "line": 62, "severity": "high", "category": "security", "description": "HMAC key 'warehouse-mms-secret-key' is hardcoded in source code. This key should be loaded from environment variable or config file to allow rotation and prevent exposure in source control."},
|
|
{"file": "internal/service/auth.go", "line": 80, "severity": "high", "category": "security", "description": "Same hardcoded HMAC key 'warehouse-mms-secret-key' used in ValidateToken. If this key is compromised, all tokens can be forged."},
|
|
{"file": "internal/handler/upload.go", "line": 44, "severity": "medium", "category": "security", "description": "Generated filename uses time.Now().UnixNano() which is predictable. An attacker could potentially guess upload filenames. Use crypto/rand for secure random filenames."},
|
|
{"file": "internal/handler/websocket.go", "line": 16, "severity": "high", "category": "security", "description": "CheckOrigin returns true allowing all origins. This enables cross-site WebSocket hijacking attacks. Should validate Origin header against allowed domains."},
|
|
{"file": "cmd/server/main.go", "line": 16, "severity": "medium", "category": "security", "description": "Default database DSN is hardcoded with password '1234'. While this is common for development, the code should require DB_DSN environment variable to be set in production."},
|
|
{"file": "internal/repository/inbound.go", "line": 77, "severity": "medium", "category": "null-pointer", "description": "order.Items is appended in loop but never initialized. If query returns no rows, order.Items remains nil. Line 77 appends to nil slice which is valid (creates new slice), but the caller receives empty Items."},
|
|
{"file": "internal/repository/inbound.go", "line": 17, "severity": "low", "category": "code-duplication", "description": "BeginTx pattern (lines 17-50) is duplicated in OutboundRepo.Create (lines 17-50). Both create order then items in same transaction pattern."},
|
|
{"file": "internal/repository/outbound.go", "line": 17, "severity": "low", "category": "code-duplication", "description": "BeginTx pattern duplicated from InboundRepo.Create. Same transaction pattern for creating orders with items."},
|
|
{"file": "internal/repository/inbound.go", "line": 171, "severity": "low", "category": "code-duplication", "description": "UpdateTx pattern (lines 171-211) is same as OutboundRepo.UpdateTx with different table names. Consider extracting common logic."},
|
|
{"file": "internal/repository/outbound.go", "line": 171, "severity": "low", "category": "code-duplication", "description": "UpdateTx pattern duplicated from InboundRepo.UpdateTx."},
|
|
{"file": "internal/service/inbound.go", "line": 94, "severity": "low", "category": "error-handling", "description": "Delete method returns error from GetByID but doesn't handle case where order.Items might be nil or empty. If Delete is called on already deleted order, behavior is unclear."},
|
|
{"file": "internal/service/outbound.go", "line": 140, "severity": "low", "category": "error-handling", "description": "Same issue as inbound Delete - no handling for nil/empty Items in Delete method."},
|
|
{"file": "internal/repository/stock.go", "line": 108, "severity": "low", "category": "null-pointer", "description": "logs is initialized as nil slice. If rows.Next() never executes (no logs), function returns nil not empty slice. Handler then checks if logs == nil and sets to empty slice, but direct callers get nil."},
|
|
{"file": "internal/repository/material_log.go", "line": 98, "severity": "low", "category": "null-pointer", "description": "logs is nil slice. If no rows, function returns nil. Callers in handler check for nil but service layer doesn't initialize empty slice."},
|
|
{"file": "internal/handler/api.go", "line": 835, "severity": "low", "category": "naming-inconsistency", "description": "UpdateUser handler checks req.Role != admin/user but Role field is not required in binding. If role is empty string, check passes but empty role is stored in database."},
|
|
{"file": "internal/handler/api.go", "line": 802, "severity": "low", "category": "naming-inconsistency", "description": "CreateUser has same role validation issue as UpdateUser."},
|
|
{"file": "internal/service/application.go", "line": 85, "severity": "medium", "category": "business-logic", "description": "Approve checks app.Status != pending but doesn't check if app.Items is empty. Approving an application with no items succeeds but does nothing."},
|
|
{"file": "internal/service/application.go", "line": 160, "severity": "medium", "category": "business-logic", "description": "Reject also doesn't validate that app.Items exists or has valid items."},
|
|
{"file": "internal/service/auth.go", "line": 203, "severity": "low", "category": "code-duplication", "description": "HashPassword function duplicates bcrypt.GenerateFromPassword logic already used in CreateUser. Could reuse CreateUser or extract common hashing logic."},
|
|
{"file": "internal/service/auth.go", "line": 121, "severity": "low", "category": "error-handling", "description": "Login returns ErrInvalidCredentials for both user-not-found and wrong-password cases. This is intentional security practice (prevents username enumeration) but worth documenting."}
|
|
] |