pyinfra/scripts/bw2secrets
2024-06-08 00:53:33 +02:00

109 lines
2.7 KiB
Python
Executable file

#!/usr/bin/env python3
import argparse
import getpass
import shutil
import subprocess as sp
from pathlib import Path
import jinja2
bitwarden_session = None
def _add_args(parser: argparse.ArgumentParser):
parser.add_argument(
"search_paths",
help="start directory to walk files to find secret references",
default=".",
nargs="*",
)
parser.add_argument(
"--bw-path", "-b",
help="custom path for bitwarden cli executable",
default=shutil.which("bw"),
)
def init_bw_session(bw_path: Path):
global bitwarden_session
if (pw_file := Path("./.bw2secrets")).exists():
bitwarden_password = pw_file.read_text().strip()
else:
print("Please, provide your bitwarden master password")
bitwarden_password = getpass.getpass("Master password: ")
res = sp.run(
[bw_path, "unlock", bitwarden_password, "--raw"], capture_output=True,
text=True,
)
res.check_returncode()
bitwarden_session = res.stdout
def find_templates(base_dirs: set[Path]) -> set[Path]:
env_templates: set[Path] = set()
for path in base_dirs:
for env_template in path.glob(f"{path}/**/*.template"):
env_templates.add(env_template)
return env_templates
def fetch_secret(bw_path: Path, secret_id: str) -> str:
global bitwarden_session
res = sp.run(
[bw_path, "get", "password", secret_id, "--session", bitwarden_session],
capture_output=True,
text=True,
)
res.check_returncode()
return res.stdout
def secret_filter(bw_path: Path, secret_id: str) -> str:
return fetch_secret(bw_path, secret_id)
def compile_file(file_path: Path, bw_path: Path):
jinja_env = jinja2.Environment(
loader=jinja2.FileSystemLoader(file_path.parent),
)
jinja_env.filters['secret'] = lambda secret_id: secret_filter(
bw_path, secret_id,
)
template = jinja_env.get_template(file_path.name)
rendered_template = template.render()
file_path.with_name(
file_path.name.replace(
".template", "",
),
).write_text(rendered_template)
def main() -> int:
parser = argparse.ArgumentParser("bw2secrets")
_add_args(parser)
args = parser.parse_args()
if not (bw_path := args.bw_path):
print("Bitwarden CLI `bw` executable not found in PATH")
return 1
search_paths: set[Path | None] = set()
for path in args.search_paths:
search_path = Path(path)
search_paths.add(search_path)
template_files = find_templates(search_paths)
init_bw_session(bw_path)
for file in template_files:
compile_file(file, bw_path)
return 0
if __name__ == "__main__":
raise SystemExit(main())