Skip to content

Commit

Permalink
Merge pull request #13 from dotenv-org/find-dotenv-vault-file
Browse files Browse the repository at this point in the history
allow to find .env.vault
  • Loading branch information
motdotla authored Aug 5, 2023
2 parents 1475d88 + 8b9b1aa commit 8d78a70
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 6 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ 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.2

### 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)

## 0.6.1

### Changed
Expand Down
1 change: 0 additions & 1 deletion setup.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import os
import sys
from setuptools import setup, find_packages

src = {}
Expand Down
2 changes: 1 addition & 1 deletion src/dotenv_vault/__version__.py
Original file line number Diff line number Diff line change
@@ -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__ = "[email protected]"
__license__ = "MIT"
19 changes: 17 additions & 2 deletions src/dotenv_vault/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,28 @@
from base64 import b64decode
import io
import os
import logging

from typing import (IO, Optional, Union)
from urllib.parse import urlparse, parse_qsl

from cryptography.hazmat.primitives.ciphers.aead import AESGCM
from cryptography.exceptions import InvalidTag
import dotenv.main as dotenv

logger = logging.getLogger(__name__)

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):
# we fall 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"


def load_dotenv(
dotenv_path: Union[str, os.PathLike, None] = None,
Expand Down Expand Up @@ -40,7 +55,7 @@ def load_dotenv(
"""
if "DOTENV_KEY" in os.environ:
vault_stream = parse_vault(open(".env.vault"))
vault_stream = parse_vault(open(load_dotenv_vault()))
return dotenv.load_dotenv(
stream=vault_stream,
verbose=verbose,
Expand Down Expand Up @@ -75,7 +90,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=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
Expand Down
22 changes: 20 additions & 2 deletions src/dotenv_vault/test_vault.py
Original file line number Diff line number Diff line change
@@ -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",
Expand All @@ -23,7 +25,7 @@ class TestParsing(unittest.TestCase):
# Missing environment.
["dotenv://:[email protected]/vault/.env.vault", False, ""]
]

def test_key_parsing(self):
for test in self.TEST_KEYS:
dotenv_key, should_pass, environment_key_check = test
Expand All @@ -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
Expand All @@ -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']
path = vault.load_dotenv_vault()
self.assertEqual(path, '/some/path/.env')

0 comments on commit 8d78a70

Please sign in to comment.