fix: audit nolint:errcheck — fix dangerous suppression patterns
CI / Nginx config check (push) Successful in 14s
CI / Docker compose check (push) Successful in 14s
CI / Env docs check (push) Successful in 15s
CI / Frontend major deps (push) Successful in 25s
CI / Frontend deps check (push) Successful in 26s
CI / Secrets scan (push) Successful in 36s
CI / Go build (push) Successful in 42s
CI / Frontend build (push) Successful in 48s
CI / Knip (push) Successful in 28s
CI / Frontend a11y check (push) Successful in 1m26s
CI / Go vet (prod) (push) Failing after 2m9s
CI / go mod tidy (push) Successful in 59s
CI / Go vet (dev) (push) Failing after 2m10s
CI / Staticcheck (prod) (push) Failing after 2m42s
CI / Staticcheck (dev) (push) Failing after 2m56s
CI / Frontend QC (audit) (push) Successful in 1m7s
CI / golangci-lint (push) Successful in 3m38s
CI / Go vulnerabilities (push) Successful in 1m40s
CI / Frontend QC (typecheck) (push) Successful in 1m45s
CI / Frontend QC (lint) (push) Failing after 1m21s
CI / Svelte strict check (push) Has been skipped
CI / Security scan (prod) (push) Successful in 4m18s
CI / Security scan (dev) (push) Successful in 4m28s
CI / Tests (prod) (push) Has been skipped
CI / Tests (dev) (push) Has been skipped
CI / Race (prod) (push) Has been skipped
CI / Race (dev) (push) Has been skipped

