Uh oh!
There was an error while loading. Please reload this page.
ADFA-4684 | Fix Gemini API key entry: show/hide, trim, and at-rest encryption - #49
Conversation
There was a problem hiding this comment.
Claude Code Review
This repository is configured for manual code reviews. Comment @claude review for a one-time review, or @claude review always to subscribe this PR to a review on every future push.
Tip: disable this comment in your organization's Code Review settings.
jatezzz
commented
Jul 20, 2026
@claude review |
There was a problem hiding this comment.
Code review is billed via overage credits. To resume reviews, an organization admin can raise the monthly limit at claude.ai/admin-settings/claude-code.
Once credits are available, comment @claude review on this pull request to trigger a review.
c809089 to
4426b31Comparejatezzz
commented
Jul 21, 2026
086fe7b to
3ded9d8Compare
hal-eisen-adfa
left a comment
There was a problem hiding this comment.
Requesting changes. Two blocking items scoped to this PR's diff (the API-key security + FilePicker rewrite). The larger AI-plugin findings from the review belong to the base PR #41 and are posted there, not here.
The rest of the PR is solid: AES/GCM at-rest encryption with legacy-plaintext passthrough, inputType="textPassword" on the key field, save-failure surfaced instead of crashing, and the in-place FilePicker refresh that fixes the second-"Toggle All" crash.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
3d33b7a to
b939ff5Compare3ded9d8 to
759d71dCompare5764d1f to
b44608fCompare45aa44d to
8f1b26aCompare6f2ea13 to
b91dd63Comparea830c7a to
3739da0Compare
hal-eisen-adfa
left a comment
There was a problem hiding this comment.
Code review of the Gemini API-key security work. The crypto core is sound — AES/GCM with a fresh random 12-byte IV per encrypt, GCM tag verification, fail-closed decrypt, and a sensible legacy-plaintext migration. No blockers; 6 non-critical findings inline below, ranked by severity. Note this is a static review — the encryption, on-device migration, and FLAG_SECURE screenshot-blocking still need device verification (install both .cgp, save a key, confirm ciphertext in prefs, revoke the Keystore alias to exercise the 'unreadable' path).
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
- Fix file picker empty state and `BadTokenException` by using the correct project context (`IdeProjectService`) and moving I/O off the main thread. - Secure Gemini API key with hardware-backed Keystore encryption (including legacy migration) and add a show/hide toggle. - Improve UI by replacing emoji markers with vector drawables and extracting hardcoded strings to `strings.xml`.
…the file picker Encrypt the key with AES/GCM under an Android Keystore secret and run all crypto off the UI thread; confine the context-file picker to the open project via normalized canonical-path checks with off-thread listing and no fallback root.
3739da0 to
c25ee89CompareEncrypt the key with AES/GCM under an Android Keystore secret, migrating existing plaintext on first read; send it as a header, never a query string. Confine the context-file picker to the open project, failing closed on an unresolvable root, and fix the crash on a second "Toggle All".
Resolves conflicts in ai-assistant/build.gradle.kts and ai-core/build.gradle.kts. Both were the same adjacent-line collision: this branch: targetSdk 34 -> 36 (the point of ADFA-4907) main: versionCode 1 -> 2, versionName 1.0.0 -> 1.1.0 (#49, #50, #58) Neither side touched the other's lines, so both changes are kept: targetSdk = 36, versionCode = 2, versionName = "1.1.0". Verified the merged build files differ from origin/main only in compileSdk and targetSdk (34 -> 36), so all of main's work on these two plugins is preserved.

Description
Fixes the Gemini API key input in the AI Assistant plugin, reported in appdevforall/CodeOnTheGo#1514 where keys wouldn't save correctly and produced 400 "invalid API key" errors. The field now has a working show/hide (eye) toggle that reveals the actual saved key, trims the value on save (dropping the trailing spaces/newlines Gemini rejects), and stops corrupting the key with a masked placeholder on edit. The key is also encrypted at rest with a hardware-backed Android Keystore secret instead of being stored as plaintext.
Details
Changes:
ic_visibility/ic_visibility_offdrawables and anImageButtonbeside the input; toggle swapsinputTypevia an explicit visibility flag (the previous bit-check never flipped back, so it always read "hidden").saveButtontrims before persisting (read side already trimmed).SecureApiKeyStore(AES/GCM, Android Keystore) in both ai-assistant (write/read) and ai-core (read for API calls); only ciphertext hits SharedPreferences, and legacy plaintext keys migrate transparently on next save.document_5111703426673150080.mp4
Ticket
ADFA-4684
Fixes:
Observation
SecureApiKeyStoreis duplicated in ai-assistay're separate Gradle projects with no shared module; the two copies must stay in sync (same aliascotg_ai_gemini_key_v1and transform) or ai-core can't decrypt what ai-assistant wrote. They interoperate because both plugins run in the host app's process (shared Keystore).