Giter VIP home page Giter VIP logo

python-doppler-env's Introduction

doppler-env

The doppler-env package automates the injection of Doppler secrets as environment variables into any Python application and works in the terminal, PyCharm, and Visual Studio Code.

Motivation

The Doppler CLI provides the easiest method of injecting secrets into your application:

doppler run -- python app.py

But when debugging with PyCharm or Visual Studio Code, a vendor-specific Python entry-point is used, preventing the Doppler CLI from acting as the application runner. At Doppler, we go to great lengths to prevent secrets ending up on developer's machines so downloading secrets to a .env file wasn't an option.

Thanks to Python's Site configuration hook via a path configuration file, we can replicate the doppler run workflow by fetching the secrets via the Doppler CLI (recommended) or API and injecting into your Python application process prior to your code by being executed.

Setup

Ensure you have installed the Doppler CLI locally and have created a Doppler Project. Then authorize the Doppler CLI to retrieve secrets from your workplace by running:

doppler login

Then install doppler-env in your local development environment or add it to the list of dev specific dependencies:

pip install doppler-env

Configuration

First, define the DOPPLER_ENV environment variable in your IDE, editor, or terminal to trigger the injection of secrets:

export DOPPLER_ENV=1

You can enable logging for troubleshooting purposes by setting the DOPPLER_ENV_LOGGING environment variable:

export DOPPLER_ENV_LOGGING=1

Then configure which secrets to fetch for your application by either using the CLI in the root directory of your application:

doppler setup

Or set the DOPPLER_PROJECT and DOPPLER_CONFIG environment variables in your debug configuration within PyCharm or Visual Studio Code.

Now whenever the Python interpreter is invoked for your application, secrets will be injected prior to your application being run:

python app.py

# >> [doppler-env]: DOPPLER_ENV environment variable set. Fetching secrets using Doppler CLI

In restrictive environments where the use of the Doppler CLI isn't possible, set a DOPPLER_TOKEN environment variable with a Service Token to fetch secrets directly from the Doppler API:

export DOPPLER_TOKEN='dp.st.dev.xxxxxxx'

python app.py

# >> [doppler-env]: DOPPLER_ENV and DOPPLER_TOKEN environment variable set. Fetching secrets from Doppler API

Acknowledgements

This approach to injecting environment variables was inspired by patch-env.

Issues

For any bug reports, issues, or enhancements, please create a repository issue.

Support

You can get support in the Doppler community forum, find us on Twitter, and for bugs or feature requests, create an issue on the DopplerHQ/python-doppler-env GitHub repository.

If you need help, either use our in-product support or head over to the Doppler Community Forum to get your questions answered by a member of the Doppler support team or

python-doppler-env's People

Contributors

ryan-blunden avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

python-doppler-env's Issues

Allow override of environment variables when calling load_dotenv

Environment

  • Doppler Env version: 0.3.1
  • Python version: 3.10
  • Operating System: Windows 10

Description

By default the doppler cli overrides environment variables found in system. You must pass --perserve-env flag to avoid the override. By default load_dotenv does not override environment variables so the behavior is reversed. I would think this would be consistent.

I am running into an issue where one of my variables setup in a doppler config is the same key name as one used by our end user computer team sets up on our workstations and I have no way of getting the up to date value from my doppler config.

Is it possible to have the same behavior as the cli and override by default by passing override=True to the load_dotenv call? And have the ability to control this behavior via environment variable?

Steps to Reproduce

  1. Have a system environment variable key name same as one in doppler config
  2. Up to date value will not be retrievable through os.getenv method when setting doppler_env=1

Expected Behavior

I expected to get the up to date value from doppler config, overriding the system environment variable of the same name

Screenshots

N/A

Additional Details

N/A

DOPPLER_ENV=1 crashes poetry

Environment

  • Doppler Env version: v3.66.5
  • Python version: 3.12.1
  • Operating System: Arch

Description

python-doppler-env breaks poetry.

Steps to Reproduce

  • Using a poetry setup described here
  • export DOPPLER_ENV =1
  • poetry install
