From 7995e97fee73545bc04137d30c2fb48d8666b8cb Mon Sep 17 00:00:00 2001 From: nsnguyen Date: Wed, 12 Jul 2023 00:19:09 -0700 Subject: [PATCH 1/8] allow to find .env.vault --- src/dotenv_vault/main.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/dotenv_vault/main.py b/src/dotenv_vault/main.py index dfaa0fc..34bf8a5 100644 --- a/src/dotenv_vault/main.py +++ b/src/dotenv_vault/main.py @@ -11,6 +11,9 @@ import dotenv.main as dotenv +DOTENV_VAULT_PATH = dotenv.find_dotenv(".env.vault") + + def load_dotenv( dotenv_path: Union[str, os.PathLike, None] = None, stream: Optional[IO[str]] = None, @@ -40,7 +43,7 @@ def load_dotenv( """ if "DOTENV_KEY" in os.environ: - vault_stream = parse_vault(open(".env.vault")) + vault_stream = parse_vault(DOTENV_VAULT_PATH) return dotenv.load_dotenv( stream=vault_stream, verbose=verbose, @@ -75,7 +78,7 @@ def parse_vault(vault_stream: io.IOBase) -> io.StringIO: raise DotEnvVaultError("NOT_FOUND_DOTENV_KEY: Cannot find ENV['DOTENV_KEY']") # Use the python-dotenv library to read the .env.vault file. - vault = dotenv.DotEnv(dotenv_path=".env.vault", stream=vault_stream) + vault = dotenv.DotEnv(dotenv_path=DOTENV_VAULT_PATH, stream=vault_stream) # Extract segments from the DOTENV_KEY environment variable one by # one and retrieve the corresponding ciphertext from the vault From 3e2ececc2862c9ea3d7b7724f60f2f371f062f17 Mon Sep 17 00:00:00 2001 From: nsnguyen Date: Wed, 12 Jul 2023 00:21:23 -0700 Subject: [PATCH 2/8] add 0.6.1 changelog --- CHANGELOG.md | 8 +++++++- src/dotenv_vault/main.py | 2 +- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08c0fad..bf538d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,12 +4,18 @@ All notable changes to this project will be documented in this file. See [standa ## [Unreleased](https://github.com/dotenv-org/python-dotenv-vault/compare/v0.5.1...master) -## 0.6.1 +## 0.7.0 ### Changed - Fix fallback issue with gunicorn not respecting the current working directory when attempting to call `find_dotenv`. [#17](https://github.com/dotenv-org/python-dotenv-vault/pull/17) +## 0.6.1 + +### Changed + +- Allow to place .env.vault file anywhere in app [#13](https://github.com/dotenv-org/python-dotenv-vault/pull/13) + ## 0.6.0 ### Changed diff --git a/src/dotenv_vault/main.py b/src/dotenv_vault/main.py index 34bf8a5..f601c2c 100644 --- a/src/dotenv_vault/main.py +++ b/src/dotenv_vault/main.py @@ -43,7 +43,7 @@ def load_dotenv( """ if "DOTENV_KEY" in os.environ: - vault_stream = parse_vault(DOTENV_VAULT_PATH) + vault_stream = parse_vault(open(DOTENV_VAULT_PATH)) return dotenv.load_dotenv( stream=vault_stream, verbose=verbose, From 5291f16a989a4046538f936280a5b35dc3e21243 Mon Sep 17 00:00:00 2001 From: nsnguyen Date: Wed, 12 Jul 2023 22:51:18 -0700 Subject: [PATCH 3/8] add logic where it should look for .env file first, and expect .env.vault should be in same location --- src/dotenv_vault/__init__.py | 2 +- src/dotenv_vault/main.py | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/dotenv_vault/__init__.py b/src/dotenv_vault/__init__.py index 211af1d..54a0aef 100644 --- a/src/dotenv_vault/__init__.py +++ b/src/dotenv_vault/__init__.py @@ -1 +1 @@ -from .main import load_dotenv +from .main import load_dotenv, load_dotenv_vault diff --git a/src/dotenv_vault/main.py b/src/dotenv_vault/main.py index f601c2c..a7ab0d3 100644 --- a/src/dotenv_vault/main.py +++ b/src/dotenv_vault/main.py @@ -11,7 +11,14 @@ import dotenv.main as dotenv -DOTENV_VAULT_PATH = dotenv.find_dotenv(".env.vault") +def load_dotenv_vault() -> str: + path = dotenv.find_dotenv() + if not path: + return path + path = os.path.dirname(path) + if '.env.vault' not in os.listdir(path): + raise FileNotFoundError('.env.vault is not in same directory as .env') + return f"{path}/.env.vault" def load_dotenv( @@ -43,7 +50,7 @@ def load_dotenv( """ if "DOTENV_KEY" in os.environ: - vault_stream = parse_vault(open(DOTENV_VAULT_PATH)) + vault_stream = parse_vault(open(load_dotenv_vault())) return dotenv.load_dotenv( stream=vault_stream, verbose=verbose, @@ -78,7 +85,7 @@ def parse_vault(vault_stream: io.IOBase) -> io.StringIO: raise DotEnvVaultError("NOT_FOUND_DOTENV_KEY: Cannot find ENV['DOTENV_KEY']") # Use the python-dotenv library to read the .env.vault file. - vault = dotenv.DotEnv(dotenv_path=DOTENV_VAULT_PATH, stream=vault_stream) + vault = dotenv.DotEnv(dotenv_path=load_dotenv_vault(), stream=vault_stream) # Extract segments from the DOTENV_KEY environment variable one by # one and retrieve the corresponding ciphertext from the vault From 6e7bf4b3f081c86f6e17e7d662594bbcddb09617 Mon Sep 17 00:00:00 2001 From: nsnguyen Date: Wed, 12 Jul 2023 22:51:26 -0700 Subject: [PATCH 4/8] add unit test --- src/dotenv_vault/test_vault.py | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/dotenv_vault/test_vault.py b/src/dotenv_vault/test_vault.py index 6b0544c..ef99860 100644 --- a/src/dotenv_vault/test_vault.py +++ b/src/dotenv_vault/test_vault.py @@ -1,12 +1,14 @@ from io import StringIO import os import unittest +from unittest import mock from dotenv.main import load_dotenv import dotenv_vault.main as vault class TestParsing(unittest.TestCase): + TEST_KEYS = [ # OK. ["dotenv://:key_0dec82bea24ada79a983dcc11b431e28838eae59a07a8f983247c7ca9027a925@dotenv.local/vault/.env.vault?environment=development", @@ -23,7 +25,7 @@ class TestParsing(unittest.TestCase): # Missing environment. ["dotenv://:key_1234@dotenv.org/vault/.env.vault", False, ""] ] - + def test_key_parsing(self): for test in self.TEST_KEYS: dotenv_key, should_pass, environment_key_check = test @@ -49,7 +51,7 @@ def test_key_parsing(self): DOTENV_VAULT_STAGING="uGHOx986lAWGU9s5mN5+b0jl0HAvNj4Mqs/zwN7Bl8UeV+C6hBg5JuKdi2AGGLka5g==" DOTENV_VAULT_PRODUCTION="YpDpGGf+eqiOPibziIQQbw4gBW/zfOBR6jow5B1UHYTTu6Kak6xy+qP/vXZWaPp4HOh2/Nu7gRK2CWfrbtk=" """ - + def test_vault_parsing(self): old_dotenv_key = os.environ.get("DOTENV_KEY") os.environ["DOTENV_KEY"] = self.PARSE_TEST_KEY @@ -61,3 +63,19 @@ def test_vault_parsing(self): os.unsetenv("DOTENV_KEY") if old_dotenv_key: os.environ["DOTENV_KEY"] = old_dotenv_key + + @mock.patch("dotenv.main.find_dotenv") + def test_load_dotenv_vault(self, find_dotenv): + find_dotenv.return_value = '/some/path/' + with mock.patch('os.listdir') as mocked_listdir: + mocked_listdir.return_value = ['.env', '.env.vault', 'some_file'] + path = vault.load_dotenv_vault() + self.assertEqual(path, '/some/path/.env.vault') + + @mock.patch("dotenv.main.find_dotenv") + def test_load_dotenv_vault_not_there(self, find_dotenv): + find_dotenv.return_value = '/some/path/' + with mock.patch('os.listdir') as mocked_listdir: + mocked_listdir.return_value = ['.env', 'some_file'] + with self.assertRaises(FileNotFoundError): + vault.load_dotenv_vault() From b1c8ca8bd8514a40c39418b13047363fe6c0569d Mon Sep 17 00:00:00 2001 From: nsnguyen Date: Wed, 12 Jul 2023 23:11:51 -0700 Subject: [PATCH 5/8] update python-dotenv dependecy version to 1.0.0 --- src/dotenv_vault/main.py | 7 ++++++- src/dotenv_vault/test_vault.py | 4 ++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/dotenv_vault/main.py b/src/dotenv_vault/main.py index a7ab0d3..e0bf739 100644 --- a/src/dotenv_vault/main.py +++ b/src/dotenv_vault/main.py @@ -3,6 +3,8 @@ from base64 import b64decode import io import os +import logging + from typing import (IO, Optional, Union) from urllib.parse import urlparse, parse_qsl @@ -10,6 +12,7 @@ from cryptography.exceptions import InvalidTag import dotenv.main as dotenv +logger = logging.getLogger(__name__) def load_dotenv_vault() -> str: path = dotenv.find_dotenv() @@ -17,7 +20,9 @@ def load_dotenv_vault() -> str: return path path = os.path.dirname(path) if '.env.vault' not in os.listdir(path): - raise FileNotFoundError('.env.vault is not in same directory as .env') + # we fall back to .env + logger.warning("No .env.vault file found. Falling back to .env") + return f"{path}/.env" return f"{path}/.env.vault" diff --git a/src/dotenv_vault/test_vault.py b/src/dotenv_vault/test_vault.py index ef99860..196022d 100644 --- a/src/dotenv_vault/test_vault.py +++ b/src/dotenv_vault/test_vault.py @@ -77,5 +77,5 @@ def test_load_dotenv_vault_not_there(self, find_dotenv): find_dotenv.return_value = '/some/path/' with mock.patch('os.listdir') as mocked_listdir: mocked_listdir.return_value = ['.env', 'some_file'] - with self.assertRaises(FileNotFoundError): - vault.load_dotenv_vault() + path = vault.load_dotenv_vault() + self.assertEqual(path, '/some/path/.env') From 80361df5613ca70f949b4aa318f8aef6a5fa7701 Mon Sep 17 00:00:00 2001 From: nguyen Date: Wed, 26 Jul 2023 23:35:45 -0700 Subject: [PATCH 6/8] bump up major version --- CHANGELOG.md | 4 ++-- setup.py | 1 - src/dotenv_vault/__version__.py | 2 +- src/dotenv_vault/main.py | 2 +- 4 files changed, 4 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bf538d3..89aa5b4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ All notable changes to this project will be documented in this file. See [standa ## [Unreleased](https://github.com/dotenv-org/python-dotenv-vault/compare/v0.5.1...master) -## 0.7.0 +## 0.6.2 ### Changed @@ -14,7 +14,7 @@ All notable changes to this project will be documented in this file. See [standa ### Changed -- Allow to place .env.vault file anywhere in app [#13](https://github.com/dotenv-org/python-dotenv-vault/pull/13) +- Look for .env.vault file at same location as .env file. Finds .env file anywhere in app (just like original python lib) [#13](https://github.com/dotenv-org/python-dotenv-vault/pull/13) ## 0.6.0 diff --git a/setup.py b/setup.py index 795b4ec..c836439 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,4 @@ import os -import sys from setuptools import setup, find_packages src = {} diff --git a/src/dotenv_vault/__version__.py b/src/dotenv_vault/__version__.py index f253c76..c29085b 100644 --- a/src/dotenv_vault/__version__.py +++ b/src/dotenv_vault/__version__.py @@ -1,7 +1,7 @@ __title__ = "python-dotenv-vault" __description__ = "Decrypt .env.vault file." __url__ = "https://github.com/dotenv-org/python-dotenv-vault" -__version__ = "0.6.1" +__version__ = "0.6.2" __author__ = "dotenv" __author_email__ = "mot@dotenv.org" __license__ = "MIT" diff --git a/src/dotenv_vault/main.py b/src/dotenv_vault/main.py index e0bf739..088d081 100644 --- a/src/dotenv_vault/main.py +++ b/src/dotenv_vault/main.py @@ -21,7 +21,7 @@ def load_dotenv_vault() -> str: path = os.path.dirname(path) if '.env.vault' not in os.listdir(path): # we fall back to .env - logger.warning("No .env.vault file found. Falling back to .env") + logger.warning(f"You set DOTENV_KEY but you are missing a .env.vault file at {path}. Did you forget to build it?") return f"{path}/.env" return f"{path}/.env.vault" From 9af1c8830417c00f69264db7d55504024b011db6 Mon Sep 17 00:00:00 2001 From: nguyen Date: Tue, 1 Aug 2023 12:23:19 -0700 Subject: [PATCH 7/8] remove load_dotenv_vault from init --- src/dotenv_vault/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dotenv_vault/__init__.py b/src/dotenv_vault/__init__.py index 54a0aef..211af1d 100644 --- a/src/dotenv_vault/__init__.py +++ b/src/dotenv_vault/__init__.py @@ -1 +1 @@ -from .main import load_dotenv, load_dotenv_vault +from .main import load_dotenv From 8b9b1aaf14e4e8719683fe063303afb3401080f7 Mon Sep 17 00:00:00 2001 From: nguyen Date: Fri, 4 Aug 2023 21:12:13 -0700 Subject: [PATCH 8/8] update changlog --- CHANGELOG.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 89aa5b4..4bce020 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,13 +8,13 @@ All notable changes to this project will be documented in this file. See [standa ### Changed -- Fix fallback issue with gunicorn not respecting the current working directory when attempting to call `find_dotenv`. [#17](https://github.com/dotenv-org/python-dotenv-vault/pull/17) +- Look for .env.vault file at same location as .env file. Finds .env file anywhere in app (just like original python lib) [#13](https://github.com/dotenv-org/python-dotenv-vault/pull/13) ## 0.6.1 ### Changed -- Look for .env.vault file at same location as .env file. Finds .env file anywhere in app (just like original python lib) [#13](https://github.com/dotenv-org/python-dotenv-vault/pull/13) +- Fix fallback issue with gunicorn not respecting the current working directory when attempting to call `find_dotenv`. [#17](https://github.com/dotenv-org/python-dotenv-vault/pull/17) ## 0.6.0