feat(03-02): add allow-listed database-default order helper

- Reject identifiers and directions outside the caller allow-list
- Emit ordinary ORDER BY without COLLATE so ICU pl-PL applies

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Jakub Zych
2026-09-17 20:13:03 +02:00
parent 20bd8fe8fc
commit 56be82f3f3
2 changed files with 85 additions and 0 deletions

46
lagoon/order.go Normal file
View File

@@ -0,0 +1,46 @@
package lagoon
import (
"fmt"
"strings"
"gorm.io/gorm"
)
// OrderBy appends a database-default ORDER BY for an allow-listed qualified
// column. Identifiers and directions are never taken from untrusted input:
// column must match allowed exactly, and dir must be asc or desc. No COLLATE
// is emitted; Postgres ICU pl-PL is the database default (CheckLocale).
func OrderBy(db *gorm.DB, column, dir string, allowed []string) (*gorm.DB, error) {
if db == nil {
return nil, fmt.Errorf("lagoon: gorm db is nil")
}
clause, err := orderClause(column, dir, allowed)
if err != nil {
return nil, err
}
return db.Order(clause), nil
}
func orderClause(column, dir string, allowed []string) (string, error) {
if !allowListed(column, allowed) {
return "", fmt.Errorf("lagoon: order column %q is not allow-listed", column)
}
switch strings.ToLower(strings.TrimSpace(dir)) {
case "asc":
return column + " ASC", nil
case "desc":
return column + " DESC", nil
default:
return "", fmt.Errorf("lagoon: order direction %q is not allow-listed", dir)
}
}
func allowListed(column string, allowed []string) bool {
for _, a := range allowed {
if a == column {
return true
}
}
return false
}