Skip to content

fix: block direct progress updates on activity-derived goals#1755

Merged
Priyanshu-byte-coder merged 1 commit into
Priyanshu-byte-coder:mainfrom
Ridanshi:fix/goal-progress-integrity
May 31, 2026
Merged

fix: block direct progress updates on activity-derived goals#1755
Priyanshu-byte-coder merged 1 commit into
Priyanshu-byte-coder:mainfrom
Ridanshi:fix/goal-progress-integrity

Conversation

@Ridanshi
Copy link
Copy Markdown
Contributor

Closes #1753

Problem

PATCH /api/goals/[id] accepted any client-supplied current value — including one equal to target — regardless of the goal's unit type. For goals whose progress is meant to come from verified GitHub activity (unit: "commits" or unit: "prs"), this allowed a user to mark a goal complete without a single real commit or pull request:

PATCH /api/goals/<id>
{ "current": 50 }   # target is 50, but user has 0 real commits
→ 200 OK

The sync endpoint (POST /api/goals/sync) queries the GitHub Search API and is the only trusted source for progress on activity-derived goals. Accepting client values in PATCH breaks that trust boundary.

Root cause

The PATCH handler performed only typeof current !== "number" || current < 0, which passes for any non-negative number including floats and values exceeding the goal target. No check existed for the goal's unit type.

Fix

src/app/api/goals/[id]/route.ts

  • Introduces ACTIVITY_DERIVED_UNITS = new Set(["commits", "prs"]).
  • After fetching the existing goal, returns 422 if existingGoal.unit is in that set. The error message directs callers to the sync endpoint.
  • Tightens the input validation: current must now be a non-negative integer (rejects floats such as 5.5).
  • Adds an upper-bound check so current cannot exceed the goal's target on manually tracked goals.

Manually tracked goals (any unit other than "commits" / "prs", e.g. "hours", "tasks", or custom strings) continue to accept client-supplied progress exactly as before.

The GitHub sync route is unaffected — it calls supabaseAdmin…update({ current }) directly and bypasses the PATCH handler entirely.

Tests

test/goals-patch-integrity.test.ts — 19 new tests:

Category Cases
Authentication unauthenticated session, unresolved user
Input validation missing field, float, negative, string
Goal not found ownership-scoped lookup returns null
Activity-derived guard commits goal → 422, prs goal → 422, regression for #1753 (setting current = target on commits), partial update on prs
Upper-bound guard current > target → 400
Legitimate manual updates hours, custom unit, reset to 0, completing at target
Webhook dispatch fires on first completion, silent when already complete, silent when not yet complete

All 19 pass; the single pre-existing failure in test/dateUtils.test.ts (timezone boundary, unrelated to goals) was already present on main before this branch.

PATCH /api/goals/[id] previously accepted any client-supplied `current`
value — including values equal to `target` — for goals whose progress is
meant to be derived from verified GitHub activity (unit: "commits" or
"prs").  This allowed goal completion without any real commits or pull
requests being made.

Changes:
- Introduce ACTIVITY_DERIVED_UNITS constant ("commits", "prs")
- Return 422 when a client attempts to set `current` on a goal tracked
  by the GitHub sync endpoint; progress for those goals must flow
  exclusively through POST /api/goals/sync, which reads from the GitHub
  Search API
- Tighten the `current` input check to require a non-negative integer
  (rejects floats, strings, and negatives more precisely)
- Add an upper-bound guard so `current` cannot exceed the goal's target
  on manually tracked goals
- Add 19 focused tests covering: auth guards, input validation, the 422
  block for commits/prs goals, the upper-bound check, legitimate manual
  updates, and webhook dispatch on goal completion

Closes Priyanshu-byte-coder#1753
@vercel
Copy link
Copy Markdown

vercel Bot commented May 31, 2026

@Ridanshi is attempting to deploy a commit to the PRIYANSHU DOSHI's projects Team on Vercel.

A member of the Team first needs to authorize it.

@github-actions github-actions Bot added gssoc26 GSSoC 2026 contribution type:bug GSSoC type bonus: bug fix type:testing GSSoC type bonus: tests (+10 pts) labels May 31, 2026
@github-actions
Copy link
Copy Markdown

GSSoC Label Checklist 🏷️

@Priyanshu-byte-coder — please apply the appropriate labels before merging:

Difficulty (pick one):

  • level:beginner — 20 pts
  • level:intermediate — 35 pts
  • level:advanced — 55 pts
  • level:critical — 80 pts

Quality (optional):

  • quality:clean — ×1.2 multiplier
  • quality:exceptional — ×1.5 multiplier

Validation (required to score):

  • gssoc:approved — counts for points
  • gssoc:invalid / gssoc:spam / gssoc:ai-slop — does not score

Type labels (type:*) are auto-detected from files and title. Review and adjust if needed.
Points formula: (difficulty × quality_multiplier) + type_bonus

Copy link
Copy Markdown

@github-actions github-actions Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your first PR on DevTrack! 🎉

A maintainer will review it within 48 hours. While you wait:

  • Make sure CI is passing (type-check + lint)
  • Double-check the PR description is filled out and the issue is linked
  • Feel free to ask questions in Discussions if you need help

If you find DevTrack useful, a ⭐ star on the repo is always appreciated — it helps the project grow and attract more contributors!

@Priyanshu-byte-coder Priyanshu-byte-coder added level2 GSSoC Level 2 - Medium complexity (25 points) gssoc:approved GSSoC: PR approved for scoring labels May 31, 2026
@Priyanshu-byte-coder Priyanshu-byte-coder merged commit c9d2760 into Priyanshu-byte-coder:main May 31, 2026
4 of 5 checks passed
@github-actions
Copy link
Copy Markdown

🎉 Merged! Thanks for contributing to DevTrack.

If the project has been useful to you, a ⭐ star on the repo is the easiest way to support it — it helps DevTrack get discovered by more developers.

Keep an eye on open issues for your next contribution!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

gssoc:approved GSSoC: PR approved for scoring gssoc26 GSSoC 2026 contribution level2 GSSoC Level 2 - Medium complexity (25 points) type:bug GSSoC type bonus: bug fix type:testing GSSoC type bonus: tests (+10 pts)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[BUG] Goal progress can be arbitrarily modified through the PATCH endpoint without verification against actual GitHub activity

2 participants