Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 0 additions & 3 deletions dev/src/cli/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import {
setLogLevel as setAdkCoreLogLevel,
} from '@google/adk';
import {Argument, Command, Option} from 'commander';
import dotenv from 'dotenv';
import * as path from 'path';
import {runIntegrationTests} from '../integration/run_integration_tests.js';
import {AdkApiServer} from '../server/adk_api_server.js';
Expand All @@ -27,8 +26,6 @@ import {runAgent} from './cli_run.js';
import {deployToAgentEngine} from './deploy/cli_deploy_agent_engine.js';
import {deployToCloudRun} from './deploy/cli_deploy_cloud_run.js';

dotenv.config({quiet: true});

const LOG_LEVEL_MAP: Record<string, LogLevel> = {
'debug': LogLevel.DEBUG,
'info': LogLevel.INFO,
Expand Down
2 changes: 2 additions & 0 deletions dev/src/cli_entrypoint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@
* Copyright 2026 Google LLC
* SPDX-License-Identifier: Apache-2.0
*/
import dotenv from 'dotenv';
import {createProgram} from './cli/cli.js';

try {
dotenv.config({quiet: true});
createProgram().parse(process.argv);
} catch (e) {
console.error(e);
Expand Down
42 changes: 42 additions & 0 deletions dev/test/cli/cli_test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
*/

import {LogLevel, setLogLevel} from '@google/adk';
import dotenv from 'dotenv';
import * as fs from 'node:fs/promises';
import * as os from 'node:os';
import * as path from 'node:path';
import {afterEach, beforeEach, describe, expect, it, Mock, vi} from 'vitest';
import {createProgram} from '../../src/cli/cli.js';
import {createAgent} from '../../src/cli/cli_create.js';
Expand Down Expand Up @@ -49,6 +53,9 @@ vi.mock('@google/adk', async (importOriginal) => {
};
});

/** Env var no production code reads, so the assertion pins the mechanism. */
const DOTENV_SENTINEL = 'ADK_DOTENV_IMPORT_SENTINEL';

describe('CLI Entrypoint', () => {
let program: ReturnType<typeof createProgram>;

Expand Down Expand Up @@ -415,4 +422,39 @@ describe('CLI Entrypoint', () => {
});
});
});

describe('module import side effects', () => {
let envDir: string;

beforeEach(async () => {
envDir = await fs.mkdtemp(path.join(os.tmpdir(), 'adk-cli-dotenv-'));
await fs.writeFile(
path.join(envDir, '.env'),
`${DOTENV_SENTINEL}=leaked\n`,
);
// dotenv resolves `${process.cwd()}/.env` at call time, so the spy
// redirects the lookup the way a real chdir would.
vi.spyOn(process, 'cwd').mockReturnValue(envDir);
});

afterEach(async () => {
delete process.env[DOTENV_SENTINEL];
await fs.rm(envDir, {recursive: true, force: true});
});

it('should not read a .env file from the working directory on import', async () => {
// Without the reset, cli.js is already in the module registry from this
// file's static import and would not re-evaluate.
vi.resetModules();
await import('../../src/cli/cli.js');

expect(process.env[DOTENV_SENTINEL]).toBeUndefined();
});

it('should still load that .env once dotenv.config runs, as the entrypoint does', () => {
dotenv.config({quiet: true});

expect(process.env[DOTENV_SENTINEL]).toBe('leaked');
});
});
});
Loading