@@ -7,7 +7,7 @@ import * as semver from "semver";
77import { isKeyringEnabled } from "../cliConfig" ;
88import { featureSetForVersion } from "../featureSet" ;
99import { getHeaderArgs } from "../headers" ;
10- import { toSafeHost } from "../util" ;
10+ import { tempFilePath , toSafeHost } from "../util" ;
1111
1212import * as cliUtils from "./cliUtils" ;
1313
@@ -19,6 +19,8 @@ import type { PathResolver } from "./pathResolver";
1919
2020const execFileAsync = promisify ( execFile ) ;
2121
22+ type KeyringFeature = "keyringAuth" | "keyringTokenRead" ;
23+
2224const EXEC_TIMEOUT_MS = 60_000 ;
2325const EXEC_LOG_INTERVAL_MS = 5_000 ;
2426
@@ -59,7 +61,11 @@ export class CliCredentialManager {
5961 configs : Pick < WorkspaceConfiguration , "get" > ,
6062 signal ?: AbortSignal ,
6163 ) : Promise < void > {
62- const binPath = await this . resolveKeyringBinary ( url , configs ) ;
64+ const binPath = await this . resolveKeyringBinary (
65+ url ,
66+ configs ,
67+ "keyringAuth" ,
68+ ) ;
6369 if ( ! binPath ) {
6470 await this . writeCredentialFiles ( url , token ) ;
6571 return ;
@@ -91,17 +97,20 @@ export class CliCredentialManager {
9197 url : string ,
9298 configs : Pick < WorkspaceConfiguration , "get" > ,
9399 ) : Promise < string | undefined > {
94- if ( ! isKeyringEnabled ( configs ) ) {
95- return undefined ;
96- }
97-
98- let binPath : string ;
100+ let binPath : string | undefined ;
99101 try {
100- binPath = await this . resolveBinary ( url ) ;
102+ binPath = await this . resolveKeyringBinary (
103+ url ,
104+ configs ,
105+ "keyringTokenRead" ,
106+ ) ;
101107 } catch ( error ) {
102108 this . logger . warn ( "Could not resolve CLI binary for token read:" , error ) ;
103109 return undefined ;
104110 }
111+ if ( ! binPath ) {
112+ return undefined ;
113+ }
105114
106115 const args = [ ...getHeaderArgs ( configs ) , "login" , "token" , "--url" , url ] ;
107116 try {
@@ -131,22 +140,23 @@ export class CliCredentialManager {
131140
132141 /**
133142 * Resolve a CLI binary for keyring operations. Returns the binary path
134- * when keyring is enabled in settings and the CLI version supports it,
135- * or undefined to fall back to file-based storage.
143+ * when keyring is enabled in settings and the CLI version supports the
144+ * requested feature, or undefined to fall back to file-based storage.
136145 *
137146 * Throws on binary resolution or version-check failure (caller decides
138147 * whether to catch or propagate).
139148 */
140149 private async resolveKeyringBinary (
141150 url : string ,
142151 configs : Pick < WorkspaceConfiguration , "get" > ,
152+ feature : KeyringFeature ,
143153 ) : Promise < string | undefined > {
144154 if ( ! isKeyringEnabled ( configs ) ) {
145155 return undefined ;
146156 }
147157 const binPath = await this . resolveBinary ( url ) ;
148158 const version = semver . parse ( await cliUtils . version ( binPath ) ) ;
149- return featureSetForVersion ( version ) . keyringAuth ? binPath : undefined ;
159+ return featureSetForVersion ( version ) [ feature ] ? binPath : undefined ;
150160 }
151161
152162 /**
@@ -217,7 +227,7 @@ export class CliCredentialManager {
217227 ) : Promise < void > {
218228 let binPath : string | undefined ;
219229 try {
220- binPath = await this . resolveKeyringBinary ( url , configs ) ;
230+ binPath = await this . resolveKeyringBinary ( url , configs , "keyringAuth" ) ;
221231 } catch ( error ) {
222232 this . logger . warn ( "Could not resolve keyring binary for delete:" , error ) ;
223233 return ;
@@ -243,8 +253,7 @@ export class CliCredentialManager {
243253 content : string ,
244254 ) : Promise < void > {
245255 await fs . mkdir ( path . dirname ( filePath ) , { recursive : true } ) ;
246- const tempPath =
247- filePath + ".temp-" + Math . random ( ) . toString ( 36 ) . substring ( 8 ) ;
256+ const tempPath = tempFilePath ( filePath , "temp" ) ;
248257 try {
249258 await fs . writeFile ( tempPath , content , { mode : 0o600 } ) ;
250259 await fs . rename ( tempPath , filePath ) ;
0 commit comments