Feat: warn that generated .env holds secrets in adk create (adk-python parity) - #456
Open
AmaadMartin wants to merge 2 commits into
Open
Feat: warn that generated .env holds secrets in adk create (adk-python parity)#456AmaadMartin wants to merge 2 commits into
AmaadMartin wants to merge 2 commits into
Conversation
added 2 commits
August 1, 2026 06:59
adk create always writes a .env into the new agent folder, and with --api_key (or the interactive Google AI backend) that file contains a plaintext credential. The CLI gave the user no signal that a secret had just been written to disk. Port the one-line warning adk-python emits at the end of its success banner (src/google/adk/cli/cli_create.py, _SUCCESS_MSG_CODE / _SUCCESS_MSG_CONFIG) so both CLIs read identically. The line is printed on stdout via console.log, matching the two adjacent calls in the same block and adk-python's click.secho banner, and is unconditional because a .env is written on every successful create. The message names the GOOGLE_API_KEY variable; it never interpolates the key value.
The byte-exact toBe on the preceding line already pins the emitted string
in full, so not.toContain('my-api-key') could never fail independently:
if toBe passes the key cannot be present, and if toBe fails the test has
already failed. Fold the leak-safety intent into the comment above the
surviving assertion.
This was referenced Aug 3, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Please ensure you have read the contribution guide before creating a pull request.
Link to Issue or Description of Change
Link to an existing issue (if applicable):
N/A — no public issue is tracking this. It is a cross-language parity port from
adk-python(src/google/adk/cli/cli_create.py,_SUCCESS_MSG_CODE/_SUCCESS_MSG_CONFIG).Or, if no issue exists, describe the change:
Problem:
adk createalways writes a.envinto the new agent folder, andwhen the user passes
--api_key(or picks the "Google AI" backend in theinteractive flow) that file holds a plaintext credential
(
dev/src/cli/cli_create.ts,generateEnvFile→GOOGLE_API_KEY=<key>). TheTypeScript CLI never told the user this:
createAgent()finished by listing thecreated files and printing the
npm run webhint, so a user who scaffolded anagent with
--api_keygot no signal that a secret had just been written todisk in cleartext.
adk-pythonalready emits that signal — its success banner ends with:Solution: Port that one line into
createAgent(), printed immediately afterthe created-files listing and before the
npm run webhint. Three lines ofsource; no new module, constant file, helper, import, type, or exported symbol.
Parity judgement calls (stated explicitly):
console.log, notlogger/console.warn.adk-pythonprints the whole banner with
click.secho(..., fg="green")(
cli_create.py), i.e. stdout, in the same stream as the file listing.Matching that keeps the two CLIs byte-comparable. The repo-wide "prefer
logger.debugoverconsole.log" guidance targets library code incore/src; this is a CLI banner the user is supposed to see, andlogger.debugwould make the warning invisible at the default log level. Thetwo adjacent calls in the same block already use
console.log.second sentence — "Please ensure .env is added to your .gitignore…" — which
adk-pythondeleted when it started generating a.gitignore. It isdeliberately not resurrected here:
.gitignoregeneration foradk createis tracked as separate work, and porting only the surviving line keeps this
change identical to the reference.
options.apiKey.adk-pythonprints it onevery successful create, and adk-js writes a
.envon every successful create.Gating it would diverge from the reference and would also miss the user who
later hand-edits a key into the generated
.env.U+26A0 U+FE0Fwarning sign and the two spaces beforeWARNING:(verified with
cat -Aagainstcli_create.py).GOOGLE_API_KEY; a non-template single-quoted string is used so no${...}can creep in. Printing the key would turn a security warning into a credential
leak into terminal scrollback and CI logs. This is pinned by a test.
Collision check (open PRs on this fork,
--state open --limit 200, every PR'sfile list queried): four open PRs touch
dev/src/cli/cli_create.tsor itstest — #364 (generates a
.gitignoreignoring.env), #286 (renames theGOOGLE_GENAI_USE_VERTEXAIenv var), #313 (geminiInitParamsAPI-keyfallback), #259 (test hermeticity against ambient
GOOGLE_CLOUD_*). None ofthem prints this warning, and none touches the console block at the end of
createAgent(), so this is not a duplicate. They overlap only at file level, indisjoint regions (imports /
generateFiles/ env-var contents / test setup), sothis branches from
mainrather than stacking; the hunks merge withoutconflict.
Testing Plan
Please describe the tests that you ran to verify your changes. This is required for all PRs that are not small documentation or typo fixes.
Unit Tests:
[x] I have added or updated unit tests for my change.
[x] All unit tests pass locally.
Four new cases in a new
describe('Secret Warning', ...)block at the end ofdev/test/cli/cli_create_test.ts. No existing test was edited, deleted,skipped, or weakened — the pre-existing cases remain the regression signal for
the prompting and file-generation behaviour.
created-files listing.
refactor cannot quietly gate it behind
if (options.apiKey).`\n⚠️ ${WARNING_TEXT}`exactly. A byte-exact match is what pins theabsence of the api key value; a separate
not.toContain('my-api-key')assertion was dropped in review because it could never fail independently of
the
toBe.existing folder) prints no warning.
Note for reproducers:
cli_create_test.tsis not hermetic against ambientGOOGLE_CLOUD_PROJECT/GOOGLE_CLOUD_LOCATION— the pre-existing caseshould handle Vertex AI selection with gcloud defaultsfails when they are set,on unmodified
mainas well as on this branch (verified by stashing: 1 failed /10 passed before, 1 failed / 14 passed after, same case). That flake is out of
scope here and is being fixed separately. Runs above use
env -u GOOGLE_CLOUD_PROJECT -u GOOGLE_CLOUD_LOCATION.Coverage. The new statement is at
dev/src/cli/cli_create.ts:311, hit 11times, no branches — 100% line and branch coverage of new code (v8 JSON report;
the remaining uncovered lines in the file are the pre-existing
process.exitpaths at 105-106, 120-121, 139, 151-152, 236-237, 253-254, 261, 273, 280-281,
291-292). Coverage is reported as a floor, not as proof; the mutation results
below are the proof.
Proof the tests can fail (mutation testing). Six mutations were applied to
cli_create.ts, each run against the new suite, then reverted. Every mutation iskilled, and every new test is killed by at least one mutation:
console.log(...)statement entirelyAssertionError: expected "log" to be called with arguments: [ StringContaining{…} ]stored in .env.→stored in .env.local.AssertionError: … to be … // Object.is equality- ⚠️ … are stored in .env.+ ⚠️ … are stored in .env.local.if (options.apiKey) { … }AssertionError: expected "log" to be called with arguments: [ StringContaining{…} ]Created the following files in …headerAssertionError: expected +0 to be greater than 1GOOGLE_API_KEY=${options.apiKey}AssertionError: expected undefined to be '\n⚠️ WARNING: …'createAgent(), before the exit guardsAssertionError: expected "log" to not be called with arguments: [ StringContaining{…} ]Mutation 2 is why test 3 asserts the exact literal rather than a substring:
expect.stringContaining('… stored in .env.')also matches… stored in .env.local., so a suffix append survived substring-only assertions. The exactassertion is deliberately confined to one case; the other three stay on the
ASCII substring so they are not brittle against the emoji prefix.
Other gates, all green on the pushed commit:
Integration test: deliberately none. The change is a console line in a
function already exercised by the
unit:devproject. An integration test wouldhave to run a real
npm installin a temp directory to observe one string —disproportionate and network-dependent.
Manual End-to-End (E2E) Tests:
Please provide instructions on how to manually test your changes, including any necessary setup or configuration.
Run against the built CLI, no mocks. Actual output tail:
Also verified in that run:
2>/dev/null, still present);test-key-123, while the generated.envdoes (GOOGLE_API_KEY=test-key-123) — the message names the variable,not the value;
cat -Aof the emitted line isM-bM-^ZM- M-oM-8M-^O WARNING: Secrets (like GOOGLE_API_KEY) are stored in .env.$,byte-identical to
_SUCCESS_MSG_CODEinadk-python'scli_create.py;--project demo-project --region us-central1(no api key)prints the same warning, confirming it is unconditional.
Caveat:
createAgentshells out tonpm install @google/adk @google/adk-devtools zod dotenv, and this sandbox's npm registry returns403 Forbiddenforinstalls into a scratch directory. The two
npm installinvocations weretherefore stubbed with a no-op
npmonPATH; everything else in the run —folder creation, real
.env/agent.ts/package.jsonwrites, the reallistFilescall, and all console output — executed for real against the builtdev/dist/esm/cli_entrypoint.js.Checklist
[x] I have read the CONTRIBUTING.md document.
[x] I have performed a self-review of my own code.
[x] I have commented my code, particularly in hard-to-understand areas.
[x] I have added tests that prove my fix is effective or that my feature works.
[x] New and existing unit tests pass locally with my changes.