From 513431148e6fee7f3b941acb1599bc9be8979145 Mon Sep 17 00:00:00 2001 From: lassulus Date: Thu, 28 Nov 2024 21:00:12 +0100 Subject: [PATCH] vars: make upload actually upload --- .../clan_cli/vars/secret_modules/__init__.py | 9 ++++---- .../vars/secret_modules/password_store.py | 17 ++++++++++++--- .../clan_cli/vars/secret_modules/sops.py | 10 ++++++++- .../clan_cli/vars/secret_modules/vm.py | 2 +- pkgs/clan-cli/clan_cli/vars/upload.py | 21 +------------------ 5 files changed, 30 insertions(+), 29 deletions(-) diff --git a/pkgs/clan-cli/clan_cli/vars/secret_modules/__init__.py b/pkgs/clan-cli/clan_cli/vars/secret_modules/__init__.py index 697a8ff9b..e1d74eaf3 100644 --- a/pkgs/clan-cli/clan_cli/vars/secret_modules/__init__.py +++ b/pkgs/clan-cli/clan_cli/vars/secret_modules/__init__.py @@ -13,9 +13,6 @@ class SecretStoreBase(StoreBase): def is_secret_store(self) -> bool: return True - def needs_upload(self) -> bool: - return True - def ensure_machine_has_access(self, generator: "Generator", name: str) -> None: pass @@ -39,5 +36,9 @@ class SecretStoreBase(StoreBase): """ @abstractmethod - def upload(self, output_dir: Path) -> None: + def populate_dir(self, output_dir: Path) -> None: + pass + + @abstractmethod + def upload(self) -> None: pass diff --git a/pkgs/clan-cli/clan_cli/vars/secret_modules/password_store.py b/pkgs/clan-cli/clan_cli/vars/secret_modules/password_store.py index 2541dffce..304c64597 100644 --- a/pkgs/clan-cli/clan_cli/vars/secret_modules/password_store.py +++ b/pkgs/clan-cli/clan_cli/vars/secret_modules/password_store.py @@ -4,11 +4,12 @@ import os import tarfile from itertools import chain from pathlib import Path -from typing import override +from tempfile import TemporaryDirectory from clan_cli.cmd import Log, RunOpts, run from clan_cli.machines.machines import Machine from clan_cli.nix import nix_shell +from clan_cli.ssh.upload import upload from clan_cli.vars.generate import Generator, Var from . import SecretStoreBase @@ -131,7 +132,6 @@ class SecretStore(SecretStoreBase): manifest += hashes return b"\n".join(manifest) - @override def needs_upload(self) -> bool: local_hash = self.generate_hash() remote_hash = self.machine.target_host.run( @@ -150,7 +150,7 @@ class SecretStore(SecretStoreBase): return local_hash.decode() != remote_hash - def upload(self, output_dir: Path) -> None: + def populate_dir(self, output_dir: Path) -> None: with tarfile.open(output_dir / "secrets.tar.gz", "w:gz") as tar: for generator in self.machine.vars_generators: dir_exists = False @@ -173,3 +173,14 @@ class SecretStore(SecretStoreBase): tar_file.gname = file.group tar.addfile(tarinfo=tar_file, fileobj=io.BytesIO(content)) (output_dir / ".pass_info").write_bytes(self.generate_hash()) + + def upload(self) -> None: + if not self.needs_upload(): + log.info("Secrets already uploaded") + return + with TemporaryDirectory(prefix="vars-upload-") as tempdir: + pass_dir = Path(tempdir) + upload_dir = Path( + self.machine.deployment["password-store"]["secretLocation"] + ) + upload(self.machine.target_host, pass_dir, upload_dir) diff --git a/pkgs/clan-cli/clan_cli/vars/secret_modules/sops.py b/pkgs/clan-cli/clan_cli/vars/secret_modules/sops.py index 3b60f471a..018ac2bb5 100644 --- a/pkgs/clan-cli/clan_cli/vars/secret_modules/sops.py +++ b/pkgs/clan-cli/clan_cli/vars/secret_modules/sops.py @@ -1,5 +1,6 @@ from dataclasses import dataclass from pathlib import Path +from tempfile import TemporaryDirectory from typing import override from clan_cli.errors import ClanError @@ -17,6 +18,7 @@ from clan_cli.secrets.secrets import ( encrypt_secret, has_secret, ) +from clan_cli.ssh.upload import upload from clan_cli.vars.generate import Generator from clan_cli.vars.var import Var @@ -114,7 +116,7 @@ class SecretStore(SecretStoreBase): self.machine.flake_dir, self.secret_path(generator, name) ).encode("utf-8") - def upload(self, output_dir: Path) -> None: + def populate_dir(self, output_dir: Path) -> None: key_name = f"{self.machine.name}-age.key" if not has_secret(sops_secrets_folder(self.machine.flake_dir) / key_name): # skip uploading the secret, not managed by us @@ -125,6 +127,12 @@ class SecretStore(SecretStoreBase): ) (output_dir / "key.txt").write_text(key) + def upload(self) -> None: + with TemporaryDirectory(prefix="sops-upload-") as tempdir: + sops_upload_dir = Path(tempdir) + self.populate_dir(sops_upload_dir) + upload(self.machine.target_host, sops_upload_dir, Path("/var/lib/sops-nix")) + def exists(self, generator: Generator, name: str) -> bool: secret_folder = self.secret_path(generator, name) return (secret_folder / "secret").exists() diff --git a/pkgs/clan-cli/clan_cli/vars/secret_modules/vm.py b/pkgs/clan-cli/clan_cli/vars/secret_modules/vm.py index 7699345dd..f6cb1b141 100644 --- a/pkgs/clan-cli/clan_cli/vars/secret_modules/vm.py +++ b/pkgs/clan-cli/clan_cli/vars/secret_modules/vm.py @@ -33,7 +33,7 @@ class SecretStore(SecretStoreBase): secret_file = self.dir / generator.name / name return secret_file.read_bytes() - def upload(self, output_dir: Path) -> None: + def populate_dir(self, output_dir: Path) -> None: if output_dir.exists(): shutil.rmtree(output_dir) shutil.copytree(self.dir, output_dir) diff --git a/pkgs/clan-cli/clan_cli/vars/upload.py b/pkgs/clan-cli/clan_cli/vars/upload.py index 1c3f0c73f..e71977f8a 100644 --- a/pkgs/clan-cli/clan_cli/vars/upload.py +++ b/pkgs/clan-cli/clan_cli/vars/upload.py @@ -1,13 +1,9 @@ import argparse import importlib import logging -from pathlib import Path -from tempfile import TemporaryDirectory from clan_cli.completions import add_dynamic_completer, complete_machines -from clan_cli.errors import ClanError from clan_cli.machines.machines import Machine -from clan_cli.ssh.upload import upload log = logging.getLogger(__name__) @@ -15,22 +11,7 @@ log = logging.getLogger(__name__) def upload_secret_vars(machine: Machine) -> None: secret_store_module = importlib.import_module(machine.secret_vars_module) secret_store = secret_store_module.SecretStore(machine=machine) - - if not secret_store.needs_upload(): - log.info("Secrets already uploaded") - return - with TemporaryDirectory(prefix="vars-upload-") as tempdir: - secret_dir = Path(tempdir) - secret_store.upload(secret_dir) - if secret_store.store_name == "password-store": - upload_dir = Path(machine.deployment["password-store"]["secretLocation"]) - upload(machine.target_host, secret_dir, upload_dir) - elif secret_store.store_name == "sops": - upload_dir = Path("/var/lib/sops-nix") - upload(machine.target_host, secret_dir, upload_dir) - else: - msg = "upload function used on unsuitable secret_store" - raise ClanError(msg) + secret_store.upload() def upload_command(args: argparse.Namespace) -> None: