Files
Charon/docs/plans/archive/codecov-acceptinvite-patch-coverage.md
akanealw eec8c28fb3
Go Benchmark / Performance Regression Check (push) Has been cancelled
Cerberus Integration / Cerberus Security Stack Integration (push) Has been cancelled
Upload Coverage to Codecov / Backend Codecov Upload (push) Has been cancelled
Upload Coverage to Codecov / Frontend Codecov Upload (push) Has been cancelled
CodeQL - Analyze / CodeQL analysis (go) (push) Has been cancelled
CodeQL - Analyze / CodeQL analysis (javascript-typescript) (push) Has been cancelled
CrowdSec Integration / CrowdSec Bouncer Integration (push) Has been cancelled
Docker Build, Publish & Test / build-and-push (push) Has been cancelled
Quality Checks / Auth Route Protection Contract (push) Has been cancelled
Quality Checks / Codecov Trigger/Comment Parity Guard (push) Has been cancelled
Quality Checks / Backend (Go) (push) Has been cancelled
Quality Checks / Frontend (React) (push) Has been cancelled
Rate Limit integration / Rate Limiting Integration (push) Has been cancelled
Security Scan (PR) / Trivy Binary Scan (push) Has been cancelled
Supply Chain Verification (PR) / Verify Supply Chain (push) Has been cancelled
WAF integration / Coraza WAF Integration (push) Has been cancelled
Docker Build, Publish & Test / Security Scan PR Image (push) Has been cancelled
Repo Health Check / Repo health (push) Has been cancelled
History Rewrite Dry-Run / Dry-run preview for history rewrite (push) Has been cancelled
Prune Renovate Branches / prune (push) Has been cancelled
Renovate / renovate (push) Has been cancelled
Nightly Build & Package / sync-development-to-nightly (push) Has been cancelled
Nightly Build & Package / Trigger Nightly Validation Workflows (push) Has been cancelled
Nightly Build & Package / build-and-push-nightly (push) Has been cancelled
Nightly Build & Package / test-nightly-image (push) Has been cancelled
Nightly Build & Package / verify-nightly-supply-chain (push) Has been cancelled
Update GeoLite2 Checksum / update-checksum (push) Has been cancelled
Container Registry Prune / prune-ghcr (push) Has been cancelled
Container Registry Prune / prune-dockerhub (push) Has been cancelled
Container Registry Prune / summarize (push) Has been cancelled
Supply Chain Verification / Verify SBOM (push) Has been cancelled
Supply Chain Verification / Verify Release Artifacts (push) Has been cancelled
Supply Chain Verification / Verify Docker Image Supply Chain (push) Has been cancelled
Monitor Caddy Major Release / check-caddy-major (push) Has been cancelled
Weekly Nightly to Main Promotion / Verify Nightly Branch Health (push) Has been cancelled
Weekly Nightly to Main Promotion / Create Promotion PR (push) Has been cancelled
Weekly Nightly to Main Promotion / Trigger Missing Required Checks (push) Has been cancelled
Weekly Nightly to Main Promotion / Notify on Failure (push) Has been cancelled
Weekly Nightly to Main Promotion / Workflow Summary (push) Has been cancelled
Weekly Security Rebuild / Security Rebuild & Scan (push) Has been cancelled
changed perms
2026-04-22 18:19:14 +00:00

4.5 KiB
Executable File
Raw Permalink Blame History

Codecov Patch Coverage Fix Plan: user_handler.go (AcceptInvite constant-time branch)

Problem Statement

Codecov patch coverage is failing at 66.66667% due to 3 uncovered patch lines in:

  • backend/internal/api/handlers/user_handler.go

Codecov reports 2 lines missing and 1 line partially covered.

Whats Uncovered (Exact Lines + Behavior)

The uncovered patch lines are in (*UserHandler).AcceptInvite:

  • Partial line: the branch condition
    • if !util.ConstantTimeCompare(user.InviteToken, req.Token) {
  • Missing lines: the branch body
    • c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid invite token"})
    • return

What behavior this represents

This branch is intended as defense-in-depth: if the stored invite token and the request token differ, reject the request with HTTP 401.

Root Cause Analysis (Hypothesis)

These lines are currently effectively unreachable under normal execution:

  1. The handler looks up the user via WHERE invite_token = req.Token.
  2. If a row is found, user.InviteToken should already equal req.Token.
  3. Therefore, !util.ConstantTimeCompare(user.InviteToken, req.Token) will never be true, leaving its body uncovered.

This yields the exact Codecov pattern we see:

  • the if line is hit (partial)
  • its body is never hit (2 lines missing)

Existing Test Harness (Repo Patterns)

Handler tests (unit)

The repository already has strong patterns for handler unit tests:

  • Use Gin in test mode: gin.SetMode(gin.TestMode)
  • Build a minimal router: r := gin.New()
  • Register a single route per test: r.POST("/invite/accept", handler.AcceptInvite)
  • Use httptest.NewRecorder() + httptest.NewRequest(...)
  • Use SQLite in-memory via GORM for isolated tests

Relevant existing files:

  • backend/internal/api/handlers/user_handler_test.go (many UserHandler endpoint tests)
  • backend/internal/api/handlers/user_handler_coverage_test.go (targeted “error/coverage” tests using gin.CreateTestContext)
  • backend/internal/api/handlers/testdb_test.go (shared OpenTestDB* helpers used across handler tests)

Because the DB query already enforces invite_token = req.Token, the constant-time compare mismatch branch in AcceptInvite is unreachable. The smallest, behavior-preserving fix (and the one that avoids creating a response oracle) is to delete the dead mismatch branch rather than trying to make it testable.

Why this is safe

  • If the token doesnt match, the DB lookup already fails and returns 404 Not Found ("Invalid or expired invite token").
  • Keeping a separate 401 Unauthorized path for a mismatch (even if unreachable today) risks future “oracle” behavior differences.
  • Removing the branch is a strict simplification: it does not introduce any new acceptance conditions.

Proposed Code Change (Minimal, Behavior-Preserving)

Edit

  • backend/internal/api/handlers/user_handler.go

Change

In (*UserHandler).AcceptInvite, remove the redundant constant-time compare mismatch block (currently the only util. usage in this file):

  • Remove the comment and if !util.ConstantTimeCompare(user.InviteToken, req.Token) { ... } block at lines ~827834 (the if is at line 830).
  • Remove the now-unused import github.com/Wikid82/charon/backend/internal/util (line 18) if it becomes unused after deleting the block.

Unit Tests

No new unit tests are expected/required for this change because it only deletes unreachable code.

If any existing tests assert a 401 for invite-token mismatch (none are expected), update those tests to assert the existing invalid-token behavior (404) instead.

Verification Steps

  1. Run VS Code task: Test: Backend with Coverage
  2. Run VS Code task: Build: Backend (or equivalent: cd backend && go build ./...)
  3. (Optional but recommended) Run: Lint: Go Vet
  4. Confirm Codecov/coverage gate remains >= 85% and the patch no longer reports uncovered lines for the removed branch.

Security Note (Avoiding an Oracle)

This approach intentionally avoids distinguishing “token exists but mismatched” vs “token not found” via different status codes/messages, which can become a token-validity oracle. After the change, invalid tokens continue to get the existing 404 response path.

Acceptance Criteria

  • Codecov patch coverage for the change is >= 85%
  • No uncovered lines remain in backend/internal/api/handlers/user_handler.go (specifically the ConstantTimeCompare mismatch branch)
  • Test: Backend with Coverage passes