This commit is contained in:
2026-07-11 12:57:41 +01:00
parent 19be37171b
commit a3c0be2890
3 changed files with 74 additions and 56 deletions
+21 -15
View File
@@ -2698,8 +2698,9 @@ func ProgressBookingHandler(w http.ResponseWriter, r *http.Request) {
// Don't award a stamp if this booking already used a loyalty redemption // Don't award a stamp if this booking already used a loyalty redemption
// (take or receive, never both). // (take or receive, never both).
var loyaltyAppliedOnThisBooking bool var loyaltyAppliedOnThisBooking bool
//nolint:errcheck // zero value is acceptable fallback on scan failure if err := tx.QueryRow(r.Context(), `SELECT EXISTS(SELECT 1 FROM booking_discounts WHERE booking_id = $1 AND discount_source = 'loyalty')`, bookingID).Scan(&loyaltyAppliedOnThisBooking); err != nil {
_ = tx.QueryRow(r.Context(), `SELECT EXISTS(SELECT 1 FROM booking_discounts WHERE booking_id = $1 AND discount_source = 'loyalty')`, bookingID).Scan(&loyaltyAppliedOnThisBooking) log.Printf("Failed to check loyalty applied on booking %s: %v", bookingID, err)
}
var newStampCount int var newStampCount int
if bookingTotal > 0 && !loyaltyAppliedOnThisBooking { if bookingTotal > 0 && !loyaltyAppliedOnThisBooking {
@@ -2735,8 +2736,9 @@ func ProgressBookingHandler(w http.ResponseWriter, r *http.Request) {
// Skip time-based campaign if already applied at payment time // Skip time-based campaign if already applied at payment time
var timeBasedApplied bool var timeBasedApplied bool
//nolint:errcheck // zero value is acceptable fallback on scan failure if err := tx.QueryRow(r.Context(), `SELECT EXISTS(SELECT 1 FROM booking_discounts WHERE booking_id = $1 AND discount_source = 'campaign' AND campaign_type = 'time_based')`, bookingID).Scan(&timeBasedApplied); err != nil {
_ = tx.QueryRow(r.Context(), `SELECT EXISTS(SELECT 1 FROM booking_discounts WHERE booking_id = $1 AND discount_source = 'campaign' AND campaign_type = 'time_based')`, bookingID).Scan(&timeBasedApplied) log.Printf("Failed to check time-based campaign applied on booking %s: %v", bookingID, err)
}
if bookingTotal > 0 && !timeBasedApplied { if bookingTotal > 0 && !timeBasedApplied {
var campaignID string var campaignID string
var campaignPercent float64 var campaignPercent float64
@@ -2778,13 +2780,14 @@ func ProgressBookingHandler(w http.ResponseWriter, r *http.Request) {
var milestoneCampaignID string var milestoneCampaignID string
var milestonePercent float64 var milestonePercent float64
//nolint:errcheck // zero value is acceptable fallback on scan failure if err := tx.QueryRow(r.Context(), `
_ = tx.QueryRow(r.Context(), `
SELECT id, discount_percent FROM discount_campaigns SELECT id, discount_percent FROM discount_campaigns
WHERE status = 'active' AND campaign_type = 'milestone' AND milestone_type = 'per_user_booking_count' WHERE status = 'active' AND campaign_type = 'milestone' AND milestone_type = 'per_user_booking_count'
AND milestone_value = $1 AND milestone_value = $1
AND NOT EXISTS (SELECT 1 FROM booking_discounts WHERE user_id = $2 AND source_id = discount_campaigns.id) AND NOT EXISTS (SELECT 1 FROM booking_discounts WHERE user_id = $2 AND source_id = discount_campaigns.id)
`, userBookingCount, booking.User.ID).Scan(&milestoneCampaignID, &milestonePercent) `, userBookingCount, booking.User.ID).Scan(&milestoneCampaignID, &milestonePercent); err != nil {
log.Printf("Failed to query per-user milestone campaign for booking %s: %v", bookingID, err)
}
if milestoneCampaignID != "" { if milestoneCampaignID != "" {
discountAmount := roundTo2(bookingTotal * milestonePercent / 100) discountAmount := roundTo2(bookingTotal * milestonePercent / 100)
@@ -2808,29 +2811,32 @@ func ProgressBookingHandler(w http.ResponseWriter, r *http.Request) {
} }
var globalMilestoneApplied bool var globalMilestoneApplied bool
//nolint:errcheck // zero value is acceptable fallback on scan failure if err := tx.QueryRow(r.Context(), `SELECT EXISTS(SELECT 1 FROM booking_discounts WHERE booking_id = $1 AND discount_source = 'campaign' AND campaign_type = 'milestone' AND milestone_type = 'global_booking_count')`, bookingID).Scan(&globalMilestoneApplied); err != nil {
_ = tx.QueryRow(r.Context(), `SELECT EXISTS(SELECT 1 FROM booking_discounts WHERE booking_id = $1 AND discount_source = 'campaign' AND campaign_type = 'milestone' AND milestone_type = 'global_booking_count')`, bookingID).Scan(&globalMilestoneApplied) log.Printf("Failed to check global milestone applied on booking %s: %v", bookingID, err)
}
if !globalMilestoneApplied { if !globalMilestoneApplied {
var globalCount int var globalCount int
//nolint:errcheck // zero value is acceptable fallback on scan failure //nolint:errcheck // zero value is acceptable fallback on scan failure
_ = tx.QueryRow(r.Context(), `SELECT COUNT(*) FROM bookings WHERE status = 'completed'`).Scan(&globalCount) _ = tx.QueryRow(r.Context(), `SELECT COUNT(*) FROM bookings WHERE status = 'completed'`).Scan(&globalCount)
var hasInPersonPayment bool var hasInPersonPayment bool
//nolint:errcheck // zero value is acceptable fallback on scan failure if err := tx.QueryRow(r.Context(), `
_ = tx.QueryRow(r.Context(), ` SELECT EXISTS(SELECT 1 FROM payments WHERE booking_id = $1 AND payment_method = 'in_person_card')`, bookingID).Scan(&hasInPersonPayment); err != nil {
SELECT EXISTS(SELECT 1 FROM payments WHERE booking_id = $1 AND payment_method = 'in_person_card')`, bookingID).Scan(&hasInPersonPayment) log.Printf("Failed to check in-person payment on booking %s: %v", bookingID, err)
}
if hasInPersonPayment { if hasInPersonPayment {
var globalCampaignID string var globalCampaignID string
var globalPercent float64 var globalPercent float64
//nolint:errcheck // zero value is acceptable fallback on scan failure if err := tx.QueryRow(r.Context(), `
_ = tx.QueryRow(r.Context(), `
SELECT id, discount_percent FROM discount_campaigns SELECT id, discount_percent FROM discount_campaigns
WHERE status = 'active' AND campaign_type = 'milestone' AND milestone_type = 'global_booking_count' WHERE status = 'active' AND campaign_type = 'milestone' AND milestone_type = 'global_booking_count'
AND milestone_value <= $1 AND milestone_value <= $1
AND (max_redemptions IS NULL OR times_redeemed < max_redemptions) AND (max_redemptions IS NULL OR times_redeemed < max_redemptions)
ORDER BY milestone_value DESC LIMIT 1 ORDER BY milestone_value DESC LIMIT 1
`, globalCount).Scan(&globalCampaignID, &globalPercent) `, globalCount).Scan(&globalCampaignID, &globalPercent); err != nil {
log.Printf("Failed to query global milestone campaign for booking %s: %v", bookingID, err)
}
if globalCampaignID != "" { if globalCampaignID != "" {
discountAmount := roundTo2(bookingTotal * globalPercent / 100) discountAmount := roundTo2(bookingTotal * globalPercent / 100)
+23 -16
View File
@@ -283,14 +283,11 @@ func AdminCreateBookingForUserHandler(w http.ResponseWriter, r *http.Request) {
} }
} }
// Get deposit info // Get deposit info — deposit_required already fetched above in the main booking query.
var depositRequired bool
var preStartPaid float64 var preStartPaid float64
//nolint:errcheck // zero value is acceptable fallback on scan failure //nolint:errcheck // zero value is acceptable fallback on scan failure (aggregate with COALESCE)
_ = db.Conn.QueryRow(r.Context(), `SELECT deposit_required FROM bookings WHERE id = $1`, existingID).Scan(&depositRequired)
//nolint:errcheck // zero value is acceptable fallback on scan failure
_ = db.Conn.QueryRow(r.Context(), `SELECT COALESCE(SUM(amount), 0) FROM payments WHERE booking_id = $1 AND payment_type IN ('deposit', 'full') AND status = 'completed'`, existingID).Scan(&preStartPaid) _ = db.Conn.QueryRow(r.Context(), `SELECT COALESCE(SUM(amount), 0) FROM payments WHERE booking_id = $1 AND payment_type IN ('deposit', 'full') AND status = 'completed'`, existingID).Scan(&preStartPaid)
populateDepositFields(&existingBooking, depositRequired, preStartPaid) populateDepositFields(&existingBooking, existingBooking.DepositRequired, preStartPaid)
w.Header().Set("Content-Type", "application/json") w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK) w.WriteHeader(http.StatusOK)
@@ -1211,13 +1208,19 @@ func RequestEditHandler(w http.ResponseWriter, r *http.Request) {
// Query payment and timing info (used for validation AND auto-approval later) // Query payment and timing info (used for validation AND auto-approval later)
var hasPayments bool var hasPayments bool
hoursUntilCurrent := currentStartTime.Sub(clock.Now()).Hours() hoursUntilCurrent := currentStartTime.Sub(clock.Now()).Hours()
//nolint:errcheck // zero value is acceptable fallback on scan failure if err := db.Conn.QueryRow(r.Context(), "SELECT EXISTS(SELECT 1 FROM payments WHERE booking_id = $1 AND status = 'completed')", bookingID).Scan(&hasPayments); err != nil {
_ = db.Conn.QueryRow(r.Context(), "SELECT EXISTS(SELECT 1 FROM payments WHERE booking_id = $1 AND status = 'completed')", bookingID).Scan(&hasPayments) log.Printf("Failed to check payments for booking %s: %v", bookingID, err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
// Check if booking has discounts (affects auto-approval decisions) // Check if booking has discounts (affects auto-approval decisions)
var hasDiscounts bool var hasDiscounts bool
//nolint:errcheck // zero value is acceptable fallback on scan failure if err := db.Conn.QueryRow(r.Context(), "SELECT EXISTS(SELECT 1 FROM booking_discounts WHERE booking_id = $1)", bookingID).Scan(&hasDiscounts); err != nil {
_ = db.Conn.QueryRow(r.Context(), "SELECT EXISTS(SELECT 1 FROM booking_discounts WHERE booking_id = $1)", bookingID).Scan(&hasDiscounts) log.Printf("Failed to check discounts for booking %s: %v", bookingID, err)
http.Error(w, "Internal server error", http.StatusInternalServerError)
return
}
if req.NewStartTime != nil && !req.NewStartTime.Equal(currentStartTime) { if req.NewStartTime != nil && !req.NewStartTime.Equal(currentStartTime) {
if hasPayments && hoursUntilCurrent < 72 { if hasPayments && hoursUntilCurrent < 72 {
@@ -1447,8 +1450,7 @@ func RequestEditHandler(w http.ResponseWriter, r *http.Request) {
var durationMinutes int var durationMinutes int
if len(req.NewServices) > 0 { if len(req.NewServices) > 0 {
//nolint:errcheck // zero value is acceptable fallback on scan failure if err := tx.QueryRow(r.Context(), `
_ = tx.QueryRow(r.Context(), `
SELECT COALESCE(SUM(dur), 60) FROM ( SELECT COALESCE(SUM(dur), 60) FROM (
SELECT s.duration_minutes AS dur SELECT s.duration_minutes AS dur
FROM services s FROM services s
@@ -1458,12 +1460,17 @@ func RequestEditHandler(w http.ResponseWriter, r *http.Request) {
FROM custom_services cs FROM custom_services cs
WHERE cs.id = ANY($1) WHERE cs.id = ANY($1)
) sub ) sub
`, req.NewServices).Scan(&durationMinutes) `, req.NewServices).Scan(&durationMinutes); err != nil {
log.Printf("Failed to calculate duration for edit request %s: %v, using default", bookingID, err)
durationMinutes = 60
}
} else { } else {
//nolint:errcheck // zero value is acceptable fallback on scan failure if err := tx.QueryRow(r.Context(), `
_ = tx.QueryRow(r.Context(), `
SELECT total_duration_minutes FROM bookings WHERE id = $1 SELECT total_duration_minutes FROM bookings WHERE id = $1
`, bookingID).Scan(&durationMinutes) `, bookingID).Scan(&durationMinutes); err != nil {
log.Printf("Failed to get booking duration for edit request %s: %v, using default", bookingID, err)
durationMinutes = 60
}
} }
_, err = tx.Exec(r.Context(), ` _, err = tx.Exec(r.Context(), `
+20 -15
View File
@@ -141,10 +141,11 @@ func calculateDiscountPreview(ctx context.Context, bookingID string, userID stri
} }
var bookingTotal float64 var bookingTotal float64
//nolint:errcheck // zero value is acceptable fallback on scan failure if err := db.Conn.QueryRow(ctx, `
_ = db.Conn.QueryRow(ctx, `
SELECT total_amount FROM bookings WHERE id = $1 SELECT total_amount FROM bookings WHERE id = $1
`, bookingID).Scan(&bookingTotal) `, bookingID).Scan(&bookingTotal); err != nil {
log.Printf("Failed to query booking total for discount preview %s: %v", bookingID, err)
}
if bookingTotal <= 0 { if bookingTotal <= 0 {
return resp return resp
@@ -185,13 +186,14 @@ func calculateDiscountPreview(ctx context.Context, bookingID string, userID stri
var milestoneCampaignID string var milestoneCampaignID string
var milestonePercent float64 var milestonePercent float64
var milestoneName string var milestoneName string
//nolint:errcheck // zero value is acceptable fallback on scan failure if err := db.Conn.QueryRow(ctx, `
_ = db.Conn.QueryRow(ctx, `
SELECT id, discount_percent, name FROM discount_campaigns SELECT id, discount_percent, name FROM discount_campaigns
WHERE status = 'active' AND campaign_type = 'milestone' AND milestone_type = 'per_user_booking_count' WHERE status = 'active' AND campaign_type = 'milestone' AND milestone_type = 'per_user_booking_count'
AND milestone_value = $1 AND milestone_value = $1
AND NOT EXISTS (SELECT 1 FROM booking_discounts WHERE user_id = $2 AND source_id = discount_campaigns.id) AND NOT EXISTS (SELECT 1 FROM booking_discounts WHERE user_id = $2 AND source_id = discount_campaigns.id)
`, userBookingCount, userID).Scan(&milestoneCampaignID, &milestonePercent, &milestoneName) `, userBookingCount, userID).Scan(&milestoneCampaignID, &milestonePercent, &milestoneName); err != nil {
log.Printf("Failed to query milestone campaign for discount preview (user %s, count %d): %v", userID, userBookingCount, err)
}
if milestoneCampaignID != "" { if milestoneCampaignID != "" {
var exists int var exists int
@@ -1021,8 +1023,7 @@ func CreateBookingPayment(w http.ResponseWriter, r *http.Request) {
// Promote deposit to confirmed if total paid meets the 20% threshold. // Promote deposit to confirmed if total paid meets the 20% threshold.
// Check is inside the transaction so it sees the just-inserted payments. // Check is inside the transaction so it sees the just-inserted payments.
var depositMet bool var depositMet bool
//nolint:errcheck // zero value is acceptable fallback on scan failure if err := tx.QueryRow(r.Context(), `
_ = tx.QueryRow(r.Context(), `
WITH booking_total AS ( WITH booking_total AS (
SELECT total_amount * 100 AS total_cents FROM bookings WHERE id = $1 SELECT total_amount * 100 AS total_cents FROM bookings WHERE id = $1
), ),
@@ -1033,7 +1034,9 @@ func CreateBookingPayment(w http.ResponseWriter, r *http.Request) {
) )
SELECT pt.paid_cents >= ROUND(bt.total_cents * 0.2) SELECT pt.paid_cents >= ROUND(bt.total_cents * 0.2)
FROM booking_total bt, paid_total pt FROM booking_total bt, paid_total pt
`, bookingID).Scan(&depositMet) `, bookingID).Scan(&depositMet); err != nil {
log.Printf("Failed to check deposit threshold for booking %s: %v", bookingID, err)
}
if depositMet { if depositMet {
if _, err := tx.Exec(r.Context(), ` if _, err := tx.Exec(r.Context(), `
@@ -1139,13 +1142,14 @@ func applyEligibleCampaignsAtPayment(ctx context.Context, q db.Querier, bookingI
var milestoneCampaignID string var milestoneCampaignID string
var milestonePercent float64 var milestonePercent float64
//nolint:errcheck // zero value is acceptable fallback on scan failure if err := q.QueryRow(ctx, `
_ = q.QueryRow(ctx, `
SELECT id, discount_percent FROM discount_campaigns SELECT id, discount_percent FROM discount_campaigns
WHERE status = 'active' AND campaign_type = 'milestone' AND milestone_type = 'per_user_booking_count' WHERE status = 'active' AND campaign_type = 'milestone' AND milestone_type = 'per_user_booking_count'
AND milestone_value = $1 AND milestone_value = $1
AND NOT EXISTS (SELECT 1 FROM booking_discounts WHERE user_id = $2 AND source_id = discount_campaigns.id) AND NOT EXISTS (SELECT 1 FROM booking_discounts WHERE user_id = $2 AND source_id = discount_campaigns.id)
`, userBookingCount, userID).Scan(&milestoneCampaignID, &milestonePercent) `, userBookingCount, userID).Scan(&milestoneCampaignID, &milestonePercent); err != nil {
log.Printf("Failed to query per-user milestone campaign: %v", err)
}
if milestoneCampaignID != "" { if milestoneCampaignID != "" {
var exists int var exists int
@@ -1251,15 +1255,16 @@ func applyEligibleCampaignsAtPayment(ctx context.Context, q db.Querier, bookingI
var globalCampaignID string var globalCampaignID string
var globalPercent float64 var globalPercent float64
//nolint:errcheck // zero value is acceptable fallback on scan failure if err := q.QueryRow(ctx, `
_ = q.QueryRow(ctx, `
SELECT id, discount_percent FROM discount_campaigns SELECT id, discount_percent FROM discount_campaigns
WHERE status = 'active' AND campaign_type = 'milestone' AND milestone_type = 'global_booking_count' WHERE status = 'active' AND campaign_type = 'milestone' AND milestone_type = 'global_booking_count'
AND milestone_value <= $1 AND milestone_value <= $1
AND (max_redemptions IS NULL OR times_redeemed < max_redemptions) AND (max_redemptions IS NULL OR times_redeemed < max_redemptions)
AND NOT EXISTS (SELECT 1 FROM booking_discounts WHERE source_id = discount_campaigns.id AND booking_id = $2) AND NOT EXISTS (SELECT 1 FROM booking_discounts WHERE source_id = discount_campaigns.id AND booking_id = $2)
ORDER BY milestone_value DESC LIMIT 1 ORDER BY milestone_value DESC LIMIT 1
`, globalCount, bookingID).Scan(&globalCampaignID, &globalPercent) `, globalCount, bookingID).Scan(&globalCampaignID, &globalPercent); err != nil {
log.Printf("Failed to query global milestone campaign: %v", err)
}
if globalCampaignID != "" { if globalCampaignID != "" {
var exists int var exists int