Skip to content

GetByID in internal/handlers/ecosystems_public.go silently swallows the aggregate stats query error, returning zero project/contributor/issue/PR counts with no indication of failure #403

Description

@Jagadeeshftw

Description

EcosystemsPublicHandler.GetByID fetches an ecosystem's detail row, then runs a second aggregate query to compute project_count, contributors_count, open_issues_count, and open_prs_count for the response — but discards that second query's error entirely:

var projectCount int64
var contributorsCount int64
var openIssuesCount int64
var openPRsCount int64
_ = h.db.Pool.QueryRow(c.Context(), `
SELECT
  (SELECT COUNT(*) FROM projects p WHERE p.ecosystem_id = $1 AND ...),
  COALESCE((SELECT COUNT(DISTINCT a.author_login) FROM (...) a), 0),
  COALESCE((SELECT COUNT(*) FROM github_issues gi INNER JOIN projects p ...), 0),
  COALESCE((SELECT COUNT(*) FROM github_pull_requests gpr INNER JOIN projects p ...), 0)
`, ecoID, ecoID, ecoID, ecoID).Scan(&projectCount, &contributorsCount, &openIssuesCount, &openPRsCount)

out := fiber.Map{
    ...
    "project_count":      projectCount,
    "contributors_count": contributorsCount,
    "open_issues_count":  openIssuesCount,
    "open_prs_count":     openPRsCount,
}
return c.Status(fiber.StatusOK).JSON(out)

If this query fails for any reason (statement timeout on the correlated-subquery-heavy aggregate, a dropped connection, a transient DB error), the _ = ...Scan(...) discards the error and projectCount/contributorsCount/openIssuesCount/openPRsCount all remain at their Go zero value (0). The handler then returns 200 OK with an ecosystem detail page that claims the ecosystem has zero projects, zero contributors, and zero open issues/PRs — a materially misleading response for what should be a simple transient-failure case, with no server-side log entry to explain why the numbers are wrong.

Requirements

  • A failure of the aggregate stats query in GetByID must not silently present fabricated all-zero counts as if they were real data.
  • At minimum, the error must be logged so operators can distinguish "genuinely zero" from "query failed."

Suggested execution

  1. In internal/handlers/ecosystems_public.go's GetByID, capture the error from the stats QueryRow(...).Scan(...) call instead of discarding it with _ =.
  2. On error, either (a) log it via slog.Warn/slog.Error and omit the count fields (or mark them nullable/nil) from the response rather than defaulting to 0, or (b) fail the request with a 500 if this repo's convention treats stats as required — pick whichever matches how Get()'s own primary-row error is already handled just above this block in the same function.
  3. Add a test that simulates the stats query failing and asserts the response either surfaces an error or omits the counts, rather than silently returning zeros.

Acceptance criteria

  • A failed aggregate-stats query in GetByID no longer silently renders as all-zero counts.
  • The failure is logged for operator visibility.
  • A test covers the stats-query-failure path.

Security notes

Data-integrity issue rather than a security vulnerability: presenting fabricated zero counts as legitimate data could mislead ecosystem maintainers or the public dashboard about real platform activity during a transient outage.

Guidelines

  • Minimum 95% test coverage
  • Timeframe: 96 hours

Metadata

Metadata

Assignees

Labels

GrantFox OSSGrantFox open-source programMaybe RewardedGrantFox: potentially rewarded contributionOfficial Campaign | FWC26GrantFox official campaign issuebackendBackend / API workbugSomething isn't working

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions