From 4a389b0fb312df308907035a4e3b301f8136a399 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Wed, 13 Nov 2024 13:23:47 +0100 Subject: [PATCH 1/3] vars/sops: simplify conditional in exists --- pkgs/clan-cli/clan_cli/vars/secret_modules/sops.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) 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 840fec357..df21fb8f4 100644 --- a/pkgs/clan-cli/clan_cli/vars/secret_modules/sops.py +++ b/pkgs/clan-cli/clan_cli/vars/secret_modules/sops.py @@ -150,9 +150,7 @@ class SecretStore(SecretStoreBase): secret_folder = self.secret_path(generator_name, name, shared) if not (secret_folder / "secret").exists(): return False - if not shared: - return True - return self.machine_has_access(generator_name, name, shared) + return not shared or self.machine_has_access(generator_name, name, shared) def collect_keys_for_secret(self, path: Path) -> set[tuple[str, KeyType]]: from clan_cli.secrets.secrets import ( From 8f1e5ed1ebd02f24f92d7d9c6813f8521fd2dab4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Thu, 14 Nov 2024 13:16:32 +0100 Subject: [PATCH 2/3] vars/get: use machine_name as variable name --- pkgs/clan-cli/clan_cli/vars/get.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/pkgs/clan-cli/clan_cli/vars/get.py b/pkgs/clan-cli/clan_cli/vars/get.py index 37d44dcd0..253167b0f 100644 --- a/pkgs/clan-cli/clan_cli/vars/get.py +++ b/pkgs/clan-cli/clan_cli/vars/get.py @@ -41,9 +41,9 @@ def get_var(machine: Machine, var_id: str) -> Var: raise ClanError(msg) -def get_command(machine: str, var_id: str, flake: FlakeId) -> None: - _machine = Machine(name=machine, flake=flake) - var = get_var(_machine, var_id) +def get_command(machine_name: str, var_id: str, flake: FlakeId) -> None: + machine = Machine(name=machine_name, flake=flake) + var = get_var(machine, var_id) if not var.exists: msg = f"Var {var.id} has not been generated yet" raise ClanError(msg) @@ -57,7 +57,7 @@ def _get_command( args: argparse.Namespace, ) -> None: get_command( - machine=args.machine, + machine_name=args.machine, var_id=args.var_id, flake=args.flake, ) From c98055c78130ef2061c04dabdc59ab2724a14d31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=B6rg=20Thalheim?= Date: Thu, 14 Nov 2024 13:17:50 +0100 Subject: [PATCH 3/3] vars: introduce ensure_machine_has_access method for sops this should help avoiding overriding existing shared secrets by not triggering vars regeneration if a machine has no access. wip --- pkgs/clan-cli/clan_cli/vars/generate.py | 6 ++- .../clan_cli/vars/secret_modules/__init__.py | 5 +++ .../clan_cli/vars/secret_modules/sops.py | 39 +++++++++---------- 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/pkgs/clan-cli/clan_cli/vars/generate.py b/pkgs/clan-cli/clan_cli/vars/generate.py index 178da5068..e20de0c7a 100644 --- a/pkgs/clan-cli/clan_cli/vars/generate.py +++ b/pkgs/clan-cli/clan_cli/vars/generate.py @@ -337,8 +337,12 @@ def ensure_consistent_state( for name, file in machine.vars_generators[generator_name]["files"].items(): shared = machine.vars_generators[generator_name]["share"] if file["secret"] and machine.secret_vars_store.exists( - generator_name, name + generator_name, name, shared=shared ): + if file["deploy"]: + machine.secret_vars_store.ensure_machine_has_access( + generator_name, name, shared=shared + ) needs_update, msg = machine.secret_vars_store.needs_fix( generator_name, name, shared=shared ) 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 1134685a3..31845eb76 100644 --- a/pkgs/clan-cli/clan_cli/vars/secret_modules/__init__.py +++ b/pkgs/clan-cli/clan_cli/vars/secret_modules/__init__.py @@ -12,6 +12,11 @@ class SecretStoreBase(StoreBase): def needs_upload(self) -> bool: return True + def ensure_machine_has_access( + self, generator_name: str, name: str, shared: bool = False + ) -> None: + pass + def needs_fix( self, generator_name: str, 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 df21fb8f4..ca4899cae 100644 --- a/pkgs/clan-cli/clan_cli/vars/secret_modules/sops.py +++ b/pkgs/clan-cli/clan_cli/vars/secret_modules/sops.py @@ -110,20 +110,15 @@ class SecretStore(SecretStoreBase): self.backend_collision_error(secret_folder) # create directory if it doesn't exist secret_folder.mkdir(parents=True, exist_ok=True) - if shared and self.exists_shared(generator_name, name): - # secret exists, but this machine doesn't have access -> add machine - # add_secret will be a no-op if the machine is already added - add_secret(self.machine.flake_dir, self.machine.name, secret_folder) - else: - # initialize the secret - encrypt_secret( - self.machine.flake_dir, - secret_folder, - value, - add_machines=[self.machine.name] if deployed else [], - add_groups=self.machine.deployment["sops"]["defaultGroups"], - git_commit=False, - ) + # initialize the secret + encrypt_secret( + self.machine.flake_dir, + secret_folder, + value, + add_machines=[self.machine.name] if deployed else [], + add_groups=self.machine.deployment["sops"]["defaultGroups"], + git_commit=False, + ) return secret_folder def get(self, generator_name: str, name: str, shared: bool = False) -> bytes: @@ -142,15 +137,17 @@ class SecretStore(SecretStoreBase): ) (output_dir / "key.txt").write_text(key) - def exists_shared(self, generator_name: str, name: str) -> bool: - secret_folder = self.secret_path(generator_name, name, shared=True) - return (secret_folder / "secret").exists() - def exists(self, generator_name: str, name: str, shared: bool = False) -> bool: secret_folder = self.secret_path(generator_name, name, shared) - if not (secret_folder / "secret").exists(): - return False - return not shared or self.machine_has_access(generator_name, name, shared) + return (secret_folder / "secret").exists() + + def ensure_machine_has_access( + self, generator_name: str, name: str, shared: bool = False + ) -> None: + if self.machine_has_access(generator_name, name, shared): + return + secret_folder = self.secret_path(generator_name, name, shared) + add_secret(self.machine.flake_dir, self.machine.name, secret_folder) def collect_keys_for_secret(self, path: Path) -> set[tuple[str, KeyType]]: from clan_cli.secrets.secrets import (