@@ -528,55 +528,66 @@ def _run_direnv_export(directory: Path) -> subprocess.CompletedProcess[str] | No
528528 )
529529
530530
531- def load_direnv_env (directory : Path ) -> dict [str , str ]:
532- """Return the environment variables an optional ``.envrc`` produces via direnv.
531+ def load_direnv_env (directory : Path ) -> tuple [ dict [str , str ] , str ]:
532+ """Return the variables an optional ``.envrc`` produces via direnv, plus direnv's stderr .
533533
534- Returns ``{}`` silently when direnv isn't installed or there's no ``.envrc``.
535- When direnv refuses an unapproved ``.envrc``, prints an actionable hint and
536- returns ``{}`` rather than crashing.
534+ Returns ``({}, '')`` silently when direnv isn't installed or there's no
535+ ``.envrc``. When direnv refuses an unapproved ``.envrc``, prints an actionable
536+ hint and returns ``({}, <stderr>)`` rather than crashing. The stderr is
537+ returned so callers can surface *why* the ``.envrc`` produced no usable values
538+ (e.g. a Vault command inside it failing), since direnv runs the file itself.
537539
538540 Args:
539541 directory: Directory whose ``.envrc`` should be evaluated.
540542
541543 Returns:
542- A mapping of exported variable names to string values .
544+ A ``( exported vars, direnv stderr)`` pair .
543545 """
544546 result = _run_direnv_export (directory )
545547 if result is None :
546- return {}
548+ return {}, ''
547549 if result .returncode != 0 or _envrc_is_blocked (result .stderr ):
548550 typer .echo (
549551 f'direnv could not load { directory } /.envrc (not approved?). Run: direnv allow { directory } ' ,
550552 err = True ,
551553 )
552- return {}
554+ return {}, result . stderr
553555 stdout = result .stdout .strip ()
554556 if not stdout :
555- return {}
557+ return {}, result . stderr
556558 try :
557559 data = json .loads (stdout )
558560 except json .JSONDecodeError :
559- return {}
560- return {key : value for key , value in data .items () if isinstance (value , str )}
561+ return {}, result . stderr
562+ return {key : value for key , value in data .items () if isinstance (value , str )}, result . stderr
561563
562564
563- def _warn_if_envrc_lacks_keys (directory : Path , direnv_env : dict [str , str ], missing : list [str ]) -> None :
564- """Warn when an evaluated ``.envrc`` didn't export the credential keys still needed.
565+ def _warn_if_envrc_lacks_keys (directory : Path , direnv_env : dict [str , str ], missing : list [str ], stderr : str ) -> None :
566+ """Warn when an evaluated ``.envrc`` didn't provide the credential keys still needed.
565567
566568 ``direnv_env`` is non-empty only when direnv actually evaluated an approved
567569 ``.envrc`` (it always includes direnv's own bookkeeping vars), which lets us
568- tell "loaded but missing the keys" apart from "blocked" or "no .envrc".
570+ tell "loaded but missing the keys" apart from "blocked" or "no .envrc". When
571+ the file ran but the keys are unset/empty, direnv's stderr usually explains
572+ why (e.g. a failed Vault lookup), so it is echoed back as the reason.
569573
570574 Args:
571575 directory: Directory whose ``.envrc`` was evaluated.
572576 direnv_env: Variables direnv exported (empty if it didn't run/was blocked).
573577 missing: Required credential variables still unset after the merge.
578+ stderr: direnv's stderr from evaluating the ``.envrc``.
574579 """
575- if direnv_env and missing :
576- typer .echo (
577- f'{ directory } /.envrc was loaded via direnv but does not export: { ", " .join (missing )} ' ,
578- err = True ,
579- )
580+ if not (direnv_env and missing ):
581+ return
582+ typer .echo (
583+ f'{ directory } /.envrc was loaded via direnv but did not provide: { ", " .join (missing )} ' ,
584+ err = True ,
585+ )
586+ diagnostic = stderr .strip ()
587+ if diagnostic :
588+ typer .echo ('direnv reported:' , err = True )
589+ for line in diagnostic .splitlines ():
590+ typer .echo (f' { line } ' , err = True )
580591
581592
582593def resolve_credentials (api_key : str | None , app_key : str | None , directory : Path ) -> tuple [str | None , str | None ]:
@@ -599,11 +610,11 @@ def resolve_credentials(api_key: str | None, app_key: str | None, directory: Pat
599610 """
600611 if api_key and app_key :
601612 return api_key , app_key
602- direnv_env = load_direnv_env (directory )
613+ direnv_env , stderr = load_direnv_env (directory )
603614 api_key = api_key or direnv_env .get (API_KEY_ENV )
604615 app_key = app_key or direnv_env .get (APP_KEY_ENV )
605616 missing = [name for name , value in ((API_KEY_ENV , api_key ), (APP_KEY_ENV , app_key )) if not value ]
606- _warn_if_envrc_lacks_keys (directory , direnv_env , missing )
617+ _warn_if_envrc_lacks_keys (directory , direnv_env , missing , stderr )
607618 return api_key , app_key
608619
609620
0 commit comments