@@ -107,48 +107,22 @@ doppler run --mount secrets.json -- cat secrets.json`,
107107 }
108108 }
109109
110- const format = models .JSON
111- fallbackPath := ""
112- legacyFallbackPath := ""
113- metadataPath := ""
114- if enableFallback {
115- fallbackPath , legacyFallbackPath = initFallbackDir (cmd , localConfig , format , nameTransformer , secretsToInclude , exitOnWriteFailure )
116- }
117- if enableCache {
118- metadataPath = controllers .MetadataFilePath (localConfig .Token .Value , localConfig .EnclaveProject .Value , localConfig .EnclaveConfig .Value , format , nameTransformer , secretsToInclude )
119- }
120-
121110 passphrase := getPassphrase (cmd , "passphrase" , localConfig )
122111 if passphrase == "" {
123112 utils .HandleError (errors .New ("invalid passphrase" ))
124113 }
125114
126- if ! enableFallback {
127- flags := []string {"fallback" , "fallback-only" , "offline" , "fallback-readonly" , "no-exit-on-write-failure" , "passphrase" }
128- for _ , flag := range flags {
129- if cmd .Flags ().Changed (flag ) {
130- utils .LogWarning (fmt .Sprintf ("--%s has no effect when the fallback file is disabled" , flag ))
131- }
132- }
133- }
134-
135- fallbackOpts := controllers.FallbackOptions {
136- Enable : enableFallback ,
137- Path : fallbackPath ,
138- LegacyPath : legacyFallbackPath ,
139- Readonly : fallbackReadonly ,
140- Exclusive : fallbackOnly ,
141- ExclusiveFlag : fallbackFlag ,
142- ExitOnWriteFailure : exitOnWriteFailure ,
143- Passphrase : passphrase ,
144- }
145-
146115 mountPath := cmd .Flag ("mount" ).Value .String ()
147- mountFormatString := cmd .Flag ("mount-format" ).Value .String ()
116+ // --format is the primary flag, --mount-format is a deprecated alias
117+ mountFormatString := cmd .Flag ("format" ).Value .String ()
118+ if cmd .Flags ().Changed ("mount-format" ) && ! cmd .Flags ().Changed ("format" ) {
119+ // Use --mount-format value if specified and --format was not
120+ mountFormatString = cmd .Flag ("mount-format" ).Value .String ()
121+ }
148122 mountTemplate := cmd .Flag ("mount-template" ).Value .String ()
149123 maxReads := utils .GetIntFlag (cmd , "mount-max-reads" , 32 )
150124 // only auto-detect the format if it hasn't been explicitly specified
151- shouldAutoDetectFormat := ! cmd .Flags ().Changed ("mount-format" )
125+ shouldAutoDetectFormat := ! cmd .Flags ().Changed ("format" ) && ! cmd . Flags (). Changed ( " mount-format" )
152126 shouldMountFile := mountPath != ""
153127 shouldMountTemplate := mountTemplate != ""
154128
@@ -205,6 +179,51 @@ doppler run --mount secrets.json -- cat secrets.json`,
205179 }
206180 }
207181
182+ // Determine the API format to use
183+ // When mounting: use the requested mount format (template requires JSON for client-side rendering)
184+ // When not mounting: always use JSON for env injection
185+ var format models.SecretsFormat
186+ if shouldMountFile && mountFormat != models .TemplateMountFormat {
187+ for _ , val := range models .SecretsFormatList {
188+ if val .String () == mountFormat {
189+ format = val
190+ break
191+ }
192+ }
193+ } else {
194+ format = models .JSON
195+ }
196+
197+ fallbackPath := ""
198+ legacyFallbackPath := ""
199+ metadataPath := ""
200+ if enableFallback {
201+ fallbackPath , legacyFallbackPath = initFallbackDir (cmd , localConfig , format , nameTransformer , secretsToInclude , exitOnWriteFailure )
202+ }
203+ if enableCache {
204+ metadataPath = controllers .MetadataFilePath (localConfig .Token .Value , localConfig .EnclaveProject .Value , localConfig .EnclaveConfig .Value , format , nameTransformer , secretsToInclude )
205+ }
206+
207+ if ! enableFallback {
208+ flags := []string {"fallback" , "fallback-only" , "offline" , "fallback-readonly" , "no-exit-on-write-failure" , "passphrase" }
209+ for _ , flag := range flags {
210+ if cmd .Flags ().Changed (flag ) {
211+ utils .LogWarning (fmt .Sprintf ("--%s has no effect when the fallback file is disabled" , flag ))
212+ }
213+ }
214+ }
215+
216+ fallbackOpts := controllers.FallbackOptions {
217+ Enable : enableFallback ,
218+ Path : fallbackPath ,
219+ LegacyPath : legacyFallbackPath ,
220+ Readonly : fallbackReadonly ,
221+ Exclusive : fallbackOnly ,
222+ ExclusiveFlag : fallbackFlag ,
223+ ExitOnWriteFailure : exitOnWriteFailure ,
224+ Passphrase : passphrase ,
225+ }
226+
208227 mountOptions := controllers.MountOptions {
209228 Enable : shouldMountFile ,
210229 Format : mountFormat ,
@@ -252,8 +271,9 @@ doppler run --mount secrets.json -- cat secrets.json`,
252271 }
253272
254273 startProcess := func () {
255- // ensure we can fetch the new secrets before restarting the process
256- secrets , fromCache := controllers .FetchSecrets (localConfig , enableCache , fallbackOpts , metadataPath , nameTransformer , dynamicSecretsTTL , format , secretsToInclude )
274+ // Fetch secrets (returns raw bytes, supports caching/fallback for all formats)
275+ secretsBytes , fromCache := controllers .FetchSecrets (localConfig , enableCache , fallbackOpts , metadataPath , nameTransformer , dynamicSecretsTTL , format , secretsToInclude )
276+
257277 secretsFetchedAt := time .Now ()
258278 if secretsFetchedAt .After (lastSecretsFetch ) {
259279 lastSecretsFetch = secretsFetchedAt
@@ -262,7 +282,24 @@ doppler run --mount secrets.json -- cat secrets.json`,
262282 watchedValuesMayBeStale = false
263283 }
264284
265- controllers .ValidateSecrets (secrets , secretsToInclude , exitOnMissingIncludedSecrets , mountOptions )
285+ // Parse secrets to map when needed:
286+ // - For env injection (not mounting)
287+ // - For validation
288+ // - For template rendering
289+ var secrets map [string ]string
290+ needsParsedSecrets := ! shouldMountFile || mountFormat == models .TemplateMountFormat
291+ if needsParsedSecrets || len (secretsToInclude ) > 0 {
292+ // Template format and env injection require JSON, so we need to parse
293+ var parseErr error
294+ secrets , parseErr = controllers .ParseSecrets (secretsBytes )
295+ if parseErr != nil {
296+ utils .HandleError (parseErr , "Unable to parse secrets" )
297+ }
298+ }
299+
300+ if needsParsedSecrets || len (secretsToInclude ) > 0 {
301+ controllers .ValidateSecrets (secrets , secretsToInclude , exitOnMissingIncludedSecrets , mountOptions )
302+ }
266303
267304 isRestart := c != nil
268305 // terminate the old process
@@ -316,7 +353,7 @@ doppler run --mount secrets.json -- cat secrets.json`,
316353 terminatedByWatch = false
317354
318355 var env []string
319- env , cleanupMount = controllers .PrepareSecrets (secrets , os .Environ (), preserveEnv , mountOptions )
356+ env , cleanupMount = controllers .PrepareSecrets (secrets , secretsBytes , os .Environ (), preserveEnv , mountOptions )
320357
321358 global .WaitGroup .Add (1 )
322359
@@ -656,13 +693,18 @@ func init() {
656693 runCmd .Flags ().Bool ("no-liveness-ping" , false , "disable the periodic liveness ping" )
657694 // secrets mount flags
658695 runCmd .Flags ().String ("mount" , "" , "write secrets to an ephemeral file, accessible at DOPPLER_CLI_SECRETS_PATH. when enabled, secrets are NOT injected into the environment" )
659- runCmd .Flags ().String ("mount- format" , "json" , fmt .Sprintf ("file format to use. if not specified, will be auto-detected from mount name. one of %v" , models .SecretsMountFormats ))
660- err = runCmd .RegisterFlagCompletionFunc ("mount- format" , func (cmd * cobra.Command , args []string , toComplete string ) ([]string , cobra.ShellCompDirective ) {
661- return [] string { projectTemplateFileName } , cobra .ShellCompDirectiveDefault
696+ runCmd .Flags ().String ("format" , "json" , fmt .Sprintf ("file format to use. if not specified, will be auto-detected from mount name. one of %v" , models .SecretsMountFormats ))
697+ err = runCmd .RegisterFlagCompletionFunc ("format" , func (cmd * cobra.Command , args []string , toComplete string ) ([]string , cobra.ShellCompDirective ) {
698+ return models . SecretsMountFormats , cobra .ShellCompDirectiveDefault
662699 })
663700 if err != nil {
664701 utils .HandleError (err )
665702 }
703+ // --mount-format is a deprecated alias for --format
704+ runCmd .Flags ().String ("mount-format" , "json" , fmt .Sprintf ("file format to use. one of %v" , models .SecretsMountFormats ))
705+ if err := runCmd .Flags ().MarkDeprecated ("mount-format" , "use --format instead" ); err != nil {
706+ utils .HandleError (err )
707+ }
666708 runCmd .Flags ().String ("mount-template" , "" , "template file to use. secrets will be rendered into this template before mount. see 'doppler secrets substitute' for more info." )
667709 runCmd .Flags ().Int ("mount-max-reads" , 0 , "maximum number of times the mounted secrets file can be read (0 for unlimited)" )
668710 runCmd .Flags ().StringSliceVar (& secretsToInclude , "only-secrets" , []string {}, "only include the specified secrets" )
0 commit comments