[doppler-env]: DOPPLER_ENV environment variable set. Fetching secrets using Doppler CLI
Loading configuration file /home/wing/.config/pypoetry/config.toml

  StopIteration

  1

  at ~/.conda/envs/xoul_API/lib/python3.12/json/decoder.py:353 in raw_decode
      349│         have extraneous data at the end.
      350│
      351│         """
      352│         try:
    → 353│             obj, end = self.scan_once(s, idx)
      354│         except StopIteration as err:
      355│             raise JSONDecodeError("Expecting value", s, err.value) from None
      356│         return obj, end
      357│

The following error occurred when trying to handle this error:


  Stack trace:

  14  ~/.conda/envs/xoul_API/lib/python3.12/site-packages/cleo/application.py:327 in run
       325│
       326│             try:
     → 327│                 exit_code = self._run(io)
       328│             except BrokenPipeError:
       329│                 # If we are piped to another process, it may close early and send a

  13  ~/.conda/envs/xoul_API/lib/python3.12/site-packages/poetry/console/application.py:190 in _run
       188│         self._load_plugins(io)
       189│
     → 190│         exit_code: int = super()._run(io)
       191│         return exit_code
       192│

  12  ~/.conda/envs/xoul_API/lib/python3.12/site-packages/cleo/application.py:431 in _run
       429│             io.input.interactive(interactive)
       430│
     → 431│         exit_code = self._run_command(command, io)
       432│         self._running_command = None
       433│

  11  ~/.conda/envs/xoul_API/lib/python3.12/site-packages/cleo/application.py:473 in _run_command
       471│
       472│         if error is not None:
     → 473│             raise error
       474│
       475│         return terminate_event.exit_code

  10  ~/.conda/envs/xoul_API/lib/python3.12/site-packages/cleo/application.py:454 in _run_command
       452│
       453│         try:
     → 454│             self._event_dispatcher.dispatch(command_event, COMMAND)
       455│
       456│             if command_event.command_should_run():

   9  ~/.conda/envs/xoul_API/lib/python3.12/site-packages/cleo/events/event_dispatcher.py:26 in dispatch
        24│
        25│         if listeners:
     →  26│             self._do_dispatch(listeners, event_name, event)
        27│
        28│         return event

   8  ~/.conda/envs/xoul_API/lib/python3.12/site-packages/cleo/events/event_dispatcher.py:85 in _do_dispatch
        83│                 break
        84│
     →  85│             listener(event, event_name, self)
        86│
        87│     def _sort_listeners(self, event_name: str) -> None:

   7  ~/.conda/envs/xoul_API/lib/python3.12/site-packages/poetry/console/application.py:299 in configure_env
       297│
       298│         env_manager = EnvManager(poetry, io=io)
     → 299│         env = env_manager.create_venv()
       300│
       301│         if env.is_venv() and io.is_verbose():

   6  ~/.conda/envs/xoul_API/lib/python3.12/site-packages/poetry/utils/env/env_manager.py:444 in create_venv
       442│             # Already inside a virtualenv.
       443│             current_python = Version.parse(
     → 444│                 ".".join(str(c) for c in env.version_info[:3])
       445│             )
       446│             if not self._poetry.package.python_constraint.allows(current_python):

   5  ~/.conda/envs/xoul_API/lib/python3.12/site-packages/poetry/utils/env/base_env.py:77 in version_info
        75│     @property
        76│     def version_info(self) -> tuple[int, int, int, str, int]:
     →  77│         version_info: tuple[int, int, int, str, int] = self.marker_env["version_info"]
        78│         return version_info
        79│

   4  ~/.conda/envs/xoul_API/lib/python3.12/site-packages/poetry/utils/env/base_env.py:95 in marker_env
        93│     def marker_env(self) -> dict[str, Any]:
        94│         if self._marker_env is None:
     →  95│             self._marker_env = self.get_marker_env()
        96│
        97│         return self._marker_env

   3  ~/.conda/envs/xoul_API/lib/python3.12/site-packages/poetry/utils/env/virtual_env.py:72 in get_marker_env
        70│         output = self.run_python_script(GET_ENVIRONMENT_INFO)
        71│
     →  72│         env: dict[str, Any] = json.loads(output)
        73│         return env
        74│

   2  ~/.conda/envs/xoul_API/lib/python3.12/json/__init__.py:346 in loads
       344│             parse_int is None and parse_float is None and
       345│             parse_constant is None and object_pairs_hook is None and not kw):
     → 346│         return _default_decoder.decode(s)
       347│     if cls is None:
       348│         cls = JSONDecoder

   1  ~/.conda/envs/xoul_API/lib/python3.12/json/decoder.py:337 in decode
       335│
       336│         """
     → 337│         obj, end = self.raw_decode(s, idx=_w(s, 0).end())
       338│         end = _w(s, end).end()
       339│         if end != len(s):

  JSONDecodeError

  Expecting value: line 1 column 2 (char 1)

  at ~/.conda/envs/xoul_API/lib/python3.12/json/decoder.py:355 in raw_decode
      351│         """
      352│         try:
      353│             obj, end = self.scan_once(s, idx)
      354│         except StopIteration as err:
    → 355│             raise JSONDecodeError("Expecting value", s, err.value) from None
      356│         return obj, end
      357│

Expected Behavior

When DOPPLER_ENV is unset, poetry installs and manages packages normally. Expected behavior is to not break the package manager.

New output in 0.3.0 breaks VSCode `black`/`isort`

Environment

  • Doppler Env version: 0.3.0
  • Python version: 3.8.12
  • Operating System: macOS 12.4

Description

New doppler output breaks VSCode tools:

image

Steps to Reproduce

I've got latest Pylance installed, and configured to use black/isort from my venv, which is created with a simple python -m venv venv

Settings:

  "python.linting.enabled": true,
  "python.linting.pylintEnabled": true,
  "python.formatting.provider": "black",
  "python.analysis.indexing": true,
  "[python]": {
    "editor.formatOnSave": true,
    "editor.codeActionsOnSave": {
      "source.organizeImports": true
    },
    "editor.rulers": [88]
  },

Expected Behavior

Not breaking VSCode (maybe not adding output when not running interactively? or at least providing a way to turn the output off with an env var or similar).

Screenshots

See above.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.