@@ -6,10 +6,8 @@ import {
66 resolveStateDir as resolveStateDirFromPaths ,
77} from "../config/paths.js" ;
88import type { OpenClawConfig } from "../config/types.openclaw.js" ;
9- import { resolveSecretInputRef } from "../config/types.secrets.js" ;
109import { loadOrCreateDeviceIdentity } from "../infra/device-identity.js" ;
1110import { loadGatewayTlsRuntime } from "../infra/tls/gateway.js" ;
12- import { resolveSecretInputString } from "../secrets/resolve-secret-input-string.js" ;
1311import { normalizeOptionalString } from "../shared/string-coerce.js" ;
1412import {
1513 GATEWAY_CLIENT_MODES ,
@@ -23,9 +21,8 @@ import {
2321 buildGatewayConnectionDetailsWithResolvers ,
2422 type GatewayConnectionDetails ,
2523} from "./connection-details.js" ;
24+ import { resolveGatewayCredentialsWithSecretInputs } from "./credentials-secret-inputs.js" ;
2625import {
27- GatewaySecretRefUnavailableError ,
28- resolveGatewayCredentialsFromConfig ,
2926 trimToUndefined ,
3027 type ExplicitGatewayAuth ,
3128 type GatewayCredentialMode ,
@@ -40,14 +37,6 @@ import {
4037 type OperatorScope ,
4138} from "./method-scopes.js" ;
4239import { PROTOCOL_VERSION } from "./protocol/index.js" ;
43- import {
44- ALL_GATEWAY_SECRET_INPUT_PATHS ,
45- assignResolvedGatewaySecretInput ,
46- isSupportedGatewaySecretInputPath ,
47- isTokenGatewaySecretInputPath ,
48- readGatewaySecretInputValue ,
49- type SupportedGatewaySecretInputPath ,
50- } from "./secret-input-paths.js" ;
5140export type { GatewayConnectionDetails } ;
5241
5342type CallGatewayBaseOptions = {
@@ -340,27 +329,6 @@ function ensureRemoteModeUrlConfigured(context: ResolvedGatewayCallContext): voi
340329 ) ;
341330}
342331
343- async function resolveGatewaySecretInputString ( params : {
344- config : OpenClawConfig ;
345- value : unknown ;
346- path : string ;
347- env : NodeJS . ProcessEnv ;
348- } ) : Promise < string | undefined > {
349- const value = await resolveSecretInputString ( {
350- config : params . config ,
351- value : params . value ,
352- env : params . env ,
353- normalize : trimToUndefined ,
354- onResolveRefError : ( ) => {
355- throw new GatewaySecretRefUnavailableError ( params . path ) ;
356- } ,
357- } ) ;
358- if ( ! value ) {
359- throw new Error ( `${ params . path } resolved to an empty or non-string value.` ) ;
360- }
361- return value ;
362- }
363-
364332async function resolveGatewayCredentials ( context : ResolvedGatewayCallContext ) : Promise < {
365333 token ?: string ;
366334 password ?: string ;
@@ -381,258 +349,23 @@ async function resolveGatewayCredentialsWithEnv(
381349 password : context . explicitAuth . password ,
382350 } ;
383351 }
384- return resolveGatewayCredentialsFromConfigWithSecretInputs ( { context, env } ) ;
385- }
386-
387- function hasConfiguredGatewaySecretRef (
388- config : OpenClawConfig ,
389- path : SupportedGatewaySecretInputPath ,
390- ) : boolean {
391- return Boolean (
392- resolveSecretInputRef ( {
393- value : readGatewaySecretInputValue ( config , path ) ,
394- defaults : config . secrets ?. defaults ,
395- } ) . ref ,
396- ) ;
397- }
398-
399- function resolveGatewayCredentialsFromConfigOptions ( params : {
400- context : ResolvedGatewayCallContext ;
401- env : NodeJS . ProcessEnv ;
402- cfg : OpenClawConfig ;
403- } ) {
404- const { context, env, cfg } = params ;
405- return {
406- cfg,
407- env,
352+ return resolveGatewayCredentialsWithSecretInputs ( {
353+ config : context . config ,
408354 explicitAuth : context . explicitAuth ,
409355 urlOverride : context . urlOverride ,
410356 urlOverrideSource : context . urlOverrideSource ,
357+ env,
411358 modeOverride : context . modeOverride ,
412359 localTokenPrecedence : context . localTokenPrecedence ,
413360 localPasswordPrecedence : context . localPasswordPrecedence ,
414361 remoteTokenPrecedence : context . remoteTokenPrecedence ,
415- remotePasswordPrecedence : context . remotePasswordPrecedence ?? "env-first" , // pragma: allowlist secret
362+ remotePasswordPrecedence : context . remotePasswordPrecedence ,
416363 remoteTokenFallback : context . remoteTokenFallback ,
417364 remotePasswordFallback : context . remotePasswordFallback ,
418- } as const ;
419- }
420-
421- function localAuthModeAllowsGatewaySecretInputPath ( params : {
422- authMode : string | undefined ;
423- path : SupportedGatewaySecretInputPath ;
424- } ) : boolean {
425- const { authMode, path } = params ;
426- if ( authMode === "none" || authMode === "trusted-proxy" ) {
427- return false ;
428- }
429- if ( authMode === "token" ) {
430- return isTokenGatewaySecretInputPath ( path ) ;
431- }
432- if ( authMode === "password" ) {
433- return ! isTokenGatewaySecretInputPath ( path ) ;
434- }
435- return true ;
436- }
437-
438- function gatewaySecretInputPathCanWin ( params : {
439- context : ResolvedGatewayCallContext ;
440- env : NodeJS . ProcessEnv ;
441- config : OpenClawConfig ;
442- path : SupportedGatewaySecretInputPath ;
443- } ) : boolean {
444- if ( ! hasConfiguredGatewaySecretRef ( params . config , params . path ) ) {
445- return false ;
446- }
447- const mode : GatewayCredentialMode =
448- params . context . modeOverride ?? ( params . config . gateway ?. mode === "remote" ? "remote" : "local" ) ;
449- if (
450- mode === "local" &&
451- ! localAuthModeAllowsGatewaySecretInputPath ( {
452- authMode : params . config . gateway ?. auth ?. mode ,
453- path : params . path ,
454- } )
455- ) {
456- return false ;
457- }
458- const sentinel = `__OPENCLAW_GATEWAY_SECRET_REF_PROBE_${ params . path . replaceAll ( "." , "_" ) } __` ;
459- const probeConfig = structuredClone ( params . config ) ;
460- for ( const candidatePath of ALL_GATEWAY_SECRET_INPUT_PATHS ) {
461- if ( ! hasConfiguredGatewaySecretRef ( probeConfig , candidatePath ) ) {
462- continue ;
463- }
464- assignResolvedGatewaySecretInput ( {
465- config : probeConfig ,
466- path : candidatePath ,
467- value : undefined ,
468- } ) ;
469- }
470- assignResolvedGatewaySecretInput ( {
471- config : probeConfig ,
472- path : params . path ,
473- value : sentinel ,
474- } ) ;
475- try {
476- const resolved = resolveGatewayCredentialsFromConfig (
477- resolveGatewayCredentialsFromConfigOptions ( {
478- context : params . context ,
479- env : params . env ,
480- cfg : probeConfig ,
481- } ) ,
482- ) ;
483- const tokenCanWin = resolved . token === sentinel && ! resolved . password ;
484- const passwordCanWin = resolved . password === sentinel && ! resolved . token ;
485- return tokenCanWin || passwordCanWin ;
486- } catch {
487- return false ;
488- }
489- }
490-
491- async function resolveConfiguredGatewaySecretInput ( params : {
492- config : OpenClawConfig ;
493- path : SupportedGatewaySecretInputPath ;
494- env : NodeJS . ProcessEnv ;
495- } ) : Promise < string | undefined > {
496- return resolveGatewaySecretInputString ( {
497- config : params . config ,
498- value : readGatewaySecretInputValue ( params . config , params . path ) ,
499- path : params . path ,
500- env : params . env ,
501365 } ) ;
502366}
503367
504- async function resolvePreferredGatewaySecretInputs ( params : {
505- context : ResolvedGatewayCallContext ;
506- env : NodeJS . ProcessEnv ;
507- config : OpenClawConfig ;
508- } ) : Promise < OpenClawConfig > {
509- let nextConfig = params . config ;
510- for ( const path of ALL_GATEWAY_SECRET_INPUT_PATHS ) {
511- if (
512- ! gatewaySecretInputPathCanWin ( {
513- context : params . context ,
514- env : params . env ,
515- config : nextConfig ,
516- path,
517- } )
518- ) {
519- continue ;
520- }
521- if ( nextConfig === params . config ) {
522- nextConfig = structuredClone ( params . config ) ;
523- }
524- try {
525- const resolvedValue = await resolveConfiguredGatewaySecretInput ( {
526- config : nextConfig ,
527- path,
528- env : params . env ,
529- } ) ;
530- assignResolvedGatewaySecretInput ( {
531- config : nextConfig ,
532- path,
533- value : resolvedValue ,
534- } ) ;
535- } catch {
536- // Keep scanning candidate paths so unresolved higher-priority refs do not
537- // prevent valid fallback refs from being considered.
538- continue ;
539- }
540- }
541- return nextConfig ;
542- }
543-
544- async function resolveGatewayCredentialsFromConfigWithSecretInputs ( params : {
545- context : ResolvedGatewayCallContext ;
546- env : NodeJS . ProcessEnv ;
547- } ) : Promise < { token ?: string ; password ?: string } > {
548- let resolvedConfig = await resolvePreferredGatewaySecretInputs ( {
549- context : params . context ,
550- env : params . env ,
551- config : params . context . config ,
552- } ) ;
553- const resolvedPaths = new Set < SupportedGatewaySecretInputPath > ( ) ;
554- for ( ; ; ) {
555- try {
556- return resolveGatewayCredentialsFromConfig (
557- resolveGatewayCredentialsFromConfigOptions ( {
558- context : params . context ,
559- env : params . env ,
560- cfg : resolvedConfig ,
561- } ) ,
562- ) ;
563- } catch ( error ) {
564- if ( ! ( error instanceof GatewaySecretRefUnavailableError ) ) {
565- throw error ;
566- }
567- const path = error . path ;
568- if ( ! isSupportedGatewaySecretInputPath ( path ) || resolvedPaths . has ( path ) ) {
569- throw error ;
570- }
571- if ( resolvedConfig === params . context . config ) {
572- resolvedConfig = structuredClone ( params . context . config ) ;
573- }
574- const resolvedValue = await resolveConfiguredGatewaySecretInput ( {
575- config : resolvedConfig ,
576- path,
577- env : params . env ,
578- } ) ;
579- assignResolvedGatewaySecretInput ( {
580- config : resolvedConfig ,
581- path,
582- value : resolvedValue ,
583- } ) ;
584- resolvedPaths . add ( path ) ;
585- }
586- }
587- }
588-
589- export async function resolveGatewayCredentialsWithSecretInputs ( params : {
590- config : OpenClawConfig ;
591- explicitAuth ?: ExplicitGatewayAuth ;
592- urlOverride ?: string ;
593- urlOverrideSource ?: "cli" | "env" ;
594- env ?: NodeJS . ProcessEnv ;
595- modeOverride ?: GatewayCredentialMode ;
596- localTokenPrecedence ?: GatewayCredentialPrecedence ;
597- localPasswordPrecedence ?: GatewayCredentialPrecedence ;
598- remoteTokenPrecedence ?: GatewayRemoteCredentialPrecedence ;
599- remotePasswordPrecedence ?: GatewayRemoteCredentialPrecedence ;
600- remoteTokenFallback ?: GatewayRemoteCredentialFallback ;
601- remotePasswordFallback ?: GatewayRemoteCredentialFallback ;
602- } ) : Promise < { token ?: string ; password ?: string } > {
603- const modeOverride = params . modeOverride ;
604- const isRemoteMode = modeOverride
605- ? modeOverride === "remote"
606- : params . config . gateway ?. mode === "remote" ;
607- const remoteFromConfig =
608- params . config . gateway ?. mode === "remote"
609- ? ( params . config . gateway ?. remote as GatewayRemoteSettings | undefined )
610- : undefined ;
611- const remoteFromOverride =
612- modeOverride === "remote"
613- ? ( params . config . gateway ?. remote as GatewayRemoteSettings | undefined )
614- : undefined ;
615- const context : ResolvedGatewayCallContext = {
616- config : params . config ,
617- configPath : resolveGatewayConfigPath ( process . env ) ,
618- isRemoteMode,
619- remote : remoteFromOverride ?? remoteFromConfig ,
620- urlOverride : trimToUndefined ( params . urlOverride ) ,
621- urlOverrideSource : params . urlOverrideSource ,
622- remoteUrl : isRemoteMode
623- ? trimToUndefined ( ( params . config . gateway ?. remote as GatewayRemoteSettings | undefined ) ?. url )
624- : undefined ,
625- explicitAuth : resolveExplicitGatewayAuth ( params . explicitAuth ) ,
626- modeOverride,
627- localTokenPrecedence : params . localTokenPrecedence ,
628- localPasswordPrecedence : params . localPasswordPrecedence ,
629- remoteTokenPrecedence : params . remoteTokenPrecedence ,
630- remotePasswordPrecedence : params . remotePasswordPrecedence ,
631- remoteTokenFallback : params . remoteTokenFallback ,
632- remotePasswordFallback : params . remotePasswordFallback ,
633- } ;
634- return resolveGatewayCredentialsWithEnv ( context , params . env ?? process . env ) ;
635- }
368+ export { resolveGatewayCredentialsWithSecretInputs } ;
636369
637370async function resolveGatewayTlsFingerprint ( params : {
638371 opts : CallGatewayBaseOptions ;
0 commit comments