Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

initial release #1

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

Manage secrets for your application using Faraday's [Secretfile spec](https://github.com/faradayio/Secretfile)

Warning: This library is a work in progress and has not yet been officially released.
Warning: This library is a work in progress and has not yet been officially released.
210 changes: 210 additions & 0 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[tool.poetry]
name = "secretfile"
version = "0.1.0"
description = ""
authors = ["Tom Caruso <[email protected]>"]

[tool.poetry.dependencies]
python = "^3.10"
hvac = "^1.1.1"
click = "^8.1.3"

[tool.poetry.dev-dependencies]
pytest = "^5.2"

[tool.poetry.scripts]
# command_name = module_for_handler : function_for_handler
secretfile = 'secretfile.cli:main'

[build-system]
requires = ["poetry-core>=1.0.0"]
build-backend = "poetry.core.masonry.api"

5 changes: 5 additions & 0 deletions secretfile/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
__version__ = '0.1.0'


from secretfile.secretfile import Secretfile, set_backend, ensure_backend
from secretfile import backends
3 changes: 3 additions & 0 deletions secretfile/backends/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from secretfile.backends.meta import SecretBackend
from secretfile.backends.vault import VaultBackend
from secretfile.backends.memory import MemoryBackend
9 changes: 9 additions & 0 deletions secretfile/backends/memory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
from secretfile.backends.meta import SecretBackend


class MemoryBackend(SecretBackend):
def __init__(self, secrets: dict[str, str]):
self._secrets = secrets

def get_secret(self, path):
return self._secrets[path]
18 changes: 18 additions & 0 deletions secretfile/backends/meta.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from abc import ABCMeta, abstractmethod


class SecretBackend(metaclass=ABCMeta):

@abstractmethod
def get_secret(self, path):
pass

def get(self, path):
return self.deserialize_secret(self.get_secret(path))

def deserialize_secret(self, secret):
"""
Deserialize the secret from the backend. It's likely that most backends won't need this,
but it's here for the ones that do.
"""
return secret
32 changes: 32 additions & 0 deletions secretfile/backends/vault.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import os
from typing import Any

import hvac

from secretfile.backends.meta import SecretBackend
from secretfile.exceptions import BackendConfigurationError


class VaultBackend(SecretBackend):
def __init__(self):
if "VAULT_ADDR" not in os.environ:
raise BackendConfigurationError("VAULT_ADDR is not set.")
if "VAULT_TOKEN" not in os.environ:
raise BackendConfigurationError("VAULT_TOKEN is not set.")

def get_secret(self, path):
return vault_get_path(path)



def vault_get_path(path: str) -> Any:
"""Get data at a given path from vault. User is expected to unpack correctly."""
hvac_client = hvac.Client(
url=os.environ["VAULT_ADDR"], token=os.environ["VAULT_TOKEN"]
)
response = hvac_client.read(path)
if response and "data" in response:
return response["data"]
else:
raise Exception(f"Could not access {path} in Vault: {response}")

19 changes: 19 additions & 0 deletions secretfile/cli.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from typing import List
import click

from secretfile.secretfile import Secretfile


@click.group()
def main():
pass


@main.command()
@click.option('--ignore', '-i', multiple=True, help="Ignore a key in the Secretfile.")
def read(ignore: List[str]):
"""Reads the Secretfile and prints out the values in a form which can be `source`d in a shell."""
for key, value in Secretfile.items():
if key in ignore:
continue
click.echo(f"export {key}={value}")
7 changes: 7 additions & 0 deletions secretfile/exceptions.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@

class SecretfileBaseException(Exception):
pass


class BackendConfigurationError(SecretfileBaseException):
pass
Loading