chore: switch from keytar to @github/keytar (#25143)

This commit is contained in:
Coco Sheng
2026-04-10 17:20:26 -04:00
committed by GitHub
parent e2a5231e30
commit 35907057ad
7 changed files with 32 additions and 38 deletions
+1 -1
View File
@@ -62,7 +62,7 @@ const external = [
'@lydell/node-pty-linux-x64', '@lydell/node-pty-linux-x64',
'@lydell/node-pty-win32-arm64', '@lydell/node-pty-win32-arm64',
'@lydell/node-pty-win32-x64', '@lydell/node-pty-win32-x64',
'keytar', '@github/keytar',
'@google/gemini-cli-devtools', '@google/gemini-cli-devtools',
]; ];
+23 -29
View File
@@ -74,13 +74,13 @@
"node": ">=20.0.0" "node": ">=20.0.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"@github/keytar": "^7.10.6",
"@lydell/node-pty": "1.1.0", "@lydell/node-pty": "1.1.0",
"@lydell/node-pty-darwin-arm64": "1.1.0", "@lydell/node-pty-darwin-arm64": "1.1.0",
"@lydell/node-pty-darwin-x64": "1.1.0", "@lydell/node-pty-darwin-x64": "1.1.0",
"@lydell/node-pty-linux-x64": "1.1.0", "@lydell/node-pty-linux-x64": "1.1.0",
"@lydell/node-pty-win32-arm64": "1.1.0", "@lydell/node-pty-win32-arm64": "1.1.0",
"@lydell/node-pty-win32-x64": "1.1.0", "@lydell/node-pty-win32-x64": "1.1.0",
"keytar": "^7.9.0",
"node-pty": "^1.0.0" "node-pty": "^1.0.0"
} }
}, },
@@ -1099,6 +1099,27 @@
"node": "^18.18.0 || ^20.9.0 || >=21.1.0" "node": "^18.18.0 || ^20.9.0 || >=21.1.0"
} }
}, },
"node_modules/@github/keytar": {
"version": "7.10.6",
"resolved": "https://registry.npmjs.org/@github/keytar/-/keytar-7.10.6.tgz",
"integrity": "sha512-mRW6cUsSG+nj4jp5gp8e91zPySaT73r+2JM6VyMZfrEgksjPmjSMr+tPGNOK3HUHV+GUU9B1LAiiYy/wmAnIxA==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"dependencies": {
"node-addon-api": "^8.3.0"
}
},
"node_modules/@github/keytar/node_modules/node-addon-api": {
"version": "8.7.0",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.7.0.tgz",
"integrity": "sha512-9MdFxmkKaOYVTV+XVRG8ArDwwQ77XIgIPyKASB1k3JPq3M8fGQQQE3YpMOrKm6g//Ktx8ivZr8xo1Qmtqub+GA==",
"license": "MIT",
"optional": true,
"engines": {
"node": "^18 || ^20 || >= 21"
}
},
"node_modules/@google-cloud/common": { "node_modules/@google-cloud/common": {
"version": "5.0.2", "version": "5.0.2",
"resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-5.0.2.tgz", "resolved": "https://registry.npmjs.org/@google-cloud/common/-/common-5.0.2.tgz",
@@ -11198,26 +11219,6 @@
"safe-buffer": "^5.0.1" "safe-buffer": "^5.0.1"
} }
}, },
"node_modules/keytar": {
"version": "7.9.0",
"resolved": "https://registry.npmjs.org/keytar/-/keytar-7.9.0.tgz",
"integrity": "sha512-VPD8mtVtm5JNtA2AErl6Chp06JBfy7diFQ7TQQhdpWOl6MrCRB+eRbvAZUsbGQS9kiMq0coJsy0W0vHpDCkWsQ==",
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"dependencies": {
"node-addon-api": "^4.3.0",
"prebuild-install": "^7.0.1"
}
},
"node_modules/keytar/node_modules/prebuild-install": {
"name": "nop",
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/nop/-/nop-1.0.0.tgz",
"integrity": "sha512-XdkOuXGx0DTwlqb0DWTcDqelgU/F3YyZ+PTRaecpDVpkYskcnh3OeUYKfvjcRQ2D1diTIGxi/a3eHVjW5yPupQ==",
"license": "MIT",
"optional": true
},
"node_modules/keyv": { "node_modules/keyv": {
"version": "4.5.4", "version": "4.5.4",
"resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz",
@@ -12240,13 +12241,6 @@
"node": ">= 0.4.0" "node": ">= 0.4.0"
} }
}, },
"node_modules/node-addon-api": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-4.3.0.tgz",
"integrity": "sha512-73sE9+3UaLYYFmDsFZnqCInzPyh3MqIwZO9cw58yIqAZhONrrabrYyYe3TuIqtIiOuTXVhsGau8hcrhhwSsDIQ==",
"license": "MIT",
"optional": true
},
"node_modules/node-domexception": { "node_modules/node-domexception": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz",
@@ -18230,13 +18224,13 @@
"node": ">=20" "node": ">=20"
}, },
"optionalDependencies": { "optionalDependencies": {
"@github/keytar": "^7.10.6",
"@lydell/node-pty": "1.1.0", "@lydell/node-pty": "1.1.0",
"@lydell/node-pty-darwin-arm64": "1.1.0", "@lydell/node-pty-darwin-arm64": "1.1.0",
"@lydell/node-pty-darwin-x64": "1.1.0", "@lydell/node-pty-darwin-x64": "1.1.0",
"@lydell/node-pty-linux-x64": "1.1.0", "@lydell/node-pty-linux-x64": "1.1.0",
"@lydell/node-pty-win32-arm64": "1.1.0", "@lydell/node-pty-win32-arm64": "1.1.0",
"@lydell/node-pty-win32-x64": "1.1.0", "@lydell/node-pty-win32-x64": "1.1.0",
"keytar": "^7.9.0",
"node-pty": "^1.0.0" "node-pty": "^1.0.0"
} }
}, },
+1 -1
View File
@@ -150,13 +150,13 @@
"simple-git": "^3.28.0" "simple-git": "^3.28.0"
}, },
"optionalDependencies": { "optionalDependencies": {
"@github/keytar": "^7.10.6",
"@lydell/node-pty": "1.1.0", "@lydell/node-pty": "1.1.0",
"@lydell/node-pty-darwin-arm64": "1.1.0", "@lydell/node-pty-darwin-arm64": "1.1.0",
"@lydell/node-pty-darwin-x64": "1.1.0", "@lydell/node-pty-darwin-x64": "1.1.0",
"@lydell/node-pty-linux-x64": "1.1.0", "@lydell/node-pty-linux-x64": "1.1.0",
"@lydell/node-pty-win32-arm64": "1.1.0", "@lydell/node-pty-win32-arm64": "1.1.0",
"@lydell/node-pty-win32-x64": "1.1.0", "@lydell/node-pty-win32-x64": "1.1.0",
"keytar": "^7.9.0",
"node-pty": "^1.0.0" "node-pty": "^1.0.0"
}, },
"lint-staged": { "lint-staged": {
+1 -1
View File
@@ -91,13 +91,13 @@
"zod-to-json-schema": "^3.25.1" "zod-to-json-schema": "^3.25.1"
}, },
"optionalDependencies": { "optionalDependencies": {
"@github/keytar": "^7.10.6",
"@lydell/node-pty": "1.1.0", "@lydell/node-pty": "1.1.0",
"@lydell/node-pty-darwin-arm64": "1.1.0", "@lydell/node-pty-darwin-arm64": "1.1.0",
"@lydell/node-pty-darwin-x64": "1.1.0", "@lydell/node-pty-darwin-x64": "1.1.0",
"@lydell/node-pty-linux-x64": "1.1.0", "@lydell/node-pty-linux-x64": "1.1.0",
"@lydell/node-pty-win32-arm64": "1.1.0", "@lydell/node-pty-win32-arm64": "1.1.0",
"@lydell/node-pty-win32-x64": "1.1.0", "@lydell/node-pty-win32-x64": "1.1.0",
"keytar": "^7.9.0",
"node-pty": "^1.0.0" "node-pty": "^1.0.0"
}, },
"devDependencies": { "devDependencies": {
@@ -42,7 +42,7 @@ const mockFileKeychain: MockKeychain = {
findCredentials: vi.fn(), findCredentials: vi.fn(),
}; };
vi.mock('keytar', () => ({ default: mockKeytar })); vi.mock('@github/keytar', () => ({ default: mockKeytar }));
vi.mock('./fileKeychain.js', () => ({ vi.mock('./fileKeychain.js', () => ({
FileKeychain: vi.fn(() => mockFileKeychain), FileKeychain: vi.fn(() => mockFileKeychain),
@@ -22,7 +22,7 @@ import { FileKeychain } from './fileKeychain.js';
export const FORCE_FILE_STORAGE_ENV_VAR = 'GEMINI_FORCE_FILE_STORAGE'; export const FORCE_FILE_STORAGE_ENV_VAR = 'GEMINI_FORCE_FILE_STORAGE';
/** /**
* Service for interacting with OS-level secure storage (e.g. keytar). * Service for interacting with OS-level secure storage (e.g. @github/keytar).
*/ */
export class KeychainService { export class KeychainService {
// Track an ongoing initialization attempt to avoid race conditions. // Track an ongoing initialization attempt to avoid race conditions.
@@ -119,7 +119,7 @@ export class KeychainService {
} }
/** /**
* Attempts to load and verify the native keychain module (keytar). * Attempts to load and verify the native keychain module (@github/keytar).
*/ */
private async getNativeKeychain(): Promise<Keychain | null> { private async getNativeKeychain(): Promise<Keychain | null> {
try { try {
@@ -152,7 +152,7 @@ export class KeychainService {
// Low-level dynamic loading and structural validation. // Low-level dynamic loading and structural validation.
private async loadKeychainModule(): Promise<Keychain | null> { private async loadKeychainModule(): Promise<Keychain | null> {
const moduleName = 'keytar'; const moduleName = '@github/keytar';
const module: unknown = await import(moduleName); const module: unknown = await import(moduleName);
const potential = (isRecord(module) && module['default']) || module; const potential = (isRecord(module) && module['default']) || module;
@@ -189,7 +189,7 @@ export class KeychainService {
*/ */
private isMacOSKeychainAvailable(): boolean { private isMacOSKeychainAvailable(): boolean {
// Probing via the `security` CLI avoids a blocking OS-level popup that // Probing via the `security` CLI avoids a blocking OS-level popup that
// occurs when calling keytar without a configured keychain. // occurs when calling @github/keytar without a configured keychain.
const result = spawnSync('security', ['default-keychain'], { const result = spawnSync('security', ['default-keychain'], {
encoding: 'utf8', encoding: 'utf8',
// We pipe stdout to read the path, but ignore stderr to suppress // We pipe stdout to read the path, but ignore stderr to suppress
+1 -1
View File
@@ -8,7 +8,7 @@ import { z } from 'zod';
/** /**
* Interface for OS-level secure storage operations. * Interface for OS-level secure storage operations.
* Note: Method names must match the underlying library (e.g. keytar) * Note: Method names must match the underlying library (e.g. @github/keytar)
* to support correct dynamic loading and schema validation. * to support correct dynamic loading and schema validation.
*/ */
export interface Keychain { export interface Keychain {