Cliffton
Back to projects

FoodTok

TeamJan 2026 – May 2026Download apkView code

3rd best
project in the cohort, ISTD Information Systems & Programming, AY 2026
0 leaked keys
release workflow fails the build if a Gemini key or endpoint appears in the compiled DEX
58 unit tests
plus a custom Trie (O(L) autocomplete) and max-heap (O(log n) feed ranking)

The problem

A six-person team building an Android recipe app for a course had shipped a working prototype with a real defect hiding in plain sight: the Gemini API key used for AI chat and recipe enrichment was compiled straight into the client, recoverable from any built APK.

Approach

  • Decompiled a release APK and found the key sitting in classes6.dex, exactly where an attacker would look first, which is what made the fix non-optional rather than a nice-to-have.
  • Moved the key server-side behind Supabase Edge Functions (Deno/TypeScript), so the client calls a proxy that holds the credential instead of embedding it, with prompts built server-side in a shared module rather than shipped in the app.
  • Closed the loop so the mistake can't silently ship again: the release workflow now decompiles the built APK and greps the DEX for AIza-pattern keys and the Gemini endpoint, failing the release if either appears.
  • Verified the CI pipeline both ways, not just the happy path: pushed a scratch branch with a deliberately failing test to confirm the pipeline actually goes red, because a pipeline never observed failing is not a verified pipeline.

Treating a lint baseline as a ratchet, not a one-time cleanup

CI inherited 12 lint errors and 392 warnings that were aborting every build. Rather than fixing all 404 at once and losing momentum, they went into a lint-baseline.xml so only new issues fail a build going forward. That ratchet later caught 3 genuine android:tint vs app:tint errors introduced on a teammate's branch, which a one-time cleanup would have missed entirely: the value of a ratchet is what it catches after the cleanup, not the cleanup itself.

Stack

  • Java
  • Android
  • Supabase
  • Gemini