Nobody has started this yet — be first.
Business impact
This is a total outage of the login flow. Every existing user is locked out -- POST /login returns 401 invalid email or password no matter what they type, because the password check itself is broken, not the credentials. Registration still works (Register issues a token directly, without going through Login), so this bug is invisible until a user's token expires (24h) and they try to log back in -- meaning it would likely reach production, pass a shallow "can I sign up?" smoke test, and only surface once real users get logged out, at which point it's a full incident: nobody can get back into their account.
Problem
CheckPassword's call to bcrypt.CompareHashAndPassword has its two arguments swapped -- it's passing the plaintext password where the library expects the bcrypt hash, and vice versa.
Current behavior
Logging in with the exact correct email and password still returns 401 invalid email or password, every single time.
Expected behavior
CheckPassword(hash, plain) returns true exactly when plain, once hashed, matches hash.
Steps to reproduce
Register with password "correct-horse-battery". POST /login with that exact same email + password.
Why this matters
bcrypt.CompareHashAndPassword(hashedPassword, password) has a specific, non-symmetric argument order -- the first argument must already be a bcrypt hash, or the function can't even parse it and returns a non-nil error (which CheckPassword collapses to false). Swapping the arguments is a realistic copy-paste/argument-order mistake that compiles cleanly (both parameters are []byte) while being 100% wrong at runtime, for every single login attempt, always.
Suggested approach
Check bcrypt.CompareHashAndPassword's documented parameter order against how CheckPassword's own two parameters (hash, plain) are named and used when calling it.
Acceptance criteria
Verification
go test ./practicetickets/... -run TestTicket04 -v
Hints (0/2)
Try it without hints first — the reading is the exercise.
Working on this ticket
Work on a branch named for the ticket — that's what you'll submit.
Branch off your fork
$git checkout -b fix/login-password-check-swappedFix it and commit
Meet every acceptance criterion, and add a test that would have caught this.
Push the branch
$git push -u origin fix/login-password-check-swappedSubmit it below
Paste your fork URL and the branch name, with a short write-up of the root cause.
Questions
Ask about anything unclear in the ticket — the maintainer and anyone who has solved it can answer. Please don't post full solutions.
Sign in to ask a question or reply.
Sign indocker-compose.ymlmigrations/0001_init.sqldocker-entrypoint-initdb.dexpense_trackerdbappcurl http://localhost:8082/healthz
To run locally against your own Postgres instead: cp .env.example .env (edit if your Postgres isn't on localhost:5434), then make migrate (applies migrations/*.sql via psql) and make run (go run ./cmd/server).
Work the tickets in PRACTICE_TICKETS.md (TICKET-01 through TICKET-10); each names one Go test in practicetickets/:
go test ./practicetickets/... -run TestTicket01 -v # a single ticket
./practice_tickets_run.sh # all 10, clean pass/fail summary
This project's own integration suite (cmd/server/*_test.go) needs a real, reachable Postgres -- point TEST_DATABASE_URL at any empty/disposable database (migrations are applied automatically, and every test truncates+reseeds before it runs) and run make test. The practicetickets/ suite defaults to postgres://postgres:postgres@localhost:5434/expense_tracker_test if TEST_DATABASE_URL is unset.
Level 1
Fix a bug
Read existing behaviour, correct